From 997f12a59278fd55d6570534fe82511d876ee24f Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Thu, 6 Apr 2017 19:14:04 -0700 Subject: [PATCH] removed all contents --- COPYING | 17 - Jenkinsfile | 382 - LICENSE.GPL-2 | 339 - LICENSE.GPL-3 | 674 - Makefile | 22 - README.md | 108 - check.sh | 16 - docs/android.md | 65 - docs/docker.md | 94 - docs/faq.md | 89 - docs/img/api_diagram.png | Bin 415769 -> 0 bytes docs/img/app_flow.png | Bin 53356 -> 0 bytes docs/img/methods.png | Bin 284198 -> 0 bytes docs/img/zt_app_flow.png | Bin 99656 -> 0 bytes docs/img/zt_why.png | Bin 198231 -> 0 bytes docs/integrations.md | 59 - docs/intro.md | 105 - docs/ios.md | 54 - docs/ios_unity3d.md | 98 - docs/linux.md | 164 - docs/network_stacks.md | 25 - docs/osx.md | 78 - docs/osx_unity3d.md | 103 - docs/technical.md | 169 - docs/tests.md | 79 - docs/walkthrough.md | 54 - ext/README.md | 1 - ext/contrib/README.md | 15 - ext/contrib/ports/unix/proj/lib/Makefile | 106 - ext/contrib/ports/unix/proj/lib/README | 31 - ext/contrib/ports/unix/proj/lib/lwipopts.h | 468 - ext/contrib/ports/unix/proj/lib/unixlib.c | 73 - ext/lwip/CHANGELOG | 4126 ------ ext/lwip/COPYING | 33 - ext/lwip/FILES | 4 - ext/lwip/README | 97 - ext/lwip/UPGRADING | 217 - ext/lwip/doc/FILES | 6 - ext/lwip/doc/contrib.txt | 58 - ext/lwip/doc/doxygen/generate.bat | 1 - ext/lwip/doc/doxygen/generate.sh | 1 - ext/lwip/doc/doxygen/main_page.h | 32 - ext/lwip/doc/ppp.txt | 529 - ext/lwip/doc/rawapi.txt | 506 - ext/lwip/doc/savannah.txt | 120 - ext/lwip/doc/sys_arch.txt | 267 - ext/lwip/src/FILES | 13 - ext/lwip/src/Filelists.mk | 169 - ext/lwip/src/api/api_lib.c | 993 -- ext/lwip/src/api/api_msg.c | 1946 --- ext/lwip/src/api/err.c | 75 - ext/lwip/src/api/netbuf.c | 263 - ext/lwip/src/api/netdb.c | 417 - ext/lwip/src/api/netifapi.c | 224 - ext/lwip/src/api/sockets.c | 2803 ---- ext/lwip/src/api/tcpip.c | 511 - ext/lwip/src/apps/httpd/fs.c | 179 - ext/lwip/src/apps/httpd/fs/404.html | 21 - ext/lwip/src/apps/httpd/fs/img/sics.gif | Bin 724 -> 0 bytes ext/lwip/src/apps/httpd/fs/index.html | 47 - ext/lwip/src/apps/httpd/fsdata.c | 298 - ext/lwip/src/apps/httpd/fsdata.h | 50 - ext/lwip/src/apps/httpd/httpd.c | 2693 ---- ext/lwip/src/apps/httpd/httpd_structs.h | 114 - ext/lwip/src/apps/httpd/makefsdata/makefsdata | 97 - .../src/apps/httpd/makefsdata/makefsdata.c | 1033 -- ext/lwip/src/apps/httpd/makefsdata/readme.txt | 13 - ext/lwip/src/apps/lwiperf/lwiperf.c | 662 - ext/lwip/src/apps/netbiosns/netbiosns.c | 366 - ext/lwip/src/apps/snmp/README | 38 - ext/lwip/src/apps/snmp/snmp_asn1.c | 749 - ext/lwip/src/apps/snmp/snmp_asn1.h | 108 - ext/lwip/src/apps/snmp/snmp_core.c | 1312 -- ext/lwip/src/apps/snmp/snmp_core_priv.h | 76 - ext/lwip/src/apps/snmp/snmp_mib2.c | 116 - ext/lwip/src/apps/snmp/snmp_mib2_icmp.c | 182 - ext/lwip/src/apps/snmp/snmp_mib2_interfaces.c | 376 - ext/lwip/src/apps/snmp/snmp_mib2_ip.c | 743 - ext/lwip/src/apps/snmp/snmp_mib2_snmp.c | 227 - ext/lwip/src/apps/snmp/snmp_mib2_system.c | 377 - ext/lwip/src/apps/snmp/snmp_mib2_tcp.c | 594 - ext/lwip/src/apps/snmp/snmp_mib2_udp.c | 357 - ext/lwip/src/apps/snmp/snmp_msg.c | 1657 --- ext/lwip/src/apps/snmp/snmp_msg.h | 193 - ext/lwip/src/apps/snmp/snmp_netconn.c | 120 - ext/lwip/src/apps/snmp/snmp_pbuf_stream.c | 156 - ext/lwip/src/apps/snmp/snmp_pbuf_stream.h | 73 - ext/lwip/src/apps/snmp/snmp_raw.c | 100 - ext/lwip/src/apps/snmp/snmp_scalar.c | 220 - ext/lwip/src/apps/snmp/snmp_table.c | 343 - ext/lwip/src/apps/snmp/snmp_threadsync.c | 218 - ext/lwip/src/apps/snmp/snmp_traps.c | 443 - ext/lwip/src/apps/snmp/snmpv3.c | 136 - ext/lwip/src/apps/snmp/snmpv3_dummy.c | 145 - ext/lwip/src/apps/snmp/snmpv3_mbedtls.c | 331 - ext/lwip/src/apps/snmp/snmpv3_priv.h | 66 - ext/lwip/src/apps/sntp/sntp.c | 726 - ext/lwip/src/core/def.c | 108 - ext/lwip/src/core/dns.c | 1502 -- ext/lwip/src/core/inet_chksum.c | 612 - ext/lwip/src/core/init.c | 388 - ext/lwip/src/core/ip.c | 124 - ext/lwip/src/core/ipv4/autoip.c | 546 - ext/lwip/src/core/ipv4/dhcp.c | 1924 --- ext/lwip/src/core/ipv4/etharp.c | 1385 -- ext/lwip/src/core/ipv4/icmp.c | 393 - ext/lwip/src/core/ipv4/igmp.c | 841 -- ext/lwip/src/core/ipv4/ip4.c | 1073 -- ext/lwip/src/core/ipv4/ip4_addr.c | 331 - ext/lwip/src/core/ipv4/ip4_frag.c | 897 -- ext/lwip/src/core/ipv6/README | 1 - ext/lwip/src/core/ipv6/dhcp6.c | 50 - ext/lwip/src/core/ipv6/ethip6.c | 157 - ext/lwip/src/core/ipv6/icmp6.c | 349 - ext/lwip/src/core/ipv6/inet6.c | 53 - ext/lwip/src/core/ipv6/ip6.c | 1108 -- ext/lwip/src/core/ipv6/ip6_addr.c | 292 - ext/lwip/src/core/ipv6/ip6_frag.c | 776 - ext/lwip/src/core/ipv6/mld6.c | 598 - ext/lwip/src/core/ipv6/nd6.c | 1884 --- ext/lwip/src/core/mem.c | 777 - ext/lwip/src/core/memp.c | 501 - ext/lwip/src/core/netif.c | 1078 -- ext/lwip/src/core/pbuf.c | 1367 -- ext/lwip/src/core/raw.c | 504 - ext/lwip/src/core/stats.c | 169 - ext/lwip/src/core/sys.c | 68 - ext/lwip/src/core/tcp.c | 2098 --- ext/lwip/src/core/tcp_in.c | 1816 --- ext/lwip/src/core/tcp_out.c | 1608 -- ext/lwip/src/core/timeouts.c | 435 - ext/lwip/src/core/udp.c | 1223 -- ext/lwip/src/include/arch/cc.h | 90 - ext/lwip/src/include/arch/perf.h | 63 - ext/lwip/src/include/arch/sys_arch.h | 59 - ext/lwip/src/include/lwip/api.h | 375 - ext/lwip/src/include/lwip/apps/FILES | 2 - ext/lwip/src/include/lwip/apps/fs.h | 103 - ext/lwip/src/include/lwip/apps/httpd.h | 236 - ext/lwip/src/include/lwip/apps/httpd_opts.h | 345 - ext/lwip/src/include/lwip/apps/lwiperf.h | 84 - ext/lwip/src/include/lwip/apps/netbiosns.h | 43 - .../src/include/lwip/apps/netbiosns_opts.h | 69 - ext/lwip/src/include/lwip/apps/snmp.h | 127 - ext/lwip/src/include/lwip/apps/snmp_core.h | 364 - ext/lwip/src/include/lwip/apps/snmp_mib2.h | 78 - ext/lwip/src/include/lwip/apps/snmp_opts.h | 289 - ext/lwip/src/include/lwip/apps/snmp_scalar.h | 113 - ext/lwip/src/include/lwip/apps/snmp_table.h | 134 - .../src/include/lwip/apps/snmp_threadsync.h | 114 - ext/lwip/src/include/lwip/apps/snmpv3.h | 90 - ext/lwip/src/include/lwip/apps/sntp.h | 76 - ext/lwip/src/include/lwip/apps/sntp_opts.h | 173 - ext/lwip/src/include/lwip/arch.h | 332 - ext/lwip/src/include/lwip/autoip.h | 98 - ext/lwip/src/include/lwip/debug.h | 112 - ext/lwip/src/include/lwip/def.h | 141 - ext/lwip/src/include/lwip/dhcp.h | 289 - ext/lwip/src/include/lwip/dhcp6.h | 58 - ext/lwip/src/include/lwip/dns.h | 118 - ext/lwip/src/include/lwip/err.h | 113 - ext/lwip/src/include/lwip/etharp.h | 151 - ext/lwip/src/include/lwip/ethip6.h | 66 - ext/lwip/src/include/lwip/icmp.h | 152 - ext/lwip/src/include/lwip/icmp6.h | 191 - ext/lwip/src/include/lwip/igmp.h | 113 - ext/lwip/src/include/lwip/inet.h | 172 - ext/lwip/src/include/lwip/inet_chksum.h | 111 - ext/lwip/src/include/lwip/init.h | 100 - ext/lwip/src/include/lwip/ip.h | 315 - ext/lwip/src/include/lwip/ip4.h | 166 - ext/lwip/src/include/lwip/ip4_addr.h | 257 - ext/lwip/src/include/lwip/ip4_frag.h | 100 - ext/lwip/src/include/lwip/ip6.h | 197 - ext/lwip/src/include/lwip/ip6_addr.h | 311 - ext/lwip/src/include/lwip/ip6_frag.h | 120 - ext/lwip/src/include/lwip/ip_addr.h | 360 - ext/lwip/src/include/lwip/mem.h | 81 - ext/lwip/src/include/lwip/memp.h | 153 - ext/lwip/src/include/lwip/mld6.h | 120 - ext/lwip/src/include/lwip/nd6.h | 362 - ext/lwip/src/include/lwip/netbuf.h | 118 - ext/lwip/src/include/lwip/netdb.h | 151 - ext/lwip/src/include/lwip/netif.h | 442 - ext/lwip/src/include/lwip/netifapi.h | 136 - ext/lwip/src/include/lwip/opt.h | 2797 ---- ext/lwip/src/include/lwip/pbuf.h | 238 - ext/lwip/src/include/lwip/priv/api_msg.h | 217 - ext/lwip/src/include/lwip/priv/memp_priv.h | 183 - ext/lwip/src/include/lwip/priv/memp_std.h | 146 - ext/lwip/src/include/lwip/priv/tcp_priv.h | 550 - ext/lwip/src/include/lwip/priv/tcpip_priv.h | 160 - ext/lwip/src/include/lwip/raw.h | 116 - ext/lwip/src/include/lwip/sio.h | 142 - ext/lwip/src/include/lwip/snmp.h | 213 - ext/lwip/src/include/lwip/sockets.h | 592 - ext/lwip/src/include/lwip/stats.h | 491 - ext/lwip/src/include/lwip/sys.h | 491 - ext/lwip/src/include/lwip/tcp.h | 423 - ext/lwip/src/include/lwip/tcpip.h | 104 - ext/lwip/src/include/lwip/timeouts.h | 121 - ext/lwip/src/include/lwip/udp.h | 201 - ext/lwip/src/include/netif/etharp.h | 2 - ext/lwip/src/include/netif/ethernet.h | 177 - ext/lwip/src/include/netif/lowpan6.h | 86 - ext/lwip/src/include/netif/lowpan6_opts.h | 70 - ext/lwip/src/include/netif/ppp/ccp.h | 156 - ext/lwip/src/include/netif/ppp/chap-md5.h | 36 - ext/lwip/src/include/netif/ppp/chap-new.h | 192 - ext/lwip/src/include/netif/ppp/chap_ms.h | 44 - ext/lwip/src/include/netif/ppp/eap.h | 169 - ext/lwip/src/include/netif/ppp/ecp.h | 50 - ext/lwip/src/include/netif/ppp/eui64.h | 94 - ext/lwip/src/include/netif/ppp/fsm.h | 175 - ext/lwip/src/include/netif/ppp/ipcp.h | 126 - ext/lwip/src/include/netif/ppp/ipv6cp.h | 183 - ext/lwip/src/include/netif/ppp/lcp.h | 171 - ext/lwip/src/include/netif/ppp/magic.h | 122 - ext/lwip/src/include/netif/ppp/mppe.h | 173 - .../src/include/netif/ppp/polarssl/arc4.h | 81 - ext/lwip/src/include/netif/ppp/polarssl/des.h | 92 - ext/lwip/src/include/netif/ppp/polarssl/md4.h | 97 - ext/lwip/src/include/netif/ppp/polarssl/md5.h | 96 - .../src/include/netif/ppp/polarssl/sha1.h | 96 - ext/lwip/src/include/netif/ppp/ppp.h | 688 - ext/lwip/src/include/netif/ppp/ppp_impl.h | 632 - ext/lwip/src/include/netif/ppp/ppp_opts.h | 593 - ext/lwip/src/include/netif/ppp/pppapi.h | 137 - ext/lwip/src/include/netif/ppp/pppcrypt.h | 136 - ext/lwip/src/include/netif/ppp/pppdebug.h | 80 - ext/lwip/src/include/netif/ppp/pppoe.h | 179 - ext/lwip/src/include/netif/ppp/pppol2tp.h | 201 - ext/lwip/src/include/netif/ppp/pppos.h | 118 - ext/lwip/src/include/netif/ppp/upap.h | 123 - ext/lwip/src/include/netif/ppp/vj.h | 161 - ext/lwip/src/include/netif/slipif.h | 87 - ext/lwip/src/include/posix/netdb.h | 33 - ext/lwip/src/include/posix/sys/socket.h | 33 - ext/lwip/src/netif/FILES | 31 - ext/lwip/src/netif/ethernet.c | 228 - ext/lwip/src/netif/ethernetif.c | 335 - ext/lwip/src/netif/lowpan6.c | 1204 -- ext/lwip/src/netif/ppp/PPPD_FOLLOWUP | 473 - ext/lwip/src/netif/ppp/auth.c | 2503 ---- ext/lwip/src/netif/ppp/ccp.c | 1740 --- ext/lwip/src/netif/ppp/chap-md5.c | 126 - ext/lwip/src/netif/ppp/chap-new.c | 677 - ext/lwip/src/netif/ppp/chap_ms.c | 962 -- ext/lwip/src/netif/ppp/demand.c | 465 - ext/lwip/src/netif/ppp/eap.c | 2423 --- ext/lwip/src/netif/ppp/ecp.c | 191 - ext/lwip/src/netif/ppp/eui64.c | 56 - ext/lwip/src/netif/ppp/fsm.c | 799 - ext/lwip/src/netif/ppp/ipcp.c | 2408 --- ext/lwip/src/netif/ppp/ipv6cp.c | 1533 -- ext/lwip/src/netif/ppp/lcp.c | 2786 ---- ext/lwip/src/netif/ppp/magic.c | 294 - ext/lwip/src/netif/ppp/mppe.c | 412 - ext/lwip/src/netif/ppp/multilink.c | 609 - ext/lwip/src/netif/ppp/polarssl/README | 22 - ext/lwip/src/netif/ppp/polarssl/arc4.c | 101 - ext/lwip/src/netif/ppp/polarssl/des.c | 422 - ext/lwip/src/netif/ppp/polarssl/md4.c | 281 - ext/lwip/src/netif/ppp/polarssl/md5.c | 300 - ext/lwip/src/netif/ppp/polarssl/sha1.c | 335 - ext/lwip/src/netif/ppp/ppp.c | 1640 --- ext/lwip/src/netif/ppp/pppapi.c | 422 - ext/lwip/src/netif/ppp/pppcrypt.c | 66 - ext/lwip/src/netif/ppp/pppoe.c | 1259 -- ext/lwip/src/netif/ppp/pppol2tp.c | 1150 -- ext/lwip/src/netif/ppp/pppos.c | 877 -- ext/lwip/src/netif/ppp/upap.c | 677 - ext/lwip/src/netif/ppp/utils.c | 961 -- ext/lwip/src/netif/ppp/vj.c | 695 - ext/lwip/src/netif/slipif.c | 555 - ext/lwip/test/unit/core/test_mem.c | 121 - ext/lwip/test/unit/core/test_mem.h | 8 - ext/lwip/test/unit/core/test_pbuf.c | 239 - ext/lwip/test/unit/core/test_pbuf.h | 8 - ext/lwip/test/unit/dhcp/test_dhcp.c | 915 -- ext/lwip/test/unit/dhcp/test_dhcp.h | 8 - ext/lwip/test/unit/etharp/test_etharp.c | 268 - ext/lwip/test/unit/etharp/test_etharp.h | 8 - ext/lwip/test/unit/lwip_check.h | 37 - ext/lwip/test/unit/lwip_unittests.c | 68 - ext/lwip/test/unit/lwipopts.h | 57 - ext/lwip/test/unit/tcp/tcp_helper.c | 305 - ext/lwip/test/unit/tcp/tcp_helper.h | 52 - ext/lwip/test/unit/tcp/test_tcp.c | 742 - ext/lwip/test/unit/tcp/test_tcp.h | 8 - ext/lwip/test/unit/tcp/test_tcp_oos.c | 1049 -- ext/lwip/test/unit/tcp/test_tcp_oos.h | 8 - ext/lwip/test/unit/udp/test_udp.c | 68 - ext/lwip/test/unit/udp/test_udp.h | 8 - ext/lwipopts.h | 2 - ext/picotcp/.gitignore | 24 - ext/picotcp/.travis.yml | 13 - ext/picotcp/COPYING | 8 - ext/picotcp/LICENSE | 339 - ext/picotcp/MODTREE | 23 - ext/picotcp/Makefile | 423 - ext/picotcp/Makefile.watcom | 403 - ext/picotcp/README.md | 103 - ext/picotcp/include/arch/pico_arm9.h | 35 - ext/picotcp/include/arch/pico_avr.h | 39 - ext/picotcp/include/arch/pico_cortex_m.h | 12 - ext/picotcp/include/arch/pico_esp8266.h | 55 - ext/picotcp/include/arch/pico_generic_gcc.h | 102 - ext/picotcp/include/arch/pico_linux.h | 33 - ext/picotcp/include/arch/pico_mbed.h | 185 - ext/picotcp/include/arch/pico_msp430.h | 38 - ext/picotcp/include/arch/pico_none.h | 22 - ext/picotcp/include/arch/pico_pic24.h | 100 - ext/picotcp/include/arch/pico_posix.h | 130 - ext/picotcp/include/heap.h | 83 - ext/picotcp/include/pico_addressing.h | 52 - ext/picotcp/include/pico_config.h | 234 - ext/picotcp/include/pico_constants.h | 54 - ext/picotcp/include/pico_device.h | 54 - ext/picotcp/include/pico_eth.h | 21 - ext/picotcp/include/pico_frame.h | 122 - ext/picotcp/include/pico_md5.h | 17 - ext/picotcp/include/pico_module_eth.h | 33 - ext/picotcp/include/pico_protocol.h | 95 - ext/picotcp/include/pico_queue.h | 166 - ext/picotcp/include/pico_socket.h | 261 - ext/picotcp/include/pico_socket_multicast.h | 10 - ext/picotcp/include/pico_stack.h | 85 - ext/picotcp/include/pico_tree.h | 93 - ext/picotcp/mkdeps.sh | 16 - ext/picotcp/modcheck.py | 50 - ext/picotcp/modules/pico_aodv.c | 674 - ext/picotcp/modules/pico_aodv.h | 130 - ext/picotcp/modules/pico_arp.c | 537 - ext/picotcp/modules/pico_arp.h | 35 - ext/picotcp/modules/pico_dev_loop.c | 66 - ext/picotcp/modules/pico_dev_loop.h | 15 - ext/picotcp/modules/pico_dev_mock.c | 307 - ext/picotcp/modules/pico_dev_mock.h | 47 - ext/picotcp/modules/pico_dev_null.c | 60 - ext/picotcp/modules/pico_dev_null.h | 15 - ext/picotcp/modules/pico_dev_pcap.c | 96 - ext/picotcp/modules/pico_dev_pcap.h | 19 - ext/picotcp/modules/pico_dev_ppp.c | 2294 --- ext/picotcp/modules/pico_dev_ppp.h | 26 - ext/picotcp/modules/pico_dev_tap.c | 220 - ext/picotcp/modules/pico_dev_tap.h | 15 - ext/picotcp/modules/pico_dev_tap_windows.c | 1083 -- ext/picotcp/modules/pico_dev_tap_windows.h | 17 - .../modules/pico_dev_tap_windows_private.h | 89 - ext/picotcp/modules/pico_dev_tun.c | 110 - ext/picotcp/modules/pico_dev_tun.h | 15 - ext/picotcp/modules/pico_dev_vde.c | 115 - ext/picotcp/modules/pico_dev_vde.h | 18 - ext/picotcp/modules/pico_dhcp_client.c | 990 -- ext/picotcp/modules/pico_dhcp_client.h | 32 - ext/picotcp/modules/pico_dhcp_common.c | 190 - ext/picotcp/modules/pico_dhcp_common.h | 191 - ext/picotcp/modules/pico_dhcp_server.c | 411 - ext/picotcp/modules/pico_dhcp_server.h | 34 - ext/picotcp/modules/pico_dns_client.c | 808 - ext/picotcp/modules/pico_dns_client.h | 46 - ext/picotcp/modules/pico_dns_common.c | 1773 --- ext/picotcp/modules/pico_dns_common.h | 523 - ext/picotcp/modules/pico_dns_sd.c | 549 - ext/picotcp/modules/pico_dns_sd.h | 91 - ext/picotcp/modules/pico_fragments.c | 391 - ext/picotcp/modules/pico_fragments.h | 11 - ext/picotcp/modules/pico_hotplug_detection.c | 134 - ext/picotcp/modules/pico_hotplug_detection.h | 20 - ext/picotcp/modules/pico_icmp4.c | 395 - ext/picotcp/modules/pico_icmp4.h | 162 - ext/picotcp/modules/pico_icmp6.c | 698 - ext/picotcp/modules/pico_icmp6.h | 256 - ext/picotcp/modules/pico_igmp.c | 1276 -- ext/picotcp/modules/pico_igmp.h | 26 - ext/picotcp/modules/pico_ipfilter.c | 458 - ext/picotcp/modules/pico_ipfilter.h | 29 - ext/picotcp/modules/pico_ipv4.c | 1585 -- ext/picotcp/modules/pico_ipv4.h | 124 - ext/picotcp/modules/pico_ipv6.c | 1921 --- ext/picotcp/modules/pico_ipv6.h | 175 - ext/picotcp/modules/pico_ipv6_nd.c | 1009 -- ext/picotcp/modules/pico_ipv6_nd.h | 26 - ext/picotcp/modules/pico_mdns.c | 3417 ----- ext/picotcp/modules/pico_mdns.h | 185 - ext/picotcp/modules/pico_mld.c | 1179 -- ext/picotcp/modules/pico_mld.h | 119 - ext/picotcp/modules/pico_mm.c | 1605 -- ext/picotcp/modules/pico_mm.h | 98 - ext/picotcp/modules/pico_nat.c | 576 - ext/picotcp/modules/pico_nat.h | 90 - ext/picotcp/modules/pico_olsr.c | 1143 -- ext/picotcp/modules/pico_olsr.h | 32 - ext/picotcp/modules/pico_posix.c | 99 - ext/picotcp/modules/pico_slaacv4.c | 266 - ext/picotcp/modules/pico_slaacv4.h | 18 - ext/picotcp/modules/pico_sntp_client.c | 395 - ext/picotcp/modules/pico_sntp_client.h | 22 - ext/picotcp/modules/pico_socket_tcp.c | 267 - ext/picotcp/modules/pico_socket_tcp.h | 33 - ext/picotcp/modules/pico_socket_udp.c | 256 - ext/picotcp/modules/pico_socket_udp.h | 19 - ext/picotcp/modules/pico_strings.c | 101 - ext/picotcp/modules/pico_strings.h | 21 - ext/picotcp/modules/pico_tcp.c | 3236 ---- ext/picotcp/modules/pico_tcp.h | 106 - ext/picotcp/modules/pico_tftp.c | 1300 -- ext/picotcp/modules/pico_tftp.h | 83 - ext/picotcp/modules/pico_udp.c | 217 - ext/picotcp/modules/pico_udp.h | 45 - ext/picotcp/rules/crc.mk | 1 - ext/picotcp/rules/cyassl.mk | 3 - ext/picotcp/rules/devloop.mk | 2 - ext/picotcp/rules/dhcp_client.mk | 2 - ext/picotcp/rules/dhcp_server.mk | 2 - ext/picotcp/rules/dns_client.mk | 2 - ext/picotcp/rules/dns_sd.mk | 2 - ext/picotcp/rules/eth.mk | 2 - ext/picotcp/rules/icmp4.mk | 5 - ext/picotcp/rules/igmp.mk | 3 - ext/picotcp/rules/ipfilter.mk | 2 - ext/picotcp/rules/ipv4.mk | 2 - ext/picotcp/rules/ipv4frag.mk | 2 - ext/picotcp/rules/ipv6.mk | 3 - ext/picotcp/rules/ipv6frag.mk | 2 - ext/picotcp/rules/mcast.mk | 1 - ext/picotcp/rules/mdns.mk | 2 - ext/picotcp/rules/memory_manager.mk | 2 - ext/picotcp/rules/mld.mk | 3 - ext/picotcp/rules/nat.mk | 2 - ext/picotcp/rules/olsr.mk | 2 - ext/picotcp/rules/pcap.mk | 1 - ext/picotcp/rules/polarssl.mk | 2 - ext/picotcp/rules/ppp.mk | 3 - ext/picotcp/rules/slaacv4.mk | 2 - ext/picotcp/rules/sntp_client.mk | 2 - ext/picotcp/rules/tap.mk | 1 - ext/picotcp/rules/tcp.mk | 3 - ext/picotcp/rules/tun.mk | 1 - ext/picotcp/rules/udp.mk | 3 - ext/picotcp/rules/wolfssl.mk | 3 - ext/picotcp/stack/pico_device.c | 408 - ext/picotcp/stack/pico_frame.c | 286 - ext/picotcp/stack/pico_md5.c | 43 - ext/picotcp/stack/pico_protocol.c | 214 - ext/picotcp/stack/pico_socket.c | 2231 --- ext/picotcp/stack/pico_socket_multicast.c | 1340 -- ext/picotcp/stack/pico_stack.c | 1165 -- ext/picotcp/stack/pico_tree.c | 575 - ext/picotcp/uncrustify.cfg | 1579 -- integrations/README.md | 59 - .../Unity3D/Assembly-CSharp-Editor.csproj | 109 - integrations/Unity3D/Assembly-CSharp.csproj | 81 - integrations/Unity3D/Assets/CameraControl.js | 194 - integrations/Unity3D/Assets/MainScene.unity | Bin 75472 -> 0 bytes integrations/Unity3D/Assets/MyZeroTier.cs | 8 - integrations/Unity3D/Assets/WorldMain.cs | 45 - integrations/Unity3D/Assets/ZT.mat | Bin 4888 -> 0 bytes integrations/Unity3D/Assets/ZTSDK.cs | 417 - .../Unity3D/Assets/ZeroTierSockets_Demo.cs | 301 - integrations/Unity3D/Assets/smcs.rsp | 1 - integrations/Unity3D/Assets/zerotier-icon.png | Bin 26898 -> 0 bytes .../ProjectSettings/AudioManager.asset | Bin 4140 -> 0 bytes .../ProjectSettings/ClusterInputManager.asset | Bin 4104 -> 0 bytes .../ProjectSettings/DynamicsManager.asset | Bin 4276 -> 0 bytes .../ProjectSettings/EditorBuildSettings.asset | Bin 4104 -> 0 bytes .../ProjectSettings/EditorSettings.asset | Bin 4212 -> 0 bytes .../ProjectSettings/GraphicsSettings.asset | Bin 4376 -> 0 bytes .../ProjectSettings/InputManager.asset | Bin 5520 -> 0 bytes .../ProjectSettings/NavMeshAreas.asset | Bin 4384 -> 0 bytes .../ProjectSettings/NetworkManager.asset | Bin 4112 -> 0 bytes .../ProjectSettings/Physics2DSettings.asset | Bin 4308 -> 0 bytes .../ProjectSettings/ProjectSettings.asset | Bin 37361 -> 0 bytes .../ProjectSettings/ProjectVersion.txt | 1 - .../ProjectSettings/QualitySettings.asset | Bin 5060 -> 0 bytes .../Unity3D/ProjectSettings/TagManager.asset | Bin 4308 -> 0 bytes .../Unity3D/ProjectSettings/TimeManager.asset | Bin 4112 -> 0 bytes .../ProjectSettings/UnityAdsSettings.asset | Bin 4116 -> 0 bytes .../UnityConnectSettings.asset | Bin 4116 -> 0 bytes integrations/Unity3D/README.md | 103 - integrations/Unity3D/Unity3D.sln | 23 - integrations/Unity3D/Unity3D.userprefs | 15 - .../Unity3D/ZeroTier-Unity3D-Test.sln | 29 - .../Unity3D/ZeroTier-Unity3D-Test.userprefs | 21 - integrations/android/README.md | 65 - .../android/android_jni_lib/java/build.xml | 118 - .../android_jni_lib/java/jni/Android.mk | 118 - .../android_jni_lib/java/jni/Android.pico.mk | 121 - .../android_jni_lib/java/jni/Application.mk | 16 - .../java/jni/Application.pico.mk | 16 - .../android/android_jni_lib/proj/app/app.iml | 115 - .../android_jni_lib/proj/app/build.gradle | 55 - .../proj/app/google-services.json | 1 - .../proj/app/proguard-rules.pro | 21 - .../com/zerotier/one/ApplicationTest.java | 13 - .../proj/app/src/main/AndroidManifest.xml | 98 - .../proj/app/src/main/ic_launcher-web.png | Bin 10882 -> 0 bytes .../src/main/java/Netcon/ZT_SDK_Wrapper.java | 15 - .../src/main/res/drawable/button_style.xml | 53 - .../proj/app/src/main/res/drawable/hex.png | Bin 689 -> 0 bytes .../app/src/main/res/drawable/ic_launcher.png | Bin 1119 -> 0 bytes .../res/drawable/sym_keyboard_allleft.png | Bin 21400 -> 0 bytes .../res/drawable/sym_keyboard_allright.png | Bin 21492 -> 0 bytes .../main/res/drawable/sym_keyboard_delete.png | Bin 20711 -> 0 bytes .../main/res/drawable/sym_keyboard_done.png | Bin 1593 -> 0 bytes .../main/res/drawable/sym_keyboard_left.png | Bin 21184 -> 0 bytes .../main/res/drawable/sym_keyboard_return.png | Bin 1719 -> 0 bytes .../main/res/drawable/sym_keyboard_right.png | Bin 20742 -> 0 bytes .../proj/app/src/main/res/drawable/txt.png | Bin 624 -> 0 bytes .../src/main/res/layout/activity_fragment.xml | 4 - .../main/res/layout/fragment_join_network.xml | 67 - .../src/main/res/layout/list_item_network.xml | 176 - .../res/layout/list_item_recent_network.xml | 12 - .../main/res/layout/network_list_fragment.xml | 49 - .../src/main/res/menu/menu_network_list.xml | 14 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 774 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 519 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1666 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 2561 -> 0 bytes .../app/src/main/res/values-w820dp/dimens.xml | 6 - .../proj/app/src/main/res/values/dimens.xml | 5 - .../proj/app/src/main/res/values/strings.xml | 55 - .../proj/app/src/main/res/values/styles.xml | 13 - .../proj/app/src/main/res/xml/app_tracker.xml | 18 - .../app/src/main/res/xml/hex_keyboard.xml | 39 - .../proj/app/src/main/res/xml/preferences.xml | 20 - .../android/android_jni_lib/proj/build.gradle | 20 - .../android_jni_lib/proj/gradle.properties | 18 - .../proj/gradle/wrapper/gradle-wrapper.jar | Bin 49896 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - .../android/android_jni_lib/proj/gradlew | 164 - .../android/android_jni_lib/proj/gradlew.bat | 90 - .../android/android_jni_lib/proj/proj.iml | 19 - .../android_jni_lib/proj/settings.gradle | 1 - .../android_jni_lib/proj/zerotierandroid.iml | 19 - integrations/android/example_app/.gitignore | 8 - .../android/example_app/app/.gitignore | 1 - .../android/example_app/app/build.gradle | 30 - .../example_app/app/proguard-rules.pro | 17 - .../ExampleInstrumentationTest.java | 29 - .../app/src/main/AndroidManifest.xml | 27 - .../app/src/main/java/ZeroTier/ZTAddress.java | 84 - .../app/src/main/java/ZeroTier/ZTSDK.java | 282 - .../joseph/example_app/MainActivity.java | 184 - .../app/src/main/jniLibs/README.md | 65 - .../app/src/main/res/layout/activity_main.xml | 19 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 3418 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2206 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4842 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 7718 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 10486 -> 0 bytes .../app/src/main/res/values-w820dp/dimens.xml | 6 - .../app/src/main/res/values/colors.xml | 6 - .../app/src/main/res/values/dimens.xml | 5 - .../app/src/main/res/values/strings.xml | 3 - .../app/src/main/res/values/styles.xml | 11 - .../joseph/example_app/ExampleUnitTest.java | 17 - integrations/android/example_app/build.gradle | 24 - .../android/example_app/gradle.properties | 19 - .../gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - integrations/android/example_app/gradlew | 160 - integrations/android/example_app/gradlew.bat | 90 - .../android/example_app/settings.gradle | 1 - integrations/apple/README.md | 6 - .../project.pbxproj | 1646 --- .../contents.xcworkspacedata | 7 - .../ZeroTierSDK_Apple.xcscmblueprint | 30 - .../xcschemes/ZeroTierSDK_OSX.xcscheme | 80 - .../ZeroTierSDK_Unity3D_OSX.xcscheme | 80 - .../ZeroTierSDK_Unity3D_iOS.xcscheme | 80 - .../xcschemes/ZeroTierSDK_iOS.xcscheme | 80 - .../xcdebugger/Breakpoints_v2.xcbkptlist | 5 - .../xcschemes/xcschememanagement.plist | 57 - .../ZeroTierSDK_OSX/Info.plist | 28 - .../ZeroTierSDK_OSX/ZeroTierSDK_OSX.h | 19 - .../ZeroTierSDK_Unity3D_OSX/Info.plist | 28 - .../ZeroTierSDK_Unity3D_iOS/Info.plist | 28 - .../ZeroTierSDK_iOS/Info.plist | 26 - .../ZeroTierSDK_iOS/ZeroTierSDK_iOS.h | 19 - .../Example_OSX_App.xcodeproj/project.pbxproj | 338 - .../contents.xcworkspacedata | 7 - .../xcdebugger/Breakpoints_v2.xcbkptlist | 23 - .../xcschemes/Example_OSX_App.xcscheme | 91 - .../xcschemes/xcschememanagement.plist | 22 - .../OSX/Example_OSX_App/AppDelegate.swift | 24 - .../AppIcon.appiconset/Contents.json | 58 - .../Base.lproj/Main.storyboard | 917 -- .../OSX/Example_OSX_App/Info.plist | 34 - .../OSX/Example_OSX_App/ViewController.swift | 275 - integrations/apple/example_app/OSX/README.md | 78 - .../Example_iOS_App.xcodeproj/project.pbxproj | 346 - .../contents.xcworkspacedata | 7 - .../xcdebugger/Breakpoints_v2.xcbkptlist | 87 - .../xcschemes/Example_iOS_App.xcscheme | 91 - .../xcschemes/xcschememanagement.plist | 22 - .../iOS/Example_iOS_App/AppDelegate.swift | 46 - .../AppIcon.appiconset/Contents.json | 73 - .../Base.lproj/LaunchScreen.storyboard | 27 - .../Base.lproj/Main.storyboard | 186 - .../iOS/Example_iOS_App/Info.plist | 47 - .../iOS/Example_iOS_App/ViewController.swift | 295 - integrations/apple/example_app/iOS/README.md | 54 - integrations/docker/README.md | 94 - integrations/docker/_remove_all.sh | 5 - integrations/docker/docker_demo/README.md | 7 - .../docker/docker_demo/docker_demo.name | 0 integrations/docker/docker_demo/hello.lua | 3 - .../docker/docker_demo/monitor_dockerfile | 28 - .../docker/docker_demo/monitor_entrypoint.sh | 50 - .../docker/docker_demo/sdk_dockerfile | 36 - .../docker/docker_demo/sdk_entrypoint.sh | 36 - integrations/docker/docker_demo/start.sh | 8 - integrations/docker/docker_demo/stop.sh | 3 - integrations/simple_app/app.cpp | 221 - make-liblwip.mk | 143 - make-linux.mk | 358 - make-mac.mk | 373 - objects.mk | 36 - src/README.md | 8 - src/debug.h | 159 - src/defs.h | 54 - src/intercept.c | 587 - src/proxy.cpp | 458 - src/rpc.c | 345 - src/rpc.h | 144 - src/sdk.h | 255 - src/sdkutils.hpp | 73 - src/service.cpp | 611 - src/sockets.c | 887 -- src/stack_drivers/README.md | 25 - src/stack_drivers/jip/README.md | 4 - src/stack_drivers/jip/jip.cpp | 52 - src/stack_drivers/jip/jip.hpp | 132 - src/stack_drivers/lwip/README.md | 2 - src/stack_drivers/lwip/lwip.cpp | 1137 -- src/stack_drivers/lwip/lwip.hpp | 534 - src/stack_drivers/lwip/lwipopts.h | 496 - src/stack_drivers/picotcp/README.md | 2 - src/stack_drivers/picotcp/picotcp.cpp | 767 - src/stack_drivers/picotcp/picotcp.hpp | 299 - src/tap.cpp | 610 - src/tap.hpp | 384 - src/wrappers/README.md | 3 - src/wrappers/dotnet/DotNetWrapper.cs | 417 - src/wrappers/java/JavaWrapper.java | 282 - src/wrappers/java/ZTAddress.java | 79 - src/wrappers/swift/Apple-Bridging-Header.h | 51 - src/wrappers/swift/XcodeWrapper.cpp | 138 - src/wrappers/swift/XcodeWrapper.hpp | 31 - src/wrappers/swift/ztsdk.swift | 198 - tests/README.md | 79 - tests/api_test/clients.sh | 46 - tests/api_test/multiclient.c | 60 - tests/api_test/multiserve.c | 66 - tests/api_test/pressureclient4.c | 63 - tests/api_test/pressureserver4.c | 67 - tests/api_test/servers.sh | 54 - tests/api_test/tcpclient4.c | 62 - tests/api_test/tcpclient6.c | 72 - tests/api_test/tcpserver4.c | 62 - tests/api_test/tcpserver6.c | 83 - tests/api_test/test.sh | 10 - tests/api_test/udpclient4.c | 88 - tests/api_test/udpclient6.c | 43 - tests/api_test/udpserver4.c | 86 - tests/api_test/udpserver6.c | 44 - tests/cleanup.sh | 11 - tests/docker/_remove_all.sh | 5 - tests/docker/_two_party_test.sh | 16 - tests/docker/build_images.sh | 32 - .../_build_single_image.sh | 30 - .../darkhttpd-1.11.x86_64/_two_party_test.sh | 16 - .../darkhttpd-1.11.x86_64.name | 0 .../darkhttpd-1.11.x86_64/monitor_dockerfile | 24 - .../monitor_entrypoint.sh | 80 - .../darkhttpd-1.11.x86_64/sdk_dockerfile | 36 - .../darkhttpd-1.11.x86_64/sdk_entrypoint.sh | 46 - .../monitor_dockerfile | 24 - .../monitor_entrypoint.sh | 80 - .../httpd-2.4.16-1.fc23.x86_64/sdk_dockerfile | 36 - .../sdk_entrypoint.sh | 47 - .../monitor_dockerfile | 24 - .../monitor_entrypoint.sh | 80 - .../httpd-2.4.16-1.ub14.x86_64/sdk_dockerfile | 37 - .../sdk_entrypoint.sh | 47 - .../_two_party_test.sh | 16 - .../httpd-2.4.18-1.fc23.x86_64.name | 0 .../monitor_dockerfile | 24 - .../monitor_entrypoint.sh | 80 - .../httpd-2.4.18-1.fc23.x86_64/sdk_dockerfile | 36 - .../sdk_entrypoint.sh | 49 - .../httpd/httpd_demo/htdocs/ZeroTierIcon.png | Bin 26898 -> 0 bytes .../docker/httpd/httpd_demo/htdocs/index.html | 69 - .../httpd/httpd_demo/monitor_dockerfile | 25 - .../httpd/httpd_demo/monitor_entrypoint.sh | 86 - tests/docker/httpd/httpd_demo/sdk_dockerfile | 42 - .../docker/httpd/httpd_demo/sdk_entrypoint.sh | 54 - .../monitor_dockerfile | 24 - .../monitor_entrypoint.sh | 80 - .../nginx-1.4.6-1.ub14.x86_64/nginx.conf_ | 55 - .../nginx-1.4.6-1.ub14.x86_64/sdk_dockerfile | 41 - .../sdk_entrypoint.sh | 50 - .../_two_party_test.sh | 16 - .../monitor_dockerfile | 24 - .../monitor_entrypoint.sh | 80 - .../nginx-1.8.0-13.fc23.x86_64/nginx.conf_ | 55 - .../nginx-1.8.0-13.fc23.x86_64/sdk_dockerfile | 38 - .../sdk_entrypoint.sh | 50 - .../monitor_dockerfile | 24 - .../monitor_entrypoint.sh | 80 - .../nginx-1.8.0-14.fc23.x86_64/nginx.conf_ | 55 - .../nginx-1.8.0-14.fc23.x86_64/sdk_dockerfile | 38 - .../sdk_entrypoint.sh | 50 - .../nodejs-0.10.36-4.fc23/httpserver.js | 7 - .../nodejs-0.10.36-4.fc23/monitor_dockerfile | 24 - .../monitor_entrypoint.sh | 57 - .../nodejs-0.10.36-4.fc23/sdk_dockerfile | 39 - .../nodejs-0.10.36-4.fc23/sdk_entrypoint.sh | 38 - tests/docker/python/python/monitor_dockerfile | 24 - .../python/python/monitor_entrypoint.sh | 80 - tests/docker/python/python/sdk_dockerfile | 36 - tests/docker/python/python/sdk_entrypoint.sh | 46 - .../docker/python/python3/monitor_dockerfile | 24 - .../python/python3/monitor_entrypoint.sh | 80 - tests/docker/python/python3/sdk_dockerfile | 35 - tests/docker/python/python3/sdk_entrypoint.sh | 46 - .../redis/redis-3.0.4-1.fc23.x86_64/hello.lua | 3 - .../monitor_dockerfile | 28 - .../monitor_entrypoint.sh | 56 - .../redis-3.0.4-1.fc23.x86_64/sdk_dockerfile | 36 - .../sdk_entrypoint.sh | 38 - .../monitor_dockerfile | 24 - .../monitor_entrypoint.sh | 57 - .../sdk_dockerfile | 35 - .../sdk_entrypoint.sh | 52 - tests/docker/test.sh | 38 - tests/httpserver.js | 10 - tests/results/README.md | 4 - tests/test.sh | 13 - tests/unit/README.md | 94 - tests/unit/_remove_all.sh | 5 - tests/unit/docker/565799d8f658068e.conf | 0 tests/unit/docker/README.md | 7 - tests/unit/docker/docker_demo.name | 0 tests/unit/docker/hello.lua | 3 - tests/unit/docker/monitor_dockerfile | 28 - tests/unit/docker/monitor_entrypoint.sh | 54 - tests/unit/docker/sdk_dockerfile | 36 - tests/unit/docker/sdk_entrypoint.sh | 36 - tests/unit/docker/start.sh | 21 - tests/unit/docker/stop.sh | 3 - tests/zts/zts.tcpclient4.c | 71 - tests/zts/zts.tcpclient6.c | 84 - tests/zts/zts.tcpserver4.c | 71 - tests/zts/zts.tcpserver6.c | 90 - tests/zts/zts.udpclient4.c | 94 - tests/zts/zts.udpclient6.c | 65 - tests/zts/zts.udpserver4.c | 79 - tests/zts/zts.udpserver6.c | 68 - zto/AUTHORS.md | 73 - zto/COPYING | 17 - zto/LICENSE.GPL-2 | 339 - zto/LICENSE.GPL-3 | 674 - zto/Makefile | 24 - zto/README.md | 125 - zto/RELEASE-NOTES.md | 132 - zto/controller/EmbeddedNetworkController.cpp | 1850 --- zto/controller/EmbeddedNetworkController.hpp | 210 - zto/controller/JSONDB.cpp | 147 - zto/controller/JSONDB.hpp | 115 - zto/controller/README.md | 248 - zto/controller/migrate-sqlite/migrate.js | 320 - zto/controller/migrate-sqlite/package.json | 15 - zto/ext/README.md | 10 - .../bin/tap-mac/tap.kext/Contents/Info.plist | 36 - .../bin/tap-mac/tap.kext/Contents/MacOS/tap | Bin 50496 -> 0 bytes .../Contents/_CodeSignature/CodeResources | 105 - .../bin/tap-windows-ndis6/x64/zttap300.cat | Bin 10017 -> 0 bytes .../bin/tap-windows-ndis6/x64/zttap300.inf | 143 - .../bin/tap-windows-ndis6/x64/zttap300.sys | Bin 30488 -> 0 bytes .../bin/tap-windows-ndis6/x86/zttap300.cat | Bin 10017 -> 0 bytes .../bin/tap-windows-ndis6/x86/zttap300.inf | 143 - .../bin/tap-windows-ndis6/x86/zttap300.sys | Bin 27928 -> 0 bytes zto/ext/http-parser/AUTHORS | 68 - zto/ext/http-parser/LICENSE-MIT | 23 - zto/ext/http-parser/README.md | 246 - zto/ext/http-parser/http_parser.c | 2470 ---- zto/ext/http-parser/http_parser.h | 432 - zto/ext/json/LICENSE.MIT | 22 - zto/ext/json/README.md | 538 - zto/ext/json/json.hpp | 12275 ---------------- zto/ext/libnatpmp/Changelog.txt | 98 - zto/ext/libnatpmp/JavaTest.java | 42 - zto/ext/libnatpmp/LICENSE | 26 - zto/ext/libnatpmp/Makefile | 177 - zto/ext/libnatpmp/README | 7 - zto/ext/libnatpmp/build.bat | 30 - zto/ext/libnatpmp/declspec.h | 21 - .../miniupnp/libnatpmp/LibraryExtractor.java | 238 - .../fr/free/miniupnp/libnatpmp/NatPmp.java | 50 - .../miniupnp/libnatpmp/NatPmpResponse.java | 28 - .../fr/free/miniupnp/libnatpmp/URLUtils.java | 81 - zto/ext/libnatpmp/getgateway.c | 573 - zto/ext/libnatpmp/getgateway.h | 49 - zto/ext/libnatpmp/libnatpmpmodule.c | 281 - zto/ext/libnatpmp/msvc/libnatpmp.sln | 29 - zto/ext/libnatpmp/msvc/libnatpmp.vcproj | 195 - zto/ext/libnatpmp/msvc/natpmpc-static.vcproj | 195 - zto/ext/libnatpmp/natpmp-jni.c | 157 - zto/ext/libnatpmp/natpmp.c | 383 - zto/ext/libnatpmp/natpmp.def | 11 - zto/ext/libnatpmp/natpmp.h | 219 - zto/ext/libnatpmp/natpmpc.1 | 19 - zto/ext/libnatpmp/natpmpc.c | 244 - zto/ext/libnatpmp/setup.py | 18 - zto/ext/libnatpmp/setupmingw32.py | 17 - zto/ext/libnatpmp/testgetgateway.c | 57 - zto/ext/libnatpmp/wingettimeofday.c | 60 - zto/ext/libnatpmp/wingettimeofday.h | 39 - zto/ext/miniupnpc/Changelog.txt | 677 - zto/ext/miniupnpc/LICENSE | 27 - zto/ext/miniupnpc/MANIFEST.in | 5 - zto/ext/miniupnpc/README | 64 - zto/ext/miniupnpc/VERSION | 1 - zto/ext/miniupnpc/apiversions.txt | 172 - zto/ext/miniupnpc/codelength.h | 54 - zto/ext/miniupnpc/connecthostport.c | 264 - zto/ext/miniupnpc/connecthostport.h | 18 - zto/ext/miniupnpc/external-ip.sh | 4 - zto/ext/miniupnpc/igd_desc_parse.c | 123 - zto/ext/miniupnpc/igd_desc_parse.h | 49 - zto/ext/miniupnpc/listdevices.c | 110 - zto/ext/miniupnpc/mingw32make.bat | 8 - zto/ext/miniupnpc/minihttptestserver.c | 659 - zto/ext/miniupnpc/minisoap.c | 128 - zto/ext/miniupnpc/minisoap.h | 15 - zto/ext/miniupnpc/minissdpc.c | 875 -- zto/ext/miniupnpc/minissdpc.h | 58 - zto/ext/miniupnpc/miniupnpc.c | 722 - zto/ext/miniupnpc/miniupnpc.def | 45 - zto/ext/miniupnpc/miniupnpc.h | 152 - zto/ext/miniupnpc/miniupnpc_declspec.h | 21 - zto/ext/miniupnpc/miniupnpcmodule.c | 695 - zto/ext/miniupnpc/miniupnpcstrings.h.in | 23 - zto/ext/miniupnpc/miniupnpctypes.h | 19 - zto/ext/miniupnpc/miniwget.c | 666 - zto/ext/miniupnpc/miniwget.h | 30 - zto/ext/miniupnpc/minixml.c | 229 - zto/ext/miniupnpc/minixml.h | 37 - zto/ext/miniupnpc/minixmlvalid.c | 163 - zto/ext/miniupnpc/portlistingparse.c | 172 - zto/ext/miniupnpc/portlistingparse.h | 65 - zto/ext/miniupnpc/pymoduletest.py | 88 - zto/ext/miniupnpc/receivedata.c | 105 - zto/ext/miniupnpc/receivedata.h | 19 - zto/ext/miniupnpc/setup.py | 28 - zto/ext/miniupnpc/setupmingw32.py | 28 - .../testdesc/linksys_WAG200G_desc.values | 14 - .../testdesc/linksys_WAG200G_desc.xml | 110 - .../testdesc/new_LiveBox_desc.values | 20 - .../miniupnpc/testdesc/new_LiveBox_desc.xml | 90 - zto/ext/miniupnpc/testigddescparse.c | 187 - zto/ext/miniupnpc/testminiwget.c | 55 - zto/ext/miniupnpc/testminiwget.sh | 96 - zto/ext/miniupnpc/testminixml.c | 89 - zto/ext/miniupnpc/testportlistingparse.c | 151 - .../DeletePortMapping.namevalue | 3 - .../testreplyparse/DeletePortMapping.xml | 6 - .../GetExternalIPAddress.namevalue | 2 - .../testreplyparse/GetExternalIPAddress.xml | 2 - .../GetSpecificPortMappingEntryReq.namevalue | 3 - .../GetSpecificPortMappingEntryReq.xml | 3 - .../GetSpecificPortMappingEntryResp.namevalue | 5 - .../GetSpecificPortMappingEntryResp.xml | 2 - .../SetDefaultConnectionService.namevalue | 1 - .../SetDefaultConnectionService.xml | 1 - zto/ext/miniupnpc/testreplyparse/readme.txt | 7 - zto/ext/miniupnpc/testupnpigd.py | 84 - zto/ext/miniupnpc/testupnpreplyparse.c | 96 - zto/ext/miniupnpc/testupnpreplyparse.sh | 14 - zto/ext/miniupnpc/updateminiupnpcstrings.sh | 53 - zto/ext/miniupnpc/upnpc.c | 855 -- zto/ext/miniupnpc/upnpcommands.c | 1237 -- zto/ext/miniupnpc/upnpcommands.h | 348 - zto/ext/miniupnpc/upnpdev.c | 23 - zto/ext/miniupnpc/upnpdev.h | 36 - zto/ext/miniupnpc/upnperrors.c | 107 - zto/ext/miniupnpc/upnperrors.h | 26 - zto/ext/miniupnpc/upnpreplyparse.c | 197 - zto/ext/miniupnpc/upnpreplyparse.h | 63 - zto/ext/miniupnpc/wingenminiupnpcstrings.c | 83 - zto/ext/tap-mac/README.txt | 19 - zto/ext/tap-mac/tuntap/Makefile | 95 - zto/ext/tap-mac/tuntap/src/lock.cc | 206 - zto/ext/tap-mac/tuntap/src/lock.h | 160 - zto/ext/tap-mac/tuntap/src/mem.cc | 76 - zto/ext/tap-mac/tuntap/src/mem.h | 48 - zto/ext/tap-mac/tuntap/src/tap/Info.plist | 36 - zto/ext/tap-mac/tuntap/src/tap/Makefile | 60 - zto/ext/tap-mac/tuntap/src/tap/kmod.cc | 93 - zto/ext/tap-mac/tuntap/src/tap/tap.cc | 533 - zto/ext/tap-mac/tuntap/src/tap/tap.h | 111 - zto/ext/tap-mac/tuntap/src/tuntap.cc | 963 -- zto/ext/tap-mac/tuntap/src/tuntap.h | 301 - zto/ext/tap-mac/tuntap/src/tuntap_mgr.cc | 372 - zto/ext/tap-mac/tuntap/src/util.h | 46 - zto/include/README.md | 4 - zto/include/ZeroTierOne.h | 2147 --- zto/make-bsd.mk | 84 - zto/make-linux.mk | 213 - zto/make-mac.mk | 111 - zto/node/Address.hpp | 202 - zto/node/Array.hpp | 107 - zto/node/AtomicCounter.hpp | 70 - zto/node/Buffer.hpp | 496 - zto/node/C25519.cpp | 2398 --- zto/node/C25519.hpp | 213 - zto/node/Capability.cpp | 65 - zto/node/Capability.hpp | 469 - zto/node/CertificateOfMembership.cpp | 231 - zto/node/CertificateOfMembership.hpp | 358 - zto/node/CertificateOfOwnership.cpp | 63 - zto/node/CertificateOfOwnership.hpp | 234 - zto/node/CertificateOfRepresentation.hpp | 176 - zto/node/Cluster.cpp | 1034 -- zto/node/Cluster.hpp | 455 - zto/node/Constants.hpp | 457 - zto/node/Dictionary.hpp | 473 - zto/node/Hashtable.hpp | 415 - zto/node/Identity.cpp | 190 - zto/node/Identity.hpp | 323 - zto/node/IncomingPacket.cpp | 1473 -- zto/node/IncomingPacket.hpp | 145 - zto/node/InetAddress.cpp | 473 - zto/node/InetAddress.hpp | 601 - zto/node/MAC.hpp | 264 - zto/node/Membership.cpp | 395 - zto/node/Membership.hpp | 300 - zto/node/MulticastGroup.hpp | 132 - zto/node/Multicaster.cpp | 395 - zto/node/Multicaster.hpp | 237 - zto/node/Mutex.hpp | 186 - zto/node/Network.cpp | 1615 -- zto/node/Network.hpp | 423 - zto/node/NetworkConfig.cpp | 364 - zto/node/NetworkConfig.hpp | 556 - zto/node/NetworkController.hpp | 116 - zto/node/Node.cpp | 1136 -- zto/node/Node.hpp | 327 - zto/node/NonCopyable.hpp | 38 - zto/node/OutboundMulticast.cpp | 103 - zto/node/OutboundMulticast.hpp | 153 - zto/node/Packet.cpp | 1169 -- zto/node/Packet.hpp | 1457 -- zto/node/Path.cpp | 34 - zto/node/Path.hpp | 319 - zto/node/Peer.cpp | 498 - zto/node/Peer.hpp | 509 - zto/node/Poly1305.cpp | 628 - zto/node/Poly1305.hpp | 55 - zto/node/README.md | 14 - zto/node/Revocation.cpp | 46 - zto/node/Revocation.hpp | 194 - zto/node/RuntimeEnvironment.hpp | 89 - zto/node/SHA512.cpp | 352 - zto/node/SHA512.hpp | 37 - zto/node/Salsa20.cpp | 1358 -- zto/node/Salsa20.hpp | 89 - zto/node/SelfAwareness.cpp | 195 - zto/node/SelfAwareness.hpp | 98 - zto/node/SharedPtr.hpp | 178 - zto/node/Switch.cpp | 881 -- zto/node/Switch.hpp | 227 - zto/node/Tag.cpp | 46 - zto/node/Tag.hpp | 201 - zto/node/Topology.cpp | 475 - zto/node/Topology.hpp | 456 - zto/node/Utils.cpp | 255 - zto/node/Utils.hpp | 386 - zto/node/World.hpp | 278 - zto/objects.mk | 34 - zto/one.cpp | 1506 -- zto/osdep/Arp.cpp | 126 - zto/osdep/Arp.hpp | 148 - zto/osdep/BSDEthernetTap.cpp | 473 - zto/osdep/BSDEthernetTap.hpp | 80 - zto/osdep/Binder.hpp | 448 - zto/osdep/BlockingQueue.hpp | 64 - zto/osdep/Http.cpp | 291 - zto/osdep/Http.hpp | 154 - zto/osdep/LinuxEthernetTap.cpp | 483 - zto/osdep/LinuxEthernetTap.hpp | 84 - zto/osdep/ManagedRoute.cpp | 543 - zto/osdep/ManagedRoute.hpp | 80 - zto/osdep/NeighborDiscovery.cpp | 264 - zto/osdep/NeighborDiscovery.hpp | 76 - zto/osdep/OSUtils.cpp | 470 - zto/osdep/OSUtils.hpp | 287 - zto/osdep/OSXEthernetTap.cpp | 659 - zto/osdep/OSXEthernetTap.hpp | 86 - zto/osdep/Phy.hpp | 1115 -- zto/osdep/PortMapper.cpp | 325 - zto/osdep/PortMapper.hpp | 71 - zto/osdep/README.md | 6 - zto/osdep/Thread.hpp | 205 - zto/osdep/WindowsEthernetTap.cpp | 1222 -- zto/osdep/WindowsEthernetTap.hpp | 152 - zto/selftest.cpp | 1163 -- zto/service/ClusterDefinition.hpp | 160 - zto/service/ClusterGeoIpService.cpp | 235 - zto/service/ClusterGeoIpService.hpp | 143 - zto/service/OneService.cpp | 2597 ---- zto/service/OneService.hpp | 209 - zto/service/README.md | 181 - zto/service/SoftwareUpdater.cpp | 406 - zto/service/SoftwareUpdater.hpp | 209 - zto/tcp-proxy/Makefile | 7 - zto/tcp-proxy/README.md | 4 - zto/tcp-proxy/tcp-proxy.cpp | 317 - zto/version.h | 53 - zto/windows/README.md | 3 - zto/windows/TapDriver6/TapDriver6.vcxproj | 396 - .../TapDriver6/TapDriver6.vcxproj.filters | 110 - zto/windows/TapDriver6/adapter.c | 1716 --- zto/windows/TapDriver6/adapter.h | 352 - zto/windows/TapDriver6/config.h | 9 - zto/windows/TapDriver6/constants.h | 196 - zto/windows/TapDriver6/device.c | 1209 -- zto/windows/TapDriver6/device.h | 50 - zto/windows/TapDriver6/endian.h | 35 - zto/windows/TapDriver6/error.c | 398 - zto/windows/TapDriver6/error.h | 114 - zto/windows/TapDriver6/hexdump.h | 63 - zto/windows/TapDriver6/lock.h | 75 - zto/windows/TapDriver6/macinfo.c | 164 - zto/windows/TapDriver6/macinfo.h | 53 - zto/windows/TapDriver6/mem.c | 401 - zto/windows/TapDriver6/mem.h | 113 - zto/windows/TapDriver6/oidrequest.c | 1028 -- zto/windows/TapDriver6/proto.h | 224 - zto/windows/TapDriver6/prototypes.h | 91 - zto/windows/TapDriver6/resource.h | 1573 -- zto/windows/TapDriver6/resource.rc | 88 - zto/windows/TapDriver6/rxpath.c | 669 - zto/windows/TapDriver6/tap-windows.h | 83 - zto/windows/TapDriver6/tap.h | 88 - zto/windows/TapDriver6/tapdrvr.c | 232 - zto/windows/TapDriver6/txpath.c | 1175 -- zto/windows/TapDriver6/types.h | 90 - zto/windows/TapDriver6/zttap300.inf | 143 - zto/windows/WinUI/APIHandler.cs | 419 - zto/windows/WinUI/AboutView.xaml | 35 - zto/windows/WinUI/AboutView.xaml.cs | 35 - zto/windows/WinUI/App.config | 6 - zto/windows/WinUI/App.xaml | 14 - zto/windows/WinUI/App.xaml.cs | 25 - zto/windows/WinUI/JoinNetworkView.xaml | 16 - zto/windows/WinUI/JoinNetworkView.xaml.cs | 126 - zto/windows/WinUI/MainWindow.xaml.cs | 233 - zto/windows/WinUI/NetworkInfoView.xaml | 85 - zto/windows/WinUI/NetworkInfoView.xaml.cs | 166 - zto/windows/WinUI/NetworkListView.xaml | 88 - zto/windows/WinUI/NetworkListView.xaml.cs | 85 - zto/windows/WinUI/NetworkMonitor.cs | 202 - zto/windows/WinUI/NetworkRoute.cs | 42 - zto/windows/WinUI/NetworksPage.xaml | 13 - zto/windows/WinUI/NetworksPage.xaml.cs | 99 - zto/windows/WinUI/PeersPage.xaml | 26 - zto/windows/WinUI/PeersPage.xaml.cs | 54 - zto/windows/WinUI/PreferencesView.xaml | 13 - zto/windows/WinUI/PreferencesView.xaml.cs | 50 - zto/windows/WinUI/Properties/AssemblyInfo.cs | 56 - .../WinUI/Properties/Resources.Designer.cs | 73 - zto/windows/WinUI/Properties/Resources.resx | 124 - .../WinUI/Properties/Settings.Designer.cs | 30 - .../WinUI/Properties/Settings.settings | 7 - zto/windows/WinUI/Resources/ZeroTierIcon.ico | Bin 45451 -> 0 bytes zto/windows/WinUI/Simple Styles.xaml | 1128 -- zto/windows/WinUI/Themes/Generic.xaml | 7 - zto/windows/WinUI/ToolbarItem.xaml | 59 - zto/windows/WinUI/ToolbarItem.xaml.cs | 310 - zto/windows/WinUI/WinUI.csproj | 265 - zto/windows/WinUI/ZeroTierIcon.ico | Bin 370070 -> 0 bytes zto/windows/WinUI/ZeroTierNetwork.cs | 494 - zto/windows/WinUI/ZeroTierPeer.cs | 116 - zto/windows/WinUI/ZeroTierPeerPhysicalPath.cs | 27 - zto/windows/WinUI/ZeroTierStatus.cs | 39 - zto/windows/WinUI/app.manifest | 55 - zto/windows/WinUI/packages.config | 5 - zto/windows/ZeroTierOne.sln | 432 - zto/windows/copyutil/App.config | 6 - zto/windows/copyutil/Program.cs | 40 - .../copyutil/Properties/AssemblyInfo.cs | 36 - zto/windows/copyutil/copyutil.csproj | 60 - zto/windows/packages/.gitignore | 3 - zto/windows/packages/repositories.config | 4 - zto/zerotier-one.spec | 170 - 1100 files changed, 287219 deletions(-) delete mode 100644 COPYING delete mode 100644 Jenkinsfile delete mode 100644 LICENSE.GPL-2 delete mode 100644 LICENSE.GPL-3 delete mode 100644 Makefile delete mode 100644 README.md delete mode 100755 check.sh delete mode 100644 docs/android.md delete mode 100644 docs/docker.md delete mode 100644 docs/faq.md delete mode 100644 docs/img/api_diagram.png delete mode 100644 docs/img/app_flow.png delete mode 100644 docs/img/methods.png delete mode 100644 docs/img/zt_app_flow.png delete mode 100644 docs/img/zt_why.png delete mode 100644 docs/integrations.md delete mode 100644 docs/intro.md delete mode 100644 docs/ios.md delete mode 100644 docs/ios_unity3d.md delete mode 100644 docs/linux.md delete mode 100644 docs/network_stacks.md delete mode 100644 docs/osx.md delete mode 100644 docs/osx_unity3d.md delete mode 100644 docs/technical.md delete mode 100644 docs/tests.md delete mode 100644 docs/walkthrough.md delete mode 100644 ext/README.md delete mode 100644 ext/contrib/README.md delete mode 100644 ext/contrib/ports/unix/proj/lib/Makefile delete mode 100644 ext/contrib/ports/unix/proj/lib/README delete mode 100644 ext/contrib/ports/unix/proj/lib/lwipopts.h delete mode 100644 ext/contrib/ports/unix/proj/lib/unixlib.c delete mode 100644 ext/lwip/CHANGELOG delete mode 100644 ext/lwip/COPYING delete mode 100644 ext/lwip/FILES delete mode 100644 ext/lwip/README delete mode 100644 ext/lwip/UPGRADING delete mode 100644 ext/lwip/doc/FILES delete mode 100644 ext/lwip/doc/contrib.txt delete mode 100644 ext/lwip/doc/doxygen/generate.bat delete mode 100755 ext/lwip/doc/doxygen/generate.sh delete mode 100644 ext/lwip/doc/doxygen/main_page.h delete mode 100644 ext/lwip/doc/ppp.txt delete mode 100644 ext/lwip/doc/rawapi.txt delete mode 100644 ext/lwip/doc/savannah.txt delete mode 100644 ext/lwip/doc/sys_arch.txt delete mode 100644 ext/lwip/src/FILES delete mode 100644 ext/lwip/src/Filelists.mk delete mode 100644 ext/lwip/src/api/api_lib.c delete mode 100644 ext/lwip/src/api/api_msg.c delete mode 100644 ext/lwip/src/api/err.c delete mode 100644 ext/lwip/src/api/netbuf.c delete mode 100644 ext/lwip/src/api/netdb.c delete mode 100644 ext/lwip/src/api/netifapi.c delete mode 100644 ext/lwip/src/api/sockets.c delete mode 100644 ext/lwip/src/api/tcpip.c delete mode 100644 ext/lwip/src/apps/httpd/fs.c delete mode 100644 ext/lwip/src/apps/httpd/fs/404.html delete mode 100644 ext/lwip/src/apps/httpd/fs/img/sics.gif delete mode 100644 ext/lwip/src/apps/httpd/fs/index.html delete mode 100644 ext/lwip/src/apps/httpd/fsdata.c delete mode 100644 ext/lwip/src/apps/httpd/fsdata.h delete mode 100644 ext/lwip/src/apps/httpd/httpd.c delete mode 100644 ext/lwip/src/apps/httpd/httpd_structs.h delete mode 100644 ext/lwip/src/apps/httpd/makefsdata/makefsdata delete mode 100644 ext/lwip/src/apps/httpd/makefsdata/makefsdata.c delete mode 100644 ext/lwip/src/apps/httpd/makefsdata/readme.txt delete mode 100644 ext/lwip/src/apps/lwiperf/lwiperf.c delete mode 100644 ext/lwip/src/apps/netbiosns/netbiosns.c delete mode 100644 ext/lwip/src/apps/snmp/README delete mode 100644 ext/lwip/src/apps/snmp/snmp_asn1.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_asn1.h delete mode 100644 ext/lwip/src/apps/snmp/snmp_core.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_core_priv.h delete mode 100644 ext/lwip/src/apps/snmp/snmp_mib2.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_mib2_icmp.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_mib2_interfaces.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_mib2_ip.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_mib2_snmp.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_mib2_system.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_mib2_tcp.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_mib2_udp.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_msg.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_msg.h delete mode 100644 ext/lwip/src/apps/snmp/snmp_netconn.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_pbuf_stream.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_pbuf_stream.h delete mode 100644 ext/lwip/src/apps/snmp/snmp_raw.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_scalar.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_table.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_threadsync.c delete mode 100644 ext/lwip/src/apps/snmp/snmp_traps.c delete mode 100644 ext/lwip/src/apps/snmp/snmpv3.c delete mode 100644 ext/lwip/src/apps/snmp/snmpv3_dummy.c delete mode 100644 ext/lwip/src/apps/snmp/snmpv3_mbedtls.c delete mode 100644 ext/lwip/src/apps/snmp/snmpv3_priv.h delete mode 100644 ext/lwip/src/apps/sntp/sntp.c delete mode 100644 ext/lwip/src/core/def.c delete mode 100644 ext/lwip/src/core/dns.c delete mode 100644 ext/lwip/src/core/inet_chksum.c delete mode 100644 ext/lwip/src/core/init.c delete mode 100644 ext/lwip/src/core/ip.c delete mode 100644 ext/lwip/src/core/ipv4/autoip.c delete mode 100644 ext/lwip/src/core/ipv4/dhcp.c delete mode 100644 ext/lwip/src/core/ipv4/etharp.c delete mode 100644 ext/lwip/src/core/ipv4/icmp.c delete mode 100644 ext/lwip/src/core/ipv4/igmp.c delete mode 100644 ext/lwip/src/core/ipv4/ip4.c delete mode 100644 ext/lwip/src/core/ipv4/ip4_addr.c delete mode 100644 ext/lwip/src/core/ipv4/ip4_frag.c delete mode 100644 ext/lwip/src/core/ipv6/README delete mode 100644 ext/lwip/src/core/ipv6/dhcp6.c delete mode 100644 ext/lwip/src/core/ipv6/ethip6.c delete mode 100644 ext/lwip/src/core/ipv6/icmp6.c delete mode 100644 ext/lwip/src/core/ipv6/inet6.c delete mode 100644 ext/lwip/src/core/ipv6/ip6.c delete mode 100644 ext/lwip/src/core/ipv6/ip6_addr.c delete mode 100644 ext/lwip/src/core/ipv6/ip6_frag.c delete mode 100644 ext/lwip/src/core/ipv6/mld6.c delete mode 100644 ext/lwip/src/core/ipv6/nd6.c delete mode 100644 ext/lwip/src/core/mem.c delete mode 100644 ext/lwip/src/core/memp.c delete mode 100644 ext/lwip/src/core/netif.c delete mode 100644 ext/lwip/src/core/pbuf.c delete mode 100644 ext/lwip/src/core/raw.c delete mode 100644 ext/lwip/src/core/stats.c delete mode 100644 ext/lwip/src/core/sys.c delete mode 100644 ext/lwip/src/core/tcp.c delete mode 100644 ext/lwip/src/core/tcp_in.c delete mode 100644 ext/lwip/src/core/tcp_out.c delete mode 100644 ext/lwip/src/core/timeouts.c delete mode 100644 ext/lwip/src/core/udp.c delete mode 100644 ext/lwip/src/include/arch/cc.h delete mode 100644 ext/lwip/src/include/arch/perf.h delete mode 100644 ext/lwip/src/include/arch/sys_arch.h delete mode 100644 ext/lwip/src/include/lwip/api.h delete mode 100644 ext/lwip/src/include/lwip/apps/FILES delete mode 100644 ext/lwip/src/include/lwip/apps/fs.h delete mode 100644 ext/lwip/src/include/lwip/apps/httpd.h delete mode 100644 ext/lwip/src/include/lwip/apps/httpd_opts.h delete mode 100644 ext/lwip/src/include/lwip/apps/lwiperf.h delete mode 100644 ext/lwip/src/include/lwip/apps/netbiosns.h delete mode 100644 ext/lwip/src/include/lwip/apps/netbiosns_opts.h delete mode 100644 ext/lwip/src/include/lwip/apps/snmp.h delete mode 100644 ext/lwip/src/include/lwip/apps/snmp_core.h delete mode 100644 ext/lwip/src/include/lwip/apps/snmp_mib2.h delete mode 100644 ext/lwip/src/include/lwip/apps/snmp_opts.h delete mode 100644 ext/lwip/src/include/lwip/apps/snmp_scalar.h delete mode 100644 ext/lwip/src/include/lwip/apps/snmp_table.h delete mode 100644 ext/lwip/src/include/lwip/apps/snmp_threadsync.h delete mode 100644 ext/lwip/src/include/lwip/apps/snmpv3.h delete mode 100644 ext/lwip/src/include/lwip/apps/sntp.h delete mode 100644 ext/lwip/src/include/lwip/apps/sntp_opts.h delete mode 100644 ext/lwip/src/include/lwip/arch.h delete mode 100644 ext/lwip/src/include/lwip/autoip.h delete mode 100644 ext/lwip/src/include/lwip/debug.h delete mode 100644 ext/lwip/src/include/lwip/def.h delete mode 100644 ext/lwip/src/include/lwip/dhcp.h delete mode 100644 ext/lwip/src/include/lwip/dhcp6.h delete mode 100644 ext/lwip/src/include/lwip/dns.h delete mode 100644 ext/lwip/src/include/lwip/err.h delete mode 100644 ext/lwip/src/include/lwip/etharp.h delete mode 100644 ext/lwip/src/include/lwip/ethip6.h delete mode 100644 ext/lwip/src/include/lwip/icmp.h delete mode 100644 ext/lwip/src/include/lwip/icmp6.h delete mode 100644 ext/lwip/src/include/lwip/igmp.h delete mode 100644 ext/lwip/src/include/lwip/inet.h delete mode 100644 ext/lwip/src/include/lwip/inet_chksum.h delete mode 100644 ext/lwip/src/include/lwip/init.h delete mode 100644 ext/lwip/src/include/lwip/ip.h delete mode 100644 ext/lwip/src/include/lwip/ip4.h delete mode 100644 ext/lwip/src/include/lwip/ip4_addr.h delete mode 100644 ext/lwip/src/include/lwip/ip4_frag.h delete mode 100644 ext/lwip/src/include/lwip/ip6.h delete mode 100644 ext/lwip/src/include/lwip/ip6_addr.h delete mode 100644 ext/lwip/src/include/lwip/ip6_frag.h delete mode 100644 ext/lwip/src/include/lwip/ip_addr.h delete mode 100644 ext/lwip/src/include/lwip/mem.h delete mode 100644 ext/lwip/src/include/lwip/memp.h delete mode 100644 ext/lwip/src/include/lwip/mld6.h delete mode 100644 ext/lwip/src/include/lwip/nd6.h delete mode 100644 ext/lwip/src/include/lwip/netbuf.h delete mode 100644 ext/lwip/src/include/lwip/netdb.h delete mode 100644 ext/lwip/src/include/lwip/netif.h delete mode 100644 ext/lwip/src/include/lwip/netifapi.h delete mode 100644 ext/lwip/src/include/lwip/opt.h delete mode 100644 ext/lwip/src/include/lwip/pbuf.h delete mode 100644 ext/lwip/src/include/lwip/priv/api_msg.h delete mode 100644 ext/lwip/src/include/lwip/priv/memp_priv.h delete mode 100644 ext/lwip/src/include/lwip/priv/memp_std.h delete mode 100644 ext/lwip/src/include/lwip/priv/tcp_priv.h delete mode 100644 ext/lwip/src/include/lwip/priv/tcpip_priv.h delete mode 100644 ext/lwip/src/include/lwip/raw.h delete mode 100644 ext/lwip/src/include/lwip/sio.h delete mode 100644 ext/lwip/src/include/lwip/snmp.h delete mode 100644 ext/lwip/src/include/lwip/sockets.h delete mode 100644 ext/lwip/src/include/lwip/stats.h delete mode 100644 ext/lwip/src/include/lwip/sys.h delete mode 100644 ext/lwip/src/include/lwip/tcp.h delete mode 100644 ext/lwip/src/include/lwip/tcpip.h delete mode 100644 ext/lwip/src/include/lwip/timeouts.h delete mode 100644 ext/lwip/src/include/lwip/udp.h delete mode 100644 ext/lwip/src/include/netif/etharp.h delete mode 100644 ext/lwip/src/include/netif/ethernet.h delete mode 100644 ext/lwip/src/include/netif/lowpan6.h delete mode 100644 ext/lwip/src/include/netif/lowpan6_opts.h delete mode 100644 ext/lwip/src/include/netif/ppp/ccp.h delete mode 100644 ext/lwip/src/include/netif/ppp/chap-md5.h delete mode 100644 ext/lwip/src/include/netif/ppp/chap-new.h delete mode 100644 ext/lwip/src/include/netif/ppp/chap_ms.h delete mode 100644 ext/lwip/src/include/netif/ppp/eap.h delete mode 100644 ext/lwip/src/include/netif/ppp/ecp.h delete mode 100644 ext/lwip/src/include/netif/ppp/eui64.h delete mode 100644 ext/lwip/src/include/netif/ppp/fsm.h delete mode 100644 ext/lwip/src/include/netif/ppp/ipcp.h delete mode 100644 ext/lwip/src/include/netif/ppp/ipv6cp.h delete mode 100644 ext/lwip/src/include/netif/ppp/lcp.h delete mode 100644 ext/lwip/src/include/netif/ppp/magic.h delete mode 100644 ext/lwip/src/include/netif/ppp/mppe.h delete mode 100644 ext/lwip/src/include/netif/ppp/polarssl/arc4.h delete mode 100644 ext/lwip/src/include/netif/ppp/polarssl/des.h delete mode 100644 ext/lwip/src/include/netif/ppp/polarssl/md4.h delete mode 100644 ext/lwip/src/include/netif/ppp/polarssl/md5.h delete mode 100644 ext/lwip/src/include/netif/ppp/polarssl/sha1.h delete mode 100644 ext/lwip/src/include/netif/ppp/ppp.h delete mode 100644 ext/lwip/src/include/netif/ppp/ppp_impl.h delete mode 100644 ext/lwip/src/include/netif/ppp/ppp_opts.h delete mode 100644 ext/lwip/src/include/netif/ppp/pppapi.h delete mode 100644 ext/lwip/src/include/netif/ppp/pppcrypt.h delete mode 100644 ext/lwip/src/include/netif/ppp/pppdebug.h delete mode 100644 ext/lwip/src/include/netif/ppp/pppoe.h delete mode 100644 ext/lwip/src/include/netif/ppp/pppol2tp.h delete mode 100644 ext/lwip/src/include/netif/ppp/pppos.h delete mode 100644 ext/lwip/src/include/netif/ppp/upap.h delete mode 100644 ext/lwip/src/include/netif/ppp/vj.h delete mode 100644 ext/lwip/src/include/netif/slipif.h delete mode 100644 ext/lwip/src/include/posix/netdb.h delete mode 100644 ext/lwip/src/include/posix/sys/socket.h delete mode 100644 ext/lwip/src/netif/FILES delete mode 100644 ext/lwip/src/netif/ethernet.c delete mode 100644 ext/lwip/src/netif/ethernetif.c delete mode 100644 ext/lwip/src/netif/lowpan6.c delete mode 100644 ext/lwip/src/netif/ppp/PPPD_FOLLOWUP delete mode 100644 ext/lwip/src/netif/ppp/auth.c delete mode 100644 ext/lwip/src/netif/ppp/ccp.c delete mode 100644 ext/lwip/src/netif/ppp/chap-md5.c delete mode 100644 ext/lwip/src/netif/ppp/chap-new.c delete mode 100644 ext/lwip/src/netif/ppp/chap_ms.c delete mode 100644 ext/lwip/src/netif/ppp/demand.c delete mode 100644 ext/lwip/src/netif/ppp/eap.c delete mode 100644 ext/lwip/src/netif/ppp/ecp.c delete mode 100644 ext/lwip/src/netif/ppp/eui64.c delete mode 100644 ext/lwip/src/netif/ppp/fsm.c delete mode 100644 ext/lwip/src/netif/ppp/ipcp.c delete mode 100644 ext/lwip/src/netif/ppp/ipv6cp.c delete mode 100644 ext/lwip/src/netif/ppp/lcp.c delete mode 100644 ext/lwip/src/netif/ppp/magic.c delete mode 100644 ext/lwip/src/netif/ppp/mppe.c delete mode 100644 ext/lwip/src/netif/ppp/multilink.c delete mode 100644 ext/lwip/src/netif/ppp/polarssl/README delete mode 100644 ext/lwip/src/netif/ppp/polarssl/arc4.c delete mode 100644 ext/lwip/src/netif/ppp/polarssl/des.c delete mode 100644 ext/lwip/src/netif/ppp/polarssl/md4.c delete mode 100644 ext/lwip/src/netif/ppp/polarssl/md5.c delete mode 100644 ext/lwip/src/netif/ppp/polarssl/sha1.c delete mode 100644 ext/lwip/src/netif/ppp/ppp.c delete mode 100644 ext/lwip/src/netif/ppp/pppapi.c delete mode 100644 ext/lwip/src/netif/ppp/pppcrypt.c delete mode 100644 ext/lwip/src/netif/ppp/pppoe.c delete mode 100644 ext/lwip/src/netif/ppp/pppol2tp.c delete mode 100644 ext/lwip/src/netif/ppp/pppos.c delete mode 100644 ext/lwip/src/netif/ppp/upap.c delete mode 100644 ext/lwip/src/netif/ppp/utils.c delete mode 100644 ext/lwip/src/netif/ppp/vj.c delete mode 100644 ext/lwip/src/netif/slipif.c delete mode 100644 ext/lwip/test/unit/core/test_mem.c delete mode 100644 ext/lwip/test/unit/core/test_mem.h delete mode 100644 ext/lwip/test/unit/core/test_pbuf.c delete mode 100644 ext/lwip/test/unit/core/test_pbuf.h delete mode 100644 ext/lwip/test/unit/dhcp/test_dhcp.c delete mode 100644 ext/lwip/test/unit/dhcp/test_dhcp.h delete mode 100644 ext/lwip/test/unit/etharp/test_etharp.c delete mode 100644 ext/lwip/test/unit/etharp/test_etharp.h delete mode 100644 ext/lwip/test/unit/lwip_check.h delete mode 100644 ext/lwip/test/unit/lwip_unittests.c delete mode 100644 ext/lwip/test/unit/lwipopts.h delete mode 100644 ext/lwip/test/unit/tcp/tcp_helper.c delete mode 100644 ext/lwip/test/unit/tcp/tcp_helper.h delete mode 100644 ext/lwip/test/unit/tcp/test_tcp.c delete mode 100644 ext/lwip/test/unit/tcp/test_tcp.h delete mode 100644 ext/lwip/test/unit/tcp/test_tcp_oos.c delete mode 100644 ext/lwip/test/unit/tcp/test_tcp_oos.h delete mode 100644 ext/lwip/test/unit/udp/test_udp.c delete mode 100644 ext/lwip/test/unit/udp/test_udp.h delete mode 100644 ext/lwipopts.h delete mode 100644 ext/picotcp/.gitignore delete mode 100644 ext/picotcp/.travis.yml delete mode 100644 ext/picotcp/COPYING delete mode 100644 ext/picotcp/LICENSE delete mode 100644 ext/picotcp/MODTREE delete mode 100644 ext/picotcp/Makefile delete mode 100644 ext/picotcp/Makefile.watcom delete mode 100644 ext/picotcp/README.md delete mode 100644 ext/picotcp/include/arch/pico_arm9.h delete mode 100644 ext/picotcp/include/arch/pico_avr.h delete mode 100644 ext/picotcp/include/arch/pico_cortex_m.h delete mode 100644 ext/picotcp/include/arch/pico_esp8266.h delete mode 100644 ext/picotcp/include/arch/pico_generic_gcc.h delete mode 100644 ext/picotcp/include/arch/pico_linux.h delete mode 100644 ext/picotcp/include/arch/pico_mbed.h delete mode 100644 ext/picotcp/include/arch/pico_msp430.h delete mode 100644 ext/picotcp/include/arch/pico_none.h delete mode 100644 ext/picotcp/include/arch/pico_pic24.h delete mode 100644 ext/picotcp/include/arch/pico_posix.h delete mode 100644 ext/picotcp/include/heap.h delete mode 100644 ext/picotcp/include/pico_addressing.h delete mode 100644 ext/picotcp/include/pico_config.h delete mode 100644 ext/picotcp/include/pico_constants.h delete mode 100644 ext/picotcp/include/pico_device.h delete mode 100644 ext/picotcp/include/pico_eth.h delete mode 100644 ext/picotcp/include/pico_frame.h delete mode 100644 ext/picotcp/include/pico_md5.h delete mode 100644 ext/picotcp/include/pico_module_eth.h delete mode 100644 ext/picotcp/include/pico_protocol.h delete mode 100644 ext/picotcp/include/pico_queue.h delete mode 100644 ext/picotcp/include/pico_socket.h delete mode 100644 ext/picotcp/include/pico_socket_multicast.h delete mode 100644 ext/picotcp/include/pico_stack.h delete mode 100644 ext/picotcp/include/pico_tree.h delete mode 100755 ext/picotcp/mkdeps.sh delete mode 100755 ext/picotcp/modcheck.py delete mode 100644 ext/picotcp/modules/pico_aodv.c delete mode 100644 ext/picotcp/modules/pico_aodv.h delete mode 100644 ext/picotcp/modules/pico_arp.c delete mode 100644 ext/picotcp/modules/pico_arp.h delete mode 100644 ext/picotcp/modules/pico_dev_loop.c delete mode 100644 ext/picotcp/modules/pico_dev_loop.h delete mode 100644 ext/picotcp/modules/pico_dev_mock.c delete mode 100644 ext/picotcp/modules/pico_dev_mock.h delete mode 100644 ext/picotcp/modules/pico_dev_null.c delete mode 100644 ext/picotcp/modules/pico_dev_null.h delete mode 100644 ext/picotcp/modules/pico_dev_pcap.c delete mode 100644 ext/picotcp/modules/pico_dev_pcap.h delete mode 100644 ext/picotcp/modules/pico_dev_ppp.c delete mode 100644 ext/picotcp/modules/pico_dev_ppp.h delete mode 100644 ext/picotcp/modules/pico_dev_tap.c delete mode 100644 ext/picotcp/modules/pico_dev_tap.h delete mode 100644 ext/picotcp/modules/pico_dev_tap_windows.c delete mode 100755 ext/picotcp/modules/pico_dev_tap_windows.h delete mode 100644 ext/picotcp/modules/pico_dev_tap_windows_private.h delete mode 100644 ext/picotcp/modules/pico_dev_tun.c delete mode 100644 ext/picotcp/modules/pico_dev_tun.h delete mode 100644 ext/picotcp/modules/pico_dev_vde.c delete mode 100644 ext/picotcp/modules/pico_dev_vde.h delete mode 100644 ext/picotcp/modules/pico_dhcp_client.c delete mode 100644 ext/picotcp/modules/pico_dhcp_client.h delete mode 100644 ext/picotcp/modules/pico_dhcp_common.c delete mode 100644 ext/picotcp/modules/pico_dhcp_common.h delete mode 100644 ext/picotcp/modules/pico_dhcp_server.c delete mode 100644 ext/picotcp/modules/pico_dhcp_server.h delete mode 100644 ext/picotcp/modules/pico_dns_client.c delete mode 100644 ext/picotcp/modules/pico_dns_client.h delete mode 100644 ext/picotcp/modules/pico_dns_common.c delete mode 100644 ext/picotcp/modules/pico_dns_common.h delete mode 100644 ext/picotcp/modules/pico_dns_sd.c delete mode 100644 ext/picotcp/modules/pico_dns_sd.h delete mode 100644 ext/picotcp/modules/pico_fragments.c delete mode 100644 ext/picotcp/modules/pico_fragments.h delete mode 100644 ext/picotcp/modules/pico_hotplug_detection.c delete mode 100644 ext/picotcp/modules/pico_hotplug_detection.h delete mode 100644 ext/picotcp/modules/pico_icmp4.c delete mode 100644 ext/picotcp/modules/pico_icmp4.h delete mode 100644 ext/picotcp/modules/pico_icmp6.c delete mode 100644 ext/picotcp/modules/pico_icmp6.h delete mode 100644 ext/picotcp/modules/pico_igmp.c delete mode 100644 ext/picotcp/modules/pico_igmp.h delete mode 100644 ext/picotcp/modules/pico_ipfilter.c delete mode 100644 ext/picotcp/modules/pico_ipfilter.h delete mode 100644 ext/picotcp/modules/pico_ipv4.c delete mode 100644 ext/picotcp/modules/pico_ipv4.h delete mode 100644 ext/picotcp/modules/pico_ipv6.c delete mode 100644 ext/picotcp/modules/pico_ipv6.h delete mode 100644 ext/picotcp/modules/pico_ipv6_nd.c delete mode 100644 ext/picotcp/modules/pico_ipv6_nd.h delete mode 100644 ext/picotcp/modules/pico_mdns.c delete mode 100644 ext/picotcp/modules/pico_mdns.h delete mode 100644 ext/picotcp/modules/pico_mld.c delete mode 100644 ext/picotcp/modules/pico_mld.h delete mode 100644 ext/picotcp/modules/pico_mm.c delete mode 100644 ext/picotcp/modules/pico_mm.h delete mode 100644 ext/picotcp/modules/pico_nat.c delete mode 100644 ext/picotcp/modules/pico_nat.h delete mode 100644 ext/picotcp/modules/pico_olsr.c delete mode 100644 ext/picotcp/modules/pico_olsr.h delete mode 100644 ext/picotcp/modules/pico_posix.c delete mode 100644 ext/picotcp/modules/pico_slaacv4.c delete mode 100644 ext/picotcp/modules/pico_slaacv4.h delete mode 100644 ext/picotcp/modules/pico_sntp_client.c delete mode 100644 ext/picotcp/modules/pico_sntp_client.h delete mode 100644 ext/picotcp/modules/pico_socket_tcp.c delete mode 100644 ext/picotcp/modules/pico_socket_tcp.h delete mode 100644 ext/picotcp/modules/pico_socket_udp.c delete mode 100644 ext/picotcp/modules/pico_socket_udp.h delete mode 100644 ext/picotcp/modules/pico_strings.c delete mode 100644 ext/picotcp/modules/pico_strings.h delete mode 100644 ext/picotcp/modules/pico_tcp.c delete mode 100644 ext/picotcp/modules/pico_tcp.h delete mode 100644 ext/picotcp/modules/pico_tftp.c delete mode 100644 ext/picotcp/modules/pico_tftp.h delete mode 100644 ext/picotcp/modules/pico_udp.c delete mode 100644 ext/picotcp/modules/pico_udp.h delete mode 100644 ext/picotcp/rules/crc.mk delete mode 100644 ext/picotcp/rules/cyassl.mk delete mode 100644 ext/picotcp/rules/devloop.mk delete mode 100644 ext/picotcp/rules/dhcp_client.mk delete mode 100644 ext/picotcp/rules/dhcp_server.mk delete mode 100644 ext/picotcp/rules/dns_client.mk delete mode 100644 ext/picotcp/rules/dns_sd.mk delete mode 100644 ext/picotcp/rules/eth.mk delete mode 100644 ext/picotcp/rules/icmp4.mk delete mode 100644 ext/picotcp/rules/igmp.mk delete mode 100644 ext/picotcp/rules/ipfilter.mk delete mode 100644 ext/picotcp/rules/ipv4.mk delete mode 100644 ext/picotcp/rules/ipv4frag.mk delete mode 100644 ext/picotcp/rules/ipv6.mk delete mode 100644 ext/picotcp/rules/ipv6frag.mk delete mode 100644 ext/picotcp/rules/mcast.mk delete mode 100644 ext/picotcp/rules/mdns.mk delete mode 100644 ext/picotcp/rules/memory_manager.mk delete mode 100644 ext/picotcp/rules/mld.mk delete mode 100644 ext/picotcp/rules/nat.mk delete mode 100644 ext/picotcp/rules/olsr.mk delete mode 100644 ext/picotcp/rules/pcap.mk delete mode 100644 ext/picotcp/rules/polarssl.mk delete mode 100644 ext/picotcp/rules/ppp.mk delete mode 100644 ext/picotcp/rules/slaacv4.mk delete mode 100644 ext/picotcp/rules/sntp_client.mk delete mode 100644 ext/picotcp/rules/tap.mk delete mode 100644 ext/picotcp/rules/tcp.mk delete mode 100644 ext/picotcp/rules/tun.mk delete mode 100644 ext/picotcp/rules/udp.mk delete mode 100644 ext/picotcp/rules/wolfssl.mk delete mode 100644 ext/picotcp/stack/pico_device.c delete mode 100644 ext/picotcp/stack/pico_frame.c delete mode 100644 ext/picotcp/stack/pico_md5.c delete mode 100644 ext/picotcp/stack/pico_protocol.c delete mode 100644 ext/picotcp/stack/pico_socket.c delete mode 100644 ext/picotcp/stack/pico_socket_multicast.c delete mode 100644 ext/picotcp/stack/pico_stack.c delete mode 100644 ext/picotcp/stack/pico_tree.c delete mode 100644 ext/picotcp/uncrustify.cfg delete mode 100644 integrations/README.md delete mode 100644 integrations/Unity3D/Assembly-CSharp-Editor.csproj delete mode 100644 integrations/Unity3D/Assembly-CSharp.csproj delete mode 100644 integrations/Unity3D/Assets/CameraControl.js delete mode 100644 integrations/Unity3D/Assets/MainScene.unity delete mode 100755 integrations/Unity3D/Assets/MyZeroTier.cs delete mode 100755 integrations/Unity3D/Assets/WorldMain.cs delete mode 100755 integrations/Unity3D/Assets/ZT.mat delete mode 100755 integrations/Unity3D/Assets/ZTSDK.cs delete mode 100644 integrations/Unity3D/Assets/ZeroTierSockets_Demo.cs delete mode 100755 integrations/Unity3D/Assets/smcs.rsp delete mode 100644 integrations/Unity3D/Assets/zerotier-icon.png delete mode 100644 integrations/Unity3D/ProjectSettings/AudioManager.asset delete mode 100644 integrations/Unity3D/ProjectSettings/ClusterInputManager.asset delete mode 100644 integrations/Unity3D/ProjectSettings/DynamicsManager.asset delete mode 100644 integrations/Unity3D/ProjectSettings/EditorBuildSettings.asset delete mode 100644 integrations/Unity3D/ProjectSettings/EditorSettings.asset delete mode 100644 integrations/Unity3D/ProjectSettings/GraphicsSettings.asset delete mode 100644 integrations/Unity3D/ProjectSettings/InputManager.asset delete mode 100644 integrations/Unity3D/ProjectSettings/NavMeshAreas.asset delete mode 100644 integrations/Unity3D/ProjectSettings/NetworkManager.asset delete mode 100644 integrations/Unity3D/ProjectSettings/Physics2DSettings.asset delete mode 100644 integrations/Unity3D/ProjectSettings/ProjectSettings.asset delete mode 100644 integrations/Unity3D/ProjectSettings/ProjectVersion.txt delete mode 100644 integrations/Unity3D/ProjectSettings/QualitySettings.asset delete mode 100644 integrations/Unity3D/ProjectSettings/TagManager.asset delete mode 100644 integrations/Unity3D/ProjectSettings/TimeManager.asset delete mode 100644 integrations/Unity3D/ProjectSettings/UnityAdsSettings.asset delete mode 100644 integrations/Unity3D/ProjectSettings/UnityConnectSettings.asset delete mode 100644 integrations/Unity3D/README.md delete mode 100644 integrations/Unity3D/Unity3D.sln delete mode 100644 integrations/Unity3D/Unity3D.userprefs delete mode 100644 integrations/Unity3D/ZeroTier-Unity3D-Test.sln delete mode 100644 integrations/Unity3D/ZeroTier-Unity3D-Test.userprefs delete mode 100644 integrations/android/README.md delete mode 100644 integrations/android/android_jni_lib/java/build.xml delete mode 100644 integrations/android/android_jni_lib/java/jni/Android.mk delete mode 100644 integrations/android/android_jni_lib/java/jni/Android.pico.mk delete mode 100644 integrations/android/android_jni_lib/java/jni/Application.mk delete mode 100644 integrations/android/android_jni_lib/java/jni/Application.pico.mk delete mode 100644 integrations/android/android_jni_lib/proj/app/app.iml delete mode 100644 integrations/android/android_jni_lib/proj/app/build.gradle delete mode 100644 integrations/android/android_jni_lib/proj/app/google-services.json delete mode 100644 integrations/android/android_jni_lib/proj/app/proguard-rules.pro delete mode 100644 integrations/android/android_jni_lib/proj/app/src/androidTest/java/com/zerotier/one/ApplicationTest.java delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/AndroidManifest.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/ic_launcher-web.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/java/Netcon/ZT_SDK_Wrapper.java delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/button_style.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/hex.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/ic_launcher.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_allleft.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_allright.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_delete.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_done.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_left.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_return.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_right.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/drawable/txt.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/layout/activity_fragment.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/layout/fragment_join_network.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/layout/list_item_network.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/layout/list_item_recent_network.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/layout/network_list_fragment.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/menu/menu_network_list.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/values-w820dp/dimens.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/values/dimens.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/values/strings.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/values/styles.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/xml/app_tracker.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/xml/hex_keyboard.xml delete mode 100644 integrations/android/android_jni_lib/proj/app/src/main/res/xml/preferences.xml delete mode 100644 integrations/android/android_jni_lib/proj/build.gradle delete mode 100644 integrations/android/android_jni_lib/proj/gradle.properties delete mode 100644 integrations/android/android_jni_lib/proj/gradle/wrapper/gradle-wrapper.jar delete mode 100644 integrations/android/android_jni_lib/proj/gradle/wrapper/gradle-wrapper.properties delete mode 100755 integrations/android/android_jni_lib/proj/gradlew delete mode 100644 integrations/android/android_jni_lib/proj/gradlew.bat delete mode 100644 integrations/android/android_jni_lib/proj/proj.iml delete mode 100644 integrations/android/android_jni_lib/proj/settings.gradle delete mode 100644 integrations/android/android_jni_lib/proj/zerotierandroid.iml delete mode 100644 integrations/android/example_app/.gitignore delete mode 100644 integrations/android/example_app/app/.gitignore delete mode 100644 integrations/android/example_app/app/build.gradle delete mode 100644 integrations/android/example_app/app/proguard-rules.pro delete mode 100644 integrations/android/example_app/app/src/androidTest/java/com/example/joseph/example_app/ExampleInstrumentationTest.java delete mode 100644 integrations/android/example_app/app/src/main/AndroidManifest.xml delete mode 100644 integrations/android/example_app/app/src/main/java/ZeroTier/ZTAddress.java delete mode 100644 integrations/android/example_app/app/src/main/java/ZeroTier/ZTSDK.java delete mode 100644 integrations/android/example_app/app/src/main/java/com/example/joseph/example_app/MainActivity.java delete mode 100644 integrations/android/example_app/app/src/main/jniLibs/README.md delete mode 100644 integrations/android/example_app/app/src/main/res/layout/activity_main.xml delete mode 100644 integrations/android/example_app/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 integrations/android/example_app/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 integrations/android/example_app/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 integrations/android/example_app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 integrations/android/example_app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 integrations/android/example_app/app/src/main/res/values-w820dp/dimens.xml delete mode 100644 integrations/android/example_app/app/src/main/res/values/colors.xml delete mode 100644 integrations/android/example_app/app/src/main/res/values/dimens.xml delete mode 100644 integrations/android/example_app/app/src/main/res/values/strings.xml delete mode 100644 integrations/android/example_app/app/src/main/res/values/styles.xml delete mode 100644 integrations/android/example_app/app/src/test/java/com/example/joseph/example_app/ExampleUnitTest.java delete mode 100644 integrations/android/example_app/build.gradle delete mode 100644 integrations/android/example_app/gradle.properties delete mode 100644 integrations/android/example_app/gradle/wrapper/gradle-wrapper.jar delete mode 100644 integrations/android/example_app/gradle/wrapper/gradle-wrapper.properties delete mode 100755 integrations/android/example_app/gradlew delete mode 100644 integrations/android/example_app/gradlew.bat delete mode 100644 integrations/android/example_app/settings.gradle delete mode 100644 integrations/apple/README.md delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/project.pbxproj delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/project.xcworkspace/xcshareddata/ZeroTierSDK_Apple.xcscmblueprint delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/xcshareddata/xcschemes/ZeroTierSDK_OSX.xcscheme delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/xcshareddata/xcschemes/ZeroTierSDK_Unity3D_OSX.xcscheme delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/xcshareddata/xcschemes/ZeroTierSDK_Unity3D_iOS.xcscheme delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/xcshareddata/xcschemes/ZeroTierSDK_iOS.xcscheme delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_OSX/Info.plist delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_OSX/ZeroTierSDK_OSX.h delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Unity3D_OSX/Info.plist delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_Unity3D_iOS/Info.plist delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_iOS/Info.plist delete mode 100644 integrations/apple/ZeroTierSDK_Apple/ZeroTierSDK_iOS/ZeroTierSDK_iOS.h delete mode 100644 integrations/apple/example_app/OSX/Example_OSX_App.xcodeproj/project.pbxproj delete mode 100644 integrations/apple/example_app/OSX/Example_OSX_App.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 integrations/apple/example_app/OSX/Example_OSX_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 integrations/apple/example_app/OSX/Example_OSX_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/Example_OSX_App.xcscheme delete mode 100644 integrations/apple/example_app/OSX/Example_OSX_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 integrations/apple/example_app/OSX/Example_OSX_App/AppDelegate.swift delete mode 100644 integrations/apple/example_app/OSX/Example_OSX_App/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 integrations/apple/example_app/OSX/Example_OSX_App/Base.lproj/Main.storyboard delete mode 100644 integrations/apple/example_app/OSX/Example_OSX_App/Info.plist delete mode 100644 integrations/apple/example_app/OSX/Example_OSX_App/ViewController.swift delete mode 100644 integrations/apple/example_app/OSX/README.md delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/project.pbxproj delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/Example_iOS_App.xcscheme delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App/AppDelegate.swift delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App/Base.lproj/LaunchScreen.storyboard delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App/Base.lproj/Main.storyboard delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App/Info.plist delete mode 100644 integrations/apple/example_app/iOS/Example_iOS_App/ViewController.swift delete mode 100644 integrations/apple/example_app/iOS/README.md delete mode 100644 integrations/docker/README.md delete mode 100755 integrations/docker/_remove_all.sh delete mode 100644 integrations/docker/docker_demo/README.md delete mode 100644 integrations/docker/docker_demo/docker_demo.name delete mode 100644 integrations/docker/docker_demo/hello.lua delete mode 100644 integrations/docker/docker_demo/monitor_dockerfile delete mode 100644 integrations/docker/docker_demo/monitor_entrypoint.sh delete mode 100644 integrations/docker/docker_demo/sdk_dockerfile delete mode 100644 integrations/docker/docker_demo/sdk_entrypoint.sh delete mode 100755 integrations/docker/docker_demo/start.sh delete mode 100755 integrations/docker/docker_demo/stop.sh delete mode 100644 integrations/simple_app/app.cpp delete mode 100644 make-liblwip.mk delete mode 100644 make-linux.mk delete mode 100644 make-mac.mk delete mode 100644 objects.mk delete mode 100644 src/README.md delete mode 100644 src/debug.h delete mode 100644 src/defs.h delete mode 100644 src/intercept.c delete mode 100644 src/proxy.cpp delete mode 100644 src/rpc.c delete mode 100644 src/rpc.h delete mode 100644 src/sdk.h delete mode 100644 src/sdkutils.hpp delete mode 100644 src/service.cpp delete mode 100644 src/sockets.c delete mode 100644 src/stack_drivers/README.md delete mode 100644 src/stack_drivers/jip/README.md delete mode 100644 src/stack_drivers/jip/jip.cpp delete mode 100644 src/stack_drivers/jip/jip.hpp delete mode 100644 src/stack_drivers/lwip/README.md delete mode 100644 src/stack_drivers/lwip/lwip.cpp delete mode 100644 src/stack_drivers/lwip/lwip.hpp delete mode 100644 src/stack_drivers/lwip/lwipopts.h delete mode 100644 src/stack_drivers/picotcp/README.md delete mode 100644 src/stack_drivers/picotcp/picotcp.cpp delete mode 100644 src/stack_drivers/picotcp/picotcp.hpp delete mode 100644 src/tap.cpp delete mode 100644 src/tap.hpp delete mode 100644 src/wrappers/README.md delete mode 100755 src/wrappers/dotnet/DotNetWrapper.cs delete mode 100644 src/wrappers/java/JavaWrapper.java delete mode 100644 src/wrappers/java/ZTAddress.java delete mode 100644 src/wrappers/swift/Apple-Bridging-Header.h delete mode 100755 src/wrappers/swift/XcodeWrapper.cpp delete mode 100755 src/wrappers/swift/XcodeWrapper.hpp delete mode 100644 src/wrappers/swift/ztsdk.swift delete mode 100644 tests/README.md delete mode 100755 tests/api_test/clients.sh delete mode 100644 tests/api_test/multiclient.c delete mode 100644 tests/api_test/multiserve.c delete mode 100644 tests/api_test/pressureclient4.c delete mode 100644 tests/api_test/pressureserver4.c delete mode 100755 tests/api_test/servers.sh delete mode 100644 tests/api_test/tcpclient4.c delete mode 100644 tests/api_test/tcpclient6.c delete mode 100644 tests/api_test/tcpserver4.c delete mode 100644 tests/api_test/tcpserver6.c delete mode 100755 tests/api_test/test.sh delete mode 100755 tests/api_test/udpclient4.c delete mode 100755 tests/api_test/udpclient6.c delete mode 100755 tests/api_test/udpserver4.c delete mode 100755 tests/api_test/udpserver6.c delete mode 100755 tests/cleanup.sh delete mode 100755 tests/docker/_remove_all.sh delete mode 100755 tests/docker/_two_party_test.sh delete mode 100755 tests/docker/build_images.sh delete mode 100755 tests/docker/darkhttpd/darkhttpd-1.11.x86_64/_build_single_image.sh delete mode 100755 tests/docker/darkhttpd/darkhttpd-1.11.x86_64/_two_party_test.sh delete mode 100644 tests/docker/darkhttpd/darkhttpd-1.11.x86_64/darkhttpd-1.11.x86_64.name delete mode 100644 tests/docker/darkhttpd/darkhttpd-1.11.x86_64/monitor_dockerfile delete mode 100644 tests/docker/darkhttpd/darkhttpd-1.11.x86_64/monitor_entrypoint.sh delete mode 100644 tests/docker/darkhttpd/darkhttpd-1.11.x86_64/sdk_dockerfile delete mode 100644 tests/docker/darkhttpd/darkhttpd-1.11.x86_64/sdk_entrypoint.sh delete mode 100644 tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/monitor_dockerfile delete mode 100644 tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/monitor_entrypoint.sh delete mode 100644 tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/sdk_dockerfile delete mode 100644 tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/sdk_entrypoint.sh delete mode 100644 tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/monitor_dockerfile delete mode 100644 tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/monitor_entrypoint.sh delete mode 100644 tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/sdk_dockerfile delete mode 100644 tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/sdk_entrypoint.sh delete mode 100755 tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/_two_party_test.sh delete mode 100644 tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/httpd-2.4.18-1.fc23.x86_64.name delete mode 100644 tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/monitor_dockerfile delete mode 100644 tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/monitor_entrypoint.sh delete mode 100644 tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/sdk_dockerfile delete mode 100644 tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/sdk_entrypoint.sh delete mode 100644 tests/docker/httpd/httpd_demo/htdocs/ZeroTierIcon.png delete mode 100644 tests/docker/httpd/httpd_demo/htdocs/index.html delete mode 100644 tests/docker/httpd/httpd_demo/monitor_dockerfile delete mode 100644 tests/docker/httpd/httpd_demo/monitor_entrypoint.sh delete mode 100644 tests/docker/httpd/httpd_demo/sdk_dockerfile delete mode 100644 tests/docker/httpd/httpd_demo/sdk_entrypoint.sh delete mode 100644 tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/monitor_dockerfile delete mode 100644 tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/monitor_entrypoint.sh delete mode 100644 tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/nginx.conf_ delete mode 100644 tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/sdk_dockerfile delete mode 100644 tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/sdk_entrypoint.sh delete mode 100755 tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/_two_party_test.sh delete mode 100644 tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/monitor_dockerfile delete mode 100644 tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/monitor_entrypoint.sh delete mode 100644 tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/nginx.conf_ delete mode 100644 tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/sdk_dockerfile delete mode 100644 tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/sdk_entrypoint.sh delete mode 100644 tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/monitor_dockerfile delete mode 100644 tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/monitor_entrypoint.sh delete mode 100644 tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/nginx.conf_ delete mode 100644 tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/sdk_dockerfile delete mode 100644 tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/sdk_entrypoint.sh delete mode 100644 tests/docker/nodejs/nodejs-0.10.36-4.fc23/httpserver.js delete mode 100644 tests/docker/nodejs/nodejs-0.10.36-4.fc23/monitor_dockerfile delete mode 100644 tests/docker/nodejs/nodejs-0.10.36-4.fc23/monitor_entrypoint.sh delete mode 100644 tests/docker/nodejs/nodejs-0.10.36-4.fc23/sdk_dockerfile delete mode 100644 tests/docker/nodejs/nodejs-0.10.36-4.fc23/sdk_entrypoint.sh delete mode 100644 tests/docker/python/python/monitor_dockerfile delete mode 100644 tests/docker/python/python/monitor_entrypoint.sh delete mode 100644 tests/docker/python/python/sdk_dockerfile delete mode 100644 tests/docker/python/python/sdk_entrypoint.sh delete mode 100644 tests/docker/python/python3/monitor_dockerfile delete mode 100644 tests/docker/python/python3/monitor_entrypoint.sh delete mode 100644 tests/docker/python/python3/sdk_dockerfile delete mode 100644 tests/docker/python/python3/sdk_entrypoint.sh delete mode 100644 tests/docker/redis/redis-3.0.4-1.fc23.x86_64/hello.lua delete mode 100644 tests/docker/redis/redis-3.0.4-1.fc23.x86_64/monitor_dockerfile delete mode 100644 tests/docker/redis/redis-3.0.4-1.fc23.x86_64/monitor_entrypoint.sh delete mode 100644 tests/docker/redis/redis-3.0.4-1.fc23.x86_64/sdk_dockerfile delete mode 100644 tests/docker/redis/redis-3.0.4-1.fc23.x86_64/sdk_entrypoint.sh delete mode 100644 tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/monitor_dockerfile delete mode 100644 tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/monitor_entrypoint.sh delete mode 100644 tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/sdk_dockerfile delete mode 100644 tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/sdk_entrypoint.sh delete mode 100755 tests/docker/test.sh delete mode 100644 tests/httpserver.js delete mode 100644 tests/results/README.md delete mode 100644 tests/test.sh delete mode 100644 tests/unit/README.md delete mode 100755 tests/unit/_remove_all.sh delete mode 100644 tests/unit/docker/565799d8f658068e.conf delete mode 100644 tests/unit/docker/README.md delete mode 100644 tests/unit/docker/docker_demo.name delete mode 100644 tests/unit/docker/hello.lua delete mode 100644 tests/unit/docker/monitor_dockerfile delete mode 100644 tests/unit/docker/monitor_entrypoint.sh delete mode 100644 tests/unit/docker/sdk_dockerfile delete mode 100644 tests/unit/docker/sdk_entrypoint.sh delete mode 100755 tests/unit/docker/start.sh delete mode 100755 tests/unit/docker/stop.sh delete mode 100644 tests/zts/zts.tcpclient4.c delete mode 100644 tests/zts/zts.tcpclient6.c delete mode 100644 tests/zts/zts.tcpserver4.c delete mode 100644 tests/zts/zts.tcpserver6.c delete mode 100755 tests/zts/zts.udpclient4.c delete mode 100755 tests/zts/zts.udpclient6.c delete mode 100755 tests/zts/zts.udpserver4.c delete mode 100755 tests/zts/zts.udpserver6.c delete mode 100644 zto/AUTHORS.md delete mode 100644 zto/COPYING delete mode 100644 zto/LICENSE.GPL-2 delete mode 100644 zto/LICENSE.GPL-3 delete mode 100644 zto/Makefile delete mode 100644 zto/README.md delete mode 100644 zto/RELEASE-NOTES.md delete mode 100644 zto/controller/EmbeddedNetworkController.cpp delete mode 100644 zto/controller/EmbeddedNetworkController.hpp delete mode 100644 zto/controller/JSONDB.cpp delete mode 100644 zto/controller/JSONDB.hpp delete mode 100644 zto/controller/README.md delete mode 100644 zto/controller/migrate-sqlite/migrate.js delete mode 100644 zto/controller/migrate-sqlite/package.json delete mode 100644 zto/ext/README.md delete mode 100644 zto/ext/bin/tap-mac/tap.kext/Contents/Info.plist delete mode 100755 zto/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap delete mode 100644 zto/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeResources delete mode 100644 zto/ext/bin/tap-windows-ndis6/x64/zttap300.cat delete mode 100644 zto/ext/bin/tap-windows-ndis6/x64/zttap300.inf delete mode 100644 zto/ext/bin/tap-windows-ndis6/x64/zttap300.sys delete mode 100644 zto/ext/bin/tap-windows-ndis6/x86/zttap300.cat delete mode 100644 zto/ext/bin/tap-windows-ndis6/x86/zttap300.inf delete mode 100644 zto/ext/bin/tap-windows-ndis6/x86/zttap300.sys delete mode 100644 zto/ext/http-parser/AUTHORS delete mode 100644 zto/ext/http-parser/LICENSE-MIT delete mode 100644 zto/ext/http-parser/README.md delete mode 100644 zto/ext/http-parser/http_parser.c delete mode 100644 zto/ext/http-parser/http_parser.h delete mode 100644 zto/ext/json/LICENSE.MIT delete mode 100644 zto/ext/json/README.md delete mode 100644 zto/ext/json/json.hpp delete mode 100644 zto/ext/libnatpmp/Changelog.txt delete mode 100644 zto/ext/libnatpmp/JavaTest.java delete mode 100644 zto/ext/libnatpmp/LICENSE delete mode 100644 zto/ext/libnatpmp/Makefile delete mode 100644 zto/ext/libnatpmp/README delete mode 100644 zto/ext/libnatpmp/build.bat delete mode 100644 zto/ext/libnatpmp/declspec.h delete mode 100644 zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/LibraryExtractor.java delete mode 100644 zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/NatPmp.java delete mode 100644 zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/NatPmpResponse.java delete mode 100644 zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/URLUtils.java delete mode 100644 zto/ext/libnatpmp/getgateway.c delete mode 100644 zto/ext/libnatpmp/getgateway.h delete mode 100644 zto/ext/libnatpmp/libnatpmpmodule.c delete mode 100644 zto/ext/libnatpmp/msvc/libnatpmp.sln delete mode 100644 zto/ext/libnatpmp/msvc/libnatpmp.vcproj delete mode 100644 zto/ext/libnatpmp/msvc/natpmpc-static.vcproj delete mode 100644 zto/ext/libnatpmp/natpmp-jni.c delete mode 100644 zto/ext/libnatpmp/natpmp.c delete mode 100644 zto/ext/libnatpmp/natpmp.def delete mode 100644 zto/ext/libnatpmp/natpmp.h delete mode 100644 zto/ext/libnatpmp/natpmpc.1 delete mode 100644 zto/ext/libnatpmp/natpmpc.c delete mode 100644 zto/ext/libnatpmp/setup.py delete mode 100644 zto/ext/libnatpmp/setupmingw32.py delete mode 100644 zto/ext/libnatpmp/testgetgateway.c delete mode 100644 zto/ext/libnatpmp/wingettimeofday.c delete mode 100644 zto/ext/libnatpmp/wingettimeofday.h delete mode 100644 zto/ext/miniupnpc/Changelog.txt delete mode 100644 zto/ext/miniupnpc/LICENSE delete mode 100644 zto/ext/miniupnpc/MANIFEST.in delete mode 100644 zto/ext/miniupnpc/README delete mode 100644 zto/ext/miniupnpc/VERSION delete mode 100644 zto/ext/miniupnpc/apiversions.txt delete mode 100644 zto/ext/miniupnpc/codelength.h delete mode 100644 zto/ext/miniupnpc/connecthostport.c delete mode 100644 zto/ext/miniupnpc/connecthostport.h delete mode 100755 zto/ext/miniupnpc/external-ip.sh delete mode 100644 zto/ext/miniupnpc/igd_desc_parse.c delete mode 100644 zto/ext/miniupnpc/igd_desc_parse.h delete mode 100644 zto/ext/miniupnpc/listdevices.c delete mode 100644 zto/ext/miniupnpc/mingw32make.bat delete mode 100644 zto/ext/miniupnpc/minihttptestserver.c delete mode 100644 zto/ext/miniupnpc/minisoap.c delete mode 100644 zto/ext/miniupnpc/minisoap.h delete mode 100644 zto/ext/miniupnpc/minissdpc.c delete mode 100644 zto/ext/miniupnpc/minissdpc.h delete mode 100644 zto/ext/miniupnpc/miniupnpc.c delete mode 100644 zto/ext/miniupnpc/miniupnpc.def delete mode 100644 zto/ext/miniupnpc/miniupnpc.h delete mode 100644 zto/ext/miniupnpc/miniupnpc_declspec.h delete mode 100644 zto/ext/miniupnpc/miniupnpcmodule.c delete mode 100644 zto/ext/miniupnpc/miniupnpcstrings.h.in delete mode 100644 zto/ext/miniupnpc/miniupnpctypes.h delete mode 100644 zto/ext/miniupnpc/miniwget.c delete mode 100644 zto/ext/miniupnpc/miniwget.h delete mode 100644 zto/ext/miniupnpc/minixml.c delete mode 100644 zto/ext/miniupnpc/minixml.h delete mode 100644 zto/ext/miniupnpc/minixmlvalid.c delete mode 100644 zto/ext/miniupnpc/portlistingparse.c delete mode 100644 zto/ext/miniupnpc/portlistingparse.h delete mode 100644 zto/ext/miniupnpc/pymoduletest.py delete mode 100644 zto/ext/miniupnpc/receivedata.c delete mode 100644 zto/ext/miniupnpc/receivedata.h delete mode 100644 zto/ext/miniupnpc/setup.py delete mode 100644 zto/ext/miniupnpc/setupmingw32.py delete mode 100644 zto/ext/miniupnpc/testdesc/linksys_WAG200G_desc.values delete mode 100644 zto/ext/miniupnpc/testdesc/linksys_WAG200G_desc.xml delete mode 100644 zto/ext/miniupnpc/testdesc/new_LiveBox_desc.values delete mode 100644 zto/ext/miniupnpc/testdesc/new_LiveBox_desc.xml delete mode 100644 zto/ext/miniupnpc/testigddescparse.c delete mode 100644 zto/ext/miniupnpc/testminiwget.c delete mode 100755 zto/ext/miniupnpc/testminiwget.sh delete mode 100644 zto/ext/miniupnpc/testminixml.c delete mode 100644 zto/ext/miniupnpc/testportlistingparse.c delete mode 100644 zto/ext/miniupnpc/testreplyparse/DeletePortMapping.namevalue delete mode 100644 zto/ext/miniupnpc/testreplyparse/DeletePortMapping.xml delete mode 100644 zto/ext/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue delete mode 100644 zto/ext/miniupnpc/testreplyparse/GetExternalIPAddress.xml delete mode 100644 zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue delete mode 100644 zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml delete mode 100644 zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue delete mode 100644 zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml delete mode 100644 zto/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue delete mode 100644 zto/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.xml delete mode 100644 zto/ext/miniupnpc/testreplyparse/readme.txt delete mode 100755 zto/ext/miniupnpc/testupnpigd.py delete mode 100644 zto/ext/miniupnpc/testupnpreplyparse.c delete mode 100755 zto/ext/miniupnpc/testupnpreplyparse.sh delete mode 100755 zto/ext/miniupnpc/updateminiupnpcstrings.sh delete mode 100644 zto/ext/miniupnpc/upnpc.c delete mode 100644 zto/ext/miniupnpc/upnpcommands.c delete mode 100644 zto/ext/miniupnpc/upnpcommands.h delete mode 100644 zto/ext/miniupnpc/upnpdev.c delete mode 100644 zto/ext/miniupnpc/upnpdev.h delete mode 100644 zto/ext/miniupnpc/upnperrors.c delete mode 100644 zto/ext/miniupnpc/upnperrors.h delete mode 100644 zto/ext/miniupnpc/upnpreplyparse.c delete mode 100644 zto/ext/miniupnpc/upnpreplyparse.h delete mode 100644 zto/ext/miniupnpc/wingenminiupnpcstrings.c delete mode 100644 zto/ext/tap-mac/README.txt delete mode 100644 zto/ext/tap-mac/tuntap/Makefile delete mode 100644 zto/ext/tap-mac/tuntap/src/lock.cc delete mode 100644 zto/ext/tap-mac/tuntap/src/lock.h delete mode 100644 zto/ext/tap-mac/tuntap/src/mem.cc delete mode 100644 zto/ext/tap-mac/tuntap/src/mem.h delete mode 100644 zto/ext/tap-mac/tuntap/src/tap/Info.plist delete mode 100644 zto/ext/tap-mac/tuntap/src/tap/Makefile delete mode 100644 zto/ext/tap-mac/tuntap/src/tap/kmod.cc delete mode 100644 zto/ext/tap-mac/tuntap/src/tap/tap.cc delete mode 100644 zto/ext/tap-mac/tuntap/src/tap/tap.h delete mode 100644 zto/ext/tap-mac/tuntap/src/tuntap.cc delete mode 100644 zto/ext/tap-mac/tuntap/src/tuntap.h delete mode 100644 zto/ext/tap-mac/tuntap/src/tuntap_mgr.cc delete mode 100644 zto/ext/tap-mac/tuntap/src/util.h delete mode 100644 zto/include/README.md delete mode 100644 zto/include/ZeroTierOne.h delete mode 100644 zto/make-bsd.mk delete mode 100644 zto/make-linux.mk delete mode 100644 zto/make-mac.mk delete mode 100644 zto/node/Address.hpp delete mode 100644 zto/node/Array.hpp delete mode 100644 zto/node/AtomicCounter.hpp delete mode 100644 zto/node/Buffer.hpp delete mode 100644 zto/node/C25519.cpp delete mode 100644 zto/node/C25519.hpp delete mode 100644 zto/node/Capability.cpp delete mode 100644 zto/node/Capability.hpp delete mode 100644 zto/node/CertificateOfMembership.cpp delete mode 100644 zto/node/CertificateOfMembership.hpp delete mode 100644 zto/node/CertificateOfOwnership.cpp delete mode 100644 zto/node/CertificateOfOwnership.hpp delete mode 100644 zto/node/CertificateOfRepresentation.hpp delete mode 100644 zto/node/Cluster.cpp delete mode 100644 zto/node/Cluster.hpp delete mode 100644 zto/node/Constants.hpp delete mode 100644 zto/node/Dictionary.hpp delete mode 100644 zto/node/Hashtable.hpp delete mode 100644 zto/node/Identity.cpp delete mode 100644 zto/node/Identity.hpp delete mode 100644 zto/node/IncomingPacket.cpp delete mode 100644 zto/node/IncomingPacket.hpp delete mode 100644 zto/node/InetAddress.cpp delete mode 100644 zto/node/InetAddress.hpp delete mode 100644 zto/node/MAC.hpp delete mode 100644 zto/node/Membership.cpp delete mode 100644 zto/node/Membership.hpp delete mode 100644 zto/node/MulticastGroup.hpp delete mode 100644 zto/node/Multicaster.cpp delete mode 100644 zto/node/Multicaster.hpp delete mode 100644 zto/node/Mutex.hpp delete mode 100644 zto/node/Network.cpp delete mode 100644 zto/node/Network.hpp delete mode 100644 zto/node/NetworkConfig.cpp delete mode 100644 zto/node/NetworkConfig.hpp delete mode 100644 zto/node/NetworkController.hpp delete mode 100644 zto/node/Node.cpp delete mode 100644 zto/node/Node.hpp delete mode 100644 zto/node/NonCopyable.hpp delete mode 100644 zto/node/OutboundMulticast.cpp delete mode 100644 zto/node/OutboundMulticast.hpp delete mode 100644 zto/node/Packet.cpp delete mode 100644 zto/node/Packet.hpp delete mode 100644 zto/node/Path.cpp delete mode 100644 zto/node/Path.hpp delete mode 100644 zto/node/Peer.cpp delete mode 100644 zto/node/Peer.hpp delete mode 100644 zto/node/Poly1305.cpp delete mode 100644 zto/node/Poly1305.hpp delete mode 100644 zto/node/README.md delete mode 100644 zto/node/Revocation.cpp delete mode 100644 zto/node/Revocation.hpp delete mode 100644 zto/node/RuntimeEnvironment.hpp delete mode 100644 zto/node/SHA512.cpp delete mode 100644 zto/node/SHA512.hpp delete mode 100644 zto/node/Salsa20.cpp delete mode 100644 zto/node/Salsa20.hpp delete mode 100644 zto/node/SelfAwareness.cpp delete mode 100644 zto/node/SelfAwareness.hpp delete mode 100644 zto/node/SharedPtr.hpp delete mode 100644 zto/node/Switch.cpp delete mode 100644 zto/node/Switch.hpp delete mode 100644 zto/node/Tag.cpp delete mode 100644 zto/node/Tag.hpp delete mode 100644 zto/node/Topology.cpp delete mode 100644 zto/node/Topology.hpp delete mode 100644 zto/node/Utils.cpp delete mode 100644 zto/node/Utils.hpp delete mode 100644 zto/node/World.hpp delete mode 100644 zto/objects.mk delete mode 100644 zto/one.cpp delete mode 100644 zto/osdep/Arp.cpp delete mode 100644 zto/osdep/Arp.hpp delete mode 100644 zto/osdep/BSDEthernetTap.cpp delete mode 100644 zto/osdep/BSDEthernetTap.hpp delete mode 100644 zto/osdep/Binder.hpp delete mode 100644 zto/osdep/BlockingQueue.hpp delete mode 100644 zto/osdep/Http.cpp delete mode 100644 zto/osdep/Http.hpp delete mode 100644 zto/osdep/LinuxEthernetTap.cpp delete mode 100644 zto/osdep/LinuxEthernetTap.hpp delete mode 100644 zto/osdep/ManagedRoute.cpp delete mode 100644 zto/osdep/ManagedRoute.hpp delete mode 100644 zto/osdep/NeighborDiscovery.cpp delete mode 100644 zto/osdep/NeighborDiscovery.hpp delete mode 100644 zto/osdep/OSUtils.cpp delete mode 100644 zto/osdep/OSUtils.hpp delete mode 100644 zto/osdep/OSXEthernetTap.cpp delete mode 100644 zto/osdep/OSXEthernetTap.hpp delete mode 100644 zto/osdep/Phy.hpp delete mode 100644 zto/osdep/PortMapper.cpp delete mode 100644 zto/osdep/PortMapper.hpp delete mode 100644 zto/osdep/README.md delete mode 100644 zto/osdep/Thread.hpp delete mode 100644 zto/osdep/WindowsEthernetTap.cpp delete mode 100644 zto/osdep/WindowsEthernetTap.hpp delete mode 100644 zto/selftest.cpp delete mode 100644 zto/service/ClusterDefinition.hpp delete mode 100644 zto/service/ClusterGeoIpService.cpp delete mode 100644 zto/service/ClusterGeoIpService.hpp delete mode 100644 zto/service/OneService.cpp delete mode 100644 zto/service/OneService.hpp delete mode 100644 zto/service/README.md delete mode 100644 zto/service/SoftwareUpdater.cpp delete mode 100644 zto/service/SoftwareUpdater.hpp delete mode 100644 zto/tcp-proxy/Makefile delete mode 100644 zto/tcp-proxy/README.md delete mode 100644 zto/tcp-proxy/tcp-proxy.cpp delete mode 100644 zto/version.h delete mode 100644 zto/windows/README.md delete mode 100644 zto/windows/TapDriver6/TapDriver6.vcxproj delete mode 100644 zto/windows/TapDriver6/TapDriver6.vcxproj.filters delete mode 100644 zto/windows/TapDriver6/adapter.c delete mode 100644 zto/windows/TapDriver6/adapter.h delete mode 100644 zto/windows/TapDriver6/config.h delete mode 100644 zto/windows/TapDriver6/constants.h delete mode 100644 zto/windows/TapDriver6/device.c delete mode 100644 zto/windows/TapDriver6/device.h delete mode 100644 zto/windows/TapDriver6/endian.h delete mode 100644 zto/windows/TapDriver6/error.c delete mode 100644 zto/windows/TapDriver6/error.h delete mode 100644 zto/windows/TapDriver6/hexdump.h delete mode 100644 zto/windows/TapDriver6/lock.h delete mode 100644 zto/windows/TapDriver6/macinfo.c delete mode 100644 zto/windows/TapDriver6/macinfo.h delete mode 100644 zto/windows/TapDriver6/mem.c delete mode 100644 zto/windows/TapDriver6/mem.h delete mode 100644 zto/windows/TapDriver6/oidrequest.c delete mode 100644 zto/windows/TapDriver6/proto.h delete mode 100644 zto/windows/TapDriver6/prototypes.h delete mode 100644 zto/windows/TapDriver6/resource.h delete mode 100644 zto/windows/TapDriver6/resource.rc delete mode 100644 zto/windows/TapDriver6/rxpath.c delete mode 100644 zto/windows/TapDriver6/tap-windows.h delete mode 100644 zto/windows/TapDriver6/tap.h delete mode 100644 zto/windows/TapDriver6/tapdrvr.c delete mode 100644 zto/windows/TapDriver6/txpath.c delete mode 100644 zto/windows/TapDriver6/types.h delete mode 100644 zto/windows/TapDriver6/zttap300.inf delete mode 100644 zto/windows/WinUI/APIHandler.cs delete mode 100644 zto/windows/WinUI/AboutView.xaml delete mode 100644 zto/windows/WinUI/AboutView.xaml.cs delete mode 100644 zto/windows/WinUI/App.config delete mode 100644 zto/windows/WinUI/App.xaml delete mode 100644 zto/windows/WinUI/App.xaml.cs delete mode 100644 zto/windows/WinUI/JoinNetworkView.xaml delete mode 100644 zto/windows/WinUI/JoinNetworkView.xaml.cs delete mode 100644 zto/windows/WinUI/MainWindow.xaml.cs delete mode 100644 zto/windows/WinUI/NetworkInfoView.xaml delete mode 100644 zto/windows/WinUI/NetworkInfoView.xaml.cs delete mode 100644 zto/windows/WinUI/NetworkListView.xaml delete mode 100644 zto/windows/WinUI/NetworkListView.xaml.cs delete mode 100644 zto/windows/WinUI/NetworkMonitor.cs delete mode 100644 zto/windows/WinUI/NetworkRoute.cs delete mode 100644 zto/windows/WinUI/NetworksPage.xaml delete mode 100644 zto/windows/WinUI/NetworksPage.xaml.cs delete mode 100644 zto/windows/WinUI/PeersPage.xaml delete mode 100644 zto/windows/WinUI/PeersPage.xaml.cs delete mode 100644 zto/windows/WinUI/PreferencesView.xaml delete mode 100644 zto/windows/WinUI/PreferencesView.xaml.cs delete mode 100644 zto/windows/WinUI/Properties/AssemblyInfo.cs delete mode 100644 zto/windows/WinUI/Properties/Resources.Designer.cs delete mode 100644 zto/windows/WinUI/Properties/Resources.resx delete mode 100644 zto/windows/WinUI/Properties/Settings.Designer.cs delete mode 100644 zto/windows/WinUI/Properties/Settings.settings delete mode 100644 zto/windows/WinUI/Resources/ZeroTierIcon.ico delete mode 100644 zto/windows/WinUI/Simple Styles.xaml delete mode 100644 zto/windows/WinUI/Themes/Generic.xaml delete mode 100644 zto/windows/WinUI/ToolbarItem.xaml delete mode 100644 zto/windows/WinUI/ToolbarItem.xaml.cs delete mode 100644 zto/windows/WinUI/WinUI.csproj delete mode 100644 zto/windows/WinUI/ZeroTierIcon.ico delete mode 100644 zto/windows/WinUI/ZeroTierNetwork.cs delete mode 100644 zto/windows/WinUI/ZeroTierPeer.cs delete mode 100644 zto/windows/WinUI/ZeroTierPeerPhysicalPath.cs delete mode 100644 zto/windows/WinUI/ZeroTierStatus.cs delete mode 100644 zto/windows/WinUI/app.manifest delete mode 100644 zto/windows/WinUI/packages.config delete mode 100644 zto/windows/ZeroTierOne.sln delete mode 100644 zto/windows/copyutil/App.config delete mode 100644 zto/windows/copyutil/Program.cs delete mode 100644 zto/windows/copyutil/Properties/AssemblyInfo.cs delete mode 100644 zto/windows/copyutil/copyutil.csproj delete mode 100644 zto/windows/packages/.gitignore delete mode 100644 zto/windows/packages/repositories.config delete mode 100644 zto/zerotier-one.spec diff --git a/COPYING b/COPYING deleted file mode 100644 index 23d42df..0000000 --- a/COPYING +++ /dev/null @@ -1,17 +0,0 @@ -ZeroTier One, an endpoint server for the ZeroTier virtual network layer. -Copyright © 2011–2016 ZeroTier, Inc. - -ZeroTier One is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at -your option) any later version. - -See the file ‘LICENSE.GPL-3’ for the text of the GNU GPL version 3. -If that file is not present, see . - -.. - Local variables: - coding: utf-8 - mode: text - End: - vim: fileencoding=utf-8 filetype=text : diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 5b5a15f..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,382 +0,0 @@ -#!/usr/bin/env groovy - -def changelog = getChangeLog currentBuild -slackSend "Building ${env.JOB_NAME} #${env.BUILD_NUMBER} \n Change Log: \n ${changelog}" - -parallel 'centos7': { - node('centos7') { - - // ------------------------------------------------------------------------------ - // --------------------------- Network Stacks (Linux) --------------------------- - // ------------------------------------------------------------------------------ - - try { - checkout scm - stage('linux lwIP IPv4') { - sh 'make clean; make lwip SDK_IPV4=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on centos7 (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('linux lwIP IPv6') { - sh 'make clean; make lwip SDK_IPV6=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on centos7 (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('linux picoTCP IPv4') { - sh 'make clean; make pico SDK_IPV4=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on centos7 (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('linux picoTCP IPv6') { - sh 'make clean; make pico SDK_IPV6=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on centos7 (<${env.BUILD_URL}|Open>)" - throw err - } - - // ------------------------------------------------------------------------------ - // ------------------------ SDK Service Library (Linux) ------------------------- - // ------------------------------------------------------------------------------ - - try { - checkout scm - stage('linux_sdk_service (lwIP IPv4)') { - sh 'make clean; make linux_sdk_service SDK_LWIP=1 SDK_IPV4=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on centos7 (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('linux_sdk_service (lwIP IPv6)') { - sh 'make clean; make linux_sdk_service SDK_LWIP=1 SDK_IPV6=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on centos7 (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('linux_sdk_service (picoTCP IPv4)') { - sh 'make clean; make linux_sdk_service SDK_PICOTCP=1 SDK_IPV4=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on centos7 (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('linux_sdk_service (picoTCP IPv6)') { - sh 'make clean; make linux_sdk_service SDK_PICOTCP=1 SDK_IPV6=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on centos7 (<${env.BUILD_URL}|Open>)" - throw err - } - - - // ------------------------------------------------------------------------------ - // ---------------------------- static library (Linux) -------------------------- - // ------------------------------------------------------------------------------ - - - try { - checkout scm - stage('macOS shared lib') { - sh 'make linux_static_lib SDK_PICOTCP=1 SDK_IPV4=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - - try { - checkout scm - stage('macOS shared lib') { - sh 'make linux_static_lib SDK_PICOTCP=1 SDK_IPV6=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - - // ------------------------------------------------------------------------------ - // --------------------------- Intercept Library (Linux) ------------------------ - // ------------------------------------------------------------------------------ - - try { - checkout scm - stage('linux_intercept') { - sh 'make clean; make linux_intercept' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on centos7 (<${env.BUILD_URL}|Open>)" - throw err - } - - // ------------------------------------------------------------------------------ - // ------------------------------ Unit tests (linux) ---------------------------- - // ------------------------------------------------------------------------------ - - try { - checkout scm - stage('linux tests') { - sh 'make tests' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on centos7 (<${env.BUILD_URL}|Open>)" - throw err - } - - } -}, 'macOS': { - node('macOS') { - - unlockKeychainMac "~/Library/Keychains/login.keychain-db" - - // ------------------------------------------------------------------------------ - // --------------------------- Network Stacks (macOS) --------------------------- - // ------------------------------------------------------------------------------ - - try { - checkout scm - stage('macOS lwIP IPv4') { - sh 'make clean; make lwip SDK_IPV4=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('macOS lwIP IPv6') { - sh 'make clean; make lwip SDK_IPV6=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('macOS picoTCP IPv4') { - sh 'make clean; make pico SDK_IPV4=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('macOS picoTCP IPv6') { - sh 'make clean; make pico SDK_IPV6=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - - - // ------------------------------------------------------------------------------ - // -------------------------- Intercept Library (macOS) ------------------------- - // ------------------------------------------------------------------------------ - - try { - checkout scm - stage('osx_intercept') { - sh 'make osx_intercept' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - - // ------------------------------------------------------------------------------ - // -------------------------- SDK Service Library (macOS) ----------------------- - // ------------------------------------------------------------------------------ - - try { - checkout scm - stage('osx_service_and_intercept (lwIP IPv4)') { - sh 'make osx_service_and_intercept SDK_LWIP=1 SDK_IPV4=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('osx_service_and_intercept (lwIP IPv6)') { - sh 'make osx_service_and_intercept SDK_LWIP=1 SDK_IPV6=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('osx_service_and_intercept (picoTCP IPv4)') { - sh 'make osx_service_and_intercept SDK_PICOTCP=1 SDK_IPV4=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - - try { - checkout scm - stage('osx_service_and_intercept (lwIP IPv4)') { - sh 'make osx_service_and_intercept SDK_PICOTCP=1 SDK_IPV6=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - - // ------------------------------------------------------------------------------ - // ---------------------------- App Frameworks (macOS) -------------------------- - // ------------------------------------------------------------------------------ - - try { - checkout scm - stage('macOS App Framework') { - sh 'make osx_app_framework' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - try { - checkout scm - stage('iOS App Framework') { - sh 'make ios_app_framework' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on iOS (<${env.BUILD_URL}|Open>)" - throw err - } - // ------------------------------------------------------------------------------ - // ----------------------------- static library (macOS) ------------------------- - // ------------------------------------------------------------------------------ - - - try { - checkout scm - stage('macOS shared lib') { - sh 'make osx_static_lib SDK_PICOTCP=1 SDK_IPV4=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - - try { - checkout scm - stage('macOS shared lib') { - sh 'make osx_static_lib SDK_PICOTCP=1 SDK_IPV6=1' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - - - // ------------------------------------------------------------------------------ - // --------------------------- Android JNI Lib (macOS) -------------------------- - // ------------------------------------------------------------------------------ - - //try { - // checkout scm - // stage('macOS android_jni_lib') { - // sh 'make android_jni_lib SDK_LWIP=1 SDK_IPV4=1' - // } - //} - //catch (err) { - // currentBuild.result = "FAILURE" - // slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - // throw err - //} - - - // ------------------------------------------------------------------------------ - // ------------------------------ Unit tests (macOS) ---------------------------- - // ------------------------------------------------------------------------------ - - try { - checkout scm - stage('macOS tests') { - sh 'make tests' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - } -} - -slackSend color: "#00ff00", message: "${env.JOB_NAME} #${env.BUILD_NUMBER} Complete (<${env.BUILD_URL}|Show More...>)" diff --git a/LICENSE.GPL-2 b/LICENSE.GPL-2 deleted file mode 100644 index d159169..0000000 --- a/LICENSE.GPL-2 +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/LICENSE.GPL-3 b/LICENSE.GPL-3 deleted file mode 100644 index 94a9ed0..0000000 --- a/LICENSE.GPL-3 +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/Makefile b/Makefile deleted file mode 100644 index 874ec3b..0000000 --- a/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# Common makefile -- loads make rules for each platform - -BUILD=build -INT=integrations -ZT1=zto - -OSTYPE=$(shell uname -s) - -ifeq ($(OSTYPE),Darwin) - include make-mac.mk -endif - -ifeq ($(OSTYPE),Linux) - include make-linux.mk -endif - -ifeq ($(OSTYPE),FreeBSD) - include make-freebsd.mk -endif -ifeq ($(OSTYPE),OpenBSD) - include make-freebsd.mk -endif diff --git a/README.md b/README.md deleted file mode 100644 index 98cb2db..0000000 --- a/README.md +++ /dev/null @@ -1,108 +0,0 @@ -ZeroTier SDK -====== - -ZeroTier-enabled apps, devices, and services. - - - For a convenient BSD socket-style API, follow the rest of this document. - - For information on the core ZT API, see [ZeroTierOne.h](zerotierone/include/ZeroTierOne.h) - -Secure virtual network access embedded directly into applications, games, and devices. Imagine starting an instance of your application or game and having it automatically be a member of your virtual network without having to rewrite your networking layer. Check out our [Integrations](integrations/) to learn how to integrate this into your application, device, or ecosystem. - -The general idea is this: - - - Your application starts. - - The API and ZeroTier service initializes inside a separate thread of your app. - - Your app can now reach anything on your flat virtual network via normal network calls. - -It's as simple as that! - -To build everything for your platform, you can start with: - - - On Linux: `make linux SDK_PICOTCP=1 SDK_IPV4=1 SDK_DEBUG=1; make -s check; ls -lG build` - - On macOS: `make apple SDK_PICOTCP=1 SDK_IPV4=1 SDK_DEBUG=1; make -s check; ls -lG build` - -*** - -The SDK couples the ZeroTier core Ethernet virtualization engine with a user-space TCP/IP stack and a carefully-crafted API which intercepts and re-directs network API calls to our service. This allows servers and applications to be used without modification or recompilation. It can be used to run services on virtual networks without elevated privileges, special configuration of the physical host, kernel support, or any other application specific configuration. It's ideal for [containerized applications](integrations/docker/), [games](integrations/Unity3D/), and [desktop/mobile apps](integrations/). - -Combine this functionality with the network/device management capabilities of [ZeroTier Central](https://my.zerotier.com) and its associated [API](https://my.zerotier.com/help/api) and we've hopefully created a simple and reliable way for you to flatten and reduce the complexity of your app's networking layer. - -The ZeroTier SDK now works on both *x64* and *ARM* architectures. We've tested a beta version for *iOS*, *Android*, *Linux*, and *macOS*. - -## How do I use it? - -There are generally two ways one might want to use the service. - - - The first approach is a *compile-time static linking* of our service library directly into your application. With this option you can bundle our entire functionality right into your app with no need to communicate with a service externally, it'll all be handled automatically. This is most typical for mobile applications, games, etc. - - - The second is a service-oriented approach where our smaller intercept library is *dynamically-linked* into your app upon startup and will communicate to a single ZeroTier service on the host which will relay traffic to and from the ZeroTier virtual network. This can be useful if you don't have access to the app's source code and can't perform a static linking. - -![Image](docs/img/methods.png) - -## How does it work? - -We've designed a background tap service that pairs the ZeroTier protocol with swappable user-space network stacks. We've provided drivers for [Lightweight IP (lwIP)](http://savannah.nongnu.org/projects/lwip/) and [picoTCP](http://www.picotcp.com/). The aim is to give you a new way to bring your applications onto your virtual network. For a more in-depth explanation of how it works take a look at our [Technical discussion](docs/technical.md) - -## APIs - -**Hook/Intercept** -- Uses dynamic loading of our library to allow function interposition or "hooking" to re-implement traditional socket API functions like `socket()`, `connect()`, `bind()`, etc. - -**Direct Call** -- Directly call the `zts_*` API specified in [src/sdk.h](src/sdk.h). For this to work, just use one of the provided headers that specify the interface for your system/architecture and then either dynamically-load our library into your app or statically-link it at compile-time. - - -*** -## Important Build Flags - -- `SDK_IPV4=1` - Enable IPv4 support -- `SDK_IPV6=1` - Enable IPv6 support - -- `SDK_DEBUG=1` - Enables SDK debugging - -- `SDK_PICOTCP=1` - Enable the use of `picoTCP` (recommended) -- `SDK_PICOTCP_DEBUG=1` - Enables debug output for the `picoTCP` network stack - -- `SDK_LWIP=1` - Enable the use of `lwIP` (deprecated) -- `SDK_LWIP_DEBUG=1` - Enables debug output for the `lwIP` library. - -*** - -### Apple - - For everything: `make apple ` - -##### iOS - - [Embedding within an app](integrations/apple/example_app/iOS) `make ios_app_framework` -> `build/ios_app_framework/*` - - Unity3D plugin `make ios_unity3d_bundle` -> `build/ios_unity3d_bundle/*` - -##### OSX - - [Linking into an app at compiletime](docs/osx_zt_sdk.md) `make osx_static_lib` -> `build/libzt.a` - - [Embedding within an app with Xcode](integrations/apple/example_app/OSX) `make osx_app_framework` -> `build/osx_app_framework/*` - - [Dynamic-linking into an app/service at runtime](docs/osx.md) `make osx_service_and_intercept` -> { `build/zerotier-sdk-service` + `build/libztintercept.so` } - - [Intercept library](docs/osx.md) `make osx_sdk_service` -> `build/zerotier-sdk-service` - - [SDK Service](docs/osx.md) `make osx_intercept` -> `build/libztintercept.so` - - [Unity3D plugin](integrations/apple/ZeroTierSDK_Apple) `make osx_unity3d_bundle` - -*** -### Linux - - For everything: `make linux ` - - [Dynamic-linking into an app/service at runtime](docs/linux.md) `make linux_shared_lib` - - Service and Intercept `make linux_service_and_intercept` -> { `build/zerotier-sdk-service` + `build/libztintercept.so` } - - [Using the SDK with Docker](integrations/docker) - -### Android - - For everything: `make android` - - - [Embedding within an app](integrations/android) `make android_jni_lib` -> `build/android_jni_lib/YOUR_ARCH/libZeroTierOneJNI.so` - -*** -### Windows - - Not yet. - - -*** -![Image](docs/img/api_diagram.png) - - -More discussion can be found in our [original blog announcement](https://www.zerotier.com/blog/?p=490) and [the SDK product page](https://www.zerotier.com/product-netcon.shtml). -If you have any feature or support requests, be sure to let us know [here](https://www.zerotier.com/community/)! diff --git a/check.sh b/check.sh deleted file mode 100755 index 2fa530b..0000000 --- a/check.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -red=`tput setaf 1` -green=`tput setaf 2` -reset=`tput sgr0` - -FILE="$1" - -if ([ -f "$FILE" ] && [ -s "$FILE" ]) || ([ -d "$FILE" ] && [ "$(ls -A "$FILE")" ]); -then - echo "${green}[OK ]${reset} $FILE" - exit 0 -else - echo "${red}[FAIL]${reset} $FILE" >&2 - exit 1 -fi diff --git a/docs/android.md b/docs/android.md deleted file mode 100644 index 229e587..0000000 --- a/docs/android.md +++ /dev/null @@ -1,65 +0,0 @@ -Android + ZeroTier SDK -==== - -Welcome! - -Imagine a flat, encrypted, no-configuration LAN for all of the instances of your Android app. This short tutorial will show you how to enable ZeroTier functionality for your Android app with little to no code modification. Check out our [ZeroTier SDK](https://www.zerotier.com/blog) page for more info on how the integration works. In this example we aim to set up a minimal [Android Studio](https://developer.android.com/studio/index.html) project which contains all of the components necessary to enable ZeroTier for your app. - -*NOTE: For Android JNI libraries to build you'll need to install [Android Studio](https://developer.android.com/studio/index.html) the [Android NDK](https://developer.android.com/ndk/index.html). Currently only Android NDK r10e is supported and can be found [here for OSX](http://dl.google.com/android/repository/android-ndk-r10e-darwin-x86_64.zip) and [here for Linux](http://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip). You'll need to tell our project where you put it by putting the path in [this file](android_jni_lib/proj/local.properties), you'll need to install the Android Build-Tools (this can typically be done through the editor the first time you start it up), and finally you should probably upgrade your Gradle plugin if it asks you to. If you don't have these things installed and configured we will detect that and just skip those builds automatically.* - -If you want to skip the following steps and just take a look at the project, go [here](example_app). - -*** - -**Step 1: App Code Modifications** - - In your project, create a new package called `ZeroTier` and class file within called `ZTSDK.java` and copy contents from `src/wrappers/java/JavaWrapper.java` - - - Start the service - - ``` - String nwid = "8056c2e21c000001"; - // Set up service - final ZTSDK zt = new ZTSDK(); - final String homeDir = getApplicationContext().getFilesDir() + "/zerotier"; - new Thread(new Runnable() { - public void run() { - // Calls to JNI code - zt.start_service(homeDir); - } - }).start(); - while(!zt.running()) { } - ``` - - - Join network and start doing network stuff! - - ``` - zt.join_network(nwid); - int sock = zt.socket(zt.AF_INET, zt.SOCK_STREAM, 0); - int err = zt.connect(sock, "10.9.9.203", 8080, nwid); - // zt.recvfrom(), zt.write(), etc... - ``` - -**Step 2: App permissions** - - - In order for your application to write the auth keys and network files to the internal storage you'll need to set a few permissions in your `AndroidManifest.xml` file at the same scope level as ``: - - ``` - - - ``` - -**Step 3: Set NDK/SDK paths** - - Specify your SDK/NDK path in `android_jni_lib/proj/local.properties`. For example: - - ``` - sdk.dir=/Users/Name/Library/Android/sdk - ndk.dir=/Users/Name/Library/Android/ndk-r10e - ``` - -**Step 4: Select build targets** - - Specify the target architectures you want to build in [Application.mk](android_jni_lib/java/jni/Application.mk). By default it will build `arm64-v8a`, `armeabi`, `armeabi-v7a`, `mips`, `mips64`, `x86`, and `x86_64`. For each architecture you wish to support a different shared library will need to be built. This is all taken care of automatically by the build script. - -**Step 4: Build Shared Library** - - `make android_jni_lib` - - The resultant `build/android_jni_lib/ARCH/libZeroTierOneJNI.so` is what you want to import into your own project to provide our API implementation to your app. Select your architecture and copy the shared library `libZeroTierOneJNI.so` into your project's JNI directory, possibly `/src/main/jniLibs/ARCH/libZeroTierOneJNI.so`. - - Selecting only the architectures you need will *significantly* reduce overall build time. diff --git a/docs/docker.md b/docs/docker.md deleted file mode 100644 index 27b6f80..0000000 --- a/docs/docker.md +++ /dev/null @@ -1,94 +0,0 @@ -Docker + ZeroTier SDK -==== - -Welcome! - -Imagine a flat, encrypted, no-configuration LAN for all of your Docker containers. - -This short tutorial will show you how to enable ZeroTier functionality for your Docker container. In this example we aim to build a Docker container with ZeroTier’s Network Container service bundled right in so that it’s effortless to hook any number of your services in the container up to your virtual network. Alternatively, you can check out a docker project directory [here](docker_demo). - - -**Step 1: Build ZeroTier shared library** - -`make linux_service_and_intercept` - - For debug output from the SDK, use `SDK_DEBUG=1`, or `ZT_DEBUG=1` to see debug output from the ZeroTier service. - -**Step 2: Build your Docker image** - -`docker build --tag=redis_test .` - -The example dockerfile below incorperates a few important elements: - -1) The ZeroTier service binaries -2) Whatever ZeroTier identity keys you plan on using (if you don't already have keys you wish to use, fret not! A new identity will be generated automatically). -3) The service we've chosen to use. In this case, redis. -``` -FROM fedora:23 -# Install apps -RUN yum -y update -RUN yum -y install redis-3.0.4-1.fc23.x86_64 -RUN yum clean all -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / -EXPOSE 9993/udp 6379/udp -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libztintercept -ADD zerotier-cli / -Add zerotier-sdk-service / -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] -``` - -**Step 3: Start container** - -`docker run -d -it redis_test /bin/bash` - -**Step 4: From container, set up environment variables** - -Set our application pre-load with `export LD_PRELOAD=./libztintercept.so`. This dynamically loads our intercept library into your application which allows us to re-direct its network calls to our virtual network. - -Tell the ZeroTier Network Containers service which network to connect to with `export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_XXXXXXXXXXXXXXXX`. - -**Step 5: Run your new ZeroTier-enabled service** - -At this point, simply run your application as you normally would. It will be automatically intercepted and linked to the ZeroTier service (and hence your virtual networks!) - -`/usr/bin/redis-server --port 6379` - -*** -**Additional info** -If you'd like to know the IP address your service can be reached at on this particular virtual network, use the following: -`zerotier-cli -D/var/lib/zerotier-one/nc_XXXXXXXXXXXXXXXX listnetworks` - -## Installing in a Docker container (or any other container engine) - -If it's not immediately obvious, installation into a Docker container is easy. Just install `zerotier-sdk-service`, `libztintercept.so`, and `liblwip.so` into the container at an appropriate locations. We suggest putting it all in `/var/lib/zerotier-one` since this is the default ZeroTier home and will eliminate the need to supply a path to any of ZeroTier's services or utilities. Then, in your Docker container entry point script launch the service with *-d* to run it in the background, set the appropriate environment variables as described above, and launch your container's main application. - -The only bit of complexity is configuring which virtual network to join. ZeroTier's service automatically joins networks that have `.conf` files in `ZTHOME/networks.d` even if the `.conf` file is empty. So one way of doing this very easily is to add the following commands to your Dockerfile or container entry point script: - - mkdir -p /var/lib/zerotier-one/networks.d - touch /var/lib/zerotier-one/networks.d/8056c2e21c000001.conf - -Replace 8056c2e21c000001 with the network ID of the network you want your container to automatically join. It's also a good idea in your container's entry point script to add a small loop to wait until the container's instance of ZeroTier generates an identity and comes online. This could be something like: - - /var/lib/zerotier-one/zerotier-sdk-service -d - while [ ! -f /var/lib/zerotier-one/identity.secret ]; do - sleep 0.1 - done - # zerotier-sdk-service is now running and has generated an identity - -(Be sure you don't bundle the identity into the container, otherwise every container will try to be the same device and they will "fight" over the device's address.) - -Now each new instance of your container will automatically join the specified network on startup. Authorizing the container on a private network still requires a manual authorization step either via the ZeroTier Central web UI or the API. We're working on some ideas to automate this via bearer token auth or similar since doing this manually or with scripts for large deployments is tedious. diff --git a/docs/faq.md b/docs/faq.md deleted file mode 100644 index 06be2e6..0000000 --- a/docs/faq.md +++ /dev/null @@ -1,89 +0,0 @@ -Frequently Asked Questions -====== - - -#### Why would I integrate ZeroTier into my app? - -The ZeroTier SDK is designed specifically for the developer that doesn't want to work with or deal with the headaches of writing a networking layer for their app. Integrating ZeroTier into your application will prevent you from having to figure out how to do the complex networking that your app might require. It will provide you with a secure, easy-to-use, P2P connectivity solution. - -##### Use in Mobile Apps -If you're writing a game and you'd like to give it the ability talk to other instances in a secure and fast manner, you can embed our library into your app and choose from a couple different APIs. If you're developing for iOS, you'll want to add our [iOS Framework](https://github.com/zerotier/ZeroTierSDK/tree/master/integrations/apple/example_app/iOS) to your project. If you're developing for Android, you'll need to add our [JNI library](https://github.com/zerotier/ZeroTierSDK/tree/master/integrations/android) to your project. Once your app starts up, a separate thread will start which contains the ZeroTier service and a network stack dedicated entirely to your app. Each of these integrations give your app two main options for talking over a ZeroTier network. The first is a "direct call" which is means you'll call functions such as `zt_socket(), zt_connect(), ...` which are reimplementations of the traditional [socket API](https://en.wikipedia.org/wiki/Berkeley_sockets). Alternatively we provide a SOCKS5 proxy server in a separate thread which you can turn on via `zt_start_proxy_server(...)`. And if you've already implemented your networking layer using the traditional socket API and you aren't using third-party libraries that need to make network calls, you can `zt_start_intercept()`. The intercept will essentially hijack your network calls and route them to our reimplementations. This has the advantage that you literally don't have to change a single line of your networking code to use ZeroTier. (NOTE, the intercept is *not* available on Android). - -##### Use in Desktop Apps -Desktop apps are a bit easier than mobile apps to integrate with ZeroTier and you'll have even more API options. The exact details vary slightly among the various [platforms/OSes we support](https://github.com/zerotier/ZeroTierSDK/tree/master/integrations), but generally you can either link the ZeroTier library into your application (same as mobile), you can use the built-in SOCKS5 proxy (same as mobile), you can use the intercept (so far tested on OSX, Linux), or you can use `LD_PRELOAD` to dynamically load just the intercept into each of your apps and all will talk to a single `zerotier-sdk-service` running on the local host. This last option is a good option if you don't have access to the source code of the application and thus cannot use the direct call or SOCKS5 proxy APIs. - -*** - - - - - - - -#### I want technical details on how this all works under the hood. - - Cool. Read [this](technical.md) and let us know [here](zerotier.com/community/) if you have any questions. - -*** - - - - - - - -#### I don't have access to my an app's source but I still want to embed ZeroTier into it. Is this possible? - - Yes! Since you can't build your app with our library you'll have to use the **Intercept** mode. This means that you will dynamically-load our library at runtime and it'll connect to the locally-running ZeroTier service and function just the same. - -*** - - - - - - -#### How do switch network stacks? - -We currently provide a driver for [picoTCP](http://www.picotcp.com/) and [lwIP](http://savannah.nongnu.org/projects/lwip/), and we recommend their useage in that order. Each one has its own pros and cons, if you experience strange behavior it might be worth it to test your app on a different stack. Use `SDK_PICOTCP=1` or `SDK_LWIP=1`. For more info, see: [Network Stacks](network_stacks.md) - -*** - - - - - - -#### Suitable for games? - -Yes. We think this solution is well suited for low-latency multiplayer games where reliability and ease of use are important. - -The ZeroTier protocol is inherently P2P and only falls back to a relay in the event that your direct link is interrupted. It's in our best interest to automatically find the quickest route for your data and to *not* handle your data. This has the obvious benefits of reduced latency for your game, but also provides you better security and control of your data and reduces our costs. It seems non-sensical to do it any other way. ZeroTier is not a "cloud" that you send all of your data to. - -We've just begun work on a native [Unity 3D](https://unity3d.com/) plugin to enable your Unity game to communicate over ZeroTier networks. You can check it out [here](../integrations/Unity3D) - -*** - - - - - - -#### Embedded Applications / IoT - -We foresee the largest application of the ZeroTier SDK to be embedded devices that require lightweight, efficient and reliable networking layers that are also secure and effortless to provision. We've specifically engineered the core service and the API library to be as lightweight and portable as possible. We'd like to see people retake control of their data and security by skipping the the "cloud" without adding complexity. - -*** - - - - - - -#### Controlling traffic? - -The SDK's interception of network calls is currently all or nothing. If engaged, the intercept library intercepts all network I/O calls and redirects them through the new path. A network-containerized application cannot communicate over the regular network connection of its host or container or with anything else except other hosts on its ZeroTier virtual LAN. Support for optional "fall-through" to the host IP stack for outgoing connections outside the virtual network and for gateway routes within the virtual network is planned. (It will be optional since in some cases total network isolation might be considered a nice security feature.) - -*** - - - - diff --git a/docs/img/api_diagram.png b/docs/img/api_diagram.png deleted file mode 100644 index 8c8118d6c430e31da77b1c563063c3114b04c2cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 415769 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

o<%5zPn8E9Mo1z_5LLs{E1 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

|KiExu`#IA<65y|3}i-tY(?u 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%0Avv)Bj+ac>eWBvQE$y6w5=l1~=+!ZwKAwyIoi2 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 b+OVwFMb&IcT|Z+H_;YYS^gFzT_v!x!{TVT? diff --git a/docs/img/app_flow.png b/docs/img/app_flow.png deleted file mode 100644 index 0850cfb19686681e5428caffb69aa6caa4470bb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53356 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%0Ahn=oU`b zIPV!P;qkqT`HX@~xUpAX^W(j=%nwa1G!R3jH_cL6iE>=&u?LmXE zGBJPF$S{e&o0dN_ZGqcque`q$U<6<1)hqqzhPiN4C^cyH6?49=UrP2|b)Rfml)PY8 znAIgIUvJHrG5hmlc`Wf`IhBt=mzsQgMM&sItU0IK*h!0@k)fwIH)6{+bl5<`O;Z9D zJ;tP(KGU#AV?}J1gE3=TZzgVus32z2Wt`H&c{Y!z2#=ah&g9Yp(TlRaX@IcEsA5{N z+Nw@|ujpBQc2LRh+I@jj{I$@nMeFN9JokK?1QMT};}O5h<{2~9aB$IA?k;9V+k@y{ z_W(2{OTg-xZ7He=-?|U%Z{ufZS1puxF6e`_24fI{8zbV!j{TTq-R1eu00LPr7)kC+K!~A*int7vPoj|?ua8_v)gEO zzQ77vu(kMXVJrHMx45-f;c@xaAk)x=O6B2un044{uX1C`by(&b=POJ&yY03%ybV%ryV71o*0F0 zwIV49OTXQi3HBOdez!MmeC*iY?3*W)r;1W|<8m|{xA$hYY)1cigJWU`h`z~7#(Y*q z54DV-Fu^o?SMulFmZm`meQt`OEfwRW$Xv zEgL}ec=pbz79$PGscv?A2XgOI;)Ex1Joy9{^NpSRmSxl=_szD(o-GX^4R-RtU2n;A zoNP6HjohbYx)BE^<}kyqo9X*xO<;TN6ivgTRb)vo%LLps!Tz#%k&hCzWxAlOdyArJ zDK?@>HmP>4X8ACQNz~Zm_5C_?aK7(sM063Ww=K{5_cZSLFySwXV>ZtAA7{ra*Ajb` z;cFkaWfxrOy6hiCH&8Rl*KemDjiyp{U4CS4m3L2nHbVe!QHKH*|H_3CIterEuh;N+ zjecGeyi##CHXSVBVq}R{GqhVsaV49AE*Hw3aioQU6jx8SrB0lskk5xn1FoC|F{+%W zSHrPE&)Zf_Qq#;<^+;k?vi!=M=T?e8CvdRW%|HJ9#w0i@d#=B4eMCig@;l~}aiV7J zr&qKy{Rda;d=nMexHigSi@$8R%bW@FkMvrtKzggz8*5o*OchKezHjglgZWNILw%Is zw-zPKr@WHk&Ms0}li+DUPK5<~D~n3V+msHZB#Xq^PMgHsWa;>CH!66-qsaFRrJWy- zG?y?@md$(3+ZexGWwV|31B)pP3@<5FD(2fcn^T|qQ7FSDh`yw>YE-R_cED}+7P}E z$A618u#TGrIN+V%@q43b3wKG}uF16h$A5w)L^~kdImJcN`jI=xG_aT8%i^oxp=bHi zW~pIzk8g7*f2p*YYM87tvK=zZOh}7)cG`0RI_6JIu6UjJw+;3mgix9m*Lal+|D(xo zgZ<%5egFX1Hw3?JE&l*SX|Di?_J%Zr{3)OFKa+LeUpnMo@!h`*I*7;>|J%%eC++{K zq)EHKo#FF)4}-yG#})A}NT-#50Ki%0Cto>#gZq20;Js3`j0{hs{Zk8BdJphyrLMHR zIO&{&jB^9xY(Wtq#o+0YSRV8E%5N}vD#^7gL1MVS>pfPK|C=!Q!<_uTn7gTQo@1rQ zyLDl2R!q!W1hQ9kG-0B^XcT>ei{Oui2#^Pim}QJ0>OG&7=V!jRn_kA>HUt=#kH57G zYn+aMvENH8B=D%nDXf9{&|~0)=ig)Ix)u4qBG*^lQoZX0M*p<#I00@z+NA${{UG7k z-a@^U14+tR@kQ;EOl2r$-r(RvtRwLsf|blB&5|7rt-XiL_tZGvEi&*~Me-leqi54O zFsLes7gw1a^V(7NfG1shhS~U7{H-WCPgg@JrD?YZaZ+tkf7C{_bH`sq6B_V|E0*{W zxnFij`~>1%Ee8EcZ1;Wr&fNL390x~L;x#SxI&J7o`W%{B z%&slEW~#=;sjmT?;?>mCn6VE&_Fh$9D_U1|gda_6-AkE9NPJQ`QS)nIt9nWFTM7lx zf>=QIvo)`8f!WfCAM?H0?4my|lS1bToY?#3Jyg=~U!YKS?>hEjzNO~#uDId+&9NuS`Kon>i%=d$SUgO)-%89 zEYPYaHgy+!1=4~yO;ASicw|2O1WEDys(FwM#rS@YnB+-9Pp}vIJ+n9}u68Z>q$|Ss zE#|AUWLid@Ba1w%Vayj#Qy8Yh{wVx}yI1(+yHqXl)IJ3|br>-h$R&E*bh2l__t!?M z%?m8tqZ_JiJP#>8TM4$c3?NdI9^+E2jx?b5%@BnvM>&4wI_}L!YHYZd#zitVtX{Jx zlF5xzKj?c_37*`N?fe#x=$l;araM7kP)6g%0-~S(mjjc-BXJlZC_|u+43hC^P5NP? zN@A4_U*o5x5>Mv+(1|23EL3A}XRnefR2uG1CVCC#+<5-#b|(!=&Ax$-rd{aI39AP7 z#jYpMrL+BQ0o16GoP$4?a5SLO0thj(fQ>1=>2AeE)Pvl&})Y zMn=d(RZRTYHKn1FLY0?3F5ADe0wUJ24ux%0Feak!F39BzHH=9qy^7`tB7cqiVyC@}=q=!O>6OQ^O3EsM_N->qT`+8CA zhErRkS!L~wO(9ofkC=JZH)}r`iF683#grfeD0zwJ)k~a_Q&l5ytB)aJkN$v>f9xGR zK(ZN5x!*wo$ie1(c$w7E`zC`Wbk3$kfXL`@bvbmaG~f?YEX|HrH>UNH+Vdu;iTE+xuviea-Mrb( z>Nh`Cn<{x=n)C7z)rNZMJyXAvPY4G;=W*t0P<(3QE5j1g1D7qGs>5qs-NuBPIP-`0 zs%RMskSe8(#(vym{v*GM4<@PMPfL9M@>X;20*)=a{&y8Bb@J~G)i)2X*B9OVwmhS? z-6FO+#Izcr5Sw(%H)_D}D$LKp^hVXoEoTMmr@AQ|-)FYUx0PAT^Q8DV5^$gW zJ47fN-qsq4rvB-(N+(Do8}BHI_3~qCYHGZ-up4-la=l=2)yny+aIM516z(1Md zci)RC|v)c#RP3$!vYVtbsL{*F#liS>c3PZiC zyoiU@$cUw(jjqAnl!p3t6~0fU zSvvrEYpAD7-#Xmxp}4;&i@p+n3UiY-1_Ii49yv(@@`c;DVWPC+9>s~GuK5NC-+F_R zM?u0Pb)IFl^C@1U-GQX15;G==FI{7{kGTl>H%sb3PV)u z6OiX>KAijf)^|&fs_b!B0=M#v%W2`Z5XQ>&uxU9BEa)Ec6g{<9w>jBwIn?Q zI6Z=2lIZ?cJr$s&+_JUL=5+6VD6d5w(EO)FE!NY0`cZ3n9#A5*dOIQPkBtEbFAN}M z^?Nv5{S}S}2vGqg?-&)z{_evjFl%)7s$qXRs4TtjfReHD8H>N15+XrkV9+yNc^6Jg z*AMVyOdBXkbYtlHZ2_^v3;09|c=L54w|xrSq zbdX(NhMcd@2Y=i(1*wC`+V4@yPI1Guqm&LcU!RgrEc9hsJ2e6{mQ;fZtJp*-zXk!} z!d{I``D!X2-P?TkevLJm1MqOVmz|3)0ft)p;dE1wfazNj;DORY+lY(4lX zon6#`%B(P@Vg1stHv<5o)m|hAKq<2(qo}XB;XHRgCoP0s;y$xe+htW&ot>{Dwqt@w zgrDC@v9+ho$q*Q_icdi2m<|TVfXNEDWdj0pQlQ)-Qr_39L>rD)?J-xtaO2fwdSSaH zoyZ#PdaKR?y)y4K*~arjnW-C>^>FcLwY&-n$A*2Cfp>OV5u0K5do@%JW0kgvWqqs$ zRdy&>Zy@34rW9db4Rt9R%Psdp+aZpdNCkE{6~qc8^q-F>EZ^l9{^F781tftdJ?E3> zyT!Nfr*ia2ajQ9(P55F~k7N0hnMGj`%2(HbnOb)x%T49g!`yko7>ed8HaA}!ix+^b z&HMH(n@>wTbhC=@pLCyEg{z>|^0Y0zbRyR9QTF=Ra)L|mbVWX zJj0$07kT*2y13fpn>9EYOB_Rb?$5^8ns>(SJK4RTJ_9+v-pVjjHRHE6nCUzupIu_w zdf*Bw;=V_MH{reA^+i*)=6v<+ITAy^Ba|FNwST|nu^2>#7u5J2-Vm30KUVFC z@{H70Ip&MkI%-t=d6CiVsI^&y)bV?%cap`D{hTbb14kL6t|uRTD2EL!y7gyk%3 z^^U?JQtp$k$o(TVsiShpm=yQGRWlvQu(KNd3&gfOmi@Zyq)h<#uHAk)ee5YEbhZso zQaPR<)jDw8mwSdCM7@FwLFR}+DA_biw__DrV+P|8hnWvQb@wWI!Hjl^4{MHR^1 zcmrL1wd$?XaGnn)pPUi^c18~!T5fnhnnO*Mp=lf9y(#Ax680t%LEEN+_K!lvPql6K z#5e4)rz%sd==ZR86Nk)OMg zzC5r;bh?1fVIAQlvKtH2+J3Rf1yU7pSk?tX61E5GO-!0I0!&Fh;QS`}>)2og_~>`T_|QpQ1IQAeXSl&|e~V{bV8p?YSvMI-XGMofY(Eroh^5WgT7QYt zzsiH`C|}h_n$ET=hrQ}smfAICHRpvew3Qxh-hlNep}>aED_tYF9_HM8b!+P$E>%}& zMp_6;!<$)8gf2bH>uXlDYN^rNPW=kuGQ9IY{grcAtM||$AFI&)1Up|7P&)LpRr}I5 zO+5fRqlpHfG^|rnJ%OKaZfL@?`Ur(Wt{8H+X>l*g7-iDfJPTv0qdMFFBqi2{t))9z zEHtFVmj0HOOEC?7SbmP-fLRXm@ruHDY?gIV^`|FQl9kS@OvOmJ%}Fq`uLaEatq}CC zPgeCq$^tF*7Cbkhi!H!Bt5WXP7se+jyzAe6PQgWUE9u<7zCc*; z@V2Vnt=lA+@iFXYd>s&no$dZf*%<)8)FPmi?t5{rUdeH@g$6^Y58~Y^&hPoWR6)v) z;X%kVb8ci*Yq=CLy@*wVKjs7=3g6856GN9iIp2nhL$Ye<3Jxguu7$fcxi$?>ovRTS!#%{u2+5`2kcmWUFv9Oz$bRe6jgCx zcyw8+OCj@Ev-Cscq00&9LVC}&W#5vlw3m1f#%OjU4`Xf4Qzkxm0A~$y%|Ca*=9Z_X zI&TZFc=5e z;`~LGr98q%VLQG1weIVx4ab`2^l$gH4;LEvFdihlW*S53nfhG6%ER>_LumOj1Q<_k zxPzunVrFxZjPnPJ?(?fiAitY6Q{!9DpS88>8dL6^pT|*H2VDt;w7gvIMJ@LD&*Lx$ft01H}!H@ zQEyeY3L})LOKaPWj*`cY_`H#Tfs1# zk*8wN6RJ2&^Yq*9sHd*`NXp&=`=!boHhTF?vl<4So}DVb!zmu)OC4kOt+sDt1*{R> zJnoFTl|`-h3+whIOG*b7grKe65%JtTMPib=R^v;>mCrm2jq16Cd4pYl>Wl`~-Dg*k zAY$p21p`;sDYN77rT|am9f1THWVF1|Z7xj@*{`bjG$2+YB8^?GM z_KE-7%)ge9+=3Bs(+dY^%KrrS0ngMBX#fAVsS3^Q^T*2p&xLbnU6-yT>ex32W_>lPU<0+Fq8ywFhXVU3`uLV865|9%cCaH+2Zpyvyf>9`eb4PP0msVf({l@VSJ z9S#0BP$(~xb{7*)sYHUM8=obUP0fD6U{2N~eKGU*%!3&m%jq4a1<|w0Iki)J!ogQD z))iaJsVAT7kG>|a1;z_gQ+ZD8*;mi-@8hHG!)dk45!Cc2rB8Ca+$SN`kmE`Hs*^y- zRXHZ;A$WoqaiXx+771}TLNvma@tT#oK)WlWGw)Oq=djfOGh|E?ZnMa`#vnX%r-k(3 z8sDP>b83inRT#bS?m{rTa@>2pvd8;E_ut-V31gBFt&nhAtF#?gsuV$ek4diJ7sw_- zz7XwSGH3ob1nTX^6Q`|oULPu1CCNCnnOn$6d#aNo9f-$RD^%c+Gu6<|=(HEVqCV7# zr13)@ZB-*w_~s{DkH;40VcSd&!G5y^gW~n0)$7cDYsLrB%9?6AIEzDwH*4X0OPuZ< z=Q@esWpS63QR4-kIp+k$k(zsBYNcVA$~gl#q%Oh}4uL?ZZ>0rSXgtG?Qj>UUs8WBM z`{#y9p8LQb?8SX``4xrlzWcH_xm>2&b8qVuF-!`=JyZ9%NkA>ZF<3!edKSe#RY?0n zKIj4V70PQOXvFbE@;2Duutq+ZvtIlpaSd`ZJCiVk`P9Gct;Y?d2x^eX94NwVen53q zy?@~iTKME6e47k!nus{;MXub^+S)GJqRFUZwday%3O*sX-#LLE&)B-s46yvxyYl7! zTQ*of?e}-^bf}NyX8FK$3!O-owCV0ff<tdge)>*ulgUD!UavwNt9(Hzsx5MRur( z8+LgrVOb#=pl#GkW?kUKKWTQ4`gUTD9&d-<;(>;>85__YA2HVmq+A~chJ_;O`^sbI zL~@mD)pIV=D*xMrBpZ1+o#zn>Y3*bV#aUZg+S+!`{or6g)<75QxKh$uGoUKgRcKIE zl&dQ7$~rZitLJhs!#8B7#I<<|wMKssDfRo~BTTL1%%}azpw+TZHlw92%t+U>v^PF7 zx=%P_37c{OcwJH%GaaxSP0OYG3grMlDGQk#1Hp7;7mHVDxjy4k!!#WZ>#mL$n*`b` zr1V{f*KLKMgN|O`Bg8!@2H&7m0!uU z{e{Fx&jR*}TX=c<$>G45*U>F*e}^6W9K_ZQhi|uDHXlO}@dao%c7`ygZ_K=kd{=Ek zK~kDGb&IzP5eduAJlA4`&>?u-3MaeSl0C;{Fhn;=g8VQwO|K!X5)2G4vR1Z79JvWQ zeODAVX(GVJtW`h|<-V95PaP&IviypP`}h4sQ8ecRdU6u>N3 z+0>*cjpc01htbV057*ou45z*M*rLo#^JD=!2(dz}m|48jH}>71RkhXjYxi9lDUqB4 z2z)m?bs=pw0G#jzoEfhj*P;7iaR~OaMdpx<(6Y6lYUAXK}tr2M23E878PqU73vCX*OwY zh${e>Wr!HZlp0g@8(wFw+j5uenTCjr3+xl(5_96D1#5yx{)0_w&|Cts?E(jxc9tU8 zRlI8~2d+vj<}nq;Dvgh{T9SeykZ+I)Nwiw1^R1B40{7OE5#^LaTbTex^2<0fnMwCUBV zDgLn>|G=g!aJmawyeZ&)HpA6xdI2nwJ=tqF1(p=}jzu z%|b?0YD#$zCh$!|P-VSDU??*g!OSCy^%#_v1CiN*5wEpAMbHnHBD>KTS=T$qG;-N3d z;L5A&A&}NhG3P_)u3M=QQChq2>y*ahGdn)>LQW2lp+&0znR?rEb&Rs@bu38ovl2S` zslnL!0l>#!Fmhd~o=;JJ%GqIhlzCj~R4xv1sJ$-;)NMS4EV;5~n>0V)&py7l-1?p6 zRKof#Uh2uqn>R@bv1Be8N}m#idjX)X%bM$1@TEGZ@!0n7RYDglij6^7b!W zP$uDCG%hxiVHlTODQ-T@KTw*_=YwX;XTIHH11-5kEE*3Gy}dSStyOckiu5b_a5?V*h&AuFTbgEY|MxH=Jd$ba99MRA%e@0`6of&g>`*l-JDr)G;MZ7}pw0+^2 zosFX4%`aJ+^P?|7D*E){k3GIeDum>hMqW=)ZZX#DYYWvS%E(Qxut}Bo$m$X^Wg#gF zT1gh^cTFJRI7ePfbnAsn)f*doRy- z@a{*Ftc8lyYpHX^mw$np+E)Q<7whS2vxas1AcZ1!hgEdccS{8J1#i5_IA1BS@9p{p zpFl%&H@wGv8oD>c!@kP`19*9KrsI{iYhN1!Rk!0Uu7E+*z^P5|?DN}Re|v>OtBmv!_SO(>tO)bJs+$QKsZ7 zSQ4a1c}YFlr2l(~(!o}^@qAxSEDA&iinBo&E4L?7dh{>z=7YPbN7}u7lik#3E?9=oFRExj2LK^x&kdDS|L_o{!bmcRpnGV) zg=KM@g~fBuQcfQ&AoH*7k09q@(II16($S$~M7Z@(lhl~i)gcRhQVH@@hbH2N7arps zD&ugRZY;3LT#Cwn-qDAT297)>c}rYf6*mg(9>A}gBQM!r8K}?Kn&(QDALaCLLK?a6 z+me!eyb?n8?_B^7yj+g}cP>Iw?l8yiAV>0j=7*@KT+|*K#~Y%`M#xh0PH*GR=*s)G z{Ij8G@PK56a0(%NA+RM`Re|Iv2VZw83)IK#1OWy&M>;ZUi<|r%GHB2~Ukx%{vgN`T zN6GmX$Q$@|DM4`i6=RE;tL!G13U$H{`l342>9yfwSv?{!$Y5%I#IM}^Ye*XG+Tr2D zGtTx)swKJF z-NM|eUPbtBozzV2H6d(AINw-}jjzqyB^@LlUmV+%l7*%XL5`?c)LAm&SL^R&faL_~ zu6U;*+h{K@Q1^k8dC*SY#fPI(XJ~B#$LzDDQwi zR&}BTGAt{I z%#Ax9kkC~Q>@5N(2ch*=kH&%X^X+w)W`}sV4@S$Ls73X3PXhVm@fuf{)G=^0elI&b zsJ&at;j8rf@%b=?vIjnvwxy!63R26%h1;DOcLL8bf+ss*%m!fU@yg0EH;*tG4OLsR zWzzABbDd>HH3hac-Mw;5Ryh?sygg&N=5JOQVrf&K%v<=qXG-Z2{a1ecrI)d!#d^tf zIRIe^z$3YMA7Gdl0?w9H0eXFE%07ZYq(9kh%u?C8!2KJKHOHv;ai3aQPaLtgiwbd~}}z z^L{F+KwU4PEagNo0A12l11Y@QVK+oPHqyrHy{fbtJh$ie2~hy!w-&gTVSgpT>#pbV zUc||WJ&(HSB5-bL2Zn#<>_#KuxIONR?H;Kq!V8qz>Wnci!Lc+n1#%UnzgkR;rmo=mqcB1;aVtbgW2)6^B_O%I6U4Olt#PhlYGL@^9P0iw&5yZRKj7NvBReU(1tRi6t^4Erjn;-OIOmlibR zk5;R;hwMvrm_Tu-bfAzAP=N|e@bG1S>0rPM#Q?LmL-rlYi2%-U)cJ#icRnDjk^CoL zZMQ=#C_iHDdczP5oD-7AE3v>sZnF52BW0uUWqUM7twUA_$N->oOe?f;BIH#p1Yh7W z=c9q6m*|$mogAr(Z-<(zsbcO$J(;4-Su7!V#GX$94`aVT)hJWmhf@!y&G@?JIF-1j zPriX|u3(-w$kfcfk#SomP4*s!iY*E;RCq*(o9VLMC5*|IKjD->PdInW=eB7+SBjgm zr#voM)@Fi@hyQ{>$t@%TR-{0c#s-!b0I~0#2NhM%C1hBO&&FtlRPwcL&L!F(AoWAe zQwx2&aAn#tjJ&Unc(xD!IFL+o0gKCbi!Sp@(KXNEYZRLUpx3cB>DO0ux43z^iFL(y zM@-kEl=<(4x2#s-)0t;#(9!8=+OdTsI|E_$Xg-9=bx^~%+O+jNbME!f+YfI7$Nw_? zH8d{M((68d%CL?&Y3Rw`qKeV@`mrAy<0%}A@AS&529RX~ern&m*nE=nVP*XRtJwAc zF6wPm?7A??$pf5Em8bmha%|pzc#T;fKm{4Erh)a8*uAb*XuzhT)poA zbydt%#HJTcxZ91~Cue~@Vy-M`JL?s*l%)7j#4eHhh$3m2e;?<0WxZ9T^-U$H&n%G3 z(Yc}7+`Zfdc&4d4IeG>KXN{iR-uko~uW$A2rSYUj?_Jir1)s0I$k@KMCD+KZZ!LMr zD75GvtB#G}%cnX@Bn;W?Ad9AI<1^sk)oK;JCRv# z+y0}J<-BF;Qye;zbPcv$rS8R?)V07fWAMI9yJIis6f{aBIXCN=gtp`|rGRLKW4Op@ zxy))(9`Rj7m?vV$*0#i3NVBDKo7cW}wGv?NUARdiKRUs=x!(cH(hwpO-|&Z!DSR7& z$t9GruhH8+0o8cR90vZ{O1H4d&W2D67C=fis{QLFGxk-QvZRCO)VOHUdc8U6q@Cm7f%+V904WwJ-n;s+shcRm)6(7P^d-RuXG1lXi1GtRTQ(1VMcB0_cU9R(6 zBZ{%C5#l%8sf3=+P6soq%Evupb-4q+saNBYmzpSVoE`}Bu;Hh%eugKx#Ci%#^1?Du z){iq$fYh4c?Xo8Uf&X}fjXJpuE5nXbnB<9dbk|a&F)J&jc5ibnh@SFV-!gYc&b|gO zmvkmrbH_BgX6a2Az7qhI&1B+T?F~booCzlYqc|RVs|ja`(Zt|X?pW4v9F$9wos`>scR6zBqHi;w`0`O{4BScg@?f`Mi7d2)L zM?o~A>Loi1;G}sGgQ}-`kHNBJrW!J5e{3w!7f7TzC3znM13>FQD}xjS)q=a~)4dOr zUhOVVPd0R9f<0r(Po9$UD-x_yF|8IyGP$XvEMw#zOkoA_#PeZ2zqVz6E*XeZ+xV6Y z2&B0a5{*a6tt@lZN2RSHTB6Q;Bo29Qr)$G1mxm&g#oQ0TcUN5LV^b?2t%ChB&It^TA1|olMs3t>7#3PT3t_DK z+5(*BjzT_&Y2AGyu>g|#BkE=Y^0=-GN#(fFJ7Gs0#x#)Zqz21sIwMm_G1Mgro-xzHYbj4NwXGNQ$Ig#04ooCu3fdTC8(lH=mkXG8xF{f>L4iN^<1c!yPfdQWXtYGqujD|AXc9`tn2g&+MSym1GZ$n-P+awAT$ zw55rG5_X5%zk-mTh0g$+a_8LeUo)U#sx%CuvTAEk5{=@nnw3WH z-wLsfrwITfUJR}8xCMADMj&I4X%OTX@Ya{~$%0PL+;9HvH$3dE6nqS~th7U`V&+cE zg>)e>>x23+TR_!nq}Y?-wqNQ-Av3^z76&^OPLBUh09Lqqv3H@VQS4&ZB@d4WT;u|< zHn&=-1&mjKL|9TnMDlNMyMt;lYuS$Gz(Z+QJi_w~4r1sq7M{pN4I+DCWnTGy1Q~#iCEOhErw3c+5+b(&(Yq<%8kG> zlc@O(7iwx>%F;9zpJL!k2Lr3W_&R*<#sv%W0Nrz0ZTB1X!=wQ?{#Bx+PYwO`M|XL& z`hU9xF1Jj2oKSOVMRrq#@(q^m3Xu2g10-+4_PI{^i~kHz5IYe!QF&ro(#~280JBW4 z6$l!7mMP_~*!&dQ|GcX258oBkPdacS1_(fT3Jv8x5;sbIW9|aW8z2g-Y91@U9NPFH zYH3J9RdpQ6N+EW7;jsdjn+X_#!3*&jUL3D?^&?_GE=yc({DbtJMvFah_gvH!01;3m zYI&yYq_fza{g=)FpKf6V9m|$4l+FWtC^5opc{qOsZ~w@4KniexVPN2ygbMZTwf8d< zMMkxn2G<{cz(KFouD@e41(*ZBSBjzrAoBVkF2t1pK7&fLGaA~j@pwCA|FkGT2MIJ2 z(p8h+;$bhSnY%9bnj>QN_xo#rngJF)a8L|j(d$%5=OLj54#w+$ACwKlHksLyC!m!! zVJ+cy1&;pfU~GUq)|)85jWQ?E-s(_g_q@sT{imh;cT%XZ(@*{ixZlhJ*k+t*jPHG! z2#WfXHXCpQZ_+&6`BK1h;t7Z5a}rAlLbeH0RgYRim|D*>-2PfqTOH)}q4TkLxFuCj zE6)!b1;7sg4d7mVSH&;r`ajDhtphB;e;fMm)M2IReNWr1#z-ARTN7 zNH3uW3oW4u1SAmh_VHftMehH-4{wb3;f?Y8q7DxU=j^k~T64`gS2Z*C1H@|p42O%y z(iK8nuUL1gRlcRi8;^=weE3t;d(CFlVZ;^KG%cbrW^Ul%aRaVT`O4x+e(Q!+?sKqv zpp05$5qdrAq804$t_fYp2BtE-ci>ev+QS9FK+t)B{YBd2ohzN!(x+*bAlt>NagTVE z`QUxGg!$Bwb$qiosFy7Q)N1kj3+5TLn}Z?EDc;(+sU%6CF_7r_9ybi6**=?~gtE}n;x(G(OC^O?Y08c8cnJgtfA761 zOH}U6d>IWsUM7aM)b2>+rs{0QXhjmHpiCbSKv*^Gy_}yji3%J!?=V`~ag;^kb&e;c zG~kEmRdihic8rq%A9cixlWa|@bj%X_@-~7fPRKp_^ZWj%uFWj%#$gSYFm3$E+$gk=r-*RtxO^!#5zOtqcJx{ZQPZPeU72m$m#_BkbmT^%Vm=~!pwQ}8|GVZli1}wDsg6?vm)rA^3!{Lg9ai`7@jzOg zST-#eS6lW`-u7cT1vg#*|E}p*)(%w&yV1~LuRKntd|c_*?`5r&Xr zadN{0$2+@X!@vm${ai*(TsWX6gJMn=v5$_I^r=J*q%J?3qN3^Y?|%n~=Z?eMu0V|= zwKP;}L3;A^&D(^&n$AWbtO;JhnRLiq_FAz_u3COE7iKRUuoIjdwWh!GOt4`n><5ABR}qkB%`L3HRPyjh>B-P+-j|T)$$|&DPjhMIHm# zSkZDf4nnBh6B%!%g&*|l1(t7doW|-ad?v3;avG^H#_g4M(&dmc?gKt` ziAAcbO~U7GEgvo(9p`+=_Lwy_eFttVGNZ&Fu_zwJ8Dn=bRu?g9Z(Ku@?6Y{i>P`ov zGjkO@U0x?UqDXPW{G9o>Vi6WXxoLm_| zd`x&O!+wBDw3duVvg2UP4885&SRj$6tpnbw4 zW{l)X9x+!I7}PUWH7e6S^V!RGb7dZmn&VXC(MKA9d~_kgbnGJ2=1J@!y`;8Ykq;z? zmbaNx9XRUM;L()T{sz03ZQW0fl5~udh+>PzXick@EhK7oq@scjD_4n7b^GWFODbu6 zV_)jSS)jVPOZahEhj)2yKJ+1Zl;d1LfE#2d%W9gc&EZ`4{SmqB6DWjYzviM5^ zt)bMz#;Isrb_C}chf|K|IPTE+rE;h-Hm5drTXXnDc$nRyQ~i8Sn&4Igct4M&byt-h zxZS7&hGYJX4RNp~O*~-1*EbaL7T5I(5=2-+s0=D>!db5$4|DH+Lcc{Qg^;784NAmfe&JD&hB6T^}r+dK%O^H%#Z zItm!jW($hP=qW^6FErNktFow+K2@-O=vN?t^XUjo@8QH_iZKG&o0^epn^O}RC5>yf zcSu$XFzFFVO#I6AL;viw`vMI>RL%FsLy>wmbso5O}!%gS{1yg(+$P|110VNY$XBV$TDtCwe7p) zgI#SFu03U$rGGc?JIwqu;3jWi=r=T-M;x0^;P3HT0FFsz93Q<*PfQ3O_pHr+no&%A zCM7e{=?XDl)NvY+o&T112Cmbaheob1h#Q%4?q}jotL7HQ1hJUWUwREH0uhXW_&$vh zIdwB(zPX!)k3Zn{{-|rHL66VKgVHr}G(EO%p|j_7a+k&AR-)qH(4s9(SJV2ha8Ft) zyIBr}Ng7~1zlL~RGh{GR=eA2$@Ygv>r$i-CE(H7-liw;FifSu*>{oj*a(vvy=@r9<+!D(qS{4V$DCxRc5NhG$`Sa;;geg;y-Sgc zx*-RRDjf_xjo#z)Fcj)FjRlQ#+vj)XkXn%Zl%SRQsgk~%i<bly2GBCT|ja`Zig&n*HX zk*-bz(YTXXYKh5|iKcu@XW|9mTYlB?nD2f$;p~ucZsSau0^5{rBqejdG}?Qi{rQ)M z(0X^1Mkd@Lk_Pvjn5v(^Xi;vzWWI88l_1_m63Q=n>n|3^$KHkks z1Ee4hJqhe$n#~lH8uO{zTM%e|pVGUqDd-dfUFmg!NX`B9fbD)x=o4VH*<*iv{~E%iO8HX^siUQm<%NZ)(O|h`I)op zMPi6@8$lx_maP$K7;V1p+f#!Uxq`r*>Cdg{mzq-F7plUQ>T@v-61odqFG`%oQ7Syf zW;kgQi%q|3tUHeWO*U24Ov5x5pG zO95uAWkg51=Uwl1+h_FONLj{MoS@+6)q34RgUi-dMvzL1Lvki=q%>iQ2|swRJ)Bfo z88~B~-8pc|{7v!WoP{=H&%|@w?JK7!_#_27LLVNQ$6x)7v2r&-AdigN%zQxjl$Q05 zXn9_$dRrYs41R%Y%Tq*D_T2U28pi0a4ZLz~T^T{YYj>ToX4b?DM)5b6G!`t}s>g8> z8W+laWIZYc?QIuY#hkX@`fD-0*}7!XWnqJSqzcS(-*~_IT5lR-I-j!DzZhOp@4-4M zV$ZF*X=mzpJiB5`yzbGDdwNqjbvL^C=He@g&E6AAcIi50%mM|h__o71j|4{30m1Le zg55XAyv7{7;OJGayy?7ao8MkunOW)nc(CJ?D{x7TOuVLRWq(4C!|&)vGxB$FsjZfV z^Cuge(!|y>={Z6Qp3KnqAm#?lI$F~7pZ2zq3OuDxu+>$*k@FTZdcP8BJc4l$Ub&bL z9GktO+nkXj=pm1~KTW?_cvTiQPN2ws+1ipb0G<6&F^4iF+_wE2|we>^67b#4A zN;M)BczJ%i$2Na*wago-R$M%Mn0FYTM7_noD7fW^zWT0G@9J(#DsOfW&5PP4^j!+P z1DNa{cXf7!fj_|{4-m-qdYCHQ{|`u*0x5*!I5g{jg^m9Nklh~O%1BYW&82@r%3s%n zRl(^|{w??4(ES%gH=+Tqj3Un*{cnBacE?Y6a4p|9cO7V7u#x$Ts_D zU-)%|*@%NHjuc_Fi;CM&kycK?|wd%OgVr(g;kTh|2sen zkfO#krpJ8m@1eDU^w4)&;e!7epo&Crr4ld1`25$9{c|H75LUqFh1tg6adNu{a7hQ3-i5%pIr=84ncV;AUj8RUE3?hmXSPgIvhr$+cuAG z62X|j*T*Eh+8Aye+&l5SAsGCWO#)0hP@;JLTPwVg0VeeO9F*aNL@S&d{?E*Oaxp%h zh1v4rA$N8K5&(^3J`W_($L3}|YCeIQy7kqn{?bn`ul<7Qeyv5B5HSDy4@ca#9Y=}(qk&NwmYiWE3!R;9EO4Oc&oGsB9o)>A= zNRP#_xvNfNvq0Sa6__kcwX$|-Scy{d7+V_{?pvEc`_ z6?D`X2b70CjgIWX-J{(d1Wp8_61WYh!1im%6tD7`)eW7x2Ki24e)pXSkZ}g3jy1i| zRZ!}1JkYS3xOBmB;4IH>mJ_&A1-{Rlx5W#TJFZfUkB|F@(uo+H?1}hoLk9^ys4oMr*ANuEd=sp6jh^59<|5g?JYnyorrfA%y-{7^sKJOj` zu4v3!745~gfqMqT2D|v2ZkH9v-_tn}Lgr3-zq0>FV)tt>fTKA8&X2G^+%spv#)%{Gj4<2OKxfJVqJd%fl;!K9?k(j4qr~fp6bt3b4^=TC$ zz0&g^R1**62E>4o2$i|X74i9mz%iloj{?$z(k>q;F@H1p&NDEJ*>*D-8!s`6#u#pS zua8(Spc|Jy-CC*_SejZba(hIW-|#y{L4Y2T#rxIO-7n^^b66hiHaZW&)qXwoKc{;N z3$zc(3HJRTUcnPE(7~4?j{Lsr!58-5m$8r(j<|ZBmd+Ch9L7K^m&D<<#3kPrzeTs? zcHilvdp}YQw%`cWM+;t*)18UcxBnDG%%|YA5m)6Zbs$3EDPYTRut zy_&yzh5gz?|DIAZ++dok^n4k*LqTN%k@TEVKp#~W#5Drxf$ohuR&Ck}LnAScX;>GL zCUM60Kne!`m6yq{r`ls`m;9D|{OcofL{uT56tWn&H$QZFMY)C+)AX0u&D@!0YeeLecu3=%sqK$Et^y+U|RD7!@9HlcoFg>=yTeB)Gf_p z4H)UKT>VLSL@gjy)ZmL7Cs;Sz5j(vxrzEDq->&5=H-=aCF4Vv@u#3^DzYn|>h}iye z>XkZFP=#k}bodU&*ZXV`yQl(Y6_wMKBk9&&1AhjR&(_RpGTC>6pj#n*4JMxstI&Iv zxiDI_RRzwtQgyHP_OtJp_MYa!phOP4K=)Xln$NiM6KPga+Lckgw-H4ynEco-*f_7* zJNwcF_ToJSx8K$}q1L)9DN#g(%eNEsUtpPtBzOVzddDqwrA*_?f0~kUKy~^3&*aJ} zD|Vg+oug*pbHSLng&^W@+9wX>94~~YY4b8new3=+%O>7 zaqYcRspICQ!~Q(!nTf0{>LZTP18zKi56a!z-#t zdh_>yDpY7Z$xoU5I?)Z^N&W<@-5ubKEawg&)!(g#V%KV`0ycU zDpA6#SCYKF`s%z+5iXxKbN?R)zZE`~ezF@rg*JbjUdm?&c;3{YsIc%4T)BV(|HgS_ zvHpHznb(Y{N08_if+;Sl#ZImz{T?kuvNthuPvzVN$Nrw}ygw6cW;OF3jK7`lKYwZp zdYy_PZhN)}aF7Z>!~(0TKAXL-jFw9g1P0gb68`0&{R;4qkS&QoZKA?|lcDQi2-~#3 z{tK)9TAn$ofgfrdL_(nK&Q50%^y+c}YQf5Qpv$wQhMu=-W`x!21e3kdB(Uaj+E^T4 z1lltXz*`N;f!SwLWqoFGb(^zo!)9kyL(U!YOg_zDU83wDTI~YijEKU%zynmX z($kQzlE(GjX7Z{ci`P5Q9gD}B&8jy;*^F~ewCu?In~yx)E}1%o@e3bS=!SCGf{7&1 z&WoNVW42~-qP|xA?w6Z-{6KCTek7xAYq7Rrdvd>W<4!>*U^wO&VU1qN)}|QR*H_^= zO$4`$Zxg7NsuuYDI&}S2S3B-C5adO+q!E5YKN(3{KF~xg?#j7LarlCo44Hdrw90v~ zBTGtpx#@|(G(rO&^AyfbbVp0x(|VQc1q9#M5|B# z?6C=B4RgZ zBE8M7CBvkgAzf?|?-Q7c*=LLV;ZT=hDkt1V1~~RUn|4UW`;;^DkEP)AW3e>M@K1O3 z5^oow(7CbL28z!n+i1|;7wzyezJ-ORfmN?jbE z@{$kx$Dw0CeCN-iRULI;ukx_VpWl*ZmZhg*ogL_vfz6uhaIZZ37y;7+9IJ-d9ng8N z!89)!&Fu@%-R>7vVZ3#`LgWuZSmo%9iy_frq0Em5(bBFoh1VtYtee9Syv}IFr71u$ zt^I^PA#oK~KcGJIaFhY*>k?0h0)i5oaBODT{ex3$FNLVK9*-8+r_kb*(>_GSo0h82knz`gS4a~k!d1P~r}C>_JH-i8!IZW00nEYZZfQqblk;|TFJ zI{ecIflVmwe*W#e4Cnd#%Fq0HUISN7CzdzL!CXnl_?Hp=%7_>W10eTtdzh5(x6< z>P#)9Yb7y$VQrYh#9dN>7***m0u4WIV+GK*APVwFV6vRa1B2jf6|J4q_NUUzSrjWu zxNxd)3S!M5^ao@K`r<*#En`4A2HvjiggpR%HJSw|&4NS|A^iJgZ3ND$!FwRBNCh%E zL7`J#k!gvFgx)6{syv8CVA2xOO+SROF5T%&m~)m|I9)%2UIt>B&6GFx#r4yq{!^|U zG4Akudqo0}IJ>pN+Z{&amc6Me5lcw5>&grIJ_Al6>*4pM>}w+wsN8Y=t@5TbdP!dR z*RYqwfsu$M6H{tpqL#S~p`TFf-@h~uwOCy05886CpJQy>*vf7^pXxr@io~3Hova?$$3DJg?<_*(_j*39y37dlA>0V$DD3ek~0iu-eXN)eL zi>)31^H9~?9YxtcNVAXFG3T?Yu>Q5u>Y^d*7Z?)rnNnSP{lzclsfjmeCQGdkh9&hJ ziYmT3JFOz>%<%EY@>`n3!S}P6VnkM`(W-o3)Y^mSNzqLPEiIOsxmtj!3r!usa^<9X z;IlYAKLJrT=@xiP_m-C~-L~3qg&=d!7tWlhT zrkv3Z@4_UbKGqdFd6---7R!!ZT@z2O0WLnGZlpR8@o8Y5n4Wqc8H112NB9ja^)4m* zxA4zeV{lNbq4^EXKpH}!KVqJU-qzJ0=;*A%18pAil_Swqi^`0g_gEoe z6$+Ch!&cz5DuIml_GhPzwcsc?V1k9Jb!+WE`-;ol62+uje0!@gvJutxSCwB21%Vok zQrYhTTTgaB6U?dkK~4b@ZmBG~pz<(@A(hEGb5dPK)%i{r$c2-$6)X+!9T3H;Q0m917aX=9)c^g;%C|ihvZofjx4arzt)6T;4MZHL42A;&NA9O3$@s%k;ZJ>Dg)iWQgp7GFpy1 zHf+WEYN0c{YAFZU=3bC#av}ybN4TKVg7`el zehf{{fDTE&)=t{Q^ur9NgouLoMYk0)zBcRU*;T2 z=s>APgb+(4-20d`7;?0Xh09v}>3(RHH7Wk6^Gzn)WF3FUEeYxuQZiW^HFNsra;;7- z3kQcNME$M%q-#Fwl#zDiCX;VFyAK>2knfA5BFM3A<<+CtA7)byFFhuNZTbRDerJ$i z%_7>Ryht^(*msJzbkGb4yzeKMLPHJnc}Ge~}~-GH-bK4Cm$Je4a&^s#L8`Rsj)Xp)CY-5&Zm zMlYlQ53(ef{Y;Ds3iU3csA7OxU-!f)~oKiR)!(wWaEj8?i@qh0w> zF#mGU7f2MLs}~^Gd}K>IMOE4(9idX|;FtjQ+e^-}JxP_t_2M@CC?6Ke=U6S+bqmgJ zWlgM)uEP*$y@yWwknmilok^W=*lO@s&-mVmeA1vagQxFO{f4iL-M5e7olZmi`}99O zDT=OaR!GVrS6qBCsC3zw+8#r)Xs9 zWxZYUgfZzW7Z!I1SZQm|GnV2zLb=yP=ACEI{n(Yy^iVRv#tar#Z%-Ix#!Gd0C?sZj ze)K3T5FR{I7%vra0Gx}W##A0QHNk!sMFjpfWg>%FE6c4s@)#B{ET$}VSFTgp4RKNN zC*_r)*)p9vqbe>css8E69Ce&s;m5Y{ND5=?U_wszk^TVuh0-YBFdfzStnGnk5oY{{t+z;_LgXIx{33ad z&Ag?Eh>D3&SP4l;AH`)z&N<3Z((OT+?GATJKUSfh{8i2SW=YZ09P>!raqCIJA6wZ? z2ATe3zFF%XBJ&`!5MRroyq}t6s%zE;Ck$Y3NFFo{jdqAr&urJVP%%NO$p zSWKPTVq6RRx`ZetOkVqWL_;PB${u7ballD_5im~2TdQ)c1A`hQJTV-_DfArS%c)}-O!UTVFwsonU=5?PpH-M}rHG(TgA>Jo{^$2j$U4f3Z{}Ie z@pAdKYJ6;#q9i-G3qQ?NHuw3svdk6q!4NY?+>>?v^SQpj?xtos&YmaSs#7AkdWX*@ z!=I)SVIMksPhOdDv=W>3)X+txWj1^~I#NGZS#)FYvA1sTlB#EXC2v5gd0G(-<#A*Y z1#gYs+FHWvm!zG!4MgJ>k@PYg2VY!DE^=0H);6nIToW%~OG^53QbYEn>6S_}cE6WF zFS6Jdjor~})%9;yl;?eMLf1dF#mo5mrrCmXFj3JKbZP832C|C|gk#m}tBmvJuX}X*+(HNjLTSw#P}6BlrBM zna<{>NTjb|)HAbOZ62ug@3@$*h16#~3dv?ue)5KbKTqK!@TUa;MMprx zeAUNAi&hV;oD8Xp%5)wQkyq4I>#4a)>W3pr56xMkox8h= z>S0CY=1GImla&@`XkB$ z*?~-)87Yzw4pKp(=x0OnVodw0M@|kLYEuk6qu$z!EIh8Hy}$T&TbHg=!-DqJ=C7&? zWZ2FQW&3BzpNWMZglC8OXGI;p081GOq#LKh8yoo9=Q^v3EM$!xXMcL2FkB^hD>*22 zR2Jh+U77U65tBd2_8PP`y#kjCe&v5sB6*{llCGqTz)&F&q^|za@1V~vTt+EL#!9bJ z)vPuL(t`%byg5L3?VM*siAJi}&m-aI9~{&f7hk-&UCyx~$;sA@qo`C+5#deame4o3 z`!Lxk&6PlRg#TNtb90Z%fF|5{?On`VU-pcNc?HaB3XJieXe7|bRUgZ(UYKSq@JxL# zB=TPA*-qsh!~wjq;8LF_DXRA#gA$*+Uvva#%il=541v;sJ(D;c2~e}b3n?O6YX^=O zhNU54YuB{LyJx2r;GRZhW{+3&q-t`zqJ%S*`kt=!Cl0FcAof3~$O7&;H#LT-s`NE) z*e*02#^iD&BOU2$c8nrWnVsry2-(@C1~Tce1)i&{XoU2yVo#1E2oTWYsD5DatU~Jv zTn9)eecams;AhaoxqepKe+Srlo*xx#Q>(y$jZQ)UVYs=T%fiEsv0?PPU%cYRA&yP*wp@Uj z%WWF9Arlg&D29h`YrMhcBZMM09B z9K(`Z(6xS2w+S4FGm4rO_LxrTplbE_t2?Dl%@)YMtoRK;!+SR);<;>&$y7asGV52r zy*vh+;4NMpuiX*~+RXDEKb-F?*{U=JF{STX4w@#M<0BSR@Iz^deRFGlzyE6 zsd?H6!eR3j1<$quJ}1Yy-=AO)u#|e)*QEChO!`~Ts(1PY#RT-n>9x9d08i_aC}$oS zNg4-!UmZbo%^p*DGFSE_A)EW&)P(_EOm305X*RLPXMiKt-7hZ$yylH~!i4{u7F@vR zw~wu-a_!IIuAyZy!T!=gQ>U)@DIpudY2qt60UGX^BmXH`90A@85tE&%b|Cq=zTf!N zP0{!KhSVH+3W}j;??OWN+KRi{+V7^KPdDQhdO$@>gr03C2Eka`8^$j-HYR$MAA z0D9P$P=e1h?mtl2O|V`#dXVluy&qucZz~$_8`-{(NzPK|HqXId;u!~u7kNTsB2&W- z06Q#dRlIdgf#_)oBSHM}HH?HVuvfv{cDbMn`V5fJ5)MO`k{d~(I0Df9cJjbw)u>+& zEmaT^UXK)uKgwZ(eIsLvd^idprkR@;WvquWinPU~WADoXU`Z@;;qS%t;u2V+NAR?H z04M%VHT$8YSDAXiPUmq%R`6^&>1I@B(@#w|aN5SZuU>N+yM~I*(lRK^Wvpq2n~CXR zUGNvRL_I&pUl%VP!rTzO3!LQE4Y_G=PvMoN^J<-F@2Bg}UmSP3gG|8Xu_iKUfTqoN zvq&{wVD;D0XxZpI$b_|3xv6;R)^{dJG8sxwr6YwSfrZz3=i;wOcmdOtN#Ft0jpJmU z8d9EdDt-yF^cE=(csi1{Qz~(`VLt}l-_r-aQL zZ$jpH7QlNl8d)&DY-{p2=abgMC7QyP})?Mq! zUW<-w;Hz0wgX77zSCI{IeL0e4FT?(JO`MCB+RV;9UQ)_rbgeeW^}ezdZ%G8NZEz&e z$n!RvYZiSS{-x$@1yrVpf}NDBU=1Fk@LqFj$Z*Ds)W|90pWn8DtP)kQC3=}5;7S5TJdMiw%QDK2{ahg~ z0jaPlp5$vI&VCsI0fRf;gv>daxV-fB95u?&eu0obVJ>XABT5Wwz1}PgN~Lwr7RWa+ zh}`I!V70U2&0VX{W$*q*}ao@Q3+q^S5FVsW=?Ax ztemWxtsWfbs`Af_MmSx6*x5JBre4@fyu?_YE)y8EPaEGr*Onhix(gg3BZ)f7qGWGp z`+A#@;~}9XO;0IKj*vk%D4Jgxs!QyRX^0%wx6@MgnyK9pIuo<3z<#S=K>fY;1mksj zq~odhO#X-h^Oq|Fvk{r9F;~UMvqYj8X-n66Q*QU=$60m$VhJe~0L1*A$5DEKm>bcR zh;SJh-7Abw)85a>O{+#cJHar9_~Zi;hYx*OEH+efE*&SQQgf*o(X1=yvI!PBKF z0Ycq1A~;k?C{-4aRdg~PP_&7KFTeI(0_Vd@BJ0Gdx{JDkrlVAUa!Z2x$LF_KlHWR( zGuJfGUxGKaQ1FNiPK@65MyK=v2NTw@d6XjE{B!TNuwy#R$)I%t;sfxw!hFHb6};K} zRlh0)dC}9vSPFn#vK(-5JSn-OgS~{G7Vx~UpVtiJPKu>fmic1<{`ivhTaHmk8T8OeL3XTEC zE2c_U)44PwT=Xi(hsyT^BZsZRZEAtnO^pNSa6FMo+@oO0p7IPI%BMF%V-ZuFY&C;< z&~vCT(;^y&LSq>eJI|U-$NORsrG|OV0|(U$wI%t7BbkiZ1}pJs#W0qguU0Xp(YD6R zCX}(?aq&VVTf#euX#uM9hGMbo7AJ-fN4uq10#TAudK`)xQZK9(nxd}d& zj(zr*#yv(IchVJD4Yj5qi<>31Tw_@Dw{xd9xmZa>HtNjkl<=(;jseZS$L`}FB!SDj z-IuSX& z%C<5~Lhnq@HnJ1Mm{-C)Dp%(RI%#I?w-!Y7#T{!I_(Q0=zwu%_(L!lvZc|K12haGn zLH9z)KWHxewQSXL=|d@F)3+ptQMZ9Bh^@C)IMCJ>@jBT(6sCiy9cKgZ)VIsfE(SH%JNiAQYp< zp>gF%&=r52Rqu!HJK0aS`)ea0&ZLZH9moSaDgLb7q(S|-kIiCx4`??IZePsE+g;=_ zzbRhCcWFpO3H+D3j1`$r-V^GA;!1iBiv?bhRx-$}?=^0AIIBpCRDPZE{PON;@HatD zQ)_m`&^63hm;d^e?0tsU=1woRyC3w?*W8-qr=(1 z57f}QpiU@;>CX%50Zpd7s%{T0OUIC{Iy{g^?k4?4F_~Drc&hQoL+Gg9dULAb1@egk z6=a-R4^H_-)}7C+V_>}|(A$*eUd3*9f(DrW8{!*~*;xFyE&YT* zUjRb~30MGb79XB-SJxG^(SQH!yff|W%96RSw+pr7Mo#x|Ul_%(zDDv^h_fCU!nB>%)Kpqs!3y4bISdx$}8u#3vwHY4oMH^-X463qOneK%dDS8^lQAFh7B zvTNml$S5C_XSKo1h6^k%E3uM7LxeccTp*Qo_OQeu4ns8emnA?YBvhA@YcXtVUr z_pou%hVLP2v>XNrpjUuS2*hJJq)nIb3Pgv?m-N-V3_0n(%LX2%R(L>zQGczVX!GrU z5SR4!XBs~ycet4btXm;4$Rsy*odk>oqqe@BYMd?CDrwESj09w?mxXmxEE>2|3*tyz zB-Uz*`-v-Pvrz*vx1<7S2T-^$6VfRGMX4HwH8F>wlI6v^ou2A4Vijtu>JBDyBroMD(NLC-fS$mQnJ5$BTGJWxGL`+y?tPL>Y)d51uKY8cn)^zgG+d)d;i zZ47t$588eUhJjN1wt9(^9)Fn0lr1w|ZEI+oDE4YpHq&a(T3_-`KV}oMkxCZ^`YN$1 z>n;}5OJ`)Tm>}kA$Pm6{ z>XvUH+5r}TdS{q!>{@-GidQDp+XUGCYD{Re z2RIO;gDzAn)Y(KnjliWfJ;_R!H-!VX*jh_&N882+Cg(NaK4Vhz`4LlGh?%YJmhY`y zu29gxWXOO$@g^rO3(?w;NmCS(=DZ?;{sQd5J{m270?p&Go#-i05KrL5Dr`EXpQ6SNG z19oE#j`% zZ@T$xWCWSFK25bgXOs-A8yZ>KkDSPr_}9A$IzL`8fUWzuWG>Su(6VdOd2Oa6J_fz` zNb;znX#MAmcz0v+yLIjW+G8w3Qa+?l)>0PE@%1AisM0Bs_LS#Gsgh==4dFKmOhQ~r zw69oM&fQn0(z5*~e<=!gMnd$*1O;ncLpc(!$9j4b?CT5ufbT~%4<^dCO5BGBRhZ7$ z6E&~V_o1k~xeS@#c+qVcTFoiKYlR)vn%P2lO10VFPp1>i`x&OJ;E#f4cv8+EQn%;1 z=tthdZag+D$%}Qn_B(4)DIWyhPm&UWnP~Ef)X6}KBh9vSkTajPO~s?E5IU8ba7X2` z<2**om0B`c98(9n267ID6!e5CJO^rqUU9A_m=m*bp1kN6BkGH>Duh3inEZ>iIT#D6ADZSw;zibSRwhOiDmdgaR`cTZz}|9kL;Lc3PJ@7WW905fe|?wB3czqc|ixMx^3Db zv#hyGQp{r`C}Hc1g zO-GD***g77h0J3L6Wq!1?L(}jd~HES*^GF9N*lmYPf#;tkkPI-veEO)Lf-fUZ|0G7 zea)fF?rE7##z=VC`fY;rFz&^JRuryy-5!cCaCQXfjV7euW-?(o5!@(&X=|O zo}}A`H|Db76e-Qt+|Nr!DPn>c=A!~B)Od_rauJpm_^b!~6&j&gXSkPOMY%3gzP}5! z>Q^Q#*nzM^(!P}?2osm%B`DL>+Cs3jC>iM&(XSUS*w!;;3a zn=Nxta_$lIFa z^!O!!4T`QBhFw|&-kUn~=c`By*qy?@8h%Ffcfc1UDze#^_5juf*UAqQrb0g|JuW{S zJlU05%-sceCVXdCDA0H~V!er%I8)_}od9R!weBb9+7*%hpny3BbUR~+ohbxyW$oq# zN*%g)mo1_;pumo_fg)GI$#aabl2pJ*)Qd#%_oKv=T5Q&y4aj;h)@QIr!5v`YYuCPj zv!CoHP2TMCE0J4xQ9Ht{h9Y553tNhqydqUf5kS;i2)&K%KqL4_h61z6tKG+Kdk|p<8129!5R@!Dfo2U|o2)-+ZI$yiG!GDgSwp&m? zu-1~c&-U^|yIm@|qug%8I&E!imUVloHULnO!@r->B{J{3wURxF>zWAY&(OH2>8Px2 zygTq!3U1;=NOEQ>^zSjpfx>2`9I#0}@c46JuT#*zz;7UuS2j!5V&DB`KLgMIedzBY z`TuYrp2(U5f{hgB7_->B7vj6TH$m~J9x9Z@BxNNY?yqhFOJ{}>n4M_NoDgQ+othXy zni39gsPmG@ITt|dtU{3iPY%qo!JCP>zbT?FK%QDcTMvzZq=u3bIKzKea{{#Z&bpc3 z^$=QlV79>CUjt<_~+%BS)Ugs8Cigw0-~DG7hQ}*5`|KARFpanw2321lQy zt4!ErBSIMVWJ>Qinr@fhZH@S^A~XXM#^P!s5ALDFgV$>UGTSc^9Eks}J4i*^kK{hO z>&gGheFI+uG0Zy-)rP;}`(ODp2&u$CNR^9+G5)@vKw11}34r1G z-wXQR3;N#*0_*mFD+p`~|J&mJe|!cp!ZGI=b;>CK{`tvpBgaou;`;-8hi@l3pME&@ z`ymq;Ozm>Y=q^l%Pk$1acOe1sAWXt1{5cVV7Q?Kx7i{!qJzYfaU30p(Eyk38T{xV~LZ1vPQc3YLf6SQ781sD-~m$=tT z1|IZJ`zG}tQ7(A@bpfjQg~+M~gp zFaFpYs^kRhgZuCVC^1BxdJ;GBwj!xb{N?VJAYf!h;ps9s(}!*LYNxf0DAg@&AMzo)~rInIF}h)z<4nrTgdbTtmpT2qU!oG~-O^t@xh zM~OXO9Dt*r&Q}1AvI}s}z6W$dYomZ2!Q^#}Y41$~37!Zfr%MQ?;&LeiZdz4V?F?1k z1iO0>@;@yN(l}9%c>`9HIiTE-U%hx`*DC=p2WT{aKomhrj2%q6?)G6}xV%MjWZ_kan**6gYT)Iy@c&*zTuvU;{g;utVRB6R_` z@Ss}H|0sWD!H`fsy_OO|L6u_D-;=BHA#FnFZJ*)J_Ibj{!%wC9!*p3Fuk-!De~?Zmvkk-9r7dVV&pQ{Llm8 z9YApcbsLPKAJVRO0=>c*s;ZS3kL~FUlXDr|xyaxx?E&3x%cY5W;AiO<4mU{ac^ds|g0DH+=h-r1&#P@Ad|< zwozBZe1v1FUZDtVmRoe)#$58)51=jLH<(V9dprgVB=Ssuvy$HZ^?)wyb;=g~WVc%per&pD$E1fWnfJd_u|96Lt+UBV`d(Mf;#g4G@5(6U>v<=23`o4u z-phH>{JFo%>wk%KUmOIJ;t1~j@<}HhbjBgAAm3(f;gO<;_PnJUswL0u8ujA^YUhQd zzdYiW8W_x$_-!GxK^4psy_}5I$9-=}H@@|i7IA@!`d$8$E7H^j=)(w>e)aSR3r2!?6~3psoA z$TA|7jQNJAt^CfX5VXLtfmgh4!>jpl^WDX#OOSv+9}U^M=1M^#V5qezTpFws$+9*a zcB0;AOHrEU^ra@WGqxcwEHAWxZtu=$bODr=8NNr|6OxTw88ccf00prcr|}xy463*W z5hxFL{r2&u#D|*mA?Hv2HkK(GAp6v*PQR}icuO*p=WA8UHG(lc`!y@VZ z8XyU^0Q^vx_FbNog?htmWuLNDd7)6AaP4l|a4FQXq%T|Z9_Y<$R~dG6&kTW}4A|7p zYv9;54w~Qi=0dbWP{S>BJ<3&NvOh#+ZmhbzFOGZaVu%9NB@=RjFs}DT>Y2;$kF)K| zsuo{-oi1+`X)M~gXJg?4h7Oq}+V4XTOMUTtA58BA4gvc1_~&+T8GIq|{rb7FzdFd3 zQU-)F(xhw-*?6@_b-y3fv^lXL^$pgZ?&5m=;ZaiODv;dGNC(ydt(pQVIv9V{N+)5 z;b8s?L}1(d!Gv)*TitwZwg=KN`>Vu`WaUZ$<*w#Pobql0HrPDkfP>%(H+_DS*WEEG zXzkM>C$4y?lrMFs-uD3pjbkOZ-uhC5ij(3cj!ZxG-v|tBn-m4%C)`*?fUN(70Taia zS+S31)SaP#Ite-AS9yH@^49XI=bL#)W(2yaS?u~G`%a4pndzs zMPu?Bi{yL7r}*d8K)thT!+wGY$d$Z&<`AaP+%GcrMeE@B-4b3vNLyFEx3`K=F_O#lw4B3*wSTl%Y%h-w#B1?60Xef0%b3q{-|zdqyq42kBbc@bd0{N` zG1--4_w%6URWZ*Vz5lso*v(PTK{O?i%0)MPk<2;TlzhyFcQbpwVJVG%8S5K`IsGXR z*0Gyh?9NRK1`=8dyUuLAQI)TK8bES{%`5>9CT)ccv zQFE-cv*5;bCA@W&YDa7fkfMn<3b`#&$VDO#pNib`5wb)`(XJZsc~!T#%#A6xVuY2e zh#mlj-4)4c{NrALlanlcZ#4Od+tTPEWc6AH9#{k5ptr9EWS)n?MXonwrcb4Uq_)oH zpex87A;$ihyX4`O`P(eHlzl%uby(@O&?B=ly6TH*fxK-1;?=%miZMCTFdI{Pl2)Mj!RZzQpea2|8O7_Nbk0oH^+@ng1E9wd=47#?bIXt$?8;Q-Gh=K z>LqfNp0OwbK*Rjm+7VMxZ-Opw) zo-7t1pd3y6On=qKgnyEbzaFQh2)uGbbstR&@Q5O6&(W`y8mUg;pQmnnNx}YR=D7dv z%Hp)paeLpYrWPdd5Z&KbZzq0~{Yn_?Z}s@aim^DeYBg9_!j%OK^~lhO$EYU`)^H&y z5+o*I{E6YU$JCnssoDqEYUL`cGzpsEE6jeMRwxcT+IRM`*Gaz^#XR)l3x0@%+&)6S zb5>bj&$q^aJChKL8S_&-|<9hL!1tWw}deu>xti(jl?ZSt`K%x@Kx`Aztb}*>?=6Gny#E zmAN#WNt3q>4LD(Au%{JFzk7D9sDx#Xi|pFpJ&$DR0rccGUZ@Is-vvXtTZD9>0aw2&fy#Y=XeY?abPP_pe7Bh9T$CyDDk(>^*r~ zA!q_{-NvoQ$NUOf{hN$Chh(_Vf;j#w#d-iie5*w=&VB8h)I@*J=>$0FH^Q@M2FDBl zzg}yGzL{XWZ9#Prj9!Wz&I8^*cKBWFmPm3A$G)N~zmL^PBHoNgYH zx=7wt{UR%UEP>>vQZE_h&k2|8A1_y!bl7q+9qR&1*U* zPSUQP)nsJfGY?5{Z~xP22!6|_Ns@GIQo%x}d%KO&VHbc^zfro$_SZQ$g^(%Hp97G# z4MWIyxT{*UMUp9AIZ@gkze#F&8mBfm=29}3Od_|f6VTpkVto>YfH*x4?ns79t|I0= zbFb!nd6U>j)&}#za;iO43v=OSnd(f7+4A{LYs+z9EOos}kFq&cux3@_CZGVF_s+cl zo||=ivsRl?_e!@fry^pkJWgmnFT=G_R8%zcYw&c}vv=*e6#tB)PjG}zJ3WPbWd5k? z->07X>va2(dftn2)Fe$Ki_P>(=QmsK5_E}VTwUl)fo)F zdGBf0I?OrhxQA4z-?MZ=0AC2Zfm4dYJ?qo@+PPG1Q(pDFy~M>Q5GMxuk2h==F~Dbl z?*iVcV{T&1N?1)h^v$)?qa?LuZ$TmD6EE(0Ny&LVz4o%eENz4#5%8Y*s5pbr+b znhAX`@j}`84dOalSM0$XGV;J&yhpzN4DYLHi=y&qzXwSJ>@W-?WOm5Sx6s%R0<&_C+v5p;ic>zLen`g+kB+R9%#) zV*i45HU^Mf#p8X=`!b%@Jkuqeood&3qd-AkaMn%|$ zYaVTKuzIiW=~MT?zoUS3^9rZfeUFeM^^r9j!zR>O;h+k&a_2=k{vFFa^@cGwPj@5! zx<^O3yK#1MDfu?1@*!Mt1#X<#C#Us6ovLkk_s675!XL#bZ66D5rnRL{xJ^QOe#|`( zwHl;a7Y-m6;uUAOhpVg+Za(2^aB!^w$)?3o@ZcIjLuPRbqCxI&0+G*N;xJSq%T?g< zve?>JAbuFN5|0agiZ@ji@I=6x+eXoHVL8xJ-sQr>z1F4>zF=|YWi&EAZ^b)X|oXld(8WprGkPVUZNV`1Xr|{EeQtZ4o)p8 z?-I5H_o=s_O!t6qS1Bxr1@F1zyt_PXkN87XXWgY56~J5V;lBj*v#6!UrYVUhb@E{; zAxTk|X$m0RGom(G@w~hh7rU{cLEii2XEpAy<<}?9(Cu|_dJ<3i8hkR&q;pChvu$;1 zZo$_p92nN{DLfPRWiqPTyr#v6HseLBN;~e$Iv>QImqly>%c%}$Z*?LDm}uo=={W*A zvcG5h2a{MddCE)Uqdmt+KQm1>;E2rlpO%=6f`WT-!}dN)r{|`|E4r;uk^>;|Y*3#; zW*xfX032>mh?XYp!cT#AV{~OSI(moep*2+{KW+P(yYRKg%!bG|Wii}0rU@C$YmBqp zrL0gx=e9?)fG)3L_=RcAW7SQ^AsLI+TQF@B-)t&6dn4~f3y|jaO_zFS#L4j%oV&tpxsxI=GKR6k6vrD*bTNZ&|yhA zI044E&o7d%fq-06uFvTTqw{hT<KTpjUrbIyZqd3*+e-VObRIqfRsCXj(6=5e3J z3dW^m*|=FFL6p6lIsO zJbFn+BF7`Kvx?a9C|l6!@Hnt0pJpOej$?j$lkNIt`R4vUdP0uD#hLzV zTrx~qIU6)q@h>E-D0<1V2?LEryD3}WB2`X_7-*Y@{-#7uw~>Tg>XAv9sa4sG&xJlJ zwsGlQ!#m8xu_pt7eZ=A<;pobc!;ENX^_ov-Y!Fp`6)G;y!SS=hAp<=d zxyHQ9GN!18Nfafz%{{4fc});|Sw(c&L(FT2enCcR{$)eFf9EV{x|tW?0N-p8sms$} z@|lk3H>FO_K1*A9zjfgUQxsGcQzT*cCb)Lm@YD2eY!a#zFq6-5*p{+y4R@n*jxiDD zdJcM}WR=uc?A1I?23nbt6DpjB0Q)n*?=jR%g*c80l(`^bslA4@uH8C;%(%6Cbq5F8 z0VgPvcniP`GVgJP#)jCbbr->>akGI$zUB~_O&)j-iPxXgx$T-DtZ3UFmq##AS-@Nq zppRN|DeT$<+ysz#GT-Y{JaT81B&IqThaTnPEtnvxMzoVsvQFeSz3v-5d-!QmbDUvP>9)k4Prd^0`^z{(RE}ibGRsrb%nHJblc4Rl(yVjeZ;p`-(XI}-u?x?5?`6WUYb6Tk&)1ErFYyTUoOh z5%7b{XhA|68`=I$JYww3Sf$bctX97*AhhI9XSMSafddgKkEqDV&Dbl*A6-4 z&q1Czy&ZYU8j}9bp-FhpBl#Of$Va&a3h^dT`{5>aLU|kkhzAibRh;6eg6)-Hs z-s3z8(0CI)UvEyf&s;)=540X}Xth5hue2!M^cecM7M?9EgHg;iYdY4sCOlA#?ISVR zlkk~mxZ+yRKhLeNzjG`*s;YS0>WC(HRls06@d&Jv{qMq8>7RaY8>I&BJaBbuK=u9X zr5^WW4U&w+jy8co;%1Sw7RW zwA185y8cfYSrGSCx07;&e$2U%1PDBgpbHHD{x0IDm=uzX_qYN+lEgaz9Mk$&Ai@?B zwfKq3w6pYQ+lBCc5Y&-ga&4t=I}Ge#5kFH4hE<2;QYViqE0q>u--{ApgCP}G!;iA; zo0ub37a`o&*vDlJxhFm!0%x+))RY(@{=q6Cq@Ky~!RT*a z>t!N>XFy&s>kzv*GB zg@KAG>WMq;p6mF^U}NSH(41KD{%Zx*YHvBUrW$fjnM6XIe}rEs8hyi1C^L)0a8-jW z-X0p(vx|RZ))jb7G;5mzCgc>@EV|A1rU-RJ#T9(yIx9!8zaU{+yOi1WV}Qd3!OQ%m zaQ8kHCJG}S>S2QX)i8BL+Wh;`2`~u>%ZqhGt4h8HAh|1TJ}5j!b8P`6LFCV(X*reF z%Gb}@WOJr}P=Q1YiF<6M5M9!rAB3s?O&$W93NQ^F0dsHo{?G!M+S`GnM$wr@V&1

{5@bPd1~zOrUpt;v8LD4Ez$1RA28*4_aTM~Fz^ORz?74xr2LUrAMR z2c}phXfj8qTZ$mVsgB^?|1+aPJ$mPFDTg=m?EEy*4^z1>**-U~-gxmGDziZ_6weaE zf#Ml9>tWHi*AI}Bw5e@Ogr z)vt|f8{Xn1 zy(mKX<^fpcXL0M%FcRn$4dSUc3ZL}+SroyErzI6wzA&|D#<#DdykLmZTokAKBUGe<3`g*A) zH|zUQ^qPZ-x}n-Q@0M*^VQv1sbm{%=zw}sgZ&99+Q>Pi;&jM1GXF+4<$Yb&g6HGX? zI5lqO_C+o)1d2OdPUhVCrHd}2eu8oUrf=7e!n%4Q7#6o#=pB0r_qPl_nV>`xZ~$vF z4@%>Q_V~*%pj~+A>hB1r$JahFQHM=t>7gHx76M;e&))RUn+0$8<0>=wrj3jF`^2!5q72r zoeDPNVZD>TA5_J`7Psw@|8711{ZK?diqK?1rNegI-p2YQ zB);1}1G7afBfu@!+%MKfQCfY*AhG9_Xoy?W<_MPiWm#N0Sz~8)mZ_J!V*TaISuvPM zg?8BF%Tn=<Uo55qeJiWofZ*ODhP~49<1Ch@a*-xaN9cRzwSw zy-{iMTE%CL#%PE0o}6WGnACCDnU`@!ZajBKSF}u zh;H5bF{{y>{YutwCBUP!x+u`J>K@U5ah%!u?9_q3(l3fSERKg7ff%+B_kGTNFCJ6I zex=`+6y?Yoqdbh_LpGQ9?;o)I3_)UQMS$bqrT1@&mw+BpDW-}2)k9u^9fahZx^$R> zWA)AO%h|y}SZ=kAz4%8r69Uc8{I|Q;aIl4bbggi4a66`f+y3WvI`6{zsBPfl`1hLr k`EaZoGDrCTbwewNeb>1E0;DFLl>h($ diff --git a/docs/img/methods.png b/docs/img/methods.png deleted file mode 100644 index 1f404b8191b0b3917494c4c9085e10247222f219..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 284198 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

ZrBv zSpUHQ7MaJBPGAWhKDxlpvSQ;)Iql?nwEq?}^=wApW-zKC^Mn=d&HHgRZy?xjZ~@OA zAgk*tx}r(y4oinAp5Mexf=|?+Oul7NbUNYxaZP^#XU=%Z;8bT7c5V@V#4PbNJYHyi z40*H=Dq%)!?>CNrZJ|mYr#M`Juf3QS5Mt#ABen!j6XtgbJc8pq*wN% z=NwV8^rl9QRxox9sM@C0bp}k2&C6R8Xt=H=C)yP2m0NV@vf_8xfhp&43-KgEt?^q~ zVq{L*GsVr@8pWcJYPXR5Bls*(>5vRZn!r(?_nX|@o|3*thi3S+(O9D?_55?DgT>~Jcx%Nk9fakzqKCFH$D)Tf`G#U z(YbXDTQ)4EK~{Z`!lFJ3V|4ULvP7}RWvokWrD=1`sjiH{9lNZy4ag81-lQc(ZeEX0 z{MR_1wajj^#qd`HZ_UR_TXlB034ejIOep|`rQ1MWRyX7`w#T`qCX#fn*2$~3Kubta zjr%GVQDFzYDl=V#cRJ-FIVU1rIEl{qAbyzbf}$lM7h~^=U-@k65ebc4s#)XI#Xc^evZ1wkuZy*_+GOQ(xTv}2$1O{R&4j63SG=$C} zMv^v$XT<-$1LFm|xRO>TVJ5hbak_*5+xg4VgBxKb1M8@?w3pR=`6>95K&3F>lo|7B z+tcthN#yYQaJ$~I`V`@tgZg`{1YZE3%1}PDmwlV5gSP+8#_scjo!R>mcL57%Uo$7D zH5yi83G5yQ!vR$5%hy~^Ize}$q)7>qmq^$a+lU574`H5Z&_N3Rk)zr40MHgP^DjTT zM+_GT!w}zyj*&o)Hv(Sn{Wu{o1*Zuw;B)VrR3ZnQC>v?@_`n+|&E_I$nfY)!u+-t@ zcZ;-R--)fOud^)CP|X0YxPjX6{WD>v%@ZGN_bueEtmtwdRNW-C7L(XBW0iJJ=gK)G z?H$+Z!s@|DLQ#tA?fyh1BXht~ggmZ&;*@iX)H8l2RfL?N`wCmV|7gyJx+~V~BulWI zpF(dqbn#=)M)`YMMrI=7$1(J0qgo_H?NpHi__>j+vmv-owStQu`a9LmWa-?o&uChX zN0@HZo~a?7n6E}oH-GkT8j8-dQ*;l%-sXLzQeJ-F#v)0dy1abmUA`rpqLq_@Q;*K0 z_<>S96VY~XQ8)ZJ^jQaty@o59_RUbN`D`4aZTe#FezwQa0}Vk!xeor!+R*kbmpzwL z{-Cw4wZc6L)aYrD9pJMuxmts5cMSWg3K1^9iVD8=G(@DB(Yb)sz&4A1#p#~50iR0g zwF3@Gl&MbLMRji1H^ZNbs=l=@MQK}Sw@4s<0rBkFafUJUuy#J*s_Ul2XLaWyG`!5k zxu9rrp}bNBD5OtvP|Mo~_o%EAVr`ZH|}t(kUsO-IqWy-qWqI`^6uJ z6__?R`j25Pq=}#f%6-iiy2YdCcC;GXLTOakn1HK}oChjbZ!v20qqX0SjpBXa=WK`6 zLNg>er%5s=Ro~cJcR84St8!LUGJ^?1ub7k|m%#fVbo0{5TooHDJt5P(P;Vc6$H&vl zC6%njtzx`r`U$#~&}IH}@X^J+T6|=6Lh@+T0BWj5DH?->mF?w1Wpw5QdD^E1(6lcG z6S$NUe7ubdea;|s(yNZ!6+PIa3-KJfxQ9b|h@&z`GD#la3=Ce2#CUl4s%D0k{xV z<&`OLUQ?~-`hsuCX@Y2ZL`{s!1r~E=Nx;VA{sKxYA`QjLUuPmSjs=Q{3l7KZB2W%p zF%M?*lwnvu`gZe`zEpKu_ozeyJ{5%bh#%esqnak+B2(rqbJ(kDCX7fVGwBC5r_4WBHh;gl^x)5Fc3hE3#q^0NY51vhHS@bKB z>#w=loLj~Sh+*2(LoxPY%NgNzCA+)^$T}s_a?OGsO%j;BN${7#pL7`45X`l@yW`OXpB$0d(8@={?TD>^fg|IYPn^dtSa4?gmZY$--}Jh zU~T4aHqSxLDY1pDf0Pi{g*iCfcUKcsR;v2d}9tPZRd-N%dXoT*2$eaP6%%0Do`@$gK-EKlx*mFR|1vCvK_+ZPO~d= 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

n9C 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 diff --git a/docs/img/zt_why.png b/docs/img/zt_why.png deleted file mode 100644 index f268bb64d4f257db7ac6c71f9b4d3e9c8e716c4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 198231 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

a-D3jUv(2@>5B;!SbM_h+V+#tiZ|Hatl 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 diff --git a/docs/integrations.md b/docs/integrations.md deleted file mode 100644 index 264555c..0000000 --- a/docs/integrations.md +++ /dev/null @@ -1,59 +0,0 @@ -ZeroTier Integrations -==== - -If you want everything built at once, type `make all` and go play outside for a few minutes, we'll copy all of the targets into the `build` directory for you along with specific instructions contained in a `README.md` on how to use each binary. You can then use `make -s check` to check the build status of each binary target. - -*NOTE for Apple platforms: In order to build iOS/OSX Frameworks and Bundles you will need XCode command line tools `xcode-select --install`* - -*NOTE: For Android JNI libraries to build you'll need to install [Android Studio](https://developer.android.com/studio/index.html) the [Android NDK](https://developer.android.com/ndk/index.html). Currently only Android NDK r10e is supported and can be found [here for OSX](http://dl.google.com/android/repository/android-ndk-r10e-darwin-x86_64.zip) and [here for Linux](http://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip). You'll need to tell our project where you put it by putting the path in [this file](android/proj/local.properties), you'll need to install the Android Build-Tools (this can typically be done through the editor the first time you start it up), and finally you should probably upgrade your Gradle plugin if it asks you to. If you don't have these things installed and configured we will detect that and just skip those builds automatically. Additionally, you can specify the target architectures you wish to build for by editing [Application.mk](android/android_jni_lib/java/jni/Application.mk). By default it will build `arm64-v8a`, `armeabi`, `armeabi-v7a`, `mips`, `mips64`, `x86`, and `x86_64`* - -Below are the specific instructions for each integration requiring *little to no modification to your code*. Remember, with a full build we'll put a copy of the appropriate integration instructions in the resultant binary's folder for you anyway. - -For more support on these integrations, or if you'd like help creating a new integration, stop by our [community section](https://www.zerotier.com/community/)! - -*** -## Important Build Flags - -- `SDK_IPV4=1` - Enable IPv4 support -- `SDK_IPV6=1` - Enable IPv6 support - -- `SDK_DEBUG=1` - Enables SDK debugging - -- `SDK_PICOTCP=1` - Enable the use of `picoTCP` (recommended) -- `SDK_PICO_DEBUG=1` - Enables debug output for the `picoTCP` network stack - -- `SDK_LWIP=1` - Enable the use of `lwIP` (deprecated) -- `SDK_LWIP_DEBUG=1` - Enables debug output for the `lwIP` library. - -*** - -### Apple - - For everything: `make apple ` - -##### iOS - - [Embedding within an app](apple/example_app/iOS) `make ios_app_framework` -> `build/ios_app_framework/*` - - Unity3D plugin `make ios_unity3d_bundle` -> `build/ios_unity3d_bundle/*` - -##### OSX - - [Linking into an app at compiletime](../docs/osx.md) `make osx_static_lib` -> `build/libzt.a` - - [Embedding within an app with Xcode](apple/example_app/OSX) `make osx_app_framework` -> `build/osx_app_framework/*` - - [Dynamic-linking into an app/service at runtime](../docs/osx.md) `make osx_service_and_intercept` -> { `build/zerotier-sdk-service` + `build/libztintercept.so` } - - [Intercept library](../docs/osx.md) `make osx_sdk_service` -> `build/zerotier-sdk-service` - - [SDK Service](../docs/osx.md) `make osx_intercept` -> `build/libztintercept.so` - - [Unity3D plugin](apple/ZeroTierSDK_Apple) `make osx_unity3d_bundle` - -*** -### Linux - - For everything: `make linux ` - - [Dynamic-linking into an app/service at runtime](../docs/linux.md) `make linux_shared_lib` - - Service and Intercept `make linux_service_and_intercept` -> { `build/zerotier-sdk-service` + `build/libztintercept.so` } - - [Using the SDK with Docker](docker) - -### Android - - For everything: `make android` - - - [Embedding within an app](android) `make android_jni_lib` -> `build/android_jni_lib/YOUR_ARCH/libZeroTierOneJNI.so` - -*** -### Windows - - Not yet. diff --git a/docs/intro.md b/docs/intro.md deleted file mode 100644 index 1f973eb..0000000 --- a/docs/intro.md +++ /dev/null @@ -1,105 +0,0 @@ -ZeroTier SDK -====== - -ZeroTier-enabled apps, devices, and services. - -Secure virtual network access embedded directly into applications, games, and devices. Imagine starting an instance of your application or game and having it automatically be a member of your virtual network without having to rewrite your networking layer. Check out our [Integrations](integrations/) to learn how to integrate this into your application, device, or ecosystem. - -The general idea is this: - - - Your application starts. - - The API and ZeroTier service initializes inside a separate thread of your app. - - Your app can now reach anything on your flat virtual network via normal network calls. - -It's as simple as that! - -To build everything for your platform, you can start with: - - - On Linux: `make linux SDK_PICOTCP=1 SDK_IPV4=1 SDK_DEBUG=1; make -s check; ls -lG build` - - On macOS: `make apple SDK_PICOTCP=1 SDK_IPV4=1 SDK_DEBUG=1; make -s check; ls -lG build` - -*** - -The SDK couples the ZeroTier core Ethernet virtualization engine with a user-space TCP/IP stack and a carefully-crafted API which intercepts and re-directs network API calls to our service. This allows servers and applications to be used without modification or recompilation. It can be used to run services on virtual networks without elevated privileges, special configuration of the physical host, kernel support, or any other application specific configuration. It's ideal for [containerized applications](integrations/docker/), [games](integrations/Unity3D/), and [desktop/mobile apps](integrations/). - -Combine this functionality with the network/device management capabilities of [ZeroTier Central](https://my.zerotier.com) and its associated [API](https://my.zerotier.com/help/api) and we've hopefully created a simple and reliable way for you to flatten and reduce the complexity of your app's networking layer. - -The ZeroTier SDK now works on both *x64* and *ARM* architectures. We've tested a beta version for *iOS*, *Android*, *Linux*, and *macOS*. - -## How do I use it? - -There are generally two ways one might want to use the service. - - - The first approach is a *compile-time static linking* of our service library directly into your application. With this option you can bundle our entire functionality right into your app with no need to communicate with a service externally, it'll all be handled automatically. This is most typical for mobile applications, games, etc. - - - The second is a service-oriented approach where our smaller intercept library is *dynamically-linked* into your app upon startup and will communicate to a single ZeroTier service on the host which will relay traffic to and from the ZeroTier virtual network. This can be useful if you don't have access to the app's source code and can't perform a static linking. - -![Image](docs/img/methods.png) - -## How does it work? - -We've designed a background tap service that pairs the ZeroTier protocol with swappable user-space network stacks. We've provided drivers for [Lightweight IP (lwIP)](http://savannah.nongnu.org/projects/lwip/) and [picoTCP](http://www.picotcp.com/). The aim is to give you a new way to bring your applications onto your virtual network. For a more in-depth explanation of how it works take a look at our [Technical discussion](docs/technical.md) - -## APIs - -**Hook/Intercept** -- Uses dynamic loading of our library to allow function interposition or "hooking" to re-implement traditional socket API functions like `socket()`, `connect()`, `bind()`, etc. - -**Direct Call** -- Directly call the `zts_*` API specified in [src/sdk.h](src/sdk.h). For this to work, just use one of the provided headers that specify the interface for your system/architecture and then either dynamically-load our library into your app or statically-link it at compile-time. - - -*** -## Important Build Flags - -- `SDK_IPV4=1` - Enable IPv4 support -- `SDK_IPV6=1` - Enable IPv6 support - -- `SDK_DEBUG=1` - Enables SDK debugging - -- `SDK_PICOTCP=1` - Enable the use of `picoTCP` (recommended) -- `SDK_PICOTCP_DEBUG=1` - Enables debug output for the `picoTCP` network stack - -- `SDK_LWIP=1` - Enable the use of `lwIP` (deprecated) -- `SDK_LWIP_DEBUG=1` - Enables debug output for the `lwIP` library. - -*** - -### Apple - - For everything: `make apple ` - -##### iOS - - [Embedding within an app](integrations/apple/example_app/iOS) `make ios_app_framework` -> `build/ios_app_framework/*` - - Unity3D plugin `make ios_unity3d_bundle` -> `build/ios_unity3d_bundle/*` - -##### OSX - - [Linking into an app at compiletime](docs/osx_zt_sdk.md) `make osx_static_lib` -> `build/libzt.a` - - [Embedding within an app with Xcode](integrations/apple/example_app/OSX) `make osx_app_framework` -> `build/osx_app_framework/*` - - [Dynamic-linking into an app/service at runtime](docs/osx.md) `make osx_service_and_intercept` -> { `build/zerotier-sdk-service` + `build/libztintercept.so` } - - [Intercept library](docs/osx.md) `make osx_sdk_service` -> `build/zerotier-sdk-service` - - [SDK Service](docs/osx.md) `make osx_intercept` -> `build/libztintercept.so` - - [Unity3D plugin](integrations/apple/ZeroTierSDK_Apple) `make osx_unity3d_bundle` - -*** -### Linux - - For everything: `make linux ` - - [Dynamic-linking into an app/service at runtime](docs/linux.md) `make linux_shared_lib` - - Service and Intercept `make linux_service_and_intercept` -> { `build/zerotier-sdk-service` + `build/libztintercept.so` } - - [Using the SDK with Docker](integrations/docker) - -### Android - - For everything: `make android` - - - [Embedding within an app](integrations/android) `make android_jni_lib` -> `build/android_jni_lib/YOUR_ARCH/libZeroTierOneJNI.so` - -*** -### Windows - - Not yet. - - -*** -![Image](docs/img/api_diagram.png) - - -More discussion can be found in our [original blog announcement](https://www.zerotier.com/blog/?p=490) and [the SDK product page](https://www.zerotier.com/product-netcon.shtml). -If you have any feature or support requests, be sure to let us know [here](https://www.zerotier.com/community/)! diff --git a/docs/ios.md b/docs/ios.md deleted file mode 100644 index 968008f..0000000 --- a/docs/ios.md +++ /dev/null @@ -1,54 +0,0 @@ -iOS + ZeroTier SDK -==== - -Welcome! - -Imagine a flat, encrypted, no-configuration LAN for all of the instances of your iOS app. - -This short tutorial will show you how to enable ZeroTier functionality for your iOS app with little to no code modification. Check out our [ZeroTier SDK](https://www.zerotier.com/blog) page for more info on how the integration works. - -*** -**Step 1: Build iOS framework** - -- `make ios_app_framework` -- This will output to `build/ios_app_framework/Release-iphoneos/ZeroTierSDK_iOS.framework` - -**Step 2: Integrate SDK into project** - -- Add the resultant framework package to your project -- Add `src` directory to *Build Settings -> Header Search Paths* -- Add `build/ios_app_framework/Release-iphoneos/` to *Build Settings -> Framework Search Paths* -- Add `ZeroTierSDK.frameworkiOS` to *General->Embedded Binaries* -- Add `src/wrappers/swift/ZTSDK.swift`, `src/wrappers/swift/XcodeWrapper.cpp` and `src/wrappers/swift/XcodeWrapper.hpp` to your project: -- Set `src/wrappers/swift/Apple-Bridging-Header.h` as your bridging-header in *Build Settings -> Objective-C Bridging-header* - -**Step 3: Start the ZeroTier service** - -Start the service: - -``` - zt.start_service(nil); - zt.join_network(nwid); -``` - -Listen for incoming connections: - -``` - let sock: Int32 = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort)) - let bind_err = zt.bind(sock, ztaddr) - zt_listen(sock, 1); - let accepted_sock: Int32 = zt.accept(sock, ztaddr) -``` - -Or, establish a connection: - -``` - let sock: Int32 = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort)) - let connect_err: Int32 = zt.connect(sock, ztaddr) -``` - -**Alternative APIs** - -CLick [here](../../../../docs/api_discussion.md) to learn more about alternative APIs such as the Intercept and SOCKS5 Proxy. \ No newline at end of file diff --git a/docs/ios_unity3d.md b/docs/ios_unity3d.md deleted file mode 100644 index 3557a7c..0000000 --- a/docs/ios_unity3d.md +++ /dev/null @@ -1,98 +0,0 @@ -Unity3D iOS + ZeroTier SDK -==== - -Welcome! - -We want your Unity apps to talk *directly* over a flat, secure, no-config virtual network without sending everything into the "cloud". Thus, we introduce the ZeroTier-Unity3D integration! - -Our implementation currently intends to be the bare minimum required to get your Unity application to talk over ZeroTier virtual networks. As a result, we've created an API that is very similar to the classic BSD-style sockets API. With this basic API it is possible to construct more abstracted network layers much like Unity's LLAPI and HLAPI. - -*NOTE: Although the API and Unity project structure is identical for iOS/OSX, if you're targeting iOS you'll need to generate an iOS unity project and integrate it with your Xcode project, instructions can be found [here](https://unity3d.com/learn/tutorials/topics/mobile-touch/building-your-unity-game-ios-device-testing).* - -*** -## API - -- `Join(nwid)`: Joins a ZeroTier virtual network -- `Leave(nwid)`: Leaves a ZeroTier virtual network -- `Socket(family, type, protocol)`: Creates a ZeroTier-administered socket (returns an `fd`) -- `Bind(fd, addr, port)`: Binds to that socket on the address and port given -- `Listen(fd, backlog)`: Puts a socket into a listening state -- `Accept(fd)`: Accepts an incoming connection -- `Connect(fd, addr, port)`: Connects to an endpoint associated with the given `fd` -- `Write(fd, buf, len)`: Sends data to the endpoint associated with the given `fd` -- `Read(fd, buf, len)`: Receives data from an endpoint associated with the given `fd` -- `SendTo(fd, buf, len, flags, addr, port)`: Sends data to a given address -- `RecvFrom(fd, ref buf, len, flags, addr, port)`: Receives data -- `Close(fd)`: Closes a connection to an endpoint - -*** -## Adding ZeroTier to your Unity app - -**Step 1: Create virtual ZeroTier [virtual network](https://my.zerotier.com/)** - -**Step 2: Add plugin to Unity project** - - Create folder `Assets/Plugins` - - Place `ZeroTierSDK_Unity3D_iOS.bundle` in folder - -**Step 3: Include wrapper class source** - - Drag `ZTSDK.cs` into your `Assets` folder. - -**Step 4: Create and use a `ZTSDK` object** - - See examples below for how to use it! - -*** - -## Listening for a connection -``` -public class Example -{ - public ZTSDK zt; - - public void example_server() - { - Thread connectThread = new Thread(() => { - // Create ZeroTier-administered socket - int sock = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Stream, (int)ProtocolType.Unspecified); - zt.Bind(sock, "0.0.0.0", 8000); - zt.Listen(sock, 1); - - // Accept() client connection - int accept_sock = -1; - while(accept_res < 0) { - accept_sock = zt.Accept(sock); - } - - // Read data from client - char[] msg = new char[1024]; - int bytes_read = 0; - while(bytes_read >= 0) { - bytes_read = zt.Read(accept_sock, ref msg, 80); - string msgstr = new string(msg); - Debug.Log("MSG (" + bytes_read + "):" + msgstr); - } - }); - connectThread.IsBackground = true; - connectThread.Start(); - } -} -``` - -## Establishing a connection -``` -public class Example -{ - public ZTSDK zt; - - public void example_client() - { - Thread connectThread = new Thread(() => { - // Create ZeroTier-administered socket - int sock = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Stream, (int)ProtocolType.Unspecified); - zt.Connect (sock, "0.0.0.0",8000); - zt.Write(sock, "Welcome to the machine!", 24); - }); - connectThread.IsBackground = true; - connectThread.Start(); - } -} -``` \ No newline at end of file diff --git a/docs/linux.md b/docs/linux.md deleted file mode 100644 index 32243cf..0000000 --- a/docs/linux.md +++ /dev/null @@ -1,164 +0,0 @@ -Linux + ZeroTier SDK -==== - -Welcome! - -Imagine a flat, encrypted, no-configuration LAN for all of your Linux applications. - -This short tutorial will show you how to inject ZeroTier functionality into your application by dynamic linking via `LD_PRELOAD`. - -## Use with Docker - -See [doc/docker_linux_zt_sdk.md](doc/docker_linux_zt_sdk.md) - -## Short and sweet example - -**Step 1: Make library and copy key files** - -``` -make linux_shared_lib -mkdir /tmp/sdk-test-home -cp -f build/lwip/liblwip.so /tmp/sdk-test-home -``` - -**Step 2: Start service and join network** - -``` -./build/zerotier-sdk-service -d -p8000 /tmp/sdk-test-home -./build/zerotier-cli -D/tmp/sdk-test-home join 8056c2e21c000001 -``` - -**Step 3: Get new IP address assigned to app** - -``` -./build/zerotier-cli -D/tmp/sdk-test-home listnetworks -``` - -**Step 4: Set environment variables** - -``` -export LD_PRELOAD=`pwd`/build/linux_shared_lib/libztintercept.so -export ZT_NC_NETWORK=/tmp/sdk-test-home/nc_8056c2e21c000001 -``` - -**Step 5: Start application** - -``` -node tests/httpserver.js -``` -**Step 6: Test it!** - -From another system on the same virtual network `curl http://APP.SPECIFIC.IP.ADDR/` - -*For a more in-depth explanation of what's happening here, see the section below:* - - -## Dynamic Linking - -Build the library: - -`make linux_shared_lib` - -This will build a binary called `zerotier-sdk-service` and a library called `libztintercept.so`. It will also build the IP stack as `build/lwip/liblwip.so`. - -The `zerotier-sdk-service` binary is almost the same as a regular ZeroTier One build except instead of creating virtual network ports using Linux's `/dev/net/tun` interface, it creates instances of a user-space TCP/IP stack for each virtual network and provides RPC access to this stack via a Unix domain socket. The latter is a library that can be loaded with the Linux `LD_PRELOAD` environment variable or by placement into `/etc/ld.so.preload` on a Linux system or container. Additional magic involving nameless Unix domain socket pairs and interprocess socket handoff is used to emulate TCP sockets with extremely low overhead and in a way that's compatible with select, poll, epoll, and other I/O event mechanisms. - -The intercept library does nothing unless the `ZT_NC_NETWORK` environment variable is set. If on program launch (or fork) it detects the presence of this environment variable, it will attempt to connect to a running `zerotier-sdk-service` at the specified Unix domain socket path. - -Unlike `zerotier-one`, `zerotier-sdk-service` does not need to be run with root privileges and will not modify the host's network configuration in any way. It can be run alongside `zerotier-one` on the same host with no ill effect, though this can be confusing since you'll have to remember the difference between "real" host interfaces (tun/tap) and network containerized endpoints. The latter are completely unknown to the kernel and will not show up in `ifconfig`. - - -#### Starting the SDK Service - -A simple test can be performed in user space (no root) in your own home directory. - -First, build the SDK service and intercept library as described above. Then create a directory to act as a temporary ZeroTier home for your test SDK service instance. You'll need to move the `liblwip.so` binary that was built with `make linux_shared_lib` into there, since the service must be able to find it there and load it. - - mkdir /tmp/sdk-test-home - cp -f build/lwip/liblwip.so /tmp/sdk-test-home - -Now you can run the service (no sudo needed, and `-d` tells it to run in the background): - - ./build/zerotier-sdk-service -d -p8000 /tmp/sdk-test-home - -As with ZeroTier One in its normal incarnation, you'll need to join a network for anything interesting to happen: - - ./build/zerotier-cli -D/tmp/sdk-test-home join 8056c2e21c000001 - -If you don't want to use [Earth](https://www.zerotier.com/public.shtml) for this test, replace 8056c2e21c000001 with a different network ID. The `-D` option tells `zerotier-cli` not to look in `/var/lib/zerotier-one` for information about a running instance of the ZeroTier system service but instead to look in `/tmp/sdk-test-home`. - -Now type: - - ./build/zerotier-cli -D/tmp/sdk-test-home listnetworks - -Try it a few times until you see that you've successfully joined the network and have an IP address. Instead of a *zt#* device, a path to a Unix domain socket will be listed for the network's port. - -Now you will want to have ZeroTier One (the normal `zerotier-one` build, not the SDK) running somewhere else, such as on another Linux system or VM. Technically you could run it on the *same* Linux system and it wouldn't matter at all, but many people find this intensely confusing until they grasp just what exactly is happening here. - -On the other Linux system, join the same network if you haven't already (8056c2e21c000001 if you're using Earth) and wait until you have an IP address. Then try pinging the IP address your SDK service instance received. You should see ping replies. - -Back on the host that's running `zerotier-sdk-service`, type `ip addr list` or `ifconfig` (ifconfig is technically deprecated so some Linux systems might not have it). Notice that the IP address of the network containers endpoint is not listed and no network device is listed for it either. That's because as far as the Linux kernel is concerned it doesn't exist. - -What are you pinging? What is happening here? - -The `zerotier-sdk-service` binary has joined a *virtual* network and is running a *virtual* TCP/IP stack entirely in user space. As far as your system is concerned it's just another program exchanging UDP packets with a few other hosts on the Internet and nothing out of the ordinary is happening at all. That's why you never had to type *sudo*. It didn't change anything on the host. - -Now you can run an application . - - export LD_PRELOAD=`pwd`/build/linux_shared_lib/libztintercept.so - export ZT_NC_NETWORK=/tmp/sdk-test-home/nc_8056c2e21c000001 - node tests/httpserver.js - -Also note that the "pwd" in `LD_PRELOAD` assumes you are in the ZeroTier source root and have built the SDK there. If not, substitute the full path to `libztintercept.so`. If you want to remove those environment variables later, use `unset LD_PRELOAD` and `unset ZT_NC_NETWORK`. - -If you don't have node.js installed, an alternative test using python would be: - - python -m SimpleHTTPServer 80 - -If you are running Python 3, use `-m http.server`. - -If all went well a small static HTTP server is now serving up the current directory, but only inside the network container. Going to port 80 on your machine won't work. To reach it, go to the other system where you joined the same network with a conventional ZeroTier instance and try: - - curl http://APP.SPECIFIC.IP.ADDR/ - -Replace `APP.SPECIFIC.IP.ADDR` with the IP address that `zerotier-sdk-service` was assigned on the virtual network. (This is the same IP you pinged in your first test.) If everything works, you should get back a copy of ZeroTier One's main README.md file. - - -*** -#### Dynamic linking compatibility test results - -The following applications have been tested and confirmed to work for the beta release: - -Fedora 23: - - httpstub.c - nginx 1.8.0 - http 2.4.16, 2.4.17 - darkhttpd 1.11 - python 2.7.10 (python -m SimpleHTTPServer) - python 3.4.3 (python -m http.server) - redis 3.0.4 - node 6.0.0-pre - sshd - -CentOS 7: - - httpstub.c - nginx 1.6.3 - httpd 2.4.6 (debug mode -X) - darkhttpd 1.11 - node 4.2.2 - redis 2.8.19 - sshd - -Ubuntu 14.04.3: - - httpstub.c - nginx 1.4.6 - python 2.7.6 (python -m SimpleHTTPServer) - python 3.4.0 (python -m http.server) - node 5.2.0 - redis 2.8.4 - sshd - -It is *likely* to work with other things but there are no guarantees. diff --git a/docs/network_stacks.md b/docs/network_stacks.md deleted file mode 100644 index 1933e87..0000000 --- a/docs/network_stacks.md +++ /dev/null @@ -1,25 +0,0 @@ -Hot-Swappable Network Stacks! -==== - -We've now enabled the ability for users to build the ZeroTier SDK with different network stacks with the mere flip of a compiler flag as well as running different stacks concurrently! This is perfect for embedded developers which may need a smaller code footprint and would like to use their own smaller or more specialized network stacks. - -`SDK_LWIP=1` and `SDK_PICOTCP=1` will enable the lwIP and picoTCP network stacks respectively. - -Currently our *lwIP* stack driver supports IPV4 and limited IPV6, whereas our *picoTCP* stack driver supports both IPV4 and IPV6 with no known issues. - -To enable specific protocol versions use `SDK_IPV4=1` and `SDK_IPV6=1` in conjunction with the above stack selection flags. - -Also, to enable debug for the SDK use `SDK_DEBUG=1`, to enable debug for the *lwIP* stack use `SDK_LWIP_DEBUG=1`. - -## Integrating Your Own Custom Stack - -If you don't know why this section exists, then I suggest turning back now. This is not for you. Otherwise, let's get on with things, here's how you can integrate your own custom network stack if for some reason lwIP or picoTCP aren't cutting it for you: - -Investigate the structure of `src/tap.cpp`, this file contains calls to functions implemented in the stack driver code (located in `src/stack_drivers`). - -Each stack is different but generally you'll need to provide: - - An initialization function to configure and bring up the stack's `interface` (or similar). - - An I/O polling loop section where you'll execute your timer calls, and check for inbound and outbound frames. - - A low-level input and output function to handle feeding ethernet frames into and out of the stack in its own unique way. - - Calls to your stack's API which roughly correspond with `handleRead()`, `handleWrite()`, `handleSocket()`, `handleConnect()`, etc - - In those calls you'll need to handle the creation, management, and destruction of your stack's "connection" objects, whatever that may be. \ No newline at end of file diff --git a/docs/osx.md b/docs/osx.md deleted file mode 100644 index 742afba..0000000 --- a/docs/osx.md +++ /dev/null @@ -1,78 +0,0 @@ -OSX + ZeroTier SDK -==== - -Welcome! - -Imagine a flat, encrypted, no-configuration LAN for all of the instances of your OSX app. - -*** - -## Via Traditional Linking (Service and Intercept) - - - This will allow the interception of traditional socket API calls such as `socket()`, `connect()`, `bind()`, etc. - -Build against our library: - - gcc app.c -o app libztintercept.so - export ZT_NC_NETWORK=/tmp/sdk-test-home/nc_8056c2e21c000001 - -Start service - - ./zerotier-sdk-service -d -p8000 /tmp/sdk-test-home & - -Run application - - ./app - -## Via `DYLD_LIBRARY_PATH` (Injecting code dynamically at runtime) - -As of the release of El Capitan, Apple requires one to turn off System Integrity Protection for code injection from external libraries. This method of intercepting network calls is now deprecated and we are investigating new methods for future releases of the SDK. If you still wish to use this method just `export DYLD_LIBRARY_PATH=./path/to/libztintercept.so:$DYLD_LIBRARY_PATH`. Also set `ZT_NC_NETWORK` appropriately. - - -## Via App Framework in XCode - -*** -**Step 1: Build OSX framework** - -- `make osx_app_framework` -- This will output to `build/osx_app_framework/Release/ZeroTierSDK_OSX.framework` - -**Step 2: Integrate SDK into project** - -- Add the resultant framework package to your project -- Add `src` directory to *Build Settings -> Header Search Paths* -- Add `build/osx_app_framework/Release/` to *Build Settings -> Framework Search Paths* -- Add `ZeroTierSDK.frameworkOSX` to *General->Embedded Binaries* -- Add `src/wrappers/swift/ZTSDK.swift`, `src/wrappers/swift/XcodeWrapper.cpp`, and `src/wrappers/swift/XcodeWrapper.hpp` to your project: -- Set `src/wrappers/swift/Apple-Bridging-Header.h` as your bridging-header in *Build Settings -> Objective-C Bridging-header* - -**Step 3: Start the ZeroTier service** - -Start the service: - -``` - zt.start_service("."); // Where the ZeroTier config files for this app will be stored - zt.join_network(nwid); -``` - -Listen for incoming connections: - -``` - let sock: Int32 = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort)) - let bind_err: Int32 = zt.bind(sock, ztaddr) - zt_listen(sock, 1); - let accepted_sock: Int32 = zt.accept(sock, ztaddr) -``` - -Or, establish a connection: - -``` - let sock: Int32 = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort)) - let connect_err: Int32 = zt.connect(sock, ztaddr) -``` - -**Alternative APIs** - -Click [here](../../../../docs/api_discussion.md) to learn more about alternative APIs such as the Intercept and SOCKS5 Proxy. \ No newline at end of file diff --git a/docs/osx_unity3d.md b/docs/osx_unity3d.md deleted file mode 100644 index fd56965..0000000 --- a/docs/osx_unity3d.md +++ /dev/null @@ -1,103 +0,0 @@ -Unity3D OSX + ZeroTier SDK -==== - -Welcome! - -We want your Unity apps to talk *directly* over a flat, secure, no-config virtual network without sending everything into the "cloud". Thus, we introduce the ZeroTier-Unity3D integration! - -Our implementation currently intends to be the bare minimum required to get your Unity application to talk over ZeroTier virtual networks. As a result, we've created an API that is very similar to the classic BSD-style sockets API. With this basic API it is possible to construct more abstracted network layers much like Unity's LLAPI and HLAPI. - -*** -## API - -- `Join(nwid)`: Joins a ZeroTier virtual network -- `Leave(nwid)`: Leaves a ZeroTier virtual network -- `Socket(family, type, protocol)`: Creates a ZeroTier-administered socket (returns an `fd`) -- `Bind(fd, addr, port)`: Binds to that socket on the address and port given -- `Listen(fd, backlog)`: Puts a socket into a listening state -- `Accept(fd)`: Accepts an incoming connection -- `Connect(fd, addr, port)`: Connects to an endpoint associated with the given `fd` -- `Write(fd, buf, len)`: Sends data to the endpoint associated with the given `fd` -- `Read(fd, buf, len)`: Receives data from an endpoint associated with the given `fd` -- `SendTo(fd, buf, len, flags, addr, port)`: Sends data to a given address -- `RecvFrom(fd, ref buf, len, flags, addr, port)`: Receives data -- `Close(fd)`: Closes a connection to an endpoint - -*** -## Adding ZeroTier to your Unity app - -**Step 1: Create virtual ZeroTier [virtual network](https://my.zerotier.com/)** - -**Step 2: Add plugin to Unity project** - - Create folder `Assets/Plugins` - - Place `ZeroTierSDK_Unity3D_OSX.bundle` in folder - -**Step 3: Include wrapper class source** - - Drag `ZTSDK.cs` into your `Assets` folder. - - Add a file `Assets/smcs.rsp` containing the flag `-unsafe`. This is needed to execute the native library. - -**Step 4: Create and use a `ZTSDK` object** - - See examples below for how to use it! - -*** - -## Listening for a connection -``` -public class Example -{ - public ZTSDK zt; - - public void example_server() - { - zt = new ZTSDK (); // Start interface - zt.Join("8056c2e21c000001"); // Join your network - - Thread connectThread = new Thread(() => { - // Create ZeroTier-administered socket - int sock = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Stream, (int)ProtocolType.Unspecified); - zt.Bind(sock, "0.0.0.0", 8000); - zt.Listen(sock, 1); - - // Accept client connection - int accept_sock = -1; - while(accept_res < 0) { - accept_sock = zt.Accept(sock); - } - - // Read data from client - char[] msg = new char[1024]; - int bytes_read = 0; - while(bytes_read >= 0) { - bytes_read = zt.Read(accept_sock, ref msg, 80); - string msgstr = new string(msg); - Debug.Log("MSG (" + bytes_read + "):" + msgstr); - } - }); - connectThread.IsBackground = true; - connectThread.Start(); - } -} -``` - -## Establishing a connection -``` -public class Example -{ - public ZTSDK zt; - - public void example_client() - { - zt = new ZTSDK (); - zt.Join("8056c2e21c000001"); - - Thread connectThread = new Thread(() => { - // Create ZeroTier-administered socket - int sock = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Stream, (int)ProtocolType.Unspecified); - zt.Connect (sock, "0.0.0.0",8000); - zt.Write(sock, "Welcome to the machine!", 24); - }); - connectThread.IsBackground = true; - connectThread.Start(); - } -} -``` \ No newline at end of file diff --git a/docs/technical.md b/docs/technical.md deleted file mode 100644 index c2d99bf..0000000 --- a/docs/technical.md +++ /dev/null @@ -1,169 +0,0 @@ -Technical Discussion -====== - -*Note: It is not necessary for you to understand anything in this document, this is merely for those curious about the inner workings of the intercept, tap service, stack driver, and network stack.* - -In this document we will walk you through what happens when your ZeroTier-enabled app does things like accepting a connection, receiving data, etc. But before we get into specific cases it's worth understanding the three major components which work together to produce this magic: - - - **Intercept Library**: Mates to your app and allows us to re-implement classic network calls such as `socket()`, `bind()`, etc - - **Tap Service / Stack Driver**: Mediates communication between the Intercept Library and the Network Stack. - - **Network Stack**: Handles incoming ethernet frames and generates outgoing frames. - -So now that we've clarified what these components do, here's the general idea: - -You make a network call, the intercept routes that to our tap service which uses the user-space network stack to generate ethernet frames which is then sent out onto your ZeroTier virtual network. - -*** - - - - - - -### Creating a socket - -Your app requests a socket: - -``` -socket() -``` - -Our library's implementation of `socket()` is executed instead of the kernel's. We automatically establish an `AF_UNIX` socket connection with the **tap service**. This is how your app will communicate with ZeroTier. An `RPC_SOCKET` message is sent to the **tap service**. The **tap service** receives the `RPC_SOCKET` message and requests the allocation of a new `Connection` object from the **stack driver** which represents the new socket. The **tap service** then repurposes the socket used for the RPC message and returns its file descriptor to your app for it to use as the new socket. - -From your app's perspective nothing out of the ordinary has happened. It called `socket()`, and got a file descriptor back. -*** - - - - - - - - - -### Establishing a connection - -You app connects to a remote host: - -``` -connect() -``` - -An `RPC_CONNECT` call is sent to the **tap service**, it is unpacked by the **stack driver** in `pico_handleConnect()`. A `pico_socket_connect()` call is made to the **network stack**. Once it establishes a connection (or fails), it sends a return value back to the app. - -``` -phyOnUnixData() -pico_handleConnect() -pico_socket_connect() -``` -*** - - - - - - - - -### Accepting a connection - -Your app places a socket into a listen state: - -``` -listen() -``` -An `RPC_LISTEN` call is sent to the **tap service** and **stack driver** - -You app accepts a connection: - -``` -accept() -``` - -The **network stack** raises a `PICO_SOCK_EV_CONN` event which calls `pico_cb_socket_activity()`. From here we request a new `pico_socket` be created to represent the new connection. This is done via `pico_socket_accept()`. Once we have a valid `pico_socket`, we create an `AF_UNIX` socket pair. We associate one end with the newly-created `pico_socket` via a `Connection` object. And we send the other end of the socket pair to the app. - -Our library's implementation of `accept()` will read and return the new file descriptor representing one end of the socket pair. From your app's prespective this is a normal file descriptor. -*** - - - - - - - - -### Receiving data - -The **tap service** monitors incoming packets, when one destined for us is detected it notifies the **stack driver** via `put()`. Then `pico_rx()` is called, its job is to re-encapsulate the ethernet frame and copy it onto the guarded `pico_frame_rxbuf`. This buffer is guarded because it is accessed via the **tap service** thread and the **network stack** thread. - -``` -wire - put() - pico_rx() ---> -``` - -Periodically the **network stack** thread will call `pico_eth_poll()`, this is responsible for reading the frames from the aformentioned `pico_frame_rxbuf` and feeding it into the stack via `pico_stack_recv()`. - -``` -pico_eth_poll() - ---> pico_stack_recv() -``` - -After some time has passed and the **network stack** has processed the incoming frames a `PICO_SOCK_EV_RD` event will be triggered which calls `pico_cb_socket_activity()`, and ultimately `pico_cb_tcp_read()`. This is where we copy the incoming data from the `pico_socket` to the `Connection`'s `rxbuf` (different from `pico_frame_rxbuf`). We then notify the **tap service** that the `PhySocket` (a wrapped file descriptor with one end visible to the application) associated with this `Connection` has data in its `rxbuf` that needs to be written so the app can read it. - -``` -pico_cb_socket_activity() - pico_cb_tcp_read() ---> - setNotifyWritable(TRUE) -``` - -After some (more) time, the **tap service** thread will call `pico_handleRead()`, this will copy the data from the `rxbuf` to the `AF_UNIX` socket which links the service and your application. - -``` -pico_handleRead() - streamSend(): ---> PhySock -``` - -After this point it's up to your application to read the data via a conventional `read()`, `recv()`, or `recvfrom()` call. - -``` -read() -``` -*** - - - - - - - -### Sending data - -Your app performs a `write()`, `send()`, or `sendto()` call. - -``` -write() -``` - -The other end of the `AF_UNIX` socket which was written to is monitored by the **tap service** thread. Once data is read from the socket, it will call `phyOnUnixData()` which will copy the buffer contents onto the `Connection`'s `txbuf`. Then `pico_handleWrite()` will be called. The **stack driver** will determine how much of the buffer can safely be sent to the **network stack** (up to `ZT_MAX_MTU` which is currently set at 2800 bytes). A call is made to `pico_socket_write()` which copies the data from the `txbuf` to the `pico_socket`. - -``` - phyOnUnixData() - handleWrite() - pico_socket_write(): ---> picosock -``` - -Periodically a `PICO_SOCK_EV_WR` event will be raised by the **network stack**, this will call `pico_cb_socket_activity()` and ultimately `pico_cb_tcp_write()` where a `pico_socket_write()` call will be made to copy any remaining `txbuf` contents into the stack. - -``` -pico_cb_tcp_write() -``` - -After some time, the **network stack** will emit an ethernet frame via `pico_eth_send()`, we then copy the frame into the **tap service** where it will then be sent onto the network. - -``` -pico_eth_send() - tap->_handler() -``` -*** - diff --git a/docs/tests.md b/docs/tests.md deleted file mode 100644 index aa2475a..0000000 --- a/docs/tests.md +++ /dev/null @@ -1,79 +0,0 @@ -Testing -====== - - - - -### Unit Tests - -To build the API unit tests: - - `make tests` - -All necessary binaries and scripts will be built and copied into `build/tests`. - -Running `build/tests/test.sh` will execute the automatic API unit tests. - -*** - - - - -### Docker Unit Tests - -**Running all docker tests** - - - Build the docker images: `make docker_images` - - - Run the docker tests from the docker containers: `make docker_test` - - - Check the results of the completed tests: `make docker_test_check` - -Each unit test will temporarily copy all required ZeroTier binaries into its local directory, then build the `sdk_dockerfile` and `monitor_dockerfile`. Once built, each container will be run and perform tests and monitoring specified in `sdk_entrypoint.sh` and `monitor_entrypoint.sh` - -Results will be written to the `tests/docker/_results/` directory which is a common shared volume between all containers involved in the test and will be a combination of raw and formatted dumps to files whose names reflect the test performed. In the event of failure, `FAIL.` will be prepended to the result file's name (e.g. `FAIL.my_application_1.0.2.x86_64`), likewise in the event of success, `OK.` will be prepended. - -To run unit tests: - -1) Disable SELinux. This is so the containers can use a shared volume to exchange MD5 sums and address information. - -2) Set up your own network at [https://my.zerotier.com/](https://my.zerotier.com/). For our example we'll just use the Earth network (8056c2e21c000001). Use its network id as follows: - -3) Generate two pairs of identity keys. Each public/private pair will be used by the *sdk* and *monitor* containers: - - mkdir -p /tmp/sdk_first - cp -f ./sdk/liblwip.so /tmp/sdk_first - ./zerotier-sdk-service -d -p8100 /tmp/sdk_first - while [ ! -f /tmp/sdk_first/identity.secret ]; do - sleep 0.1 - done - ./zerotier-cli -D/tmp/sdk_first join 8056c2e21c000001 - kill `cat /tmp/sdk_first/zerotier-one.pid` - - mkdir -p /tmp/sdk_second - cp -f ./sdk/liblwip.so /tmp/sdk_second - ./zerotier-sdk-service -d -p8101 /tmp/sdk_second - while [ ! -f /tmp/sdk_second/identity.secret ]; do - sleep 0.1 - done - ./zerotier-cli -D/tmp/sdk_second join 8056c2e21c000001 - kill `cat /tmp/sdk_second/zerotier-one.pid` - -4) Copy the identity files to *tests/docker*. Names will be altered during copy step so the dockerfiles know which identities to use for each image/container: - - cp /tmp/sdk_first/identity.public ./sdk/tests/docker/sdk_identity.public - cp /tmp/sdk_first/identity.secret ./sdk/tests/docker/sdk_identity.secret - - cp /tmp/sdk_second/identity.public ./sdk/tests/docker/monitor_identity.public - cp /tmp/sdk_second/identity.secret ./sdk/tests/docker/monitor_identity.secret - - -5) Place a blank network config file in the `tests/docker` directory (e.g. "8056c2e21c000001.conf") - - This will be used to inform test-specific scripts what network to use for testing - -After you've created your network and placed its blank config file in `tests/docker` run the following to perform unit tests for httpd: - - ./build.sh httpd - ./test.sh httpd - -It's useful to note that the keyword *httpd* in this example is merely a substring for a test name, this means that if we replaced it with *x86_64*, *fc23*, or *nginx*, it would run all unit tests for *x86_64*, *Fedora 23*, or *nginx* respectively. - diff --git a/docs/walkthrough.md b/docs/walkthrough.md deleted file mode 100644 index b020098..0000000 --- a/docs/walkthrough.md +++ /dev/null @@ -1,54 +0,0 @@ -Walkthrough -====== - -In this document we'll run through a simple example which should demonstrate the concept of the ZeroTier SDK. For this tutorial you'll need two devices (or at least the ability to run a VM or something like [Docker](https://www.docker.com/)). We will demonstrate a simple TCP server application intercepted on linux. This is only one of *many* ways the SDK can be used, but it'll at least convey the core concept how how the intercept works. - -#### On your first device: - - Download ZeroTier at [zerotier.com](https://www.zerotier.com/product-one.shtml) - - Install it on a device/computer - - Create an account and new virtual network at [my.zerotier.com](https://my.zerotier.com/) - - Join your device to the network and assign it an address `zerotier-cli join ` - - Use `zerotier-cli listnetworks` to verify that you've joined the network. -*** - - - -#### On your second device: - -##### Build the SDK -``` -make linux SDK_PICOTCP=1 SDK_IPV4=1 SDK_DEBUG=1; make -s check; ls -lG build -``` - -##### Build test apps - -``` -make tests -``` - -##### Start the SDK service in the background -``` -./zerotier-cli -U -p8000 /netpath & -``` - -##### Set environment variables -``` -export ZT_NC_NETWORK=/netpath/nc_XXXXXXXXXXXXXXXX -export LD_PRELOAD=./libztintercept.so -``` - -Where `netpath` can be any path you'd like the client's keys and configuration to be stored and `XXXXXXXXXXXXXXXX` is the 16-digit network ID. - -##### Start your app -``` -./build/tests/linux.tcpserver4.out 8001 -``` - -Now, on your first device, `./build/tests/linux.tcpclient4.out 8001` where `` is the ip address that you assigned to your first device. - -Now, you'll note that your new TCP server is automatically intercepted and available at on port 8001. The `tcpclient4` sample app running on the device with a normal instance of ZeroTier running will be able to connect directly to your intercepted `tcpserver4` app on the second machine running the SDK. -*** - - -You've just uplifted your app onto your private ZeroTier network. - diff --git a/ext/README.md b/ext/README.md deleted file mode 100644 index f296fa5..0000000 --- a/ext/README.md +++ /dev/null @@ -1 +0,0 @@ -The ext/ folder contains third party code, drivers, installation support files, etc. \ No newline at end of file diff --git a/ext/contrib/README.md b/ext/contrib/README.md deleted file mode 100644 index feb9ae6..0000000 --- a/ext/contrib/README.md +++ /dev/null @@ -1,15 +0,0 @@ -You are reading this file because you want to build a new copy of the LwIP library for -use in ZeroTier. - -Subdirectories: - - ports/ -- contains ports for various architectures (for our purposes, unix) - -In order for the Network Containers feature to work in ZeroTier, a copy of the LwIP libary -is needed since we dynamically load it into memory. You can build a new copy of the libary -by going to /contrib/ports/unix/proj/lib and running make. - -This will generate: liblwip.so - -You can enable LwIP debug traces by adding the flag -DLWIP_DEBUG -See additional debug info here: http://lwip.wikia.com/wiki/Debugging_lwIP diff --git a/ext/contrib/ports/unix/proj/lib/Makefile b/ext/contrib/ports/unix/proj/lib/Makefile deleted file mode 100644 index 5bb6a1f..0000000 --- a/ext/contrib/ports/unix/proj/lib/Makefile +++ /dev/null @@ -1,106 +0,0 @@ -# -# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# 3. The name of the author may not be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -# OF SUCH DAMAGE. -# -# This file is part of the lwIP TCP/IP stack. -# -# Author: Adam Dunkels -# - -CONTRIBDIR=../../../.. -LWIPARCH=$(CONTRIBDIR)/ports/unix - -#Set this to where you have the lwip core module checked out from CVS -#default assumes it's a dir named lwip at the same level as the contrib module -LWIPDIR=$(CONTRIBDIR)/../lwip/src - - -CCDEP=gcc -CC=gcc -CFLAGS=-g -Wall -DIPv4 -fPIC - -CFLAGS:=$(CFLAGS) \ - -I$(LWIPDIR)/include -I$(LWIPARCH)/include -I$(LWIPDIR)/include/ipv4 \ - -I$(LWIPDIR) -I. - - -# COREFILES, CORE4FILES: The minimum set of files needed for lwIP. -COREFILES=$(LWIPDIR)/core/mem.c $(LWIPDIR)/core/memp.c $(LWIPDIR)/core/netif.c \ - $(LWIPDIR)/core/pbuf.c $(LWIPDIR)/core/raw.c $(LWIPDIR)/core/stats.c \ - $(LWIPDIR)/core/sys.c $(LWIPDIR)/core/tcp.c $(LWIPDIR)/core/tcp_in.c \ - $(LWIPDIR)/core/tcp_out.c $(LWIPDIR)/core/udp.c $(LWIPDIR)/core/dhcp.c \ - $(LWIPDIR)/core/init.c $(LWIPDIR)/core/timers.c $(LWIPDIR)/core/def.c -CORE4FILES=$(wildcard $(LWIPDIR)/core/ipv4/*.c) $(LWIPDIR)/core/ipv4/inet.c \ - $(LWIPDIR)/core/ipv4/inet_chksum.c - -# SNMPFILES: Extra SNMPv1 agent -SNMPFILES=$(LWIPDIR)/core/snmp/asn1_dec.c $(LWIPDIR)/core/snmp/asn1_enc.c \ - $(LWIPDIR)/core/snmp/mib2.c $(LWIPDIR)/core/snmp/mib_structs.c \ - $(LWIPDIR)/core/snmp/msg_in.c $(LWIPDIR)/core/snmp/msg_out.c - -# APIFILES: The files which implement the sequential and socket APIs. -APIFILES=$(LWIPDIR)/api/api_lib.c $(LWIPDIR)/api/api_msg.c $(LWIPDIR)/api/tcpip.c \ - $(LWIPDIR)/api/err.c $(LWIPDIR)/api/sockets.c $(LWIPDIR)/api/netbuf.c $(LWIPDIR)/api/netdb.c - -# NETIFFILES: Files implementing various generic network interface functions.' -NETIFFILES=$(LWIPDIR)/netif/etharp.c $(LWIPDIR)/netif/slipif.c - -# NETIFFILES: Add PPP netif -NETIFFILES+=$(LWIPDIR)/netif/ppp/auth.c $(LWIPDIR)/netif/ppp/chap.c \ - $(LWIPDIR)/netif/ppp/chpms.c $(LWIPDIR)/netif/ppp/fsm.c \ - $(LWIPDIR)/netif/ppp/ipcp.c $(LWIPDIR)/netif/ppp/lcp.c \ - $(LWIPDIR)/netif/ppp/magic.c $(LWIPDIR)/netif/ppp/md5.c \ - $(LWIPDIR)/netif/ppp/pap.c $(LWIPDIR)/netif/ppp/ppp.c \ - $(LWIPDIR)/netif/ppp/randm.c $(LWIPDIR)/netif/ppp/vj.c - -# ARCHFILES: Architecture specific files. -ARCHFILES=$(wildcard $(LWIPARCH)/*.c $(LWIPARCH)tapif.c $(LWIPARCH)/netif/list.c $(LWIPARCH)/netif/tcpdump.c) - - -# LWIPFILES: All the above. -LWIPFILES=$(COREFILES) $(CORE4FILES) $(SNMPFILES) $(APIFILES) $(NETIFFILES) $(ARCHFILES) -LWIPFILESW=$(wildcard $(LWIPFILES)) -LWIPOBJS=$(notdir $(LWIPFILESW:.c=.o)) - -LWIPLIB=liblwip.so - -%.o: - $(CC) $(CFLAGS) -c $(<:.o=.c) - -all: $(LWIPLIB) -.PHONY: all - -clean: - rm -f *.o $(LWIPLIB) *.s .depend* *.core core - -depend dep: .depend - -include .depend - -$(LWIPLIB): $(LWIPOBJS) unixlib.o - $(CC) -g -nostartfiles -shared -o $@ $^ - -.depend: unixlib.c $(LWIPFILES) - $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend diff --git a/ext/contrib/ports/unix/proj/lib/README b/ext/contrib/ports/unix/proj/lib/README deleted file mode 100644 index cd6cc7b..0000000 --- a/ext/contrib/ports/unix/proj/lib/README +++ /dev/null @@ -1,31 +0,0 @@ -This directory contains an example of how to compile lwIP as a self -initialising shared library on Linux. - -Some brief instructions: - -* Compile the code: - - > make clean all - - This should produce liblwip4unixlib.so. This is the shared library. - -* Link an application against the shared library - - If you're using gcc you can do this by including -llwip4unixlib in -your link command. - -* Run your application - - Ensure that LD_LIBRARY_PATH includes the directory that contains -liblwip4unixlib.so (ie. this directory) - - - -If you are unsure about shared libraries and libraries on linux in -general, you might find this HOWTO useful: - - - - - -Kieran Mansley, October 2002. \ No newline at end of file diff --git a/ext/contrib/ports/unix/proj/lib/lwipopts.h b/ext/contrib/ports/unix/proj/lib/lwipopts.h deleted file mode 100644 index 48d35f3..0000000 --- a/ext/contrib/ports/unix/proj/lib/lwipopts.h +++ /dev/null @@ -1,468 +0,0 @@ -/** - * @file - * - * lwIP Options Configuration - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIPOPTS_H__ -#define __LWIPOPTS_H__ - -/* - * Include user defined options first. Anything not defined in these files - * will be set to standard values. Override anything you dont like! - */ -#include "lwipopts.h" -#include "lwip/debug.h" - - -//#define LWIP_DEBUG 0 -//#define TCP_DEBUG LWIP_DBG_OFF - -/* - -#define LWIP_MALLOC_MEMPOOL 1 -*/ - -/* -#define LWIP_CHECKSUM_ON_COPY 1 - -#define TCP_OVERSIZE TCP_MSS -*/ - -#ifndef TCP_SND_QUEUELEN -#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) -#endif - -//#define TCP_WND - - -//#define PBUF_POOL_BUFSIZE 2048 - -/*------------------------------------------------------------------------------ ----------------------------------- Timers -------------------------------------- -------------------------------------------------------------------------------*/ - -/* these are originally defined in tcp_impl.h */ -#ifndef TCP_TMR_INTERVAL -/* The TCP timer interval in milliseconds. */ -#define TCP_TMR_INTERVAL 25 -#endif /* TCP_TMR_INTERVAL */ - -#ifndef TCP_FAST_INTERVAL -/* the fine grained timeout in milliseconds */ -#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL -#endif /* TCP_FAST_INTERVAL */ - -#ifndef TCP_SLOW_INTERVALs -/* the coarse grained timeout in milliseconds */ -#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) -#endif /* TCP_SLOW_INTERVAL */ - - -/*------------------------------------------------------------------------------ ---------------------------- Platform specific locking ------------------------- -------------------------------------------------------------------------------*/ - -/** - * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain - * critical regions during buffer allocation, deallocation and memory - * allocation and deallocation. - */ -#define SYS_LIGHTWEIGHT_PROT 0 - -/** - * NO_SYS==1: Provides VERY minimal functionality. Otherwise, - * use lwIP facilities. - */ - -/* set to 1 so we have no thread behaviour */ -#define NO_SYS 1 - -/* set to 1 so we can use our own timers */ -#define NO_SYS_NO_TIMERS 1 - - -/*------------------------------------------------------------------------------ --------------------------------- Memory options -------------------------------- -------------------------------------------------------------------------------*/ - - -#define LWIP_CHKSUM_ALGORITHM 2 - - -/** - * 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 - */ -#define MEM_ALIGNMENT 1 - -/** - * 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. - */ -#define MEM_SIZE 1024 * 1024 * 64 -#define TCP_SND_BUF 1024 * 63 - - -/*------------------------------------------------------------------------------ --------------------------- Internal Memory Pool Sizes -------------------------- -------------------------------------------------------------------------------*/ - -/** - * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). - * If the application sends a lot of data out of ROM (or other static memory), - * this should be set high. - */ -#define MEMP_NUM_PBUF 256 - -/** - * MEMP_NUM_RAW_PCB: Number of raw connection PCBs - * (requires the LWIP_RAW option) - */ -#define MEMP_NUM_RAW_PCB 32 - -/** - * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One - * per active UDP "connection". - * (requires the LWIP_UDP option) - */ -#define MEMP_NUM_UDP_PCB 4 - -/** - * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. - * (requires the LWIP_TCP option) - */ -#define MEMP_NUM_TCP_PCB 128 - -/** - * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. - * (requires the LWIP_TCP option) - */ -#define MEMP_NUM_TCP_PCB_LISTEN 128 - -/** - * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. - * (requires the LWIP_TCP option) - */ -#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN - -/** - * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for - * reassembly (whole packets, not fragments!) - */ -#define MEMP_NUM_REASSDATA 1 - -/** - * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing - * packets (pbufs) that are waiting for an ARP request (to resolve - * their destination address) to finish. - * (requires the ARP_QUEUEING option) - */ -#define MEMP_NUM_ARP_QUEUE 2 - -/** - * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. - * (requires NO_SYS==0) - */ -#define MEMP_NUM_SYS_TIMEOUT 3 - -/** - * MEMP_NUM_NETBUF: the number of struct netbufs. - * (only needed if you use the sequential API, like api_lib.c) - */ -#define MEMP_NUM_NETBUF 2 - -/** - * MEMP_NUM_NETCONN: the number of struct netconns. - * (only needed if you use the sequential API, like api_lib.c) - */ -#define MEMP_NUM_NETCONN 4 - -/** - * 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) - */ -#define MEMP_NUM_TCPIP_MSG_API 8 - -/** - * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used - * for incoming packets. - * (only needed if you use tcpip.c) - */ -#define MEMP_NUM_TCPIP_MSG_INPKT 8 - -/** - * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. - */ -#define PBUF_POOL_SIZE 128 /* was 32 */ - - -/*------------------------------------------------------------------------------ ------------------------------------ ARP options -------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_ARP==1: Enable ARP functionality. - */ -#define LWIP_ARP 1 - - -/*------------------------------------------------------------------------------ ------------------------------------- IP options--------------------------------- -------------------------------------------------------------------------------*/ - -/** - * IP_FORWARD==1: Enables the ability to forward IP packets across network - * interfaces. If you are going to run lwIP on a device with only one network - * interface, define this to 0. - */ -#define IP_FORWARD 0 - -/** - * IP_OPTIONS: 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). - */ -#define IP_OPTIONS_ALLOWED 1 - -/** - * 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. - */ -#define IP_REASSEMBLY 1 - -/** - * 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. - */ -#define IP_FRAG 1 - -/** - * 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. - */ -#define IP_REASS_MAXAGE 3 - -/** - * 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! - */ -#define IP_REASS_MAX_PBUFS 4 - -/** - * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP - * fragmentation. Otherwise pbufs are allocated and reference the original - * packet data to be fragmented. -*/ -#define IP_FRAG_USES_STATIC_BUF 0 - -/** - * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. - */ -#define IP_DEFAULT_TTL 255 - - -/*------------------------------------------------------------------------------ -------------------------------- ICMP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_ICMP==1: Enable ICMP module inside the IP stack. - * Be careful, disable that make your product non-compliant to RFC1122 - */ -#define LWIP_ICMP 1 - - -/*------------------------------------------------------------------------------ -------------------------------- RAW Options ------------------------------------ -------------------------------------------------------------------------------*/ - -/** - * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. - */ -#define LWIP_RAW 1 - - -/*------------------------------------------------------------------------------ -------------------------------- DHCP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_DHCP==1: Enable DHCP module. - */ -#define LWIP_DHCP 0 - - -/*------------------------------------------------------------------------------ ------------------------------- AUTOIP Options ---------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_AUTOIP==1: Enable AUTOIP module. - */ -#define LWIP_AUTOIP 0 - - -/*------------------------------------------------------------------------------ -------------------------------- SNMP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP - * transport. - */ -#define LWIP_SNMP 0 - - -/*------------------------------------------------------------------------------ -------------------------------- IGMP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_IGMP==1: Turn on IGMP module. - */ -#define LWIP_IGMP 0 - - -/*------------------------------------------------------------------------------ --------------------------------- DNS Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS - * transport. - */ -#define LWIP_DNS 0 - - -/*------------------------------------------------------------------------------ --------------------------------- UDP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_UDP==1: Turn on UDP. - */ -#define LWIP_UDP 1 - - -/*------------------------------------------------------------------------------ --------------------------------- TCP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_TCP==1: Turn on TCP. - */ -#define LWIP_TCP 1 - -#define LWIP_LISTEN_BACKLOG 0 - - -/*------------------------------------------------------------------------------ --------------------------------- Pbuf Options ---------------------------------- -------------------------------------------------------------------------------*/ - -/** - * PBUF_LINK_HLEN: the number of bytes that should be allocated for a - * link level header. The default is 14, the standard value for - * Ethernet. - */ -#define PBUF_LINK_HLEN 16 - -/** - * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is - * designed to accomodate single full size TCP frame in one pbuf, including - * TCP_MSS, IP header, and link header. -* - */ -#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) - - -/*------------------------------------------------------------------------------ ---------------------------------- LOOPIF Options ------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c - */ -#define LWIP_HAVE_LOOPIF 0 - - -/*------------------------------------------------------------------------------ ----------------------------- Sequential Layer Options -------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) - */ -#define LWIP_NETCONN 0 - - -/*------------------------------------------------------------------------------ ---------------------------------- Socket Options ------------------------------- -------------------------------------------------------------------------------*/ -/** - * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) - */ -#define LWIP_SOCKET 0 - - -/*------------------------------------------------------------------------------ ------------------------------- Statistics Options ------------------------------ -------------------------------------------------------------------------------*/ - -/** - * LWIP_STATS==1: Enable statistics collection in lwip_stats. - */ -#define LWIP_STATS 1 - -/*------------------------------------------------------------------------------ ---------------------------------- PPP Options ---------------------------------- -------------------------------------------------------------------------------*/ - -/** - * PPP_SUPPORT==1: Enable PPP. - */ -#define PPP_SUPPORT 0 - - -/* Misc */ - -#endif /* __LWIPOPTS_H__ */ diff --git a/ext/contrib/ports/unix/proj/lib/unixlib.c b/ext/contrib/ports/unix/proj/lib/unixlib.c deleted file mode 100644 index 950ae1c..0000000 --- a/ext/contrib/ports/unix/proj/lib/unixlib.c +++ /dev/null @@ -1,73 +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. - * - * Author: Kieran Mansley - * - * $Id: unixlib.c,v 1.10 2010/02/17 16:52:30 goldsimon Exp $ - */ - -/*-----------------------------------------------------------------------------------*/ -/* unixlib.c - * - * The initialisation functions for a shared library - * - * You may need to configure this file to your own needs - it is only an example - * of how lwIP can be used as a self initialising shared library. - * - * In particular, you should change the gateway, ipaddr, and netmask to be the values - * you would like the stack to use. - */ -/*-----------------------------------------------------------------------------------*/ - -/* -#include "lwip/init.h" -#include "lwip/sys.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/pbuf.h" -#include "lwip/tcp.h" -#include "lwip/tcpip.h" -#include "lwip/netif.h" -#include "lwip/stats.h" -#include "lwip/sockets.h" - -#include "netif/tapif.h" - -struct netif netif; -*/ - -static void -tcpip_init_done(void *arg) -{ - -} - -void _init(void){ - -} - -void _fini(void){ -} diff --git a/ext/lwip/CHANGELOG b/ext/lwip/CHANGELOG deleted file mode 100644 index 39177b8..0000000 --- a/ext/lwip/CHANGELOG +++ /dev/null @@ -1,4126 +0,0 @@ -HISTORY - -(git master) - - * [Enter new changes just after this line - do not remove this line] - - ++ New features: - - 2016-07-27: Simon Goldschmidt - * opt.h, timeouts.h/.c: added LWIP_TIMERS_CUSTOM to override the default - implementation of timeouts - - 2016-07-xx: Dirk Ziegelmeier - * Large overhaul of doxygen documentation - - 2016-04-05: Simon Goldschmidt - * timers.h/.c: prepare for overriding current timeout implementation: all - stack-internal caclic timers are avaliable in the lwip_cyclic_timers array - - 2016-03-23: Simon Goldschmidt - * tcp: call accept-callback with ERR_MEM when allocating a pcb fails on - passive open to inform the application about this error - ATTENTION: applications have to handle NULL pcb in accept callback! - - 2016-02-22: Ivan Delamer - * Initial 6LoWPAN support - - 2016-02-XX to 2016-03-XX: Dirk Ziegelmeier - * Cleanup TCPIP thread sync methods in a way that it is possibe to use them - in arbitrary code that needs things to be done in TCPIP thread. Used to - decouple netconn, netif, ppp and 6LoWPAN from LWIP core. - - 2016-02-XX: Dirk Ziegelmeier - * Implement dual-stack support in RAW, UDP and TCP. Add new IP address - type IPADDR_ANY_TYPE for this. Netconn/Socket API: Dual-stack is - automatically supported when an IPv6 netconn/socket is created. - - 2015-12-26: Martin Hentschel and Dirk Ziegelmeier - * Rewrite SNMP agent. SNMPv2c + MIB compiler. - - 2015-11-12: Dirk Ziegelmeier - * Decouple SNMP stack from lwIP core and move stack to apps/ directory. - Breaking change: Users have to call snmp_init() now! - - 2015-11-12: Dirk Ziegelmeier - * Implement possibility to declare private memory pools. This is useful to - decouple some apps from the core (SNMP stack) or make contrib app usage - simpler (httpserver_raw) - - 2015-10-09: Simon Goldschmidt - * started to move "private" header files containing implementation details to - "lwip/priv/" include directory to seperate the API from the implementation. - - 2015-10-07: Simon Goldschmidt - * added sntp client as first "supported" application layer protocol implementation - added 'apps' folder - - 2015-09-30: Dirk Ziegelmeier - * snmp_structs.h, mib_structs.c, mib2.c: snmp: fixed ugly inheritance - implementation by aggregating the "base class" (struct mib_node) in all - derived node classes to get more type-safe code - - 2015-09-23: Simon Goldschmidt - * netif.h/.c, nd6.c: task #13729: Convert netif addresses (IPv4 & IPv6) to - ip_addr_t (so they can be used without conversion/temporary storage) - - 2015-09-08: Dirk Ziegelmeier - * snmp: Separate mib2 counter/table callbacks from snmp agent. This both cleans - up the code and should allow integration of a 3rd party agent/mib2. Simple - counters are kept in MIB2_STATS, tree/table change function prototypes moved to - snmp_mib2.h. - - 2015-09-03: Simon Goldschmidt - * opt.h, dns.h/.c: DNS/IPv6: added support for AAAA records - - 2015-09-01: Simon Goldschmidt - * task #12178: hardware checksum capabilities can be configured per netif - (use NETIF_SET_CHECKSUM_CTRL() in your netif's init function) - - 2015-08-30: Simon Goldschmidt - * PBUF_REF with "custom" pbufs is now supported for RX pbufs (see pcapif in - contrib for an example, LWIP_SUPPORT_CUSTOM_PBUF is required) - - 2015-08-30: Simon Goldschmidt - * support IPv4 source based routing: define LWIP_HOOK_IP4_ROUTE_SRC to point - to a routing function - - 2015-08-05: Simon Goldschmidt - * many files: allow multicast socket options IP_MULTICAST_TTL, IP_MULTICAST_IF - and IP_MULTICAST_LOOP to be used without IGMP - - 2015-04-24: Simon Goldschmidt - * dhcp.h/c, autoip.h/.c: added functions dhcp/autoip_supplied_address() to - check for the source of address assignment (replacement for NETIF_FLAG_DHCP) - - 2015-04-10: Simon Goldschmidt - * many files: task #13480: added LWIP_IPV4 define - IPv4 can be disabled, - leaving an IPv6-only stack - - 2015-04-09: Simon Goldschmidt - * nearly all files: task #12722 (improve IPv4/v6 address handling): renamed - ip_addr_t to ip4_addr_t, renamed ipX_addr_t to ip_addr_t and added IP - version; ip_addr_t is used for all generic IP addresses for the API, - ip(4/6)_addr_t are only used internally or when initializing netifs or when - calling version-related functions - - 2015-03-24: Simon Goldschmidt - * opt.h, ip4_addr.h, ip4.c, ip6.c: loopif is not required for loopback traffic - any more but passed through any netif (ENABLE_LOOPBACK has to be enabled) - - 2015-03-23: Simon Goldschmidt - * opt.h, etharp.c: with ETHARP_TABLE_MATCH_NETIF== 1, duplicate (Auto)-IP - addresses on multiple netifs should now be working correctly (if correctly - addressed by routing, that is) - - 2015-03-23: Simon Goldschmidt - * etharp.c: Stable etharp entries that are about to expire are now refreshed - using unicast to prevent unnecessary broadcast. Only if no answer is received - after 15 seconds, broadcast is used. - - 2015-03-06: Philip Gladstone - * netif.h/.c: patch #8359 (Provide utility function to add an IPv6 address to - an interface) - - 2015-03-05: Simon Goldschmidt - * netif.c, ip4.c, dhcp.c, autoip.c: fixed bug #37068 (netif up/down handling - is unclear): correclty separated administrative status of a netif (up/down) - from 'valid address' status - ATTENTION: netif_set_up() now always has to be called, even when dhcp/autoip - is used! - - 2015-02-26: patch by TabascoEye - * netif.c, udp.h/.c: fixed bug #40753 (re-bind UDP pcbs on change of IP address) - - 2015-02-22: chrysn, Simon Goldschmidt - * *.*: Changed nearly all functions taking 'ip(X)_addr_t' pointer to take - const pointers (changed user callbacks: raw_recv_fn, udp_recv_fn; changed - port callbacks: netif_output_fn, netif_igmp_mac_filter_fn) - - 2015-02-19: Ivan Delamer - * netif.h, dhcp.c: Removed unused netif flag for DHCP. The preferred way to evaluate - if DHCP is active is through netif->dhcp field. - - 2015-02-19: Ivan Delamer - * netif.h, slipif.c, ppp.c: Removed unused netif flag for point to point connections - - 2015-02-18: Simon Goldschmidt - * api_lib.c: fixed bug #37958 "netconn API doesn't handle correctly - connections half-closed by peer" - - 2015-02-18: Simon Goldschmidt - * tcp.c: tcp_alloc() prefers killing CLOSING/LAST_ACK over active connections - (see bug #39565) - - 2015-02-16: Claudius Zingerli, Sergio Caprile - * opt.h, dhcp.h/.c: patch #8361 "Add support for NTP option in DHCP" - - 2015-02-14: Simon Goldschmidt - * opt.h, snmp*: added support for write-access community and dedicated - community for sending traps - - 2015-02-13: Simon Goldschmidt - * opt.h, memp.c: added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when - a memp pool was empty and an item is now available - - 2015-02-13: Simon Goldschmidt - * opt.h, pbuf.h/.c, etharp.c: Added the option PBUF_LINK_ENCAPSULATION_HLEN to - allocate additional header space for TX on netifs requiring additional headers - - 2015-02-12: chrysn - * timers.h/.c: introduce sys_timeouts_sleeptime (returns the time left before - the next timeout is due, for NO_SYS==1) - - 2015-02-11: Nick van Ijzendoorn - * opt.h, sockets.h/c: patch #7702 "Include ability to increase the socket number - with defined offset" - - 2015-02-11: Frederick Baksik - * opt.h, def.h, others: patch #8423 "arch/perf.h" should be made an optional item - - 2015-02-11: Simon Goldschmidt - * api_msg.c, opt.h: started to implement fullduplex sockets/netconns - (note that this is highly unstable yet!) - - 2015-01-17: Simon Goldschmidt - * api: allow enabling socket API without (public) netconn API - netconn API is - still used by sockets, but keeping it private (static) should allow better - compiler optimizations - - 2015-01-16: Simon Goldschmidt - * tcp_in.c: fixed bug #20506 "Initial congestion window is very small" again - by implementing the calculation formula from RFC3390 - - 2014-12-10: Simon Goldschmidt - * api: added option LWIP_NETCONN_SEM_PER_THREAD to use a semaphore per thread - instead of using one per netconn and per select call - - 2014-12-08: Simon Goldschmidt - * ip6.h: fixed bug #43778: IPv6 header version not set on 16-bit platform - (macro IP6H_VTCFL_SET()) - - 2014-12-08: Simon Goldschmidt - * icmp.c, ip4.c, pbuf.c, udp.c, pbuf.h: task #11472 Support PBUF_REF for RX - (IPv6 and IPv4/v6 reassembly might not work yet) - - 2014-11-06: Simon Goldschmidt - * sockets.c/.h, init.c: lwip_socket_init() is not needed any more - -> compatibility define - - 2014-09-16: Simon Goldschmidt - * dns.c, opt.h: reduced ram usage by parsing DNS responses in place - - 2014-09-16: Simon Goldschmidt - * pbuf.h/.c: added pbuf_take_at() and pbuf_put_at() - - 2014-09-15: Simon Goldschmidt - * dns.c: added source port randomization to make the DNS client more robust - (see bug #43144) - - 2013-09-02: Simon Goldschmidt - * arch.h and many other files: added optional macros PACK_STRUCT_FLD_8() and - PACK_STRUCT_FLD_S() to prevent gcc 4 from warning about struct members that - do not need packing - - 2013-08-19: Simon Goldschmidt - * netif.h: bug #42998: made NETIF_MAX_HWADDR_LEN overridable for some special - networks - - 2013-03-17: Simon Goldschmidt (patch by Ghobad Emadi) - * opt.h, etharp.c: Added LWIP_HOOK_ETHARP_GET_GW to implement IPv4 routing with - multiple gateways - - 2013-04-20: Fatih Asici - * opt.h, etharp.h/.c: patch #7993: Added support for transmitting packets - with VLAN headers via hook function LWIP_HOOK_VLAN_SET and to check them - via hook function LWIP_HOOK_VLAN_CHECK - - 2014-02-20: Simon Goldschmidt (based on patch by Artem Pisarenko) - * patch #7885: modification of api modules to support FreeRTOS-MPU - (don't pass stack-pointers to other threads) - - 2014-02-05: Simon Goldschmidt (patch by "xtian" and "alex_ab") - * patch #6537/#7858: TCP window scaling support - - 2014-01-17: Jiri Engelthaler - * icmp, icmp6, opt.h: patch #8027: Completed HW checksuming for IPv4 and - IPv6 ICMP's - - 2012-08-22: Sylvain Rochet - * New PPP stack for lwIP, developed in ppp-new branch. - Based from pppd 2.4.5, released 2009-11-17, with huge changes to match - code size and memory requirements for embedded devices, including: - - Gluing together the previous low-level PPP code in lwIP to pppd 2.4.5, which - is more or less what pppd sys-* files are, so that we get something working - using the unix port. - - Merged some patchs from lwIP Git repository which add interesting features - or fix bugs. - - Merged some patchs from Debian pppd package which add interesting features - or fix bugs. - - Ported PPP timeout handling to the lwIP timers system - - Disabled all the PPP code using filesystem access, replaced in necessary cases - to configuration variables. - - Disabled all the PPP code forking processes. - - Removed IPX support, lwIP does not support IPX. - - Ported and improved random module from the previous PPP port. - - Removed samba TDB (file-driven database) usage, because it needs a filesystem. - - MS-CHAP required a DES implementation, we added the latest PolarSSL DES - implementation which is under a BSD-ish license. - - Also switched to PolarSSL MD4,MD5,SHA1 implementations, which are meant to be - used in embedded devices with reduced memory footprint. - - Removed PPP configuration file parsing support. - - Added macro definition EAP_SUPPORT to make EAP support optional. - - Added macro definition CHAP_SUPPORT to make CHAP support optional. - - Added macro definition MSCHAP_SUPPORT to make MSCHAP support optional. - - Added macro definition PAP_SUPPORT to make PAP support optional. - - Cleared all Linux syscall calls. - - Disabled demand support using a macro, so that it can be ported later. - - Disabled ECP support using a macro, so that it can be ported later. - - Disabled CCP support using a macro, so that it can be ported later. - - Disabled CBCP support using a macro, so that it can be ported later. - - Disabled LQR support using a macro, so that it can be ported later. - - Print packet debug feature optional, through PRINTPKT_SUPPORT - - Removed POSIX signal usage. - - Fully ported PPPoS code from the previous port. - - Fully ported PPPoE code from the previous port. - - Fully ported VJ compression protocol code from the previous port. - - Removed all malloc()/free() use from PPP, replaced by stack usage or PBUF. - - Disabled PPP server support using a macro, so that it can be ported later. - - Switched all PPP debug to lwIP debug system. - - Created PPP Control Block (PPP PCB), removed PPP unit integer everywhere, - removed all global variables everywhere, did everything necessary for - the PPP stack to support more than one PPP session (pppd only support - one session per process). - - Removed the statically allocated output buffer, now using PBUF. - - Improved structure size of all PPP modules, deep analyze of code to reduce - variables size to the bare minimum. Switched all boolean type (char type in - most architecture) to compiler generated bitfields. - - Added PPP IPv6 support, glued lwIP IPv6 support to PPP. - - Now using a persistent netif interface which can then be used in lwIP - functions requiring a netif. - - Now initializing PPP in lwip_init() function. - - Reworked completely the PPP state machine, so that we don't end up in - anymore in inconsistent state, especially with PPPoE. - - Improved the way we handle PPP reconnection after disconnect, cleaning - everything required so that we start the PPP connection again from a - clean state. - - Added PPP holdoff support, allow the lwIP user to wait a little bit before - reconnecting, prevents connection flood, especially when using PPPoL2TP. - - Added PPPoL2TP LAC support (a.k.a. UDP tunnels), adding a VPN client - feature to lwIP, L2TP being a widely used tunnel protocol. - - Switched all used PPP types to lwIP types (u8t, u16t, u32t, ...) - - Added PPP API "sequential" thread-safe API, based from NETIFAPI. - - 2011-07-21: Simon Goldschmidt - * sockets.c, opt.h: (bug #30185): added LWIP_FIONREAD_LINUXMODE that makes - ioctl/FIONREAD return the size of the next pending datagram. - - 2011-05-25: Simon Goldschmidt - * again nearly the whole stack, renamed ip.c to ip4.c, ip_addr.c to ip4_addr.c, - combined ipv4/ipv6 inet_chksum.c, added ip.h, ip_addr.h: Combined IPv4 - and IPv6 code where possible, added defines to access IPv4/IPv6 in non-IP - code so that the code is more readable. - - 2011-05-17: Patch by Ivan Delamer (only checked in by Simon Goldschmidt) - * nearly the whole stack: Finally, we got decent IPv6 support, big thanks to - Ivan! (this is work in progress: we're just post release anyway :-) - - - ++ Bugfixes: - - 2016-07-20: Simon Goldschmidt - * memp.h/.c: fixed bug #48442 (memp stats don't work for MEMP_MEM_MALLOC) - - 2016-07-21: Simon Goldschmidt (patch by Ambroz Bizjak) - * tcp_in.c, tcp_out.c: fixed bug #48543 (TCP sent callback may prematurely - report sent data when only part of a segment is acked) and don't include - SYN/FIN in snd_buf counter - - 2016-07-19: Simon Goldschmidt - * etharp.c: fixed bug #48477 (ARP input packet might update static entry) - - 2016-07-11: Simon Goldschmidt - * tcp_in.c: fixed bug #48476 (TCP sent callback called wrongly due to picking - up old pcb->acked - - 2016-06-30: Simon Goldschmidt (original patch by Fabian Koch) - * tcp_in.c: fixed bug #48170 (Vulnerable to TCP RST spoofing) - - 2016-05-20: Dirk Ziegelmeier - * sntp.h/.c: Fix return value of sntp_getserver() call to return a pointer - - 2016-04-05: Simon Goldschmidt (patch by Philip Gladstone) - * udp.c: patch #8358: allow more combinations of listening PCB for IPv6 - - 2016-04-05: Simon Goldschmidt - * netconn/socket API: fixed bug# 43739 (Accept not reporting errors about - aborted connections): netconn_accept() returns ERR_ABRT (sockets: ECONNABORTED) - for aborted connections, ERR_CLSD (sockets: EINVAL) if the listening netconn - is closed, which better seems to follow the standard. - - 2016-03-23: Florent Matignon - * dhcp.c: fixed bug #38203: DHCP options are not recorded in all DHCP ack messages - - 2016-03-22: Simon Goldschmidt - * tcp: changed accept handling to be done internally: the application does not - have to call tcp_accepted() any more. Instead, when delaying accept (e.g. sockets - do), call tcp_backlog_delayed()/tcp_backlog_accepted() (fixes bug #46696) - - 2016-03-22: Simon Goldschmidt - * dns.c: ignore dns response parsing errors, only abort resolving for correct - responses or error responses from correct server (bug #47459) - - 2016-03-17: Simon Goldschmidt - * api_msg.c: fixed bug #47448 (netconn/socket leak if RST is received during close) - - 2016-03-17: Joel Cunningham - * api_msg.c: don't fail closing a socket/netconn when failing to allocate the - FIN segment; blocking the calling thread for a while is better than risking - leaking a netconn/socket (see bug #46701) - - 2016-03-16: Joel Cunningham - * tcp_out.c: reset rto timer on fast retransmission - - 2016-03-16: Deomid Ryabkov - * tcp_out.c: fixed bug #46384 Segment size calculation bug with MSS != TCP_MSS - - 2016-03-05: Simon Goldschmidt - * err.h/.c, sockets.c: ERR_IF is not necessarily a fatal error - - 2015-11-19: fix by Kerem Hadimli - * sockets.c: fixed bug #46471: lwip_accept() leaks socket descriptors if new - netconn was already closed because of peer behavior - - 2015-11-12: fix by Valery Ushakov - * tcp_in.c: fixed bug #46365 tcp_accept_null() should call tcp_abort() - - 2015-10-02: Dirk Ziegelmeier/Simon Goldschmidt - * snmp: cleaned up snmp structs API (fixed race conditions from bug #46089, - reduce ram/rom usage of tables): incompatible change for private MIBs - - 2015-09-30: Simon Goldschmidt - * ip4_addr.c: fixed bug #46072: ip4addr_aton() does not check the number range - of all address parts - - 2015-08-28: Simon Goldschmidt - * tcp.c, tcp_in.c: fixed bug #44023: TCP ssthresh value is unclear: ssthresh - is set to the full send window for active open, too, and is updated once - after SYN to ensure the correct send window is used - - 2015-08-28: Simon Goldschmidt - * tcp: fixed bug #45559: Window scaling casts u32_t to u16_t without checks - - 2015-08-26: Simon Goldschmidt - * ip6_frag.h/.c: fixed bug bug #41009: IPv6 reassembly broken on 64-bit platforms: - define IPV6_FRAG_COPYHEADER==1 on these platforms to copy the IPv6 header - instead of referencing it, which gives more room for struct ip6_reass_helper - - 2015-08-25: Simon Goldschmidt - * sockets.c: fixed bug #45827: recvfrom: TCP window is updated with MSG_PEEK - - 2015-08-20: Manoj Kumar - * snmp_msg.h, msg_in.c: fixed bug #43790: Sending octet string of Length >255 - from SNMP agent - - 2015-08-19: Jens Nielsen - * icmp.c, ip4.c, tcp_in.c, udp.c, raw.c: fixed bug #45120: Broadcast & multiple - interfaces handling - - 2015-08-19: Simon Goldschmidt (patch by "Sandra") - * dns.c: fixed bug #45004: dns response without answer might be discarded - - 2015-08-18: Chrysn - * timers.c: patch #8704 fix sys_timeouts_sleeptime function - - 2015-07-01: Erik Ekman - * puf.c: fixed bug #45454 (pbuf_take_at() skips write and returns OK if offset - is at start of pbuf in chain) - - 2015-05-19: Simon Goldschmidt - * dhcp.h/.c: fixed bugs #45140 and #45141 (dhcp was not stopped correctly after - fixing bug #38204) - - 2015-03-21: Simon Goldschmidt (patch by Homyak) - * tcp_in.c: fixed bug #44766 (LWIP_WND_SCALE: tcphdr->wnd was not scaled in - two places) - - 2015-03-21: Simon Goldschmidt - * tcp_impl.h, tcp.c, tcp_in.c: fixed bug #41318 (Bad memory ref in tcp_input() - after tcp_close()) - - 2015-03-21: Simon Goldschmidt - * tcp_in.c: fixed bug #38468 (tcp_sent() not called on half-open connection for - data ACKed with the same ack as FIN) - - 2015-03-21: Simon Goldschmidt (patch by Christoffer Lind) - * dhcp.h/.c: fixed bug #38204 (DHCP lease time not handled correctly) - - 2015-03-20: Simon Goldschmidt - * dhcp.c: fixed bug #38714 (Missing option and client address in DHCPRELEASE message) - - 2015-03-19: Simon Goldschmidt - * api.h, tcpip.h, api_lib.c, api_msg.c: fixed race conditions in assigning - netconn->last_err (fixed bugs #38121 and #37676) - - 2015-03-09: Simon Goldschmidt - * ip4.c: fixed the IPv4 part of bug #43904 (ip_route() must detect linkup status) - - 2015-03-04: Simon Goldschmidt - * nd6.c: fixed bug #43784 (a host should send at least one Router Solicitation) - - 2015-03-04: Valery Ushakov - * ip6.c: fixed bug #41094 (Byte-order bug in IPv6 fragmentation header test) - - 2015-03-04: Zach Smith - * nd6.c: fixed bug #38153 (nd6_input() byte order issues) - - 2015-02-26: Simon Goldschmidt - * netif.c, tcp.h/.c: fixed bug #44378 (TCP connections are not aborted on netif - remove) - - 2015-02-25: Simon Goldschmidt - * ip4.c, etharp.c: fixed bug #40177 (System hangs when dealing with corrupted - packets), implemented task #12357 (Ensure that malicious packets don't - assert-fail): improved some pbuf_header calls to not assert-fail. - - 2015-02-25: patch by Joel Cunningham - * udp.h/.c, sockets.c: fixed bug #43028 (IP_MULTICAST_TTL affects unicast - datagrams) - - 2015-02-25: patch by Greg Renda - * ip4_frag.c: fixed bug #38210 (ip reassembly while remove oldest datagram) - - 2015-02-25: Simon Goldschmidt - * sockets.c: fixed bug #38165 (socket with mulicast): ensure igmp membership - are dropped when socket (not netconn!) is closed. - - 2015-02-25: Simon Goldschmidt - * ip4.h/.c, udp.c: fixed bug #38061 (wrong multicast routing in IPv4) by - adding an optional default netif for multicast routing - - 2015-02-25: Simon Goldschmidt - * netconn API: fixed that netconn_connect still used message passing for - LWIP_TCPIP_CORE_LOCKING==1 - - 2015-02-22: patch by Jens Nielsen - * icmp.c: fixed bug #38803 (Source address in broadcast ping reply) - - 2015-02-22: Simon Goldschmidt - * udp.h, sockets.c: added proper accessor functions for pcb->multicast_ip - (previously used by get/setsockopt only) - - 2015-02-18: Simon Goldschmidt - * sockets.c: Fixed select not reporting received FIN as 'readable' in certain - rare cases (bug #43779: select(), close(), and TCP retransmission error) - - 2015-02-17: Simon Goldschmidt - * err.h, sockets.c, api_msg.c: fixed bug #38853 "connect() use a wrong errno": - return ERR_ALREADY/EALRADY during connect, ERR_ISCONN/EISCONN when already - connected - - 2015-02-17: Simon Goldschmidt - * tcp_impl.h, tcp_out.c, tcp.c, api_msg.c: fixed bug #37614 "Errors from - ipX_output are not processed". Now tcp_output(_segment) checks for the return - value of ipX_output and does not try to send more on error. A netif driver - can call tcp_txnow() (from tcpip_thread!) to try to send again if TX buffers - are available again. - - 2015-02-14: patches by Freddie Chopin - * snmp*: made community writable, fixed some const pointers - - 2015-02-13: Simon Goldschmidt - * msg_in.c: fixed bug #22070 "MIB_OBJECT_WRITE_ONLY not implemented in SNMP" - - 2015-02-12: Simon Goldschmidt - * ip.h, ip4.c, ip6.c: fixed bug #36403 "ip4_input() and ip6_input() always pass - inp to higher layers": now the accepting netif is passed up, but the input - netif is available through ip_current_input_netif() if required. - - 2015-02-11: patch by hichard - * tcpip.c: fixed bug #43094 "The function tcpip_input() forget to handle IPv6" - - 2015-02-10: Simon Goldschmidt - * netconn API: fixed that netconn_close/netconn_delete still used message passing - for LWIP_TCPIP_CORE_LOCKING==1 - - 2015-02-10: Simon Goldschmidt - * netconn/socket api: fixed bug #44225 "closing TCP socket should time out - eventually", implemented task #6930 "Implement SO_LINGER": closing TCP sockets - times out after 20 seconds or after the configured SND_TIMEOUT or depending - on the linger settings. - - 2015-01-27: Simon Goldschmidt - * api_msg.c: fixed that SHUT_RD followed by SHUT_WR was different to SHUT_RDWR, - fixed return value of lwip_netconn_do_close on unconnected netconns - - 2015-01-17: Simon Goldschmidt - * sockets.c: fixed bug #43361 select() crashes with stale FDs - - 2015-01-17: Simon Goldschmidt - * sockets.c/.h, memp_std.h: fixed bug #40788 "lwip_setsockopt_internal() crashes" - by rewriting set/getsockopt functions to combine checks with the actual code - and add more NULL checks; this also fixes that CORE_LOCKING used message - passing for set/getsockopt. - - 2014-12-19: Simon Goldschmidt - * opt.h, dhcp.h/.c: prevent dhcp from starting when netif link is down (only - when LWIP_DHCP_CHECK_LINK_UP==1, which is disabled by default for - compatibility reasons) - - 2014-12-17: Simon Goldschmidt - * tcp_out.c: fixed bug #43840 Checksum error for TCP_CHECKSUM_ON_COPY==1 for - no-copy data with odd length - - 2014-12-10: Simon Goldschmidt - * sockets.c, tcp.c, others: fixed bug #43797 set/getsockopt: SO_SNDTIMEO/SO_RCVTIMEO - take int as option but should take timeval (LWIP_SO_SNDRCVTIMEO_STANDARD==0 can - be used to revert to the old 'winsock' style behaviour) - Fixed implementation of SO_ACCEPTCONN to just look at the pcb state - - 2014-12-09: Simon Goldschmidt - * ip4.c: fixed bug #43596 IGMP queries from 0.0.0.0 are discarded - - 2014-10-21: Simon Goldschmidt (patch by Joel Cunningham and Albert Huitsing) - * sockts.c: fixed bugs #41495 Possible threading issue in select() and #43278 - event_callback() handle context switch when calling sys_sem_signal() - - 2014-10-21: Simon Goldschmidt - * api_msg.c: fixed bug #38219 Assert on TCP netconn_write with sndtimeout set - - 2014-09-16: Kevin Cernekee - * dns.c: patch #8480 Fix handling of dns_seqno wraparound - - 2014-09-16: Simon Goldschmidt - * tcp_out.c: fixed bug #43192 tcp_enqueue_flags() should not check TCP_SND_QUEUELEN - when sending FIN - - 2014-09-03: Simon Goldschmidt - * msg_in.c: fixed bug #39355 SNMP Memory Leak in case of error - - 2014-09-02: Simon Goldschmidt - * err.h/.c, sockets.c, api_msg.c: fixed bug #43110 call getpeername() before - listen() will cause a error - - 2014-09-02: Simon Goldschmidt - * sockets.c: fixed bug #42117 lwip_fcntl does not set errno - - 2014-09-02: Simon Goldschmidt - * tcp.c: fixed bug #42299 tcp_abort() leaves freed pcb on tcp_bound_pcbs list - - 2014-08-20: Simon Goldschmidt - * dns.c: fixed bug #42987 lwIP is vulnerable to DNS cache poisoning due to - non-randomized TXIDs - - 2014-06-03: Simon Goldschmidt - * tcp_impl.h, tcp_in.c: fixed bug #37969 SYN packet dropped as short packet in - tcp_input function - - 2014-05-20: Simon Goldschmidt - * tcp_out.c: fixed bug #37184 tcp_write problem for pcbs in the SYN_SENT state - - 2014-05-19: Simon Goldschmidt - * *.h: Fixed bug #35874 reserved identifier violation (removed leading underscores - from header include guards) - - 2014-04-08: Simon Goldschmidt - * tcp.c: Fixed bug #36167 tcp server crash when client closes (maximum window) - - 2014-04-06: Simon Goldschmidt - * tcp_in.c: Fixed bug #36210 lwIP does not elicit an empty ACK when received - unacceptable ACK - - 2014-04-06: Simon Goldschmidt - * dhcp.c, ip4.c/.h, ip6.c/.h, udp.c/.h, ip.h: Fixed bug #41787 DHCP Discovery - is invalid when an IP is set to thet netif. - - 2014-03-14: Simon Goldschmidt - * tcp_out.c: Fixed bug #36153 TCP Cheksum error if LWIP_CHECKSUM_ON_COPY=1 - - 2014-03-11: Simon Goldschmidt (patch by Mason) - * opt.h, sockets.c: fixed bug #35928 BSD sockets functions must set errno for - POSIX-compliance - - 2014-02-27: Simon Goldschmidt - * dhcp.c: fixed bug #40303 DHCP xid renewed when sending a DHCPREQUEST - - 2014-02-27: Simon Goldschmidt - * raw.c: fixed bug #41680 raw socket can not receive IPv6 packet when - IP_SOF_BROADCAST_RECV==1 - - 2014-02-27: Simon Goldschmidt - * api_msg.c, sockets.c: fixed bug #38404 getpeeraddr returns success on - unconnected/listening TCP sockets - - 2014-02-27: Simon Goldschmidt - * sockets.c: fixed bug #41729 Some socket functions return Exyz instead of -1 - - 2014-02-25: Simon Goldschmidt - * ip4.c: fixed bug #39514 ip_route() may return an IPv6-only interface - - 2014-02-25: Simon Goldschmidt, patch by Fatih Asici - * pbuf.c: fixed bug #39356 Wrong increment in pbuf_memfind() - - 2014-02-25: Simon Goldschmidt - * netif.c/.h, udp.c: fixed bug #39225 udp.c uses netif_matches_ip6_addr() incorrectly; - renamed function netif_matches_ip6_addr() to netif_get_ip6_addr_match() - - 2014-02-25: Simon Goldschmidt - * igmp.c: fixed bug #39145 IGMP membership report for 224.0.0.1 - - 2014-02-22: Simon Goldschmidt (patch by Amir Shalem) - * etharp.c, opt.h: fixed bug #34681 Limit ARP queue length by ARP_QUEUE_LEN (=3) - - 2014-02-22: Simon Goldschmidt (patch by Amir Shalem) - * etharp.h/.c: fixed bug #34682 Limit ARP request flood for unresolved entry - - 2014-02-20: Simon Goldschmidt - * tcp_out.c: fixed bug #39683 Assertion "seg->tcphdr not aligned" failed with - MEM_ALIGNMENT = 8 - - 2014-02-20: Simon Goldschmidt - * sockets.c: fixed bug #39882 No function shall set errno to 0 - - 2014-02-20: Simon Goldschmidt - * mib_structs.c: fixed bug #40050 SNMP problem with MIB arrays > 255 - - 2014-02-20: Simon Goldschmidt - * api.h, sockets.c: fixed bug #41499 netconn::recv_avail can overflow - - 2014-01-08: Stathis Voukelatos - * memp_std.h: patch #7928 Fixed size calculation in MALLOC memory pool - creation macro - - 2014-01-18: Brian Fahs - * tcp_out.c: patch #8237: tcp_rexmit_rto fails to update pcb->unsent_oversize - when necessary - - 2014-01-17: Grant Erickson, Jay Logue, Simon Goldschmidt - * ipv6.c, netif.c: patch #7913 Enable Support for IPv6 Loopback - - 2014-01-16: Stathis Voukelatos - * netif.c: patch #7902 Fixed netif_poll() operation when LWIP_LOOPBACK_MAX_PBUFS > 0 - - 2014-01-14: "Freddie Chopin" - * snmp.h, mib2.c: fixed constness and spelling of sysdescr - - 2014-01-14: Simon Goldschmidt (patch by Thomas Faber) - * tcpip.c: patch #8241: Fix implicit declaration of ip_input with - LWIP_TCPIP_CORE_LOCKING_INPUT disabled - - 2014-01-14: chrysn - * timers.c: patch #8244 make timeouts usable reliably from outside of the - timeout routine - - 2014-01-10: Simon Goldschmidt - * ip_frag.c, ip6_frag.c: fixed bug #41041 Potential use-after-free in IPv6 reassembly - - 2014-01-10: Simon Goldschmidt - * memp.c: fixed bug #41188 Alignment error in memp_init() when MEMP_SEPARATE_POOLS==1 - - 2014-01-10: Simon Goldschmidt - * tcp.c: fixed bug #39898 tcp_fasttmr() possible lock due to infinte queue process loop - - 2013-06-29: Simon Goldschmidt - * inet.h, sockets.h: partially fixed bug #37585: IPv6 compatibility (in socket structs) - - 2013-06-29: Simon Goldschmidt - * inet6.h: bug #37585/task #12600: fixed struct in6_addr.s6_addr to conform to spec - - 2013-04-24: patch by Liam - * api_msg.c: patch #8008 Fix a potential null pointer dereference in assert - - 2013-04-24: Simon Goldschmidt - * igmp.c: fixed possible division by zero - - 2013-04-24: Simon Goldschmidt - * ip6.h, some ipv6 C files: fixed bug #38526 Coverity: Recursive Header Inclusion in ip6.h - - 2013-04-24: Simon Goldschmidt (patch by Emil Ljungdahl): - * netif.c: fixed bug #38586 netif_loop_output() "deadlocks" - - 2013-01-15: Simon Goldschmidt - * ip4.c: fixed bug #37665 ip_canforward operates on address in wrong byte order - - 2013-01-15: Simon Goldschmidt - * pbuf.h: fixed bug #38097 pbuf_free_ooseq() warning - - 2013-01-14: Simon Goldschmidt - * dns.c: fixed bug #37705 Possible memory corruption in DNS query - - 2013-01-11: Simon Goldschmidt - * raw.c: fixed bug #38066 Raw pcbs can alter packet without eating it - - 2012-08-22: Simon Goldschmidt - * memp.c: fixed bug #37166: memp_sanity check loops itself - - 2012-08-13: Simon Goldschmidt - * dhcp.c: fixed bug #36645: Calling dhcp_release before dhcp_start - dereferences NULL - - 2012-08-13: Simon Goldschmidt - * msg_out.c: fixed bug #36840 snmp_send_trap() NULL de-reference if traps - configured but no interfaces available - - 2012-08-13: Simon Goldschmidt - * dns.c: fixed bug #36899 DNS TTL 0 is cached for a long time - - 2012-05-11: Simon Goldschmidt (patch by Marty) - * memp.c: fixed bug #36412: memp.c does not compile when - MEMP_OVERFLOW_CHECK > zero and MEMP_SEPARATE_POOLS == 1 - - 2012-05-03: Simon Goldschmidt (patch by Sylvain Rochet) - * ppp.c: fixed bug #36283 (PPP struct used on header size computation and - not packed) - - 2012-05-03: Simon Goldschmidt (patch by David Empson) - * ppp.c: fixed bug #36388 (PPP: checksum-only in last pbuf leads to pbuf with - zero length) - - 2012-03-25: Simon Goldschmidt - * api_msg.c: Fixed bug #35817: do_connect() invalidly signals op_completed - for UDP/RAW with LWIP_TCPIP_CORE_LOCKING==1 - - 2012-03-25: Simon Goldschmidt - * api_msg.h, api_lib.c, api_msg.c, netifapi.c: fixed bug #35931: Name space - pollution in api_msg.c and netifapi.c - - 2011-08-24: Simon Goldschmidt - * inet6.h: fixed bug #34124 struct in6_addr does not conform to the standard - - - -(STABLE-1.4.1) - - ++ New features: - - 2012-03-25: Simon Goldschmidt (idea by Mason) - * posix/*: added posix-compatibility include files posix/netdb.h and posix/sys/socket.h - which are a simple wrapper to the correct lwIP include files. - - 2012-01-16: Simon Goldschmidt - * opt.h, icmp.c: Added option CHECKSUM_GEN_ICMP - - 2011-12-17: Simon Goldschmidt - * ip.h: implemented API functions to access so_options of IP pcbs (UDP, TCP, RAW) - (fixes bug #35061) - - 2011-09-27: Simon Goldschmidt - * opt.h, tcp.c, tcp_in.c: Implemented limiting data on ooseq queue (task #9989) - (define TCP_OOSEQ_MAX_BYTES / TCP_OOSEQ_MAX_PBUFS in lwipopts.h) - - 2011-09-21: Simon Goldschmidt - * opt.h, api.h, api_lib.c, api_msg.h/.c, sockets.c: Implemented timeout on - send (TCP only, bug #33820) - - 2011-09-21: Simon Goldschmidt - * init.c: Converted runtime-sanity-checks into compile-time checks that can - be disabled (since runtime checks can often not be seen on embedded targets) - - 2011-09-11: Simon Goldschmidt - * ppp.h, ppp_impl.h: splitted ppp.h to an internal and external header file - to get a clear separation of which functions an application or port may use - (task #11281) - - 2011-09-11: Simon Goldschmidt - * opt.h, tcp_impl.h, tcp.c, udp.h/.c: Added a config option to randomize - initial local TCP/UDP ports (so that different port ranges are used after - a reboot; bug #33818; this one added tcp_init/udp_init functions again) - - 2011-09-03: Simon Goldschmidt - * dhcp.c: DHCP uses LWIP_RAND() for xid's (bug #30302) - - 2011-08-24: Simon Goldschmidt - * opt.h, netif.h/.c: added netif remove callback (bug #32397) - - 2011-07-26: Simon Goldschmidt - * etharp.c: ETHARP_SUPPORT_VLAN: add support for an external VLAN filter - function instead of only checking for one VLAN (define ETHARP_VLAN_CHECK_FN) - - 2011-07-21: Simon Goldschmidt (patch by hanhui) - * ip4.c, etharp.c, pbuf.h: bug #33634 ip_forward() have a faulty behaviour: - Added pbuf flags to mark incoming packets as link-layer broadcast/multicast. - Also added code to allow ip_forward() to forward non-broadcast packets to - the input netif (set IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1). - - 2011-06-26: Simon Goldschmidt (patch by Cameron Gutman) - * tcp.c, tcp_out.c: bug #33604: added some more asserts to check that - pcb->state != LISTEN - - 2011-05-14: Simon Goldschmidt (patch by Stéphane Lesage) - * tcpip.c/.h: patch #7449 allow tcpip callback from interrupt with static - memory message - - - ++ Bugfixes: - - 2012-09-26: Simon Goldschmidt - * api_msg.c: fixed bug #37405 'err_tcp()' uses already freed 'netconn' object - - 2012-09-26: patch by Henrik Persson - * dhcp.c: patch #7843 Fix corner case with dhcp timeouts - - 2012-09-26: patch by Henrik Persson - * dhcp.c: patch #7840 Segfault in dhcp_parse_reply if no end marker in dhcp packet - - 2012-08-22: Simon Goldschmidt - * memp.c: fixed bug #37166: memp_sanity check loops itself - - 2012-05-08: Simon Goldschmidt - * tcp_out.c: fixed bug: #36380 unsent_oversize mismatch in 1.4.1RC1 (this was - a debug-check issue only) - - 2012-03-27: Simon Goldschmidt - * vj.c: fixed bug #35756 header length calculation problem in ppp/vj.c - - 2012-03-27: Simon Goldschmidt (patch by Mason) - * tcp_out.c: fixed bug #35945: SYN packet should provide the recv MSS not the - send MSS - - 2012-03-22: Simon Goldschmidt - * ip4.c: fixed bug #35927: missing refragmentaion in ip_forward - - 2012-03-20: Simon Goldschmidt (patch by Mason) - * netdb.c: fixed bug #35907: lwip_gethostbyname_r returns an invalid h_addr_list - - 2012-03-12: Simon Goldschmidt (patch by Bostjan Meglic) - * ppp.c: fixed bug #35809: PPP GetMask(): Compiler warning on big endian, - possible bug on little endian system - - 2012-02-23: Simon Goldschmidt - * etharp.c: fixed bug #35595: Impossible to send broadcast without a gateway - (introduced when fixing bug# 33551) - - 2012-02-16: Simon Goldschmidt - * ppp.c: fixed pbuf leak when PPP session is aborted through pppSigHUP() - (bug #35541: PPP Memory Leak) - - 2012-02-16: Simon Goldschmidt - * etharp.c: fixed bug #35531: Impossible to send multicast without a gateway - (introduced when fixing bug# 33551) - - 2012-02-16: Simon Goldschmidt (patch by Stéphane Lesage) - * msg_in.c, msg_out.c: fixed bug #35536 SNMP: error too big response is malformed - - 2012-02-15: Simon Goldschmidt - * init.c: fixed bug #35537: MEMP_NUM_* sanity checks should be disabled with - MEMP_MEM_MALLOC==1 - - 2012-02-12: Simon Goldschmidt - * tcp.h, tcp_in.c, tcp_out.c: partly fixed bug #25882: TCP hangs on - MSS > pcb->snd_wnd (by not creating segments bigger than half the window) - - 2012-02-11: Simon Goldschmidt - * tcp.c: fixed bug #35435: No pcb state check before adding it to time-wait - queue while closing - - 2012-01-22: Simon Goldschmidt - * tcp.c, tcp_in.c: fixed bug #35305: pcb may be freed too early on shutdown(WR) - - 2012-01-21: Simon Goldschmidt - * tcp.c: fixed bug #34636: FIN_WAIT_2 - Incorrect shutdown of TCP pcb - - 2012-01-20: Simon Goldschmidt - * dhcp.c: fixed bug #35151: DHCP asserts on incoming option lengths - - 2012-01-20: Simon Goldschmidt - * pbuf.c: fixed bug #35291: NULL pointer in pbuf_copy - - 2011-11-25: Simon Goldschmidt - * tcp.h/.c, tcp_impl.h, tcp_in.c: fixed bug #31177: tcp timers can corrupt - tcp_active_pcbs in some cases - - 2011-11-23: Simon Goldschmidt - * sys.c: fixed bug #34884: sys_msleep() body needs to be surrounded with - '#ifndef sys_msleep' - - 2011-11-22: Simon Goldschmidt - * netif.c, etharp.h/.c: fixed bug #34684: Clear the arp table cache when - netif is brought down - - 2011-10-28: Simon Goldschmidt - * tcp_in.c: fixed bug #34638: Dead code in tcp_receive - pcb->dupacks - - 2011-10-23: Simon Goldschmidt - * mem.c: fixed bug #34429: possible memory corruption with - LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT set to 1 - - 2011-10-18: Simon Goldschmidt - * arch.h, netdb.c: fixed bug #34592: lwip_gethostbyname_r uses nonstandard - error value - - 2011-10-18: Simon Goldschmidt - * opt.h: fixed default values of TCP_SNDLOWAT and TCP_SNDQUEUELOWAT for small - windows (bug #34176 select after non-blocking send times out) - - 2011-10-18: Simon Goldschmidt - * tcp_impl.h, tcp_out.c: fixed bug #34587: TCP_BUILD_MSS_OPTION doesn't - consider netif->mtu, causes slow network - - 2011-10-18: Simon Goldschmidt - * sockets.c: fixed bug #34581 missing parentheses in udplite sockets code - - 2011-10-18: Simon Goldschmidt - * sockets.h: fixed bug #34580 fcntl() is missing in LWIP_COMPAT_SOCKETS - - 2011-10-17: Simon Goldschmidt - * api_msg.c: fixed bug #34569: shutdown(SHUT_WR) crashes netconn/socket api - - 2011-10-13: Simon Goldschmidt - * tcp_in.c, tcp_out.c: fixed bug #34517 (persist timer is started although no - zero window is received) by starting the persist timer when a zero window is - received, not when we have more data queued for sending than fits into the - window - - 2011-10-13: Simon Goldschmidt - * def.h, timers.c: fixed bug #34541: LWIP_U32_DIFF is unnecessarily complex - - 2011-10-13: Simon Goldschmidt - * sockets.c, api_lib.c: fixed bug #34540: compiler error when CORE_LOCKING is - used and not all protocols are enabled - - 2011-10-12: Simon Goldschmidt - * pbuf.c: fixed bug #34534: Error in sending fragmented IP if MEM_ALIGNMENT > 4 - - 2011-10-09: Simon Goldschmidt - * tcp_out.c: fixed bug #34426: tcp_zero_window_probe() transmits incorrect - byte value when pcb->unacked != NULL - - 2011-10-09: Simon Goldschmidt - * ip4.c: fixed bug #34447 LWIP_IP_ACCEPT_UDP_PORT(dst_port) wrong - - 2011-09-27: Simon Goldschmidt - * tcp_in.c, tcp_out.c: Reset pcb->unsent_oversize in 2 more places... - - 2011-09-27: Simon Goldschmidt - * tcp_in.c: fixed bug #28288: Data after FIN in oos queue - - 2011-09-27: Simon Goldschmidt - * dhcp.c: fixed bug #34406 dhcp_option_hostname() can overflow the pbuf - - 2011-09-24: Simon Goldschmidt - * mem.h: fixed bug #34377 MEM_SIZE_F is not defined if MEM_LIBC_MALLOC==1 - - 2011-09-23: Simon Goldschmidt - * pbuf.h, tcp.c, tcp_in.c: fixed bug #33871: rejecting TCP_EVENT_RECV() for - the last packet including FIN can lose data - - 2011-09-22: Simon Goldschmidt - * tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into - account - - 2011-09-21: Simon Goldschmidt - * opt.h: fixed default value of TCP_SND_BUF to not violate the sanity checks - in init.c - - 2011-09-20: Simon Goldschmidt - * timers.c: fixed bug #34337 (possible NULL pointer in sys_check_timeouts) - - 2011-09-11: Simon Goldschmidt - * tcp_out.c: use pcb->mss instead of TCP_MSS for preallocate mss-sized pbufs - (bug #34019) - - 2011-09-09: Simon Goldschmidt - * udp.c: fixed bug #34072: UDP broadcast is received from wrong UDP pcb if - udp port matches - - 2011-09-03: Simon Goldschmidt - * tcp_in.c: fixed bug #33952 PUSH flag in incoming packet is lost when packet - is aggregated and sent to application - - 2011-09-01: Simon Goldschmidt - * opt.h: fixed bug #31809 LWIP_EVENT_API in opts.h is inconsistent compared - to other options - - 2011-09-01: Simon Goldschmidt - * tcp_in.c: fixed bug #34111 RST for ACK to listening pcb has wrong seqno - - 2011-08-24: Simon Goldschmidt - * api_msg.c, sockets.c: fixed bug #33956 Wrong error returned when calling - accept() on UDP connections - - 2011-08-24: Simon Goldschmidt - * sockets.h: fixed bug #34057 socklen_t should be a typedef - - 2011-08-24: Simon Goldschmidt - * pbuf.c: fixed bug #34112 Odd check in pbuf_alloced_custom (typo) - - 2011-08-24: Simon Goldschmidt - * dhcp.c: fixed bug #34122 dhcp: hostname can overflow - - 2011-08-24: Simon Goldschmidt - * netif.c: fixed bug #34121 netif_add/netif_set_ipaddr fail on NULL ipaddr - - 2011-08-22: Simon Goldschmidt - * tcp_out.c: fixed bug #33962 TF_FIN not always set after FIN is sent. (This - merely prevents nagle from not transmitting fast after closing.) - - 2011-07-22: Simon Goldschmidt - * api_lib.c, api_msg.c, sockets.c, api.h: fixed bug #31084 (socket API returns - always EMSGSIZE on non-blocking sockets if data size > send buffers) -> now - lwip_send() sends as much as possible for non-blocking sockets - - 2011-07-22: Simon Goldschmidt - * pbuf.c/.h, timers.c: freeing ooseq pbufs when the pbuf pool is empty implemented - for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() - at regular intervals from main level. - - 2011-07-21: Simon Goldschmidt - * etharp.c: fixed bug #33551 (ARP entries may time out although in use) by - sending an ARP request when an ARP entry is used in the last minute before - it would time out. - - 2011-07-04: Simon Goldschmidt - * sys_arch.txt: Fixed documentation after changing sys arch prototypes for 1.4.0. - - 2011-06-26: Simon Goldschmidt - * tcp.c: fixed bug #31723 (tcp_kill_prio() kills pcbs with the same prio) by - updating its documentation only. - - 2011-06-26: Simon Goldschmidt - * mem.c: fixed bug #33545: With MEM_USE_POOLS==1, mem_malloc can return an - unaligned pointer. - - 2011-06-26: Simon Goldschmidt - * mem.c: fixed bug #33544 "warning in mem.c in lwip 1.4.0 with NO_SYS=1" - - 2011-05-25: Simon Goldschmidt - * tcp.c: fixed bug #33398 (pointless conversion when checking TCP port range) - - - -(STABLE-1.4.0) - - ++ New features: - - 2011-03-27: Simon Goldschmidt - * tcp_impl.h, tcp_in.c, tcp_out.c: Removed 'dataptr' from 'struct tcp_seg' and - calculate it in tcp_zero_window_probe (the only place where it was used). - - 2010-11-21: Simon Goldschmidt - * dhcp.c/.h: Added a function to deallocate the struct dhcp from a netif - (fixes bug #31525). - - 2010-07-12: Simon Goldschmidt (patch by Stephane Lesage) - * ip.c, udp.c/.h, pbuf.h, sockets.c: task #10495: Added support for - IP_MULTICAST_LOOP at socket- and raw-API level. - - 2010-06-16: Simon Goldschmidt - * ip.c: Added an optional define (LWIP_IP_ACCEPT_UDP_PORT) that can allow - link-layer-addressed UDP traffic to be received while a netif is down (just - like DHCP during configuration) - - 2010-05-22: Simon Goldschmidt - * many many files: bug #27352: removed packing from ip_addr_t, the packed - version is now only used in protocol headers. Added global storage for - current src/dest IP address while in input functions. - - 2010-05-16: Simon Goldschmidt - * def.h: task #10391: Add preprocessor-macros for compile-time htonl - calculation (and use them throughout the stack where applicable) - - 2010-05-16: Simon Goldschmidt - * opt.h, memp_std.h, memp.c, ppp_oe.h/.c: PPPoE now uses its own MEMP pool - instead of the heap (moved struct pppoe_softc from ppp_oe.c to ppp_oe.h) - - 2010-05-16: Simon Goldschmidt - * opt.h, memp_std.h, dns.h/.c: DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses its own - MEMP pool instead of the heap - - 2010-05-13: Simon Goldschmidt - * tcp.c, udp.c: task #6995: Implement SO_REUSEADDR (correctly), added - new option SO_REUSE_RXTOALL to pass received UDP broadcast/multicast - packets to more than one pcb. - - 2010-05-02: Simon Goldschmidt - * netbuf.h/.c, sockets.c, api_msg.c: use checksum-on-copy for sending - UDP data for LWIP_NETIF_TX_SINGLE_PBUF==1 - - 2010-04-30: Simon Goldschmidt - * udp.h/.c, pbuf.h/.c: task #6849: added udp_send(_to/_if) functions that - take a precalculated checksum, added pbuf_fill_chksum() to copy data - into a pbuf and at the same time calculating the checksum for that data - - 2010-04-29: Simon Goldschmidt - * ip_addr.h, etharp.h/.c, autoip.c: Create overridable macros for copying - 2-byte-aligned IP addresses and MAC addresses - - 2010-04-28: Patch by Bill Auerbach - * ip.c: Inline generating IP checksum to save a function call - - 2010-04-14: Simon Goldschmidt - * tcpip.h/.c, timers.c: Added an overridable define to get informed when the - tcpip_thread processes messages or timeouts to implement a watchdog. - - 2010-03-28: Simon Goldschmidt - * ip_frag.c: create a new (contiguous) PBUF_RAM for every outgoing - fragment if LWIP_NETIF_TX_SINGLE_PBUF==1 - - 2010-03-27: Simon Goldschmidt - * etharp.c: Speedup TX by moving code from find_entry to etharp_output/ - etharp_query to prevent unnecessary function calls (inspired by - patch #7135). - - 2010-03-20: Simon Goldschmidt - * opt.h, tcpip.c/.h: Added an option to disable tcpip_(un)timeout code - since the linker cannot do this automatically to save space. - - 2010-03-20: Simon Goldschmidt - * opt.h, etharp.c/.h: Added support for static ARP table entries - - 2010-03-14: Simon Goldschmidt - * tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum - when creating TCP segments, not when (re-)transmitting them. - - 2010-03-07: Simon Goldschmidt - * sockets.c: bug #28775 (select/event_callback: only check select_cb_list - on change) plus use SYS_LIGHTWEIGHT_PROT to protect the select code. - This should speed up receiving data on sockets as the select code in - event_callback is only executed when select is waiting. - - 2010-03-06: Simon Goldschmidt - * tcp_out.c: task #7013 (Create option to have all packets delivered to - netif->output in one piece): Always copy to try to create single pbufs - in tcp_write. - - 2010-03-06: Simon Goldschmidt - * api.h, api_lib.c, sockets.c: task #10167 (sockets: speed up TCP recv - by not allocating a netbuf): added function netconn_recv_tcp_pbuf() - for tcp netconns to receive pbufs, not netbufs; use that function - for tcp sockets. - - 2010-03-05: Jakob Ole Stoklundsen / Simon Goldschmidt - * opt.h, tcp.h, tcp_impl.h, tcp.c, tcp_in.c, tcp_out.c: task #7040: - Work on tcp_enqueue: Don't waste memory when chaining segments, - added option TCP_OVERSIZE to prevent creating many small pbufs when - calling tcp_write with many small blocks of data. Instead, pbufs are - allocated larger than needed and the space is used for later calls to - tcp_write. - - 2010-02-21: Simon Goldschmidt - * stats.c/.h: Added const char* name to mem- and memp-stats for easier - debugging. - - 2010-02-21: Simon Goldschmidt - * tcp.h (and usages), added tcp_impl.h: Splitted API and internal - implementation of tcp to make API usage cleare to application programmers - - 2010-02-14: Simon Goldschmidt/Stephane Lesage - * ip_addr.h: Improved some defines working on ip addresses, added faster - macro to copy addresses that cannot be NULL - - 2010-02-13: Simon Goldschmidt - * api.h, api_lib.c, api_msg.c, sockets.c: task #7865 (implement non- - blocking send operation) - - 2010-02-12: Simon Goldschmidt - * sockets.c/.h: Added a minimal version of posix fctl() to have a - standardised way to set O_NONBLOCK for nonblocking sockets. - - 2010-02-12: Simon Goldschmidt - * dhcp.c/.h, autoip.c/.h: task #10139 (Prefer statically allocated - memory): added autoip_set_struct() and dhcp_set_struct() to let autoip - and dhcp work with user-allocated structs instead of callin mem_malloc - - 2010-02-12: Simon Goldschmidt/Jeff Barber - * tcp.c/h: patch #6865 (SO_REUSEADDR for TCP): if pcb.so_options has - SOF_REUSEADDR set, allow binding to endpoint in TIME_WAIT - - 2010-02-12: Simon Goldschmidt - * sys layer: task #10139 (Prefer statically allocated memory): converted - mbox and semaphore functions to take pointers to sys_mbox_t/sys_sem_t; - converted sys_mbox_new/sys_sem_new to take pointers and return err_t; - task #7212: Add Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX - to let sys.h use binary semaphores instead of mutexes - as before) - - 2010-02-09: Simon Goldschmidt (Simon Kallweit) - * timers.c/.h: Added function sys_restart_timeouts() from patch #7085 - (Restart system timeout handling) - - 2010-02-09: Simon Goldschmidt - * netif.c/.h, removed loopif.c/.h: task #10153 (Integrate loopif into - netif.c) - loopif does not have to be created by the port any more, - just define LWIP_HAVE_LOOPIF to 1. - - 2010-02-08: Simon Goldschmidt - * inet.h, ip_addr.c/.h: Added reentrant versions of inet_ntoa/ipaddr_ntoa - inet_ntoa_r/ipaddr_ntoa_r - - 2010-02-08: Simon Goldschmidt - * netif.h: Added netif_s/get_igmp_mac_filter() macros - - 2010-02-05: Simon Goldschmidt - * netif.h: Added function-like macros to get/set the hostname on a netif - - 2010-02-04: Simon Goldschmidt - * nearly every file: Replaced struct ip_addr by typedef ip_addr_t to - make changing the actual implementation behind the typedef easier. - - 2010-02-01: Simon Goldschmidt - * opt.h, memp_std.h, dns.h, netdb.c, memp.c: Let netdb use a memp pool - for allocating memory when getaddrinfo() is called. - - 2010-01-31: Simon Goldschmidt - * dhcp.h, dhcp.c: Reworked the code that parses DHCP options: parse - them once instead of parsing for every option. This also removes - the need for mem_malloc from dhcp_recv and makes it possible to - correctly retrieve the BOOTP file. - - 2010-01-30: simon Goldschmidt - * sockets.c: Use SYS_LIGHTWEIGHT_PROT instead of a semaphore to protect - the sockets array. - - 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) - * api.h, api_msg.c, sockets.c: Added except set support in select - (patch #6860) - - 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) - * api.h, sockets.h, err.h, api_lib.c, api_msg.c, sockets.c, err.c: - Add non-blocking support for connect (partly from patch #6860), - plus many cleanups in socket & netconn API. - - 2010-01-27: Simon Goldschmidt - * opt.h, tcp.h, init.c, api_msg.c: Added TCP_SNDQUEUELOWAT corresponding - to TCP_SNDLOWAT and added tcp_sndqueuelen() - this fixes bug #28605 - - 2010-01-26: Simon Goldschmidt - * snmp: Use memp pools for snmp instead of the heap; added 4 new pools. - - 2010-01-14: Simon Goldschmidt - * ppp.c/.h: Fixed bug #27856: PPP: Set netif link- and status-callback - by adding ppp_set_netif_statuscallback()/ppp_set_netif_linkcallback() - - 2010-01-13: Simon Goldschmidt - * mem.c: The heap now may be moved to user-defined memory by defining - LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address - (patch #6966 and bug #26133) - - 2010-01-10: Simon Goldschmidt (Bill Auerbach) - * opt.h, memp.c: patch #6822 (Add option to place memory pools in - separate arrays) - - 2010-01-10: Simon Goldschmidt - * init.c, igmp.c: patch #6463 (IGMP - Adding Random Delay): added define - LWIP_RAND() for lwip-wide randomization (to be defined in cc.h) - - 2009-12-31: Simon Goldschmidt - * tcpip.c, init.c, memp.c, sys.c, memp_std.h, sys.h, tcpip.h - added timers.c/.h: Separated timer implementation from semaphore/mbox - implementation, moved timer implementation to timers.c/.h, timers are - now only called from tcpip_thread or by explicitly checking them. - (TASK#7235) - - 2009-12-27: Simon Goldschmidt - * opt.h, etharp.h/.c, init.c, tcpip.c: Added an additional option - LWIP_ETHERNET to support ethernet without ARP (necessary for pure PPPoE) - - - ++ Bugfixes: - - 2011-04-20: Simon Goldschmidt - * sys_arch.txt: sys_arch_timeouts() is not needed any more. - - 2011-04-13: Simon Goldschmidt - * tcp.c, udp.c: Fixed bug #33048 (Bad range for IP source port numbers) by - using ports in the IANA private/dynamic range (49152 through 65535). - - 2011-03-29: Simon Goldschmidt, patch by Emil Lhungdahl: - * etharp.h/.c: Fixed broken VLAN support. - - 2011-03-27: Simon Goldschmidt - * tcp.c: Fixed bug #32926 (TCP_RMV(&tcp_bound_pcbs) is called on unbound tcp - pcbs) by checking if the pcb was bound (local_port != 0). - - 2011-03-27: Simon Goldschmidt - * ppp.c: Fixed bug #32280 (ppp: a pbuf is freed twice) - - 2011-03-27: Simon Goldschmidt - * sockets.c: Fixed bug #32906: lwip_connect+lwip_send did not work for udp and - raw pcbs with LWIP_TCPIP_CORE_LOCKING==1. - - 2011-03-27: Simon Goldschmidt - * tcp_out.c: Fixed bug #32820 (Outgoing TCP connections created before route - is present never times out) by starting retransmission timer before checking - route. - - 2011-03-22: Simon Goldschmidt - * ppp.c: Fixed bug #32648 (PPP code crashes when terminating a link) by only - calling sio_read_abort() if the file descriptor is valid. - - 2011-03-14: Simon Goldschmidt - * err.h/.c, sockets.c, api_msg.c: fixed bug #31748 (Calling non-blocking connect - more than once can render a socket useless) since it mainly involves changing - "FATAL" classification of error codes: ERR_USE and ERR_ISCONN just aren't fatal. - - 2011-03-13: Simon Goldschmidt - * sockets.c: fixed bug #32769 (ESHUTDOWN is linux-specific) by fixing - err_to_errno_table (ERR_CLSD: ENOTCONN instead of ESHUTDOWN), ERR_ISCONN: - use EALRADY instead of -1 - - 2011-03-13: Simon Goldschmidt - * api_lib.c: netconn_accept: return ERR_ABRT instead of ERR_CLSD if the - connection has been aborted by err_tcp (since this is not a normal closing - procedure). - - 2011-03-13: Simon Goldschmidt - * tcp.c: tcp_bind: return ERR_VAL instead of ERR_ISCONN when trying to bind - with pcb->state != CLOSED - - 2011-02-17: Simon Goldschmidt - * rawapi.txt: Fixed bug #32561 tcp_poll argument definition out-of-order in - documentation - - 2011-02-17: Simon Goldschmidt - * many files: Added missing U/UL modifiers to fix 16-bit-arch portability. - - 2011-01-24: Simon Goldschmidt - * sockets.c: Fixed bug #31741: lwip_select seems to have threading problems - - 2010-12-02: Simon Goldschmidt - * err.h: Fixed ERR_IS_FATAL so that ERR_WOULDBLOCK is not fatal. - - 2010-11-23: Simon Goldschmidt - * api.h, api_lib.c, api_msg.c, sockets.c: netconn.recv_avail is only used for - LWIP_SO_RCVBUF and ioctl/FIONREAD. - - 2010-11-23: Simon Goldschmidt - * etharp.c: Fixed bug #31720: ARP-queueing: RFC 1122 recommends to queue at - least 1 packet -> ARP_QUEUEING==0 now queues the most recent packet. - - 2010-11-23: Simon Goldschmidt - * tcp_in.c: Fixed bug #30577: tcp_input: don't discard ACK-only packets after - refusing 'refused_data' again. - - 2010-11-22: Simon Goldschmidt - * sockets.c: Fixed bug #31590: getsockopt(... SO_ERROR ...) gives EINPROGRESS - after a successful nonblocking connection. - - 2010-11-22: Simon Goldschmidt - * etharp.c: Fixed bug #31722: IP packets sent with an AutoIP source addr - must be sent link-local - - 2010-11-22: Simon Goldschmidt - * timers.c: patch #7329: tcp_timer_needed prototype was ifdef'ed out for - LWIP_TIMERS==0 - - 2010-11-20: Simon Goldschmidt - * sockets.c: Fixed bug #31170: lwip_setsockopt() does not set socket number - - 2010-11-20: Simon Goldschmidt - * sockets.h: Fixed bug #31304: Changed SHUT_RD, SHUT_WR and SHUT_RDWR to - resemble other stacks. - - 2010-11-20: Simon Goldschmidt - * dns.c: Fixed bug #31535: TCP_SND_QUEUELEN must be at least 2 or else - no-copy TCP writes will never succeed. - - 2010-11-20: Simon Goldschmidt - * dns.c: Fixed bug #31701: Error return value from dns_gethostbyname() does - not match documentation: return ERR_ARG instead of ERR_VAL if not - initialized or wrong argument. - - 2010-10-20: Simon Goldschmidt - * sockets.h: Fixed bug #31385: sizeof(struct sockaddr) is 30 but should be 16 - - 2010-10-05: Simon Goldschmidt - * dhcp.c: Once again fixed #30038: DHCP/AutoIP cooperation failed when - replugging the network cable after an AutoIP address was assigned. - - 2010-08-10: Simon Goldschmidt - * tcp.c: Fixed bug #30728: tcp_new_port() did not check listen pcbs - - 2010-08-03: Simon Goldschmidt - * udp.c, raw.c: Don't chain empty pbufs when sending them (fixes bug #30625) - - 2010-08-01: Simon Goldschmidt (patch by Greg Renda) - * ppp.c: Applied patch #7264 (PPP protocols are rejected incorrectly on big - endian architectures) - - 2010-07-28: Simon Goldschmidt - * api_lib.c, api_msg.c, sockets.c, mib2.c: Fixed compilation with TCP or UDP - disabled. - - 2010-07-27: Simon Goldschmidt - * tcp.c: Fixed bug #30565 (tcp_connect() check bound list): that check did no - harm but never did anything - - 2010-07-21: Simon Goldschmidt - * ip.c: Fixed invalid fix for bug #30402 (CHECKSUM_GEN_IP_INLINE does not - add IP options) - - 2010-07-16: Kieran Mansley - * msg_in.c: Fixed SNMP ASN constant defines to not use ! operator - - 2010-07-10: Simon Goldschmidt - * ip.c: Fixed bug #30402: CHECKSUM_GEN_IP_INLINE does not add IP options - - 2010-06-30: Simon Goldschmidt - * api_msg.c: fixed bug #30300 (shutdown parameter was not initialized in - netconn_delete) - - 2010-06-28: Kieran Mansley - * timers.c remove unportable printing of C function pointers - - 2010-06-24: Simon Goldschmidt - * init.c, timers.c/.h, opt.h, memp_std.h: From patch #7221: added flag - NO_SYS_NO_TIMERS to drop timer support for NO_SYS==1 for easier upgrading - - 2010-06-24: Simon Goldschmidt - * api(_lib).c/.h, api_msg.c/.h, sockets.c/.h: Fixed bug #10088: Correctly - implemented shutdown at socket level. - - 2010-06-21: Simon Goldschmidt - * pbuf.c/.h, ip_frag.c/.h, opt.h, memp_std.h: Fixed bug #29361 (ip_frag has - problems with zero-copy DMA MACs) by adding custom pbufs and implementing - custom pbufs that reference other (original) pbufs. Additionally set - IP_FRAG_USES_STATIC_BUF=0 as default to be on the safe side. - - 2010-06-15: Simon Goldschmidt - * dhcp.c: Fixed bug #29970: DHCP endian issue parsing option responses - - 2010-06-14: Simon Goldschmidt - * autoip.c: Fixed bug #30039: AutoIP does not reuse previous addresses - - 2010-06-12: Simon Goldschmidt - * dhcp.c: Fixed bug #30038: dhcp_network_changed doesn't reset AUTOIP coop - state - - 2010-05-17: Simon Goldschmidt - * netdb.c: Correctly NULL-terminate h_addr_list - - 2010-05-16: Simon Goldschmidt - * def.h/.c: changed the semantics of LWIP_PREFIX_BYTEORDER_FUNCS to prevent - "symbol already defined" i.e. when linking to winsock - - 2010-05-05: Simon Goldschmidt - * def.h, timers.c: Fixed bug #29769 (sys_check_timeouts: sys_now() may - overflow) - - 2010-04-21: Simon Goldschmidt - * api_msg.c: Fixed bug #29617 (sometime cause stall on delete listening - connection) - - 2010-03-28: Luca Ceresoli - * ip_addr.c/.h: patch #7143: Add a few missing const qualifiers - - 2010-03-27: Luca Ceresoli - * mib2.c: patch #7130: remove meaningless const qualifiers - - 2010-03-26: Simon Goldschmidt - * tcp_out.c: Make LWIP_NETIF_TX_SINGLE_PBUF work for TCP, too - - 2010-03-26: Simon Goldschmidt - * various files: Fixed compiling with different options disabled (TCP/UDP), - triggered by bug #29345; don't allocate acceptmbox if LWIP_TCP is disabled - - 2010-03-25: Simon Goldschmidt - * sockets.c: Fixed bug #29332: lwip_select() processes readset incorrectly - - 2010-03-25: Simon Goldschmidt - * tcp_in.c, test_tcp_oos.c: Fixed bug #29080: Correctly handle remote side - overrunning our rcv_wnd in ooseq case. - - 2010-03-22: Simon Goldschmidt - * tcp.c: tcp_listen() did not copy the pcb's prio. - - 2010-03-19: Simon Goldschmidt - * snmp_msg.c: Fixed bug #29256: SNMP Trap address was not correctly set - - 2010-03-14: Simon Goldschmidt - * opt.h, etharp.h: Fixed bug #29148 (Incorrect PBUF_POOL_BUFSIZE for ports - where ETH_PAD_SIZE > 0) by moving definition of ETH_PAD_SIZE to opt.h - and basing PBUF_LINK_HLEN on it. - - 2010-03-08: Simon Goldschmidt - * netif.c, ipv4/ip.c: task #10241 (AutoIP: don't break existing connections - when assiging routable address): when checking incoming packets and - aborting existing connection on address change, filter out link-local - addresses. - - 2010-03-06: Simon Goldschmidt - * sockets.c: Fixed LWIP_NETIF_TX_SINGLE_PBUF for LWIP_TCPIP_CORE_LOCKING - - 2010-03-06: Simon Goldschmidt - * ipv4/ip.c: Don't try to forward link-local addresses - - 2010-03-06: Simon Goldschmidt - * etharp.c: Fixed bug #29087: etharp: don't send packets for LinkLocal- - addresses to gw - - 2010-03-05: Simon Goldschmidt - * dhcp.c: Fixed bug #29072: Correctly set ciaddr based on message-type - and state. - - 2010-03-05: Simon Goldschmidt - * api_msg.c: Correctly set TCP_WRITE_FLAG_MORE when netconn_write is split - into multiple calls to tcp_write. - - 2010-02-21: Simon Goldschmidt - * opt.h, mem.h, dns.c: task #10140: Remove DNS_USES_STATIC_BUF (keep - the implementation of DNS_USES_STATIC_BUF==1) - - 2010-02-20: Simon Goldschmidt - * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Task #10088: Correctly implement - close() vs. shutdown(). Now the application does not get any more - recv callbacks after calling tcp_close(). Added tcp_shutdown(). - - 2010-02-19: Simon Goldschmidt - * mem.c/.h, pbuf.c: Renamed mem_realloc() to mem_trim() to prevent - confusion with realloc() - - 2010-02-15: Simon Goldschmidt/Stephane Lesage - * netif.c/.h: Link status does not depend on LWIP_NETIF_LINK_CALLBACK - (fixes bug #28899) - - 2010-02-14: Simon Goldschmidt - * netif.c: Fixed bug #28877 (Duplicate ARP gratuitous packet with - LWIP_NETIF_LINK_CALLBACK set on) by only sending if both link- and - admin-status of a netif are up - - 2010-02-14: Simon Goldschmidt - * opt.h: Disable ETHARP_TRUST_IP_MAC by default since it slows down packet - reception and is not really necessary - - 2010-02-14: Simon Goldschmidt - * etharp.c/.h: Fixed ARP input processing: only add a new entry if a - request was directed as us (RFC 826, Packet Reception), otherwise - only update existing entries; internalized some functions - - 2010-02-14: Simon Goldschmidt - * netif.h, etharp.c, tcpip.c: Fixed bug #28183 (ARP and TCP/IP cannot be - disabled on netif used for PPPoE) by adding a new netif flag - (NETIF_FLAG_ETHERNET) that tells the stack the device is an ethernet - device but prevents usage of ARP (so that ethernet_input can be used - for PPPoE). - - 2010-02-12: Simon Goldschmidt - * netif.c: netif_set_link_up/down: only do something if the link state - actually changes - - 2010-02-12: Simon Goldschmidt/Stephane Lesage - * api_msg.c: Fixed bug #28865 (Cannot close socket/netconn in non-blocking - connect) - - 2010-02-12: Simon Goldschmidt - * mem.h: Fixed bug #28866 (mem_realloc function defined in mem.h) - - 2010-02-09: Simon Goldschmidt - * api_lib.c, api_msg.c, sockets.c, api.h, api_msg.h: Fixed bug #22110 - (recv() makes receive window update for data that wasn't received by - application) - - 2010-02-09: Simon Goldschmidt/Stephane Lesage - * sockets.c: Fixed bug #28853 (lwip_recvfrom() returns 0 on receive time-out - or any netconn_recv() error) - - 2010-02-09: Simon Goldschmidt - * ppp.c: task #10154 (PPP: Update snmp in/out counters for tx/rx packets) - - 2010-02-09: Simon Goldschmidt - * netif.c: For loopback packets, adjust the stats- and snmp-counters - for the loopback netif. - - 2010-02-08: Simon Goldschmidt - * igmp.c/.h, ip.h: Moved most defines from igmp.h to igmp.c for clarity - since they are not used anywhere else. - - 2010-02-08: Simon Goldschmidt (Stéphane Lesage) - * igmp.c, igmp.h, stats.c, stats.h: Improved IGMP stats - (patch from bug #28798) - - 2010-02-08: Simon Goldschmidt (Stéphane Lesage) - * igmp.c: Fixed bug #28798 (Error in "Max Response Time" processing) and - another bug when LWIP_RAND() returns zero. - - 2010-02-04: Simon Goldschmidt - * nearly every file: Use macros defined in ip_addr.h (some of them new) - to work with IP addresses (preparation for bug #27352 - Change ip_addr - from struct to typedef (u32_t) - and better code). - - 2010-01-31: Simon Goldschmidt - * netif.c: Don't call the link-callback from netif_set_up/down() since - this invalidly retriggers DHCP. - - 2010-01-29: Simon Goldschmidt - * ip_addr.h, inet.h, def.h, inet.c, def.c, more: Cleanly separate the - portability file inet.h and its contents from the stack: moved htonX- - functions to def.h (and the new def.c - they are not ipv4 dependent), - let inet.h depend on ip_addr.h and not the other way round. - This fixes bug #28732. - - 2010-01-28: Kieran Mansley - * tcp.c: Ensure ssthresh >= 2*MSS - - 2010-01-27: Simon Goldschmidt - * tcp.h, tcp.c, tcp_in.c: Fixed bug #27871: Calling tcp_abort() in recv - callback can lead to accessing unallocated memory. As a consequence, - ERR_ABRT means the application has called tcp_abort()! - - 2010-01-25: Simon Goldschmidt - * snmp_structs.h, msg_in.c: Partly fixed bug #22070 (MIB_OBJECT_WRITE_ONLY - not implemented in SNMP): write-only or not-accessible are still - returned by getnext (though not by get) - - 2010-01-24: Simon Goldschmidt - * snmp: Renamed the private mib node from 'private' to 'mib_private' to - not use reserved C/C++ keywords - - 2010-01-23: Simon Goldschmidt - * sockets.c: Fixed bug #28716: select() returns 0 after waiting for less - than 1 ms - - 2010-01-21: Simon Goldschmidt - * tcp.c, api_msg.c: Fixed bug #28651 (tcp_connect: no callbacks called - if tcp_enqueue fails) both in raw- and netconn-API - - 2010-01-19: Simon Goldschmidt - * api_msg.c: Fixed bug #27316: netconn: Possible deadlock in err_tcp - - 2010-01-18: Iordan Neshev/Simon Goldschmidt - * src/netif/ppp: reorganised PPP sourcecode to 2.3.11 including some - bugfix backports from 2.4.x. - - 2010-01-18: Simon Goldschmidt - * mem.c: Fixed bug #28679: mem_realloc calculates mem_stats wrong - - 2010-01-17: Simon Goldschmidt - * api_lib.c, api_msg.c, (api_msg.h, api.h, sockets.c, tcpip.c): - task #10102: "netconn: clean up conn->err threading issues" by adding - error return value to struct api_msg_msg - - 2010-01-17: Simon Goldschmidt - * api.h, api_lib.c, sockets.c: Changed netconn_recv() and netconn_accept() - to return err_t (bugs #27709 and #28087) - - 2010-01-14: Simon Goldschmidt - * ...: Use typedef for function prototypes throughout the stack. - - 2010-01-13: Simon Goldschmidt - * api_msg.h/.c, api_lib.c: Fixed bug #26672 (close connection when receive - window = 0) by correctly draining recvmbox/acceptmbox - - 2010-01-11: Simon Goldschmidt - * pap.c: Fixed bug #13315 (PPP PAP authentication can result in - erroneous callbacks) by copying the code from recent pppd - - 2010-01-10: Simon Goldschmidt - * raw.c: Fixed bug #28506 (raw_bind should filter received packets) - - 2010-01-10: Simon Goldschmidt - * tcp.h/.c: bug #28127 (remove call to tcp_output() from tcp_ack(_now)()) - - 2010-01-08: Simon Goldschmidt - * sockets.c: Fixed bug #28519 (lwip_recvfrom bug with len > 65535) - - 2010-01-08: Simon Goldschmidt - * dns.c: Copy hostname for DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1 since string - passed to dns_local_addhost() might be volatile - - 2010-01-07: Simon Goldschmidt - * timers.c, tcp.h: Call tcp_timer_needed() with NO_SYS==1, too - - 2010-01-06: Simon Goldschmidt - * netdb.h: Fixed bug #28496: missing include guards in netdb.h - - 2009-12-31: Simon Goldschmidt - * many ppp files: Reorganised PPP source code from ucip structure to pppd - structure to easily compare our code against the pppd code (around v2.3.1) - - 2009-12-27: Simon Goldschmidt - * tcp_in.c: Another fix for bug #28241 (ooseq processing) and adapted - unit test - - -(STABLE-1.3.2) - - ++ New features: - - 2009-10-27 Simon Goldschmidt/Stephan Lesage - * netifapi.c/.h: Added netifapi_netif_set_addr() - - 2009-10-07 Simon Goldschmidt/Fabian Koch - * api_msg.c, netbuf.c/.h, opt.h: patch #6888: Patch for UDP Netbufs to - support dest-addr and dest-port (optional: LWIP_NETBUF_RECVINFO) - - 2009-08-26 Simon Goldschmidt/Simon Kallweit - * slipif.c/.h: bug #26397: SLIP polling support - - 2009-08-25 Simon Goldschmidt - * opt.h, etharp.h/.c: task #9033: Support IEEE 802.1q tagged frame (VLAN), - New configuration options ETHARP_SUPPORT_VLAN and ETHARP_VLAN_CHECK. - - 2009-08-25 Simon Goldschmidt - * ip_addr.h, netdb.c: patch #6900: added define ip_ntoa(struct ip_addr*) - - 2009-08-24 Jakob Stoklund Olesen - * autoip.c, dhcp.c, netif.c: patch #6725: Teach AutoIP and DHCP to respond - to netif_set_link_up(). - - 2009-08-23 Simon Goldschmidt - * tcp.h/.c: Added function tcp_debug_state_str() to convert a tcp state - to a human-readable string. - - ++ Bugfixes: - - 2009-12-24: Kieran Mansley - * tcp_in.c Apply patches from Oleg Tyshev to improve OOS processing - (BUG#28241) - - 2009-12-06: Simon Goldschmidt - * ppp.h/.c: Fixed bug #27079 (Yet another leak in PPP): outpacket_buf can - be statically allocated (like in ucip) - - 2009-12-04: Simon Goldschmidt (patch by Ioardan Neshev) - * pap.c: patch #6969: PPP: missing PAP authentication UNTIMEOUT - - 2009-12-03: Simon Goldschmidt - * tcp.h, tcp_in.c, tcp_out.c: Fixed bug #28106: dup ack for fast retransmit - could have non-zero length - - 2009-12-02: Simon Goldschmidt - * tcp_in.c: Fixed bug #27904: TCP sends too many ACKs: delay resetting - tcp_input_pcb until after calling the pcb's callbacks - - 2009-11-29: Simon Goldschmidt - * tcp_in.c: Fixed bug #28054: Two segments with FIN flag on the out-of- - sequence queue, also fixed PBUF_POOL leak in the out-of-sequence code - - 2009-11-29: Simon Goldschmidt - * pbuf.c: Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by - queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty - - 2009-11-26: Simon Goldschmidt - * tcp.h: Fixed bug #28098: Nagle can prevent fast retransmit from sending - segment - - 2009-11-26: Simon Goldschmidt - * tcp.h, sockets.c: Fixed bug #28099: API required to disable Nagle - algorithm at PCB level - - 2009-11-22: Simon Goldschmidt - * tcp_out.c: Fixed bug #27905: FIN isn't combined with data on unsent - - 2009-11-22: Simon Goldschmidt (suggested by Bill Auerbach) - * tcp.c: tcp_alloc: prevent increasing stats.err for MEMP_TCP_PCB when - reusing time-wait pcb - - 2009-11-20: Simon Goldschmidt (patch by Albert Bartel) - * sockets.c: Fixed bug #28062: Data received directly after accepting - does not wake up select - - 2009-11-11: Simon Goldschmidt - * netdb.h: Fixed bug #27994: incorrect define for freeaddrinfo(addrinfo) - - 2009-10-30: Simon Goldschmidt - * opt.h: Increased default value for TCP_MSS to 536, updated default - value for TCP_WND to 4*TCP_MSS to keep delayed ACK working. - - 2009-10-28: Kieran Mansley - * tcp_in.c, tcp_out.c, tcp.h: re-work the fast retransmission code - to follow algorithm from TCP/IP Illustrated - - 2009-10-27: Kieran Mansley - * tcp_in.c: fix BUG#27445: grow cwnd with every duplicate ACK - - 2009-10-25: Simon Goldschmidt - * tcp.h: bug-fix in the TCP_EVENT_RECV macro (has to call tcp_recved if - pcb->recv is NULL to keep rcv_wnd correct) - - 2009-10-25: Simon Goldschmidt - * tcp_in.c: Fixed bug #26251: RST process in TIME_WAIT TCP state - - 2009-10-23: Simon Goldschmidt (David Empson) - * tcp.c: Fixed bug #27783: Silly window avoidance for small window sizes - - 2009-10-21: Simon Goldschmidt - * tcp_in.c: Fixed bug #27215: TCP sent() callback gives leading and - trailing 1 byte len (SYN/FIN) - - 2009-10-21: Simon Goldschmidt - * tcp_out.c: Fixed bug #27315: zero window probe and FIN - - 2009-10-19: Simon Goldschmidt - * dhcp.c/.h: Minor code simplification (don't store received pbuf, change - conditional code to assert where applicable), check pbuf length before - testing for valid reply - - 2009-10-19: Simon Goldschmidt - * dhcp.c: Removed most calls to udp_connect since they aren't necessary - when using udp_sendto_if() - always stay connected to IP_ADDR_ANY. - - 2009-10-16: Simon Goldschmidt - * ip.c: Fixed bug #27390: Source IP check in ip_input() causes it to drop - valid DHCP packets -> allow 0.0.0.0 as source address when LWIP_DHCP is - enabled - - 2009-10-15: Simon Goldschmidt (Oleg Tyshev) - * tcp_in.c: Fixed bug #27329: dupacks by unidirectional data transmit - - 2009-10-15: Simon Goldschmidt - * api_lib.c: Fixed bug #27709: conn->err race condition on netconn_recv() - timeout - - 2009-10-15: Simon Goldschmidt - * autoip.c: Fixed bug #27704: autoip starts with wrong address - LWIP_AUTOIP_CREATE_SEED_ADDR() returned address in host byte order instead - of network byte order - - 2009-10-11 Simon Goldschmidt (Jörg Kesten) - * tcp_out.c: Fixed bug #27504: tcp_enqueue wrongly concatenates segments - which are not consecutive when retransmitting unacked segments - - 2009-10-09 Simon Goldschmidt - * opt.h: Fixed default values of some stats to only be enabled if used - Fixes bug #27338: sys_stats is defined when NO_SYS = 1 - - 2009-08-30 Simon Goldschmidt - * ip.c: Fixed bug bug #27345: "ip_frag() does not use the LWIP_NETIF_LOOPBACK - function" by checking for loopback before calling ip_frag - - 2009-08-25 Simon Goldschmidt - * dhcp.c: fixed invalid dependency to etharp_query if DHCP_DOES_ARP_CHECK==0 - - 2009-08-23 Simon Goldschmidt - * ppp.c: bug #27078: Possible memory leak in pppInit() - - 2009-08-23 Simon Goldschmidt - * netdb.c, dns.c: bug #26657: DNS, if host name is "localhost", result - is error. - - 2009-08-23 Simon Goldschmidt - * opt.h, init.c: bug #26649: TCP fails when TCP_MSS > TCP_SND_BUF - Fixed wrong parenthesis, added check in init.c - - 2009-08-23 Simon Goldschmidt - * ppp.c: bug #27266: wait-state debug message in pppMain occurs every ms - - 2009-08-23 Simon Goldschmidt - * many ppp files: bug #27267: Added include to string.h where needed - - 2009-08-23 Simon Goldschmidt - * tcp.h: patch #6843: tcp.h macro optimization patch (for little endian) - - -(STABLE-1.3.1) - - ++ New features: - - 2009-05-10 Simon Goldschmidt - * opt.h, sockets.c, pbuf.c, netbuf.h, pbuf.h: task #7013: Added option - LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only - one pbuf to help MACs that don't support scatter-gather DMA. - - 2009-05-09 Simon Goldschmidt - * icmp.h, icmp.c: Shrinked ICMP code, added option to NOT check icoming - ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN - - 2009-05-05 Simon Goldschmidt, Jakob Stoklund Olesen - * ip.h, ip.c: Added ip_current_netif() & ip_current_header() to receive - extended info about the currently received packet. - - 2009-04-27 Simon Goldschmidt - * sys.h: Made SYS_LIGHTWEIGHT_PROT and sys_now() work with NO_SYS=1 - - 2009-04-25 Simon Goldschmidt - * mem.c, opt.h: Added option MEM_USE_POOLS_TRY_BIGGER_POOL to try the next - bigger malloc pool if one is empty (only usable with MEM_USE_POOLS). - - 2009-04-21 Simon Goldschmidt - * dns.c, init.c, dns.h, opt.h: task #7507, patch #6786: DNS supports static - hosts table. New configuration options DNS_LOCAL_HOSTLIST and - DNS_LOCAL_HOSTLIST_IS_DYNAMIC. Also, DNS_LOOKUP_LOCAL_EXTERN() can be defined - as an external function for lookup. - - 2009-04-15 Simon Goldschmidt - * dhcp.c: patch #6763: Global DHCP XID can be redefined to something more unique - - 2009-03-31 Kieran Mansley - * tcp.c, tcp_out.c, tcp_in.c, sys.h, tcp.h, opts.h: add support for - TCP timestamp options, off by default. Rework tcp_enqueue() to - take option flags rather than specified option data - - 2009-02-18 Simon Goldschmidt - * cc.h: Added printf formatter for size_t: SZT_F - - 2009-02-16 Simon Goldschmidt (patch by Rishi Khan) - * icmp.c, opt.h: patch #6539: (configurable) response to broadcast- and multicast - pings - - 2009-02-12 Simon Goldschmidt - * init.h: Added LWIP_VERSION to get the current version of the stack - - 2009-02-11 Simon Goldschmidt (suggested by Gottfried Spitaler) - * opt.h, memp.h/.c: added MEMP_MEM_MALLOC to use mem_malloc/mem_free instead - of the pool allocator (can save code size with MEM_LIBC_MALLOC if libc-malloc - is otherwise used) - - 2009-01-28 Jonathan Larmour (suggested by Bill Bauerbach) - * ipv4/inet_chksum.c, ipv4/lwip/inet_chksum.h: inet_chksum_pseudo_partial() - is only used by UDPLITE at present, so conditionalise it. - - 2008-12-03 Simon Goldschmidt (base on patch from Luca Ceresoli) - * autoip.c: checked in (slightly modified) patch #6683: Customizable AUTOIP - "seed" address. This should reduce AUTOIP conflicts if - LWIP_AUTOIP_CREATE_SEED_ADDR is overridden. - - 2008-10-02 Jonathan Larmour and Rishi Khan - * sockets.c (lwip_accept): Return EWOULDBLOCK if would block on non-blocking - socket. - - 2008-06-30 Simon Goldschmidt - * mem.c, opt.h, stats.h: fixed bug #21433: Calling mem_free/pbuf_free from - interrupt context isn't safe: LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT allows - mem_free to run between mem_malloc iterations. Added illegal counter for - mem stats. - - 2008-06-27 Simon Goldschmidt - * stats.h/.c, some other files: patch #6483: stats module improvement: - Added defines to display each module's statistic individually, added stats - defines for MEM, MEMP and SYS modules, removed (unused) rexmit counter. - - 2008-06-17 Simon Goldschmidt - * err.h: patch #6459: Made err_t overridable to use a more efficient type - (define LWIP_ERR_T in cc.h) - - 2008-06-17 Simon Goldschmidt - * slipif.c: patch #6480: Added a configuration option for slipif for symmetry - to loopif - - 2008-06-17 Simon Goldschmidt (patch by Luca Ceresoli) - * netif.c, loopif.c, ip.c, netif.h, loopif.h, opt.h: Checked in slightly - modified version of patch # 6370: Moved loopif code to netif.c so that - loopback traffic is supported on all netifs (all local IPs). - Added option to limit loopback packets for each netifs. - - - ++ Bugfixes: - 2009-08-12 Kieran Mansley - * tcp_in.c, tcp.c: Fix bug #27209: handle trimming of segments when - out of window or out of order properly - - 2009-08-12 Kieran Mansley - * tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1 - - 2009-07-28 Simon Goldschmidt - * mem.h: Fixed bug #27105: "realloc() cannot replace mem_realloc()"s - - 2009-07-27 Kieran Mansley - * api.h api_msg.h netdb.h sockets.h: add missing #include directives - - 2009-07-09 Kieran Mansley - * api_msg.c, sockets.c, api.h: BUG23240 use signed counters for - recv_avail and don't increment counters until message successfully - sent to mbox - - 2009-06-25 Kieran Mansley - * api_msg.c api.h: BUG26722: initialise netconn write variables - in netconn_alloc - - 2009-06-25 Kieran Mansley - * tcp.h: BUG26879: set ret value in TCP_EVENT macros when function is not set - - 2009-06-25 Kieran Mansley - * tcp.c, tcp_in.c, tcp_out.c, tcp.h: BUG26301 and BUG26267: correct - simultaneous close behaviour, and make snd_nxt have the same meaning - as in the RFCs. - - 2009-05-12 Simon Goldschmidt - * etharp.h, etharp.c, netif.c: fixed bug #26507: "Gratuitous ARP depends on - arp_table / uses etharp_query" by adding etharp_gratuitous() - - 2009-05-12 Simon Goldschmidt - * ip.h, ip.c, igmp.c: bug #26487: Added ip_output_if_opt that can add IP options - to the IP header (used by igmp_ip_output_if) - - 2009-05-06 Simon Goldschmidt - * inet_chksum.c: On little endian architectures, use LWIP_PLATFORM_HTONS (if - defined) for SWAP_BYTES_IN_WORD to speed up checksumming. - - 2009-05-05 Simon Goldschmidt - * sockets.c: bug #26405: Prematurely released semaphore causes lwip_select() - to crash - - 2009-05-04 Simon Goldschmidt - * init.c: snmp was not initialized in lwip_init() - - 2009-05-04 Frédéric Bernon - * dhcp.c, netbios.c: Changes if IP_SOF_BROADCAST is enabled. - - 2009-05-03 Simon Goldschmidt - * tcp.h: bug #26349: Nagle algorithm doesn't send although segment is full - (and unsent->next == NULL) - - 2009-05-02 Simon Goldschmidt - * tcpip.h, tcpip.c: fixed tcpip_untimeout (does not need the time, broken after - 1.3.0 in CVS only) - fixes compilation of ppp_oe.c - - 2009-05-02 Simon Goldschmidt - * msg_in.c: fixed bug #25636: SNMPSET value is ignored for integer fields - - 2009-05-01 Simon Goldschmidt - * pap.c: bug #21680: PPP upap_rauthnak() drops legal NAK packets - - 2009-05-01 Simon Goldschmidt - * ppp.c: bug #24228: Memory corruption with PPP and DHCP - - 2009-04-29 Frédéric Bernon - * raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the - SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception - of broadcast packets even when this option wasn't set. Port maintainers - which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h. - If you want this option also filter broadcast on recv operations, you also - have to set IP_SOF_BROADCAST_RECV=1 in opt.h. - - 2009-04-28 Simon Goldschmidt, Jakob Stoklund Olesen - * dhcp.c: patch #6721, bugs #25575, #25576: Some small fixes to DHCP and - DHCP/AUTOIP cooperation - - 2009-04-25 Simon Goldschmidt, Oleg Tyshev - * tcp_out.c: bug #24212: Deadlocked tcp_retransmit due to exceeded pcb->cwnd - Fixed by sorting the unsent and unacked queues (segments are inserted at the - right place in tcp_output and tcp_rexmit). - - 2009-04-25 Simon Goldschmidt - * memp.c, mem.c, memp.h, mem_std.h: bug #26213 "Problem with memory allocation - when debugging": memp_sizes contained the wrong sizes (including sanity - regions); memp pools for MEM_USE_POOLS were too small - - 2009-04-24 Simon Goldschmidt, Frédéric Bernon - * inet.c: patch #6765: Fix a small problem with the last changes (incorrect - behavior, with with ip address string not ended by a '\0', a space or a - end of line) - - 2009-04-19 Simon Goldschmidt - * rawapi.txt: Fixed bug #26069: Corrected documentation: if tcp_connect fails, - pcb->err is called, not pcb->connected (with an error code). - - 2009-04-19 Simon Goldschmidt - * tcp_out.c: Fixed bug #26236: "TCP options (timestamp) don't work with - no-copy-tcpwrite": deallocate option data, only concat segments with same flags - - 2009-04-19 Simon Goldschmidt - * tcp_out.c: Fixed bug #25094: "Zero-length pbuf" (options are now allocated - in the header pbuf, not the data pbuf) - - 2009-04-18 Simon Goldschmidt - * api_msg.c: fixed bug #25695: Segmentation fault in do_writemore() - - 2009-04-15 Simon Goldschmidt - * sockets.c: tried to fix bug #23559: lwip_recvfrom problem with tcp - - 2009-04-15 Simon Goldschmidt - * dhcp.c: task #9192: mem_free of dhcp->options_in and dhcp->msg_in - - 2009-04-15 Simon Goldschmidt - * ip.c, ip6.c, tcp_out.c, ip.h: patch #6808: Add a utility function - ip_hinted_output() (for smaller code mainly) - - 2009-04-15 Simon Goldschmidt - * inet.c: patch #6765: Supporting new line characters in inet_aton() - - 2009-04-15 Simon Goldschmidt - * dhcp.c: patch #6764: DHCP rebind and renew did not send hostnam option; - Converted constant OPTION_MAX_MSG_SIZE to netif->mtu, check if netif->mtu - is big enough in dhcp_start - - 2009-04-15 Simon Goldschmidt - * netbuf.c: bug #26027: netbuf_chain resulted in pbuf memory leak - - 2009-04-15 Simon Goldschmidt - * sockets.c, ppp.c: bug #25763: corrected 4 occurrences of SMEMCPY to MEMCPY - - 2009-04-15 Simon Goldschmidt - * sockets.c: bug #26121: set_errno can be overridden - - 2009-04-09 Kieran Mansley (patch from Luca Ceresoli ) - * init.c, opt.h: Patch#6774 TCP_QUEUE_OOSEQ breaks compilation when - LWIP_TCP==0 - - 2009-04-09 Kieran Mansley (patch from Roy Lee ) - * tcp.h: Patch#6802 Add do-while-clauses to those function like - macros in tcp.h - - 2009-03-31 Kieran Mansley - * tcp.c, tcp_in.c, tcp_out.c, tcp.h, opt.h: Rework the way window - updates are calculated and sent (BUG20515) - - * tcp_in.c: cope with SYN packets received during established states, - and retransmission of initial SYN. - - * tcp_out.c: set push bit correctly when tcp segments are merged - - 2009-03-27 Kieran Mansley - * tcp_out.c set window correctly on probes (correcting change made - yesterday) - - 2009-03-26 Kieran Mansley - * tcp.c, tcp_in.c, tcp.h: add tcp_abandon() to cope with dropping - connections where no reset required (bug #25622) - - * tcp_out.c: set TCP_ACK flag on keepalive and zero window probes - (bug #20779) - - 2009-02-18 Simon Goldschmidt (Jonathan Larmour and Bill Auerbach) - * ip_frag.c: patch #6528: the buffer used for IP_FRAG_USES_STATIC_BUF could be - too small depending on MEM_ALIGNMENT - - 2009-02-16 Simon Goldschmidt - * sockets.h/.c, api_*.h/.c: fixed arguments of socket functions to match the standard; - converted size argument of netconn_write to 'size_t' - - 2009-02-16 Simon Goldschmidt - * tcp.h, tcp.c: fixed bug #24440: TCP connection close problem on 64-bit host - by moving accept callback function pointer to TCP_PCB_COMMON - - 2009-02-12 Simon Goldschmidt - * dhcp.c: fixed bug #25345 (DHCPDECLINE is sent with "Maximum message size" - option) - - 2009-02-11 Simon Goldschmidt - * dhcp.c: fixed bug #24480 (releasing old udp_pdb and pbuf in dhcp_start) - - 2009-02-11 Simon Goldschmidt - * opt.h, api_msg.c: added configurable default valud for netconn->recv_bufsize: - RECV_BUFSIZE_DEFAULT (fixes bug #23726: pbuf pool exhaustion on slow recv()) - - 2009-02-10 Simon Goldschmidt - * tcp.c: fixed bug #25467: Listen backlog is not reset on timeout in SYN_RCVD: - Accepts_pending is decrease on a corresponding listen pcb when a connection - in state SYN_RCVD is close. - - 2009-01-28 Jonathan Larmour - * pbuf.c: reclaim pbufs from TCP out-of-sequence segments if we run - out of pool pbufs. - - 2008-12-19 Simon Goldschmidt - * many files: patch #6699: fixed some warnings on platform where sizeof(int) == 2 - - 2008-12-10 Tamas Somogyi, Frédéric Bernon - * sockets.c: fixed bug #25051: lwip_recvfrom problem with udp: fromaddr and - port uses deleted netbuf. - - 2008-10-18 Simon Goldschmidt - * tcp_in.c: fixed bug ##24596: Vulnerability on faulty TCP options length - in tcp_parseopt - - 2008-10-15 Simon Goldschmidt - * ip_frag.c: fixed bug #24517: IP reassembly crashes on unaligned IP headers - by packing the struct ip_reass_helper. - - 2008-10-03 David Woodhouse, Jonathan Larmour - * etharp.c (etharp_arp_input): Fix type aliasing problem copying ip address. - - 2008-10-02 Jonathan Larmour - * dns.c: Hard-code structure sizes, to avoid issues on some compilers where - padding is included. - - 2008-09-30 Jonathan Larmour - * sockets.c (lwip_accept): check addr isn't NULL. If it's valid, do an - assertion check that addrlen isn't NULL. - - 2008-09-30 Jonathan Larmour - * tcp.c: Fix bug #24227, wrong error message in tcp_bind. - - 2008-08-26 Simon Goldschmidt - * inet.h, ip_addr.h: fixed bug #24132: Cross-dependency between ip_addr.h and - inet.h -> moved declaration of struct in_addr from ip_addr.h to inet.h - - 2008-08-14 Simon Goldschmidt - * api_msg.c: fixed bug #23847: do_close_internal references freed memory (when - tcp_close returns != ERR_OK) - - 2008-07-08 Frédéric Bernon - * stats.h: Fix some build bugs introduced with patch #6483 (missing some parameters - in macros, mainly if MEM_STATS=0 and MEMP_STATS=0). - - 2008-06-24 Jonathan Larmour - * tcp_in.c: Fix for bug #23693 as suggested by Art R. Ensure cseg is unused - if tcp_seg_copy fails. - - 2008-06-17 Simon Goldschmidt - * inet_chksum.c: Checked in some ideas of patch #6460 (loop optimizations) - and created defines for swapping bytes and folding u32 to u16. - - 2008-05-30 Kieran Mansley - * tcp_in.c Remove redundant "if" statement, and use real rcv_wnd - rather than rcv_ann_wnd when deciding if packets are in-window. - Contributed by - - 2008-05-30 Kieran Mansley - * mem.h: Fix BUG#23254. Change macro definition of mem_* to allow - passing as function pointers when MEM_LIBC_MALLOC is defined. - - 2008-05-09 Jonathan Larmour - * err.h, err.c, sockets.c: Fix bug #23119: Reorder timeout error code to - stop it being treated as a fatal error. - - 2008-04-15 Simon Goldschmidt - * dhcp.c: fixed bug #22804: dhcp_stop doesn't clear NETIF_FLAG_DHCP - (flag now cleared) - - 2008-03-27 Simon Goldschmidt - * mem.c, tcpip.c, tcpip.h, opt.h: fixed bug #21433 (Calling mem_free/pbuf_free - from interrupt context isn't safe): set LWIP_USE_HEAP_FROM_INTERRUPT to 1 - in lwipopts.h or use pbuf_free_callback(p)/mem_free_callback(m) to free pbufs - or heap memory from interrupt context - - 2008-03-26 Simon Goldschmidt - * tcp_in.c, tcp.c: fixed bug #22249: division by zero could occur if a remote - host sent a zero mss as TCP option. - - -(STABLE-1.3.0) - - ++ New features: - - 2008-03-10 Jonathan Larmour - * inet_chksum.c: Allow choice of one of the sample algorithms to be - made from lwipopts.h. Fix comment on how to override LWIP_CHKSUM. - - 2008-01-22 Frédéric Bernon - * tcp.c, tcp_in.c, tcp.h, opt.h: Rename LWIP_CALCULATE_EFF_SEND_MSS in - TCP_CALCULATE_EFF_SEND_MSS to have coherent TCP options names. - - 2008-01-14 Frédéric Bernon - * rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable - to refuse data on a TCP_EVENT_RECV call". Important, behavior changes for the - tcp_recv callback (see rawapi.txt). - - 2008-01-14 Frédéric Bernon, Marc Chaland - * ip.c: Integrate patch #6369" ip_input : checking before realloc". - - 2008-01-12 Frédéric Bernon - * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field - netconn::sem per netconn::op_completed like suggested for the task #7490 - "Add return value to sys_mbox_post". - - 2008-01-12 Frédéric Bernon - * api_msg.c, opt.h: replace DEFAULT_RECVMBOX_SIZE per DEFAULT_TCP_RECVMBOX_SIZE, - DEFAULT_UDP_RECVMBOX_SIZE and DEFAULT_RAW_RECVMBOX_SIZE (to optimize queues - sizes), like suggested for the task #7490 "Add return value to sys_mbox_post". - - 2008-01-10 Frédéric Bernon - * tcpip.h, tcpip.c: add tcpip_callback_with_block function for the task #7490 - "Add return value to sys_mbox_post". tcpip_callback is always defined as - "blocking" ("block" parameter = 1). - - 2008-01-10 Frédéric Bernon - * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field - netconn::mbox (sys_mbox_t) per netconn::sem (sys_sem_t) for the task #7490 - "Add return value to sys_mbox_post". - - 2008-01-05 Frédéric Bernon - * sys_arch.txt, api.h, api_lib.c, api_msg.h, api_msg.c, tcpip.c, sys.h, opt.h: - Introduce changes for task #7490 "Add return value to sys_mbox_post" with some - modifications in the sys_mbox api: sys_mbox_new take a "size" parameters which - indicate the number of pointers query by the mailbox. There is three defines - in opt.h to indicate sizes for tcpip::mbox, netconn::recvmbox, and for the - netconn::acceptmbox. Port maintainers, you can decide to just add this new - parameter in your implementation, but to ignore it to keep the previous behavior. - The new sys_mbox_trypost function return a value to know if the mailbox is - full or if the message is posted. Take a look to sys_arch.txt for more details. - This new function is used in tcpip_input (so, can be called in an interrupt - context since the function is not blocking), and in recv_udp and recv_raw. - - 2008-01-04 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour - * rawapi.txt, api.h, api_lib.c, api_msg.h, api_msg.c, sockets.c, tcp.h, tcp.c, - tcp_in.c, init.c, opt.h: rename backlog options with TCP_ prefix, limit the - "backlog" parameter in an u8_t, 0 is interpreted as "smallest queue", add - documentation in the rawapi.txt file. - - 2007-12-31 Kieran Mansley (based on patch from Per-Henrik Lundbolm) - * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Add TCP persist timer - - 2007-12-31 Frédéric Bernon, Luca Ceresoli - * autoip.c, etharp.c: ip_addr.h: Integrate patch #6348: "Broadcast ARP packets - in autoip". The change in etharp_raw could be removed, since all calls to - etharp_raw use ethbroadcast for the "ethdst_addr" parameter. But it could be - wrong in the future. - - 2007-12-30 Frédéric Bernon, Tom Evans - * ip.c: Fix bug #21846 "LwIP doesn't appear to perform any IP Source Address - Filtering" reported by Tom Evans. - - 2007-12-21 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour - * tcp.h, opt.h, api.h, api_msg.h, tcp.c, tcp_in.c, api_lib.c, api_msg.c, - sockets.c, init.c: task #7252: Implement TCP listen backlog: Warning: raw API - applications have to call 'tcp_accepted(pcb)' in their accept callback to - keep accepting new connections. - - 2007-12-13 Frédéric Bernon - * api_msg.c, err.h, err.c, sockets.c, dns.c, dns.h: replace "enum dns_result" - by err_t type. Add a new err_t code "ERR_INPROGRESS". - - 2007-12-12 Frédéric Bernon - * dns.h, dns.c, opt.h: move DNS options to the "right" place. Most visibles - are the one which have ram usage. - - 2007-12-05 Frédéric Bernon - * netdb.c: add a LWIP_DNS_API_HOSTENT_STORAGE option to decide to use a static - set of variables (=0) or a local one (=1). In this last case, your port should - provide a function "struct hostent* sys_thread_hostent( struct hostent* h)" - which have to do a copy of "h" and return a pointer ont the "per-thread" copy. - - 2007-12-03 Simon Goldschmidt - * ip.c: ip_input: check if a packet is for inp first before checking all other - netifs on netif_list (speeds up packet receiving in most cases) - - 2007-11-30 Simon Goldschmidt - * udp.c, raw.c: task #7497: Sort lists (pcb, netif, ...) for faster access - UDP: move a (connected) pcb selected for input to the front of the list of - pcbs so that it is found faster next time. Same for RAW pcbs that have eaten - a packet. - - 2007-11-28 Simon Goldschmidt - * etharp.c, stats.c, stats.h, opt.h: Introduced ETHARP_STATS - - 2007-11-25 Simon Goldschmidt - * dhcp.c: dhcp_unfold_reply() uses pbuf_copy_partial instead of its own copy - algorithm. - - 2007-11-24 Simon Goldschmidt - * netdb.h, netdb.c, sockets.h/.c: Moved lwip_gethostbyname from sockets.c - to the new file netdb.c; included lwip_getaddrinfo. - - 2007-11-21 Simon Goldschmidt - * tcp.h, opt.h, tcp.c, tcp_in.c: implemented calculating the effective send-mss - based on the MTU of the netif used to send. Enabled by default. Disable by - setting LWIP_CALCULATE_EFF_SEND_MSS to 0. This fixes bug #21492. - - 2007-11-19 Frédéric Bernon - * api_msg.c, dns.h, dns.c: Implement DNS_DOES_NAME_CHECK option (check if name - received match the name query), implement DNS_USES_STATIC_BUF (the place where - copy dns payload to parse the response), return an error if there is no place - for a new query, and fix some minor problems. - - 2007-11-16 Simon Goldschmidt - * new files: ipv4/inet.c, ipv4/inet_chksum.c, ipv6/inet6.c - removed files: core/inet.c, core/inet6.c - Moved inet files into ipv4/ipv6 directory; splitted inet.c/inet.h into - inet and chksum part; changed includes in all lwIP files as appropriate - - 2007-11-16 Simon Goldschmidt - * api.h, api_msg.h, api_lib.c, api_msg.c, socket.h, socket.c: Added sequential - dns resolver function for netconn api (netconn_gethostbyname) and socket api - (gethostbyname/gethostbyname_r). - - 2007-11-15 Jim Pettinato, Frédéric Bernon - * opt.h, init.c, tcpip.c, dhcp.c, dns.h, dns.c: add DNS client for simple name - requests with RAW api interface. Initialization is done in lwip_init() with - build time options. DNS timer is added in tcpip_thread context. DHCP can set - DNS server ip addresses when options are received. You need to set LWIP_DNS=1 - in your lwipopts.h file (LWIP_DNS=0 in opt.h). DNS_DEBUG can be set to get - some traces with LWIP_DEBUGF. Sanity check have been added. There is a "todo" - list with points to improve. - - 2007-11-06 Simon Goldschmidt - * opt.h, mib2.c: Patch #6215: added ifAdminStatus write support (if explicitly - enabled by defining SNMP_SAFE_REQUESTS to 0); added code to check link status - for ifOperStatus if LWIP_NETIF_LINK_CALLBACK is defined. - - 2007-11-06 Simon Goldschmidt - * api.h, api_msg.h and dependent files: Task #7410: Removed the need to include - core header files in api.h (ip/tcp/udp/raw.h) to hide the internal - implementation from netconn api applications. - - 2007-11-03 Frédéric Bernon - * api.h, api_lib.c, api_msg.c, sockets.c, opt.h: add SO_RCVBUF option for UDP & - RAW netconn. You need to set LWIP_SO_RCVBUF=1 in your lwipopts.h (it's disabled - by default). Netconn API users can use the netconn_recv_bufsize macro to access - it. This is a first release which have to be improve for TCP. Note it used the - netconn::recv_avail which need to be more "thread-safe" (note there is already - the problem for FIONREAD with lwip_ioctl/ioctlsocket). - - 2007-11-01 Frédéric Bernon, Marc Chaland - * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, tcp.h, tcp_out.c: - Integrate "patch #6250 : MSG_MORE flag for send". MSG_MORE is used at socket api - layer, NETCONN_MORE at netconn api layer, and TCP_WRITE_FLAG_MORE at raw api - layer. This option enable to delayed TCP PUSH flag on multiple "write" calls. - Note that previous "copy" parameter for "write" APIs is now called "apiflags". - - 2007-10-24 Frédéric Bernon - * api.h, api_lib.c, api_msg.c: Add macro API_EVENT in the same spirit than - TCP_EVENT_xxx macros to get a code more readable. It could also help to remove - some code (like we have talk in "patch #5919 : Create compile switch to remove - select code"), but it could be done later. - - 2007-10-08 Simon Goldschmidt - * many files: Changed initialization: many init functions are not needed any - more since we now rely on the compiler initializing global and static - variables to zero! - - 2007-10-06 Simon Goldschmidt - * ip_frag.c, memp.c, mib2.c, ip_frag.h, memp_std.h, opt.h: Changed IP_REASSEMBLY - to enqueue the received pbufs so that multiple packets can be reassembled - simultaneously and no static reassembly buffer is needed. - - 2007-10-05 Simon Goldschmidt - * tcpip.c, etharp.h, etharp.c: moved ethernet_input from tcpip.c to etharp.c so - all netifs (or ports) can use it. - - 2007-10-05 Frédéric Bernon - * netifapi.h, netifapi.c: add function netifapi_netif_set_default. Change the - common function to reduce a little bit the footprint (for all functions using - only the "netif" parameter). - - 2007-10-03 Frédéric Bernon - * netifapi.h, netifapi.c: add functions netifapi_netif_set_up, netifapi_netif_set_down, - netifapi_autoip_start and netifapi_autoip_stop. Use a common function to reduce - a little bit the footprint (for all functions using only the "netif" parameter). - - 2007-09-15 Frédéric Bernon - * udp.h, udp.c, sockets.c: Changes for "#20503 IGMP Improvement". Add IP_MULTICAST_IF - option in socket API, and a new field "multicast_ip" in "struct udp_pcb" (for - netconn and raw API users), only if LWIP_IGMP=1. Add getsockopt processing for - IP_MULTICAST_TTL and IP_MULTICAST_IF. - - 2007-09-10 Frédéric Bernon - * snmp.h, mib2.c: enable to remove SNMP timer (which consumne several cycles - even when it's not necessary). snmp_agent.txt tell to call snmp_inc_sysuptime() - each 10ms (but, it's intrusive if you use sys_timeout feature). Now, you can - decide to call snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but - call to a lower frequency). Or, you can decide to not call snmp_inc_sysuptime() - or snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro. - This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside - snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only - when it's queried (any direct call to "sysuptime" is changed by a call to - snmp_get_sysuptime). - - 2007-09-09 Frédéric Bernon, Bill Florac - * igmp.h, igmp.c, netif.h, netif.c, ip.c: To enable to have interfaces with IGMP, - and others without it, there is a new NETIF_FLAG_IGMP flag to set in netif->flags - if you want IGMP on an interface. igmp_stop() is now called inside netif_remove(). - igmp_report_groups() is now called inside netif_set_link_up() (need to have - LWIP_NETIF_LINK_CALLBACK=1) to resend reports once the link is up (avoid to wait - the next query message to receive the matching multicast streams). - - 2007-09-08 Frédéric Bernon - * sockets.c, ip.h, api.h, tcp.h: declare a "struct ip_pcb" which only contains - IP_PCB. Add in the netconn's "pcb" union a "struct ip_pcb *ip;" (no size change). - Use this new field to access to common pcb fields (ttl, tos, so_options, etc...). - Enable to access to these fields with LWIP_TCP=0. - - 2007-09-05 Frédéric Bernon - * udp.c, ipv4/icmp.c, ipv4/ip.c, ipv6/icmp.c, ipv6/ip6.c, ipv4/icmp.h, - ipv6/icmp.h, opt.h: Integrate "task #7272 : LWIP_ICMP option". The new option - LWIP_ICMP enable/disable ICMP module inside the IP stack (enable per default). - Be careful, disabling ICMP make your product non-compliant to RFC1122, but - help to reduce footprint, and to reduce "visibility" on the Internet. - - 2007-09-05 Frédéric Bernon, Bill Florac - * opt.h, sys.h, tcpip.c, slipif.c, ppp.c, sys_arch.txt: Change parameters list - for sys_thread_new (see "task #7252 : Create sys_thread_new_ex()"). Two new - parameters have to be provided: a task name, and a task stack size. For this - one, since it's platform dependant, you could define the best one for you in - your lwipopts.h. For port maintainers, you can just add these new parameters - in your sys_arch.c file, and but it's not mandatory, use them in your OS - specific functions. - - 2007-09-05 Frédéric Bernon - * inet.c, autoip.c, msg_in.c, msg_out.c, init.c: Move some build time checkings - inside init.c for task #7142 "Sanity check user-configurable values". - - 2007-09-04 Frédéric Bernon, Bill Florac - * igmp.h, igmp.c, memp_std.h, memp.c, init.c, opt.h: Replace mem_malloc call by - memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the - value). It will avoid potential fragmentation problems, use a counter to know - how many times a group is used on an netif, and free it when all applications - leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity - check if LWIP_IGMP!=0). - - 2007-09-03 Frédéric Bernon - * igmp.h, igmp.c, sockets.c, api_msg.c: Changes for "#20503 IGMP Improvement". - Initialize igmp_mac_filter to NULL in netif_add (this field should be set in - the netif's "init" function). Use the "imr_interface" field (for socket layer) - and/or the "interface" field (for netconn layer), for join/leave operations. - The igmp_join/leavegroup first parameter change from a netif to an ipaddr. - This field could be a netif's ipaddr, or "any" (same meaning than ip_addr_isany). - - 2007-08-30 Frédéric Bernon - * Add netbuf.h, netbuf.c, Change api.h, api_lib.c: #7249 "Split netbuf functions - from api/api_lib". Now netbuf API is independant of netconn, and can be used - with other API (application based on raw API, or future "socket2" API). Ports - maintainers just have to add src/api/netbuf.c in their makefile/projects. - - 2007-08-30 Frédéric Bernon, Jonathan Larmour - * init.c: Add first version of lwip_sanity_check for task #7142 "Sanity check - user-configurable values". - - 2007-08-29 Frédéric Bernon - * igmp.h, igmp.c, tcpip.c, init.c, netif.c: change igmp_init and add igmp_start. - igmp_start is call inside netif_add. Now, igmp initialization is in the same - spirit than the others modules. Modify some IGMP debug traces. - - 2007-08-29 Frédéric Bernon - * Add init.h, init.c, Change opt.h, tcpip.c: Task #7213 "Add a lwip_init function" - Add lwip_init function to regroup all modules initializations, and to provide - a place to add code for task #7142 "Sanity check user-configurable values". - Ports maintainers should remove direct initializations calls from their code, - and add init.c in their makefiles. Note that lwip_init() function is called - inside tcpip_init, but can also be used by raw api users since all calls are - disabled when matching options are disabled. Also note that their is new options - in opt.h, you should configure in your lwipopts.h (they are enabled per default). - - 2007-08-26 Marc Boucher - * api_msg.c: do_close_internal(): Reset the callbacks and arg (conn) to NULL - since they can under certain circumstances be called with an invalid conn - pointer after the connection has been closed (and conn has been freed). - - 2007-08-25 Frédéric Bernon (Artem Migaev's Patch) - * netif.h, netif.c: Integrate "patch #6163 : Function to check if link layer is up". - Add a netif_is_link_up() function if LWIP_NETIF_LINK_CALLBACK option is set. - - 2007-08-22 Frédéric Bernon - * netif.h, netif.c, opt.h: Rename LWIP_NETIF_CALLBACK in LWIP_NETIF_STATUS_CALLBACK - to be coherent with new LWIP_NETIF_LINK_CALLBACK option before next release. - - 2007-08-22 Frédéric Bernon - * tcpip.h, tcpip.c, ethernetif.c, opt.h: remove options ETHARP_TCPIP_INPUT & - ETHARP_TCPIP_ETHINPUT, now, only "ethinput" code is supported, even if the - name is tcpip_input (we keep the name of 1.2.0 function). - - 2007-08-17 Jared Grubb - * memp_std.h, memp.h, memp.c, mem.c, stats.c: (Task #7136) Centralize mempool - settings into new memp_std.h and optional user file lwippools.h. This adds - more dynamic mempools, and allows the user to create an arbitrary number of - mempools for mem_malloc. - - 2007-08-16 Marc Boucher - * api_msg.c: Initialize newconn->state to NETCONN_NONE in accept_function; - otherwise it was left to NETCONN_CLOSE and sent_tcp() could prematurely - close the connection. - - 2007-08-16 Marc Boucher - * sockets.c: lwip_accept(): check netconn_peer() error return. - - 2007-08-16 Marc Boucher - * mem.c, mem.h: Added mem_calloc(). - - 2007-08-16 Marc Boucher - * tcpip.c, tcpip.h memp.c, memp.h: Added distinct memp (MEMP_TCPIP_MSG_INPKT) - for input packets to prevent floods from consuming all of MEMP_TCPIP_MSG - and starving other message types. - Renamed MEMP_TCPIP_MSG to MEMP_TCPIP_MSG_API - - 2007-08-16 Marc Boucher - * pbuf.c, pbuf.h, etharp.c, tcp_in.c, sockets.c: Split pbuf flags in pbuf - type and flgs (later renamed to flags). - Use enum pbuf_flag as pbuf_type. Renumber PBUF_FLAG_*. - Improved lwip_recvfrom(). TCP push now propagated. - - 2007-08-16 Marc Boucher - * ethernetif.c, contrib/ports/various: ethbroadcast now a shared global - provided by etharp. - - 2007-08-16 Marc Boucher - * ppp_oe.c ppp_oe.h, auth.c chap.c fsm.c lcp.c ppp.c ppp.h, - etharp.c ethernetif.c, etharp.h, opt.h tcpip.h, tcpip.c: - Added PPPoE support and various PPP improvements. - - 2007-07-25 Simon Goldschmidt - * api_lib.c, ip_frag.c, pbuf.c, api.h, pbuf.h: Introduced pbuf_copy_partial, - making netbuf_copy_partial use this function. - - 2007-07-25 Simon Goldschmidt - * tcp_in.c: Fix bug #20506: Slow start / initial congestion window starts with - 2 * mss (instead of 1 * mss previously) to comply with some newer RFCs and - other stacks. - - 2007-07-13 Jared Grubb (integrated by Frédéric Bernon) - * opt.h, netif.h, netif.c, ethernetif.c: Add new configuration option to add - a link callback in the netif struct, and functions to handle it. Be carefull - for port maintainers to add the NETIF_FLAG_LINK_UP flag (like in ethernetif.c) - if you want to be sure to be compatible with future changes... - - 2007-06-30 Frédéric Bernon - * sockets.h, sockets.c: Implement MSG_PEEK flag for recv/recvfrom functions. - - 2007-06-21 Simon Goldschmidt - * etharp.h, etharp.c: Combined etharp_request with etharp_raw for both - LWIP_AUTOIP =0 and =1 to remove redundant code. - - 2007-06-21 Simon Goldschmidt - * mem.c, memp.c, mem.h, memp.h, opt.h: task #6863: Introduced the option - MEM_USE_POOLS to use 4 pools with different sized elements instead of a - heap. This both prevents memory fragmentation and gives a higher speed - at the cost of more memory consumption. Turned off by default. - - 2007-06-21 Simon Goldschmidt - * api_lib.c, api_msg.c, api.h, api_msg.h: Converted the length argument of - netconn_write (and therefore also api_msg_msg.msg.w.len) from u16_t into - int to be able to send a bigger buffer than 64K with one time (mainly - used from lwip_send). - - 2007-06-21 Simon Goldschmidt - * tcp.h, api_msg.c: Moved the nagle algorithm from netconn_write/do_write - into a define (tcp_output_nagle) in tcp.h to provide it to raw api users, too. - - 2007-06-21 Simon Goldschmidt - * api.h, api_lib.c, api_msg.c: Fixed bug #20021: Moved sendbuf-processing in - netconn_write from api_lib.c to api_msg.c to also prevent multiple context- - changes on low memory or empty send-buffer. - - 2007-06-18 Simon Goldschmidt - * etharp.c, etharp.h: Changed etharp to use a defined hardware address length - of 6 to avoid loading netif->hwaddr_len every time (since this file is only - used for ethernet and struct eth_addr already had a defined length of 6). - - 2007-06-17 Simon Goldschmidt - * sockets.c, sockets.h: Implemented socket options SO_NO_CHECK for UDP sockets - to disable UDP checksum generation on transmit. - - 2007-06-13 Frédéric Bernon, Simon Goldschmidt - * debug.h, api_msg.c: change LWIP_ERROR to use it to check errors like invalid - pointers or parameters, and let the possibility to redefined it in cc.h. Use - this macro to check "conn" parameter in api_msg.c functions. - - 2007-06-11 Simon Goldschmidt - * sockets.c, sockets.h: Added UDP lite support for sockets - - 2007-06-10 Simon Goldschmidt - * udp.h, opt.h, api_msg.c, ip.c, udp.c: Included switch LWIP_UDPLITE (enabled - by default) to switch off UDP-Lite support if not needed (reduces udp.c code - size) - - 2007-06-09 Dominik Spies (integrated by Frédéric Bernon) - * autoip.h, autoip.c, dhcp.h, dhcp.c, netif.h, netif.c, etharp.h, etharp.c, opt.h: - AutoIP implementation available for IPv4, with new options LWIP_AUTOIP and - LWIP_DHCP_AUTOIP_COOP if you want to cooperate with DHCP. Some tips to adapt - (see TODO mark in the source code). - - 2007-06-09 Simon Goldschmidt - * etharp.h, etharp.c, ethernetif.c: Modified order of parameters for - etharp_output() to match netif->output so etharp_output() can be used - directly as netif->output to save one function call. - - 2007-06-08 Simon Goldschmidt - * netif.h, ethernetif.c, slipif.c, loopif.c: Added define - NETIF_INIT_SNMP(netif, type, speed) to initialize per-netif snmp variables, - added initialization of those to ethernetif, slipif and loopif. - - 2007-05-18 Simon Goldschmidt - * opt.h, ip_frag.c, ip_frag.h, ip.c: Added option IP_FRAG_USES_STATIC_BUF - (defaulting to off for now) that can be set to 0 to send fragmented - packets by passing PBUF_REFs down the stack. - - 2007-05-23 Frédéric Bernon - * api_lib.c: Implement SO_RCVTIMEO for accept and recv on TCP - connections, such present in patch #5959. - - 2007-05-23 Frédéric Bernon - * api.h, api_lib.c, api_msg.c, sockets.c: group the different NETCONN_UDPxxx - code in only one part... - - 2007-05-18 Simon Goldschmidt - * opt.h, memp.h, memp.c: Added option MEMP_OVERFLOW_CHECK to check for memp - elements to overflow. This is achieved by adding some bytes before and after - each pool element (increasing their size, of course), filling them with a - prominent value and checking them on freeing the element. - Set it to 2 to also check every element in every pool each time memp_malloc() - or memp_free() is called (slower but more helpful). - - 2007-05-10 Simon Goldschmidt - * opt.h, memp.h, memp.c, pbuf.c (see task #6831): use a new memp pool for - PBUF_POOL pbufs instead of the old pool implementation in pbuf.c to reduce - code size. - - 2007-05-11 Frédéric Bernon - * sockets.c, api_lib.c, api_msg.h, api_msg.c, netifapi.h, netifapi.c, tcpip.c: - Include a function pointer instead of a table index in the message to reduce - footprint. Disable some part of lwip_send and lwip_sendto if some options are - not set (LWIP_TCP, LWIP_UDP, LWIP_RAW). - - 2007-05-10 Simon Goldschmidt - * *.h (except netif/ppp/*.h): Included patch #5448: include '#ifdef __cplusplus - \ extern "C" {' in all header files. Now you can write your application using - the lwIP stack in C++ and simply #include the core files. Note I have left - out the netif/ppp/*h header files for now, since I don't know which files are - included by applications and which are for internal use only. - - 2007-05-09 Simon Goldschmidt - * opt.h, *.c/*.h: Included patch #5920: Create define to override C-library - memcpy. 2 Defines are created: MEMCPY() for normal memcpy, SMEMCPY() for - situations where some compilers might inline the copy and save a function - call. Also replaced all calls to memcpy() with calls to (S)MEMCPY(). - - 2007-05-08 Simon Goldschmidt - * mem.h: If MEM_LIBC_MALLOC==1, allow the defines (e.g. mem_malloc() -> malloc()) - to be overriden in case the C-library malloc implementation is not protected - against concurrent access. - - 2007-05-04 Simon Goldschmidt (Atte Kojo) - * etharp.c: Introduced fast one-entry-cache to speed up ARP lookup when sending - multiple packets to the same host. - - 2007-05-04 Frédéric Bernon, Jonathan Larmour - * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fix bug #19162 "lwip_sento: a possible - to corrupt remote addr/port connection state". Reduce problems "not enought memory" with - netbuf (if we receive lot of datagrams). Improve lwip_sendto (only one exchange between - sockets api and api_msg which run in tcpip_thread context). Add netconn_sento function. - Warning, if you directly access to "fromaddr" & "fromport" field from netbuf struct, - these fields are now renamed "addr" & "port". - - 2007-04-11 Jonathan Larmour - * sys.h, api_lib.c: Provide new sys_mbox_tryfetch function. Require ports to provide new - sys_arch_mbox_tryfetch function to get a message if one is there, otherwise return - with SYS_MBOX_EMPTY. sys_arch_mbox_tryfetch can be implemented as a function-like macro - by the port in sys_arch.h if desired. - - 2007-04-06 Frédéric Bernon, Simon Goldschmidt - * opt.h, tcpip.h, tcpip.c, netifapi.h, netifapi.c: New configuration option LWIP_NETIF_API - allow to use thread-safe functions to add/remove netif in list, and to start/stop dhcp - clients, using new functions from netifapi.h. Disable as default (no port change to do). - - 2007-04-05 Frédéric Bernon - * sockets.c: remplace ENOBUFS errors on alloc_socket by ENFILE to be more BSD compliant. - - 2007-04-04 Simon Goldschmidt - * arch.h, api_msg.c, dhcp.c, msg_in.c, sockets.c: Introduced #define LWIP_UNUSED_ARG(x) - use this for and architecture-independent form to tell the compiler you intentionally - are not using this variable. Can be overriden in cc.h. - - 2007-03-28 Frédéric Bernon - * opt.h, netif.h, dhcp.h, dhcp.c: New configuration option LWIP_NETIF_HOSTNAME allow to - define a hostname in netif struct (this is just a pointer, so, you can use a hardcoded - string, point on one of your's ethernetif field, or alloc a string you will free yourself). - It will be used by DHCP to register a client hostname, but can also be use when you call - snmp_set_sysname. - - 2007-03-28 Frédéric Bernon - * netif.h, netif.c: A new NETIF_FLAG_ETHARP flag is defined in netif.h, to allow to - initialize a network interface's flag with. It tell this interface is an ethernet - device, and we can use ARP with it to do a "gratuitous ARP" (RFC 3220 "IP Mobility - Support for IPv4" section 4.6) when interface is "up" with netif_set_up(). - - 2007-03-26 Frédéric Bernon, Jonathan Larmour - * opt.h, tcpip.c: New configuration option LWIP_ARP allow to disable ARP init at build - time if you only use PPP or SLIP. The default is enable. Note we don't have to call - etharp_init in your port's initilization sequence if you use tcpip.c, because this call - is done in tcpip_init function. - - 2007-03-22 Frédéric Bernon - * stats.h, stats.c, msg_in.c: Stats counters can be change to u32_t if necessary with the - new option LWIP_STATS_LARGE. If you need this option, define LWIP_STATS_LARGE to 1 in - your lwipopts.h. More, unused counters are not defined in the stats structs, and not - display by stats_display(). Note that some options (SYS_STATS and RAW_STATS) are defined - but never used. Fix msg_in.c with the correct #if test for a stat display. - - 2007-03-21 Kieran Mansley - * netif.c, netif.h: Apply patch#4197 with some changes (originator: rireland@hmgsl.com). - Provides callback on netif up/down state change. - - 2007-03-11 Frédéric Bernon, Mace Gael, Steve Reynolds - * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, igmp.h, igmp.c, - ip.c, netif.h, tcpip.c, opt.h: - New configuration option LWIP_IGMP to enable IGMP processing. Based on only one - filter per all network interfaces. Declare a new function in netif to enable to - control the MAC filter (to reduce lwIP traffic processing). - - 2007-03-11 Frédéric Bernon - * tcp.h, tcp.c, sockets.c, tcp_out.c, tcp_in.c, opt.h: Keepalive values can - be configured at run time with LWIP_TCP_KEEPALIVE, but don't change this - unless you know what you're doing (default are RFC1122 compliant). Note - that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set in seconds. - - 2007-03-08 Frédéric Bernon - * tcp.h: Keepalive values can be configured at compile time, but don't change - this unless you know what you're doing (default are RFC1122 compliant). - - 2007-03-08 Frédéric Bernon - * sockets.c, api.h, api_lib.c, tcpip.c, sys.h, sys.c, err.c, opt.h: - Implement LWIP_SO_RCVTIMEO configuration option to enable/disable SO_RCVTIMEO - on UDP sockets/netconn. - - 2007-03-08 Simon Goldschmidt - * snmp_msg.h, msg_in.c: SNMP UDP ports can be configured at compile time. - - 2007-03-06 Frédéric Bernon - * api.h, api_lib.c, sockets.h, sockets.c, tcpip.c, sys.h, sys.c, err.h: - Implement SO_RCVTIMEO on UDP sockets/netconn. - - 2007-02-28 Kieran Mansley (based on patch from Simon Goldschmidt) - * api_lib.c, tcpip.c, memp.c, memp.h: make API msg structs allocated - on the stack and remove the API msg type from memp - - 2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) - * sockets.h, sockets.c: Move socket initialization to new - lwip_socket_init() function. - NOTE: this changes the API with ports. Ports will have to be - updated to call lwip_socket_init() now. - - 2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) - * api_lib.c: Use memcpy in netbuf_copy_partial. - - - ++ Bug fixes: - - 2008-03-17 Frédéric Bernon, Ed Kerekes - * igmp.h, igmp.c: Fix bug #22613 "IGMP iphdr problem" (could have - some problems to fill the IP header on some targets, use now the - ip.h macros to do it). - - 2008-03-13 Frédéric Bernon - * sockets.c: Fix bug #22435 "lwip_recvfrom with TCP break;". Using - (lwip_)recvfrom with valid "from" and "fromlen" parameters, on a - TCP connection caused a crash. Note that using (lwip_)recvfrom - like this is a bit slow and that using (lwip)getpeername is the - good lwip way to do it (so, using recv is faster on tcp sockets). - - 2008-03-12 Frédéric Bernon, Jonathan Larmour - * api_msg.c, contrib/apps/ping.c: Fix bug #22530 "api_msg.c's - recv_raw() does not consume data", and the ping sample (with - LWIP_SOCKET=1, the code did the wrong supposition that lwip_recvfrom - returned the IP payload, without the IP header). - - 2008-03-04 Jonathan Larmour - * mem.c, stats.c, mem.h: apply patch #6414 to avoid compiler errors - and/or warnings on some systems where mem_size_t and size_t differ. - * pbuf.c, ppp.c: Fix warnings on some systems with mem_malloc. - - 2008-03-04 Kieran Mansley (contributions by others) - * Numerous small compiler error/warning fixes from contributions to - mailing list after 1.3.0 release candidate made. - - 2008-01-25 Cui hengbin (integrated by Frédéric Bernon) - * dns.c: Fix bug #22108 "DNS problem" caused by unaligned structures. - - 2008-01-15 Kieran Mansley - * tcp_out.c: BUG20511. Modify persist timer to start when we are - prevented from sending by a small send window, not just a zero - send window. - - 2008-01-09 Jonathan Larmour - * opt.h, ip.c: Rename IP_OPTIONS define to IP_OPTIONS_ALLOWED to avoid - conflict with Linux system headers. - - 2008-01-06 Jonathan Larmour - * dhcp.c: fix bug #19927: "DHCP NACK problem" by clearing any existing set IP - address entirely on receiving a DHCPNAK, and restarting discovery. - - 2007-12-21 Simon Goldschmidt - * sys.h, api_lib.c, api_msg.c, sockets.c: fix bug #21698: "netconn->recv_avail - is not protected" by using new macros for interlocked access to modify/test - netconn->recv_avail. - - 2007-12-20 Kieran Mansley (based on patch from Oleg Tyshev) - * tcp_in.c: fix bug# 21535 (nrtx not reset correctly in SYN_SENT state) - - 2007-12-20 Kieran Mansley (based on patch from Per-Henrik Lundbolm) - * tcp.c, tcp_in.c, tcp_out.c, tcp.h: fix bug #20199 (better handling - of silly window avoidance and prevent lwIP from shrinking the window) - - 2007-12-04 Simon Goldschmidt - * tcp.c, tcp_in.c: fix bug #21699 (segment leak in ooseq processing when last - data packet was lost): add assert that all segment lists are empty in - tcp_pcb_remove before setting pcb to CLOSED state; don't directly set CLOSED - state from LAST_ACK in tcp_process - - 2007-12-02 Simon Goldschmidt - * sockets.h: fix bug #21654: exclude definition of struct timeval from #ifndef FD_SET - If including for system-struct timeval, LWIP_TIMEVAL_PRIVATE now - has to be set to 0 in lwipopts.h - - 2007-12-02 Simon Goldschmidt - * api_msg.c, api_lib.c: fix bug #21656 (recvmbox problem in netconn API): always - allocate a recvmbox in netconn_new_with_proto_and_callback. For a tcp-listen - netconn, this recvmbox is later freed and a new mbox is allocated for acceptmbox. - This is a fix for thread-safety and allocates all items needed for a netconn - when the netconn is created. - - 2007-11-30 Simon Goldschmidt - * udp.c: first attempt to fix bug #21655 (DHCP doesn't work reliably with multiple - netifs): if LWIP_DHCP is enabled, UDP packets to DHCP_CLIENT_PORT are passed - to netif->dhcp->pcb only (if that exists) and not to any other pcb for the same - port (only solution to let UDP pcbs 'bind' to a netif instead of an IP address) - - 2007-11-27 Simon Goldschmidt - * ip.c: fixed bug #21643 (udp_send/raw_send don't fail if netif is down) by - letting ip_route only use netifs that are up. - - 2007-11-27 Simon Goldschmidt - * err.h, api_lib.c, api_msg.c, sockets.c: Changed error handling: ERR_MEM, ERR_BUF - and ERR_RTE are seen as non-fatal, all other errors are fatal. netconns and - sockets block most operations once they have seen a fatal error. - - 2007-11-27 Simon Goldschmidt - * udp.h, udp.c, dhcp.c: Implemented new function udp_sendto_if which takes the - netif to send as an argument (to be able to send on netifs that are down). - - 2007-11-26 Simon Goldschmidt - * tcp_in.c: Fixed bug #21582: pcb->acked accounting can be wrong when ACKs - arrive out-of-order - - 2007-11-21 Simon Goldschmidt - * tcp.h, tcp_out.c, api_msg.c: Fixed bug #20287: tcp_output_nagle sends too early - Fixed the nagle algorithm; nagle now also works for all raw API applications - and has to be explicitly disabled with 'tcp_pcb->flags |= TF_NODELAY' - - 2007-11-12 Frédéric Bernon - * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fixed bug #20900. Now, most - of the netconn_peer and netconn_addr processing is done inside tcpip_thread - context in do_getaddr. - - 2007-11-10 Simon Goldschmidt - * etharp.c: Fixed bug: assert fired when MEMP_ARP_QUEUE was empty (which can - happen any time). Now the packet simply isn't enqueued when out of memory. - - 2007-11-01 Simon Goldschmidt - * tcp.c, tcp_in.c: Fixed bug #21494: The send mss (pcb->mss) is set to 536 (or - TCP_MSS if that is smaller) as long as no MSS option is received from the - remote host. - - 2007-11-01 Simon Goldschmidt - * tcp.h, tcp.c, tcp_in.c: Fixed bug #21491: The MSS option sent (with SYN) - is now based on TCP_MSS instead of pcb->mss (on passive open now effectively - sending our configured TCP_MSS instead of the one received). - - 2007-11-01 Simon Goldschmidt - * tcp_in.c: Fixed bug #21181: On active open, the initial congestion window was - calculated based on the configured TCP_MSS, not on the MSS option received - with SYN+ACK. - - 2007-10-09 Simon Goldschmidt - * udp.c, inet.c, inet.h: Fixed UDPLite: send: Checksum was always generated too - short and also was generated wrong if checksum coverage != tot_len; - receive: checksum was calculated wrong if checksum coverage != tot_len - - 2007-10-08 Simon Goldschmidt - * mem.c: lfree was not updated in mem_realloc! - - 2007-10-07 Frédéric Bernon - * sockets.c, api.h, api_lib.c: First step to fix "bug #20900 : Potential - crash error problem with netconn_peer & netconn_addr". VERY IMPORTANT: - this change cause an API breakage for netconn_addr, since a parameter - type change. Any compiler should cause an error without any changes in - yours netconn_peer calls (so, it can't be a "silent change"). It also - reduce a little bit the footprint for socket layer (lwip_getpeername & - lwip_getsockname use now a common lwip_getaddrname function since - netconn_peer & netconn_addr have the same parameters). - - 2007-09-20 Simon Goldschmidt - * tcp.c: Fixed bug #21080 (tcp_bind without check pcbs in TIME_WAIT state) - by checking tcp_tw_pcbs also - - 2007-09-19 Simon Goldschmidt - * icmp.c: Fixed bug #21107 (didn't reset IP TTL in ICMP echo replies) - - 2007-09-15 Mike Kleshov - * mem.c: Fixed bug #21077 (inaccuracy in calculation of lwip_stat.mem.used) - - 2007-09-06 Frédéric Bernon - * several-files: replace some #include "arch/cc.h" by "lwip/arch.h", or simply remove - it as long as "lwip/opt.h" is included before (this one include "lwip/debug.h" which - already include "lwip/arch.h"). Like that, default defines are provided by "lwip/arch.h" - if they are not defined in cc.h, in the same spirit than "lwip/opt.h" for lwipopts.h. - - 2007-08-30 Frédéric Bernon - * igmp.h, igmp.c: Some changes to remove some redundant code, add some traces, - and fix some coding style. - - 2007-08-28 Frédéric Bernon - * tcpip.c: Fix TCPIP_MSG_INPKT processing: now, tcpip_input can be used for any - kind of packets. These packets are considered like Ethernet packets (payload - pointing to ethhdr) if the netif got the NETIF_FLAG_ETHARP flag. Else, packets - are considered like IP packets (payload pointing to iphdr). - - 2007-08-27 Frédéric Bernon - * api.h, api_lib.c, api_msg.c: First fix for "bug #20900 : Potential crash error - problem with netconn_peer & netconn_addr". Introduce NETCONN_LISTEN netconn_state - and remove obsolete ones (NETCONN_RECV & NETCONN_ACCEPT). - - 2007-08-24 Kieran Mansley - * inet.c Modify (acc >> 16) test to ((acc >> 16) != 0) to help buggy - compiler (Paradigm C++) - - 2007-08-09 Frédéric Bernon, Bill Florac - * stats.h, stats.c, igmp.h, igmp.c, opt.h: Fix for bug #20503 : IGMP Improvement. - Introduce IGMP_STATS to centralize statistics management. - - 2007-08-09 Frédéric Bernon, Bill Florac - * udp.c: Fix for bug #20503 : IGMP Improvement. Enable to receive a multicast - packet on a udp pcb binded on an netif's IP address, and not on "any". - - 2007-08-09 Frédéric Bernon, Bill Florac - * igmp.h, igmp.c, ip.c: Fix minor changes from bug #20503 : IGMP Improvement. - This is mainly on using lookup/lookfor, and some coding styles... - - 2007-07-26 Frédéric Bernon (and "thedoctor") - * igmp.c: Fix bug #20595 to accept IGMPv3 "Query" messages. - - 2007-07-25 Simon Goldschmidt - * api_msg.c, tcp.c: Another fix for bug #20021: by not returning an error if - tcp_output fails in tcp_close, the code in do_close_internal gets simpler - (tcp_output is called again later from tcp timers). - - 2007-07-25 Simon Goldschmidt - * ip_frag.c: Fixed bug #20429: use the new pbuf_copy_partial instead of the old - copy_from_pbuf, which illegally modified the given pbuf. - - 2007-07-25 Simon Goldschmidt - * tcp_out.c: tcp_enqueue: pcb->snd_queuelen didn't work for chaine PBUF_RAMs: - changed snd_queuelen++ to snd_queuelen += pbuf_clen(p). - - 2007-07-24 Simon Goldschmidt - * api_msg.c, tcp.c: Fix bug #20480: Check the pcb passed to tcp_listen() for the - correct state (must be CLOSED). - - 2007-07-13 Thomas Taranowski (commited by Jared Grubb) - * memp.c: Fix bug #20478: memp_malloc returned NULL+MEMP_SIZE on failed - allocation. It now returns NULL. - - 2007-07-13 Frédéric Bernon - * api_msg.c: Fix bug #20318: api_msg "recv" callbacks don't call pbuf_free in - all error cases. - - 2007-07-13 Frédéric Bernon - * api_msg.c: Fix bug #20315: possible memory leak problem if tcp_listen failed, - because current code doesn't follow rawapi.txt documentation. - - 2007-07-13 Kieran Mansley - * src/core/tcp_in.c Apply patch#5741 from Oleg Tyshev to fix bug in - out of sequence processing of received packets - - 2007-07-03 Simon Goldschmidt - * nearly-all-files: Added assertions where PBUF_RAM pbufs are used and an - assumption is made that this pbuf is in one piece (i.e. not chained). These - assumptions clash with the possibility of converting to fully pool-based - pbuf implementations, where PBUF_RAM pbufs might be chained. - - 2007-07-03 Simon Goldschmidt - * api.h, api_lib.c, api_msg.c: Final fix for bug #20021 and some other problems - when closing tcp netconns: removed conn->sem, less context switches when - closing, both netconn_close and netconn_delete should safely close tcp - connections. - - 2007-07-02 Simon Goldschmidt - * ipv4/ip.h, ipv6/ip.h, opt.h, netif.h, etharp.h, ipv4/ip.c, netif.c, raw.c, - tcp_out.c, udp.c, etharp.c: Added option LWIP_NETIF_HWADDRHINT (default=off) - to cache ARP table indices with each pcb instead of single-entry cache for - the complete stack. - - 2007-07-02 Simon Goldschmidt - * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Added some ASSERTS and casts to prevent - warnings when assigning to smaller types. - - 2007-06-28 Simon Goldschmidt - * tcp_out.c: Added check to prevent tcp_pcb->snd_queuelen from overflowing. - - 2007-06-28 Simon Goldschmidt - * tcp.h: Fixed bug #20287: Fixed nagle algorithm (sending was done too early if - a segment contained chained pbufs) - - 2007-06-28 Frédéric Bernon - * autoip.c: replace most of rand() calls by a macro LWIP_AUTOIP_RAND which compute - a "pseudo-random" value based on netif's MAC and some autoip fields. It's always - possible to define this macro in your own lwipopts.h to always use C library's - rand(). Note that autoip_create_rand_addr doesn't use this macro. - - 2007-06-28 Frédéric Bernon - * netifapi.h, netifapi.c, tcpip.h, tcpip.c: Update code to handle the option - LWIP_TCPIP_CORE_LOCKING, and do some changes to be coherent with last modifications - in api_lib/api_msg (use pointers and not type with table, etc...) - - 2007-06-26 Simon Goldschmidt - * udp.h: Fixed bug #20259: struct udp_hdr was lacking the packin defines. - - 2007-06-25 Simon Goldschmidt - * udp.c: Fixed bug #20253: icmp_dest_unreach was called with a wrong p->payload - for udp packets with no matching pcb. - - 2007-06-25 Simon Goldschmidt - * udp.c: Fixed bug #20220: UDP PCB search in udp_input(): a non-local match - could get udp input packets if the remote side matched. - - 2007-06-13 Simon Goldschmidt - * netif.c: Fixed bug #20180 (TCP pcbs listening on IP_ADDR_ANY could get - changed in netif_set_ipaddr if previous netif->ip_addr.addr was 0. - - 2007-06-13 Simon Goldschmidt - * api_msg.c: pcb_new sets conn->err if protocol is not implemented - -> netconn_new_..() does not allocate a new connection for unsupported - protocols. - - 2007-06-13 Frédéric Bernon, Simon Goldschmidt - * api_lib.c: change return expression in netconn_addr and netconn_peer, because - conn->err was reset to ERR_OK without any reasons (and error was lost)... - - 2007-06-13 Frédéric Bernon, Matthias Weisser - * opt.h, mem.h, mem.c, memp.c, pbuf.c, ip_frag.c, vj.c: Fix bug #20162. Rename - MEM_ALIGN in LWIP_MEM_ALIGN and MEM_ALIGN_SIZE in LWIP_MEM_ALIGN_SIZE to avoid - some macro names collision with some OS macros. - - 2007-06-11 Simon Goldschmidt - * udp.c: UDP Lite: corrected the use of chksum_len (based on RFC3828: if it's 0, - create checksum over the complete packet. On RX, if it's < 8 (and not 0), - discard the packet. Also removed the duplicate 'udphdr->chksum = 0' for both - UDP & UDP Lite. - - 2007-06-11 Srinivas Gollakota & Oleg Tyshev - * tcp_out.c: Fix for bug #20075 : "A problem with keep-alive timer and TCP flags" - where TCP flags wasn't initialized in tcp_keepalive. - - 2007-06-03 Simon Goldschmidt - * udp.c: udp_input(): Input pbuf was not freed if pcb had no recv function - registered, p->payload was modified without modifying p->len if sending - icmp_dest_unreach() (had no negative effect but was definitively wrong). - - 2007-06-03 Simon Goldschmidt - * icmp.c: Corrected bug #19937: For responding to an icmp echo request, icmp - re-used the input pbuf even if that didn't have enough space to include the - link headers. Now the space is tested and a new pbuf is allocated for the - echo response packet if the echo request pbuf isn't big enough. - - 2007-06-01 Simon Goldschmidt - * sockets.c: Checked in patch #5914: Moved sockopt processing into tcpip_thread. - - 2007-05-23 Frédéric Bernon - * api_lib.c, sockets.c: Fixed bug #5958 for netconn_listen (acceptmbox only - allocated by do_listen if success) and netconn_accept errors handling. In - most of api_lib functions, we replace some errors checkings like "if (conn==NULL)" - by ASSERT, except for netconn_delete. - - 2007-05-23 Frédéric Bernon - * api_lib.c: Fixed bug #5957 "Safe-thread problem inside netconn_recv" to return - an error code if it's impossible to fetch a pbuf on a TCP connection (and not - directly close the recvmbox). - - 2007-05-22 Simon Goldschmidt - * tcp.c: Fixed bug #1895 (tcp_bind not correct) by introducing a list of - bound but unconnected (and non-listening) tcp_pcbs. - - 2007-05-22 Frédéric Bernon - * sys.h, sys.c, api_lib.c, tcpip.c: remove sys_mbox_fetch_timeout() (was only - used for LWIP_SO_RCVTIMEO option) and use sys_arch_mbox_fetch() instead of - sys_mbox_fetch() in api files. Now, users SHOULD NOT use internal lwIP features - like "sys_timeout" in their application threads. - - 2007-05-22 Frédéric Bernon - * api.h, api_lib.c, api_msg.h, api_msg.c: change the struct api_msg_msg to see - which parameters are used by which do_xxx function, and to avoid "misusing" - parameters (patch #5938). - - 2007-05-22 Simon Goldschmidt - * api_lib.c, api_msg.c, raw.c, api.h, api_msg.h, raw.h: Included patch #5938: - changed raw_pcb.protocol from u16_t to u8_t since for IPv4 and IPv6, proto - is only 8 bits wide. This affects the api, as there, the protocol was - u16_t, too. - - 2007-05-18 Simon Goldschmidt - * memp.c: addition to patch #5913: smaller pointer was returned but - memp_memory was the same size -> did not save memory. - - 2007-05-16 Simon Goldschmidt - * loopif.c, slipif.c: Fix bug #19729: free pbuf if netif->input() returns - != ERR_OK. - - 2007-05-16 Simon Goldschmidt - * api_msg.c, udp.c: If a udp_pcb has a local_ip set, check if it is the same - as the one of the netif used for sending to prevent sending from old - addresses after a netif address gets changed (partly fixes bug #3168). - - 2007-05-16 Frédéric Bernon - * tcpip.c, igmp.h, igmp.c: Fixed bug "#19800 : IGMP: igmp_tick() will not work - with NO_SYS=1". Note that igmp_init is always in tcpip_thread (and not in - tcpip_init) because we have to be sure that network interfaces are already - added (mac filter is updated only in igmp_init for the moment). - - 2007-05-16 Simon Goldschmidt - * mem.c, memp.c: Removed semaphores from memp, changed sys_sem_wait calls - into sys_arch_sem_wait calls to prevent timers from running while waiting - for the heap. This fixes bug #19167. - - 2007-05-13 Simon Goldschmidt - * tcp.h, sockets.h, sockets.c: Fixed bug from patch #5865 by moving the defines - for socket options (lwip_set/-getsockopt) used with level IPPROTO_TCP from - tcp.h to sockets.h. - - 2007-05-07 Simon Goldschmidt - * mem.c: Another attempt to fix bug #17922. - - 2007-05-04 Simon Goldschmidt - * pbuf.c, pbuf.h, etharp.c: Further update to ARP queueing: Changed pbuf_copy() - implementation so that it can be reused (don't allocate the target - pbuf inside pbuf_copy()). - - 2007-05-04 Simon Goldschmidt - * memp.c: checked in patch #5913: in memp_malloc() we can return memp as mem - to save a little RAM (next pointer of memp is not used while not in pool). - - 2007-05-03 "maq" - * sockets.c: Fix ioctl FIONREAD when some data remains from last recv. - (patch #3574). - - 2007-04-23 Simon Goldschmidt - * loopif.c, loopif.h, opt.h, src/netif/FILES: fix bug #2595: "loopif results - in NULL reference for incoming TCP packets". Loopif has to be configured - (using LWIP_LOOPIF_MULTITHREADING) to directly call netif->input() - (multithreading environments, e.g. netif->input() = tcpip_input()) or - putting packets on a list that is fed to the stack by calling loopif_poll() - (single-thread / NO_SYS / polling environment where e.g. - netif->input() = ip_input). - - 2007-04-17 Jonathan Larmour - * pbuf.c: Use s32_t in pbuf_realloc(), as an s16_t can't reliably hold - the difference between two u16_t's. - * sockets.h: FD_SETSIZE needs to match number of sockets, which is - MEMP_NUM_NETCONN in sockets.c right now. - - 2007-04-12 Jonathan Larmour - * icmp.c: Reset IP header TTL in ICMP ECHO responses (bug #19580). - - 2007-04-12 Kieran Mansley - * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Modify way the retransmission - timer is reset to fix bug#19434, with help from Oleg Tyshev. - - 2007-04-11 Simon Goldschmidt - * etharp.c, pbuf.c, pbuf.h: 3rd fix for bug #11400 (arp-queuing): More pbufs than - previously thought need to be copied (everything but PBUF_ROM!). Cleaned up - pbuf.c: removed functions no needed any more (by etharp). - - 2007-04-11 Kieran Mansley - * inet.c, ip_addr.h, sockets.h, sys.h, tcp.h: Apply patch #5745: Fix - "Constant is long" warnings with 16bit compilers. Contributed by - avatar@mmlab.cse.yzu.edu.tw - - 2007-04-05 Frédéric Bernon, Jonathan Larmour - * api_msg.c: Fix bug #16830: "err_tcp() posts to connection mailbox when no pend on - the mailbox is active". Now, the post is only done during a connect, and do_send, - do_write and do_join_leave_group don't do anything if a previous error was signaled. - - 2007-04-03 Frédéric Bernon - * ip.c: Don't set the IP_DF ("Don't fragment") flag in the IP header in IP output - packets. See patch #5834. - - 2007-03-30 Frédéric Bernon - * api_msg.c: add a "pcb_new" helper function to avoid redundant code, and to add - missing pcb allocations checking (in do_bind, and for each raw_new). Fix style. - - 2007-03-30 Frédéric Bernon - * most of files: prefix all debug.h define with "LWIP_" to avoid any conflict with - others environment defines (these were too "generic"). - - 2007-03-28 Frédéric Bernon - * api.h, api_lib.c, sockets.c: netbuf_ref doesn't check its internal pbuf_alloc call - result and can cause a crash. lwip_send now check netbuf_ref result. - - 2007-03-28 Simon Goldschmidt - * sockets.c Remove "#include " from sockets.c to avoid multiple - definition of macros (in errno.h and lwip/arch.h) if LWIP_PROVIDE_ERRNO is - defined. This is the way it should have been already (looking at - doc/sys_arch.txt) - - 2007-03-28 Kieran Mansley - * opt.h Change default PBUF_POOL_BUFSIZE (again) to accomodate default MSS + - IP and TCP headers *and* physical link headers - - 2007-03-26 Frédéric Bernon (based on patch from Dmitry Potapov) - * api_lib.c: patch for netconn_write(), fixes a possible race condition which cause - to send some garbage. It is not a definitive solution, but the patch does solve - the problem for most cases. - - 2007-03-22 Frédéric Bernon - * api_msg.h, api_msg.c: Remove obsolete API_MSG_ACCEPT and do_accept (never used). - - 2007-03-22 Frédéric Bernon - * api_lib.c: somes resources couldn't be freed if there was errors during - netconn_new_with_proto_and_callback. - - 2007-03-22 Frédéric Bernon - * ethernetif.c: update netif->input calls to check return value. In older ports, - it's a good idea to upgrade them, even if before, there could be another problem - (access to an uninitialized mailbox). - - 2007-03-21 Simon Goldschmidt - * sockets.c: fixed bug #5067 (essentialy a signed/unsigned warning fixed - by casting to unsigned). - - 2007-03-21 Frédéric Bernon - * api_lib.c, api_msg.c, tcpip.c: integrate sys_mbox_fetch(conn->mbox, NULL) calls from - api_lib.c to tcpip.c's tcpip_apimsg(). Now, use a local variable and not a - dynamic one from memp to send tcpip_msg to tcpip_thread in a synchrone call. - Free tcpip_msg from tcpip_apimsg is not done in tcpip_thread. This give a - faster and more reliable communication between api_lib and tcpip. - - 2007-03-21 Frédéric Bernon - * opt.h: Add LWIP_NETIF_CALLBACK (to avoid compiler warning) and set it to 0. - - 2007-03-21 Frédéric Bernon - * api_msg.c, igmp.c, igmp.h: Fix C++ style comments - - 2007-03-21 Kieran Mansley - * opt.h Change default PBUF_POOL_BUFSIZE to accomodate default MSS + - IP and TCP headers - - 2007-03-21 Kieran Mansley - * Fix all uses of pbuf_header to check the return value. In some - cases just assert if it fails as I'm not sure how to fix them, but - this is no worse than before when they would carry on regardless - of the failure. - - 2007-03-21 Kieran Mansley - * sockets.c, igmp.c, igmp.h, memp.h: Fix C++ style comments and - comment out missing header include in icmp.c - - 2007-03-20 Frédéric Bernon - * memp.h, stats.c: Fix stats_display function where memp_names table wasn't - synchronized with memp.h. - - 2007-03-20 Frédéric Bernon - * tcpip.c: Initialize tcpip's mbox, and verify if initialized in tcpip_input, - tcpip_ethinput, tcpip_callback, tcpip_apimsg, to fix a init problem with - network interfaces. Also fix a compiler warning. - - 2007-03-20 Kieran Mansley - * udp.c: Only try and use pbuf_header() to make space for headers if - not a ROM or REF pbuf. - - 2007-03-19 Frédéric Bernon - * api_msg.h, api_msg.c, tcpip.h, tcpip.c: Add return types to tcpip_apimsg() - and api_msg_post(). - - 2007-03-19 Frédéric Bernon - * Remove unimplemented "memp_realloc" function from memp.h. - - 2007-03-11 Simon Goldschmidt - * pbuf.c: checked in patch #5796: pbuf_alloc: len field claculation caused - memory corruption. - - 2007-03-11 Simon Goldschmidt (based on patch from Dmitry Potapov) - * api_lib.c, sockets.c, api.h, api_msg.h, sockets.h: Fixed bug #19251 - (missing `const' qualifier in socket functions), to get more compatible to - standard POSIX sockets. - - 2007-03-11 Frédéric Bernon (based on patch from Dmitry Potapov) - * sockets.c: Add asserts inside bind, connect and sendto to check input - parameters. Remove excessive set_errno() calls after get_socket(), because - errno is set inside of get_socket(). Move last sock_set_errno() inside - lwip_close. - - 2007-03-09 Simon Goldschmidt - * memp.c: Fixed bug #11400: New etharp queueing introduced bug: memp_memory - was allocated too small. - - 2007-03-06 Simon Goldschmidt - * tcpip.c: Initialize dhcp timers in tcpip_thread (if LWIP_DHCP) to protect - the stack from concurrent access. - - 2007-03-06 Frédéric Bernon, Dmitry Potapov - * tcpip.c, ip_frag.c, ethernetif.c: Fix some build problems, and a redundancy - call to "lwip_stats.link.recv++;" in low_level_input() & ethernetif_input(). - - 2007-03-06 Simon Goldschmidt - * ip_frag.c, ip_frag.h: Reduce code size: don't include code in those files - if IP_FRAG == 0 and IP_REASSEMBLY == 0 - - 2007-03-06 Frédéric Bernon, Simon Goldschmidt - * opt.h, ip_frag.h, tcpip.h, tcpip.c, ethernetif.c: add new configuration - option named ETHARP_TCPIP_ETHINPUT, which enable the new tcpip_ethinput. - Allow to do ARP processing for incoming packets inside tcpip_thread - (protecting ARP layer against concurrent access). You can also disable - old code using tcp_input with new define ETHARP_TCPIP_INPUT set to 0. - Older ports have to use tcpip_ethinput. - - 2007-03-06 Simon Goldschmidt (based on patch from Dmitry Potapov) - * err.h, err.c: fixed compiler warning "initialization dircards qualifiers - from pointer target type" - - 2007-03-05 Frédéric Bernon - * opt.h, sockets.h: add new configuration options (LWIP_POSIX_SOCKETS_IO_NAMES, - ETHARP_TRUST_IP_MAC, review SO_REUSE) - - 2007-03-04 Frédéric Bernon - * api_msg.c: Remove some compiler warnings : parameter "pcb" was never - referenced. - - 2007-03-04 Frédéric Bernon - * api_lib.c: Fix "[patch #5764] api_lib.c cleanup: after patch #5687" (from - Dmitry Potapov). - The api_msg struct stay on the stack (not moved to netconn struct). - - 2007-03-04 Simon Goldschmidt (based on patch from Dmitry Potapov) - * pbuf.c: Fix BUG#19168 - pbuf_free can cause deadlock (if - SYS_LIGHTWEIGHT_PROT=1 & freeing PBUF_RAM when mem_sem is not available) - Also fixed cast warning in pbuf_alloc() - - 2007-03-04 Simon Goldschmidt - * etharp.c, etharp.h, memp.c, memp.h, opt.h: Fix BUG#11400 - don't corrupt - existing pbuf chain when enqueuing multiple pbufs to a pending ARP request - - 2007-03-03 Frédéric Bernon - * udp.c: remove obsolete line "static struct udp_pcb *pcb_cache = NULL;" - It is static, and never used in udp.c except udp_init(). - - 2007-03-02 Simon Goldschmidt - * tcpip.c: Moved call to ip_init(), udp_init() and tcp_init() from - tcpip_thread() to tcpip_init(). This way, raw API connections can be - initialized before tcpip_thread is running (e.g. before OS is started) - - 2007-03-02 Frédéric Bernon - * rawapi.txt: Fix documentation mismatch with etharp.h about etharp_tmr's call - interval. - - 2007-02-28 Kieran Mansley - * pbuf.c: Fix BUG#17645 - ensure pbuf payload pointer is not moved - outside the region of the pbuf by pbuf_header() - - 2007-02-28 Kieran Mansley - * sockets.c: Fix BUG#19161 - ensure milliseconds timeout is non-zero - when supplied timeout is also non-zero - -(STABLE-1.2.0) - - 2006-12-05 Leon Woestenberg - * CHANGELOG: Mention STABLE-1.2.0 release. - - ++ New features: - - 2006-12-01 Christiaan Simons - * mem.h, opt.h: Added MEM_LIBC_MALLOC option. - Note this is a workaround. Currently I have no other options left. - - 2006-10-26 Christiaan Simons (accepted patch by Jonathan Larmour) - * ipv4/ip_frag.c: rename MAX_MTU to IP_FRAG_MAX_MTU and move define - to include/lwip/opt.h. - * ipv4/lwip/ip_frag.h: Remove unused IP_REASS_INTERVAL. - Move IP_REASS_MAXAGE and IP_REASS_BUFSIZE to include/lwip/opt.h. - * opt.h: Add above new options. - - 2006-08-18 Christiaan Simons - * tcp_{in,out}.c: added SNMP counters. - * ipv4/ip.c: added SNMP counters. - * ipv4/ip_frag.c: added SNMP counters. - - 2006-08-08 Christiaan Simons - * etharp.{c,h}: added etharp_find_addr() to read - (stable) ethernet/IP address pair from ARP table - - 2006-07-14 Christiaan Simons - * mib_structs.c: added - * include/lwip/snmp_structs.h: added - * netif.{c,h}, netif/ethernetif.c: added SNMP statistics to netif struct - - 2006-07-06 Christiaan Simons - * snmp/asn1_{enc,dec}.c added - * snmp/mib2.c added - * snmp/msg_{in,out}.c added - * include/lwip/snmp_asn1.h added - * include/lwip/snmp_msg.h added - * doc/snmp_agent.txt added - - 2006-03-29 Christiaan Simons - * inet.c, inet.h: Added platform byteswap support. - Added LWIP_PLATFORM_BYTESWAP define (defaults to 0) and - optional LWIP_PLATFORM_HTONS(), LWIP_PLATFORM_HTONL() macros. - - ++ Bug fixes: - - 2006-11-30 Christiaan Simons - * dhcp.c: Fixed false triggers of request_timeout. - - 2006-11-28 Christiaan Simons - * netif.c: In netif_add() fixed missing clear of ip_addr, netmask, gw and flags. - - 2006-10-11 Christiaan Simons - * api_lib.c etharp.c, ip.c, memp.c, stats.c, sys.{c,h} tcp.h: - Partially accepted patch #5449 for ANSI C compatibility / build fixes. - * ipv4/lwip/ip.h ipv6/lwip/ip.h: Corrected UDP-Lite protocol - identifier from 170 to 136 (bug #17574). - - 2006-10-10 Christiaan Simons - * api_msg.c: Fixed Nagle algorithm as reported by Bob Grice. - - 2006-08-17 Christiaan Simons - * udp.c: Fixed bug #17200, added check for broadcast - destinations for PCBs bound to a unicast address. - - 2006-08-07 Christiaan Simons - * api_msg.c: Flushing TCP output in do_close() (bug #15926). - - 2006-06-27 Christiaan Simons - * api_msg.c: Applied patch for cold case (bug #11135). - In accept_function() ensure newconn->callback is always initialized. - - 2006-06-15 Christiaan Simons - * mem.h: added MEM_SIZE_F alias to fix an ancient cold case (bug #1748), - facilitate printing of mem_size_t and u16_t statistics. - - 2006-06-14 Christiaan Simons - * api_msg.c: Applied patch #5146 to handle allocation failures - in accept() by Kevin Lawson. - - 2006-05-26 Christiaan Simons - * api_lib.c: Removed conn->sem creation and destruction - from netconn_write() and added sys_sem_new to netconn_new_*. - -(STABLE-1_1_1) - - 2006-03-03 Christiaan Simons - * ipv4/ip_frag.c: Added bound-checking assertions on ip_reassbitmap - access and added pbuf_alloc() return value checks. - - 2006-01-01 Leon Woestenberg - * tcp_{in,out}.c, tcp_out.c: Removed 'even sndbuf' fix in TCP, which is - now handled by the checksum routine properly. - - 2006-02-27 Leon Woestenberg - * pbuf.c: Fix alignment; pbuf_init() would not work unless - pbuf_pool_memory[] was properly aligned. (Patch by Curt McDowell.) - - 2005-12-20 Leon Woestenberg - * tcp.c: Remove PCBs which stay in LAST_ACK state too long. Patch - submitted by Mitrani Hiroshi. - - 2005-12-15 Christiaan Simons - * inet.c: Disabled the added summing routine to preserve code space. - - 2005-12-14 Leon Woestenberg - * tcp_in.c: Duplicate FIN ACK race condition fix by Kelvin Lawson. - Added Curt McDowell's optimized checksumming routine for future - inclusion. Need to create test case for unaliged, aligned, odd, - even length combination of cases on various endianess machines. - - 2005-12-09 Christiaan Simons - * inet.c: Rewrote standard checksum routine in proper portable C. - - 2005-11-25 Christiaan Simons - * udp.c tcp.c: Removed SO_REUSE hack. Should reside in socket code only. - * *.c: introduced cc.h LWIP_DEBUG formatters matching the u16_t, s16_t, - u32_t, s32_t typedefs. This solves most debug word-length assumes. - - 2005-07-17 Leon Woestenberg - * inet.c: Fixed unaligned 16-bit access in the standard checksum - routine by Peter Jolasson. - * slipif.c: Fixed implementation assumption of single-pbuf datagrams. - - 2005-02-04 Leon Woestenberg - * tcp_out.c: Fixed uninitialized 'queue' referenced in memerr branch. - * tcp_{out|in}.c: Applied patch fixing unaligned access. - - 2005-01-04 Leon Woestenberg - * pbuf.c: Fixed missing semicolon after LWIP_DEBUG statement. - - 2005-01-03 Leon Woestenberg - * udp.c: UDP pcb->recv() was called even when it was NULL. - -(STABLE-1_1_0) - - 2004-12-28 Leon Woestenberg - * etharp.*: Disabled multiple packets on the ARP queue. - This clashes with TCP queueing. - - 2004-11-28 Leon Woestenberg - * etharp.*: Fixed race condition from ARP request to ARP timeout. - Halved the ARP period, doubled the period counts. - ETHARP_MAX_PENDING now should be at least 2. This prevents - the counter from reaching 0 right away (which would allow - too little time for ARP responses to be received). - - 2004-11-25 Leon Woestenberg - * dhcp.c: Decline messages were not multicast but unicast. - * etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD. - Do not try hard to insert arbitrary packet's source address, - etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD. - etharp_query() now always DOES call ETHARP_TRY_HARD so that users - querying an address will see it appear in the cache (DHCP could - suffer from this when a server invalidly gave an in-use address.) - * ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are - comparing network addresses (identifiers), not the network masks - themselves. - * ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given - IP address actually belongs to the network of the given interface. - - 2004-11-24 Kieran Mansley - * tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state. - -(STABLE-1_1_0-RC1) - - 2004-10-16 Kieran Mansley - * tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately, - even if one is already pending, if the rcv_wnd is above a threshold - (currently TCP_WND/2). This avoids waiting for a timer to expire to send a - delayed ACK in order to open the window if the stack is only receiving data. - - 2004-09-12 Kieran Mansley - * tcp*.*: Retransmit time-out handling improvement by Sam Jansen. - - 2004-08-20 Tony Mountifield - * etharp.c: Make sure the first pbuf queued on an ARP entry - is properly ref counted. - - 2004-07-27 Tony Mountifield - * debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler - warnings about comparison. - * pbuf.c: Stopped compiler complaining of empty if statement - when LWIP_DEBUGF() empty. Closed an unclosed comment. - * tcp.c: Stopped compiler complaining of empty if statement - when LWIP_DEBUGF() empty. - * ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons(). - * inet.c: Added a couple of casts to quiet the compiler. - No need to test isascii(c) before isdigit(c) or isxdigit(c). - - 2004-07-22 Tony Mountifield - * inet.c: Made data types consistent in inet_ntoa(). - Added casts for return values of checksum routines, to pacify compiler. - * ip_frag.c, tcp_out.c, sockets.c, pbuf.c - Small corrections to some debugging statements, to pacify compiler. - - 2004-07-21 Tony Mountifield - * etharp.c: Removed spurious semicolon and added missing end-of-comment. - * ethernetif.c Updated low_level_output() to match prototype for - netif->linkoutput and changed low_level_input() similarly for consistency. - * api_msg.c: Changed recv_raw() from int to u8_t, to match prototype - of raw_recv() in raw.h and so avoid compiler error. - * sockets.c: Added trivial (int) cast to keep compiler happier. - * ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros. - -(STABLE-1_0_0) - - ++ Changes: - - 2004-07-05 Leon Woestenberg - * sockets.*: Restructured LWIP_PRIVATE_TIMEVAL. Make sure - your cc.h file defines this either 1 or 0. If non-defined, - defaults to 1. - * .c: Added and includes where used. - * etharp.c: Made some array indices unsigned. - - 2004-06-27 Leon Woestenberg - * netif.*: Added netif_set_up()/down(). - * dhcp.c: Changes to restart program flow. - - 2004-05-07 Leon Woestenberg - * etharp.c: In find_entry(), instead of a list traversal per candidate, do a - single-pass lookup for different candidates. Should exploit locality. - - 2004-04-29 Leon Woestenberg - * tcp*.c: Cleaned up source comment documentation for Doxygen processing. - * opt.h: ETHARP_ALWAYS_INSERT option removed to comply with ARP RFC. - * etharp.c: update_arp_entry() only adds new ARP entries when adviced to by - the caller. This deprecates the ETHARP_ALWAYS_INSERT overrule option. - - ++ Bug fixes: - - 2004-04-27 Leon Woestenberg - * etharp.c: Applied patch of bug #8708 by Toni Mountifield with a solution - suggested by Timmy Brolin. Fix for 32-bit processors that cannot access - non-aligned 32-bit words, such as soms 32-bit TCP/IP header fields. Fix - is to prefix the 14-bit Ethernet headers with two padding bytes. - - 2004-04-23 Leon Woestenberg - * ip_addr.c: Fix in the ip_addr_isbroadcast() check. - * etharp.c: Fixed the case where the packet that initiates the ARP request - is not queued, and gets lost. Fixed the case where the packets destination - address is already known; we now always queue the packet and perform an ARP - request. - -(STABLE-0_7_0) - - ++ Bug fixes: - - * Fixed TCP bug for SYN_SENT to ESTABLISHED state transition. - * Fixed TCP bug in dequeueing of FIN from out of order segment queue. - * Fixed two possible NULL references in rare cases. - -(STABLE-0_6_6) - - ++ Bug fixes: - - * Fixed DHCP which did not include the IP address in DECLINE messages. - - ++ Changes: - - * etharp.c has been hauled over a bit. - -(STABLE-0_6_5) - - ++ Bug fixes: - - * Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic. - * Packets sent from ARP queue had invalid source hardware address. - - ++ Changes: - - * Pass-by ARP requests do now update the cache. - - ++ New features: - - * No longer dependent on ctype.h. - * New socket options. - * Raw IP pcb support. - -(STABLE-0_6_4) - - ++ Bug fixes: - - * Some debug formatters and casts fixed. - * Numereous fixes in PPP. - - ++ Changes: - - * DEBUGF now is LWIP_DEBUGF - * pbuf_dechain() has been re-enabled. - * Mentioned the changed use of CVS branches in README. - -(STABLE-0_6_3) - - ++ Bug fixes: - - * Fixed pool pbuf memory leak in pbuf_alloc(). - Occured if not enough PBUF_POOL pbufs for a packet pbuf chain. - Reported by Savin Zlobec. - - * PBUF_POOL chains had their tot_len field not set for non-first - pbufs. Fixed in pbuf_alloc(). - - ++ New features: - - * Added PPP stack contributed by Marc Boucher - - ++ Changes: - - * Now drops short packets for ICMP/UDP/TCP protocols. More robust. - - * ARP queueuing now queues the latest packet instead of the first. - This is the RFC recommended behaviour, but can be overridden in - lwipopts.h. - -(0.6.2) - - ++ Bugfixes: - - * TCP has been fixed to deal with the new use of the pbuf->ref - counter. - - * DHCP dhcp_inform() crash bug fixed. - - ++ Changes: - - * Removed pbuf_pool_free_cache and pbuf_pool_alloc_cache. Also removed - pbuf_refresh(). This has sped up pbuf pool operations considerably. - Implemented by David Haas. - -(0.6.1) - - ++ New features: - - * The packet buffer implementation has been enhanced to support - zero-copy and copy-on-demand for packet buffers which have their - payloads in application-managed memory. - Implemented by David Haas. - - Use PBUF_REF to make a pbuf refer to RAM. lwIP will use zero-copy - if an outgoing packet can be directly sent on the link, or perform - a copy-on-demand when necessary. - - The application can safely assume the packet is sent, and the RAM - is available to the application directly after calling udp_send() - or similar function. - - ++ Bugfixes: - - * ARP_QUEUEING should now correctly work for all cases, including - PBUF_REF. - Implemented by Leon Woestenberg. - - ++ Changes: - - * IP_ADDR_ANY is no longer a NULL pointer. Instead, it is a pointer - to a '0.0.0.0' IP address. - - * The packet buffer implementation is changed. The pbuf->ref counter - meaning has changed, and several pbuf functions have been - adapted accordingly. - - * netif drivers have to be changed to set the hardware address length field - that must be initialized correctly by the driver (hint: 6 for Ethernet MAC). - See the contrib/ports/c16x cs8900 driver as a driver example. - - * netif's have a dhcp field that must be initialized to NULL by the driver. - See the contrib/ports/c16x cs8900 driver as a driver example. - -(0.5.x) This file has been unmaintained up to 0.6.1. All changes are - logged in CVS but have not been explained here. - -(0.5.3) Changes since version 0.5.2 - - ++ Bugfixes: - - * memp_malloc(MEMP_API_MSG) could fail with multiple application - threads because it wasn't protected by semaphores. - - ++ Other changes: - - * struct ip_addr now packed. - - * The name of the time variable in arp.c has been changed to ctime - to avoid conflicts with the time() function. - -(0.5.2) Changes since version 0.5.1 - - ++ New features: - - * A new TCP function, tcp_tmr(), now handles both TCP timers. - - ++ Bugfixes: - - * A bug in tcp_parseopt() could cause the stack to hang because of a - malformed TCP option. - - * The address of new connections in the accept() function in the BSD - socket library was not handled correctly. - - * pbuf_dechain() did not update the ->tot_len field of the tail. - - * Aborted TCP connections were not handled correctly in all - situations. - - ++ Other changes: - - * All protocol header structs are now packed. - - * The ->len field in the tcp_seg structure now counts the actual - amount of data, and does not add one for SYN and FIN segments. - -(0.5.1) Changes since version 0.5.0 - - ++ New features: - - * Possible to run as a user process under Linux. - - * Preliminary support for cross platform packed structs. - - * ARP timer now implemented. - - ++ Bugfixes: - - * TCP output queue length was badly initialized when opening - connections. - - * TCP delayed ACKs were not sent correctly. - - * Explicit initialization of BSS segment variables. - - * read() in BSD socket library could drop data. - - * Problems with memory alignment. - - * Situations when all TCP buffers were used could lead to - starvation. - - * TCP MSS option wasn't parsed correctly. - - * Problems with UDP checksum calculation. - - * IP multicast address tests had endianess problems. - - * ARP requests had wrong destination hardware address. - - ++ Other changes: - - * struct eth_addr changed from u16_t[3] array to u8_t[6]. - - * A ->linkoutput() member was added to struct netif. - - * TCP and UDP ->dest_* struct members where changed to ->remote_*. - - * ntoh* macros are now null definitions for big endian CPUs. - -(0.5.0) Changes since version 0.4.2 - - ++ New features: - - * Redesigned operating system emulation layer to make porting easier. - - * Better control over TCP output buffers. - - * Documenation added. - - ++ Bugfixes: - - * Locking issues in buffer management. - - * Bugfixes in the sequential API. - - * IP forwarding could cause memory leakage. This has been fixed. - - ++ Other changes: - - * Directory structure somewhat changed; the core/ tree has been - collapsed. - -(0.4.2) Changes since version 0.4.1 - - ++ New features: - - * Experimental ARP implementation added. - - * Skeleton Ethernet driver added. - - * Experimental BSD socket API library added. - - ++ Bugfixes: - - * In very intense situations, memory leakage could occur. This has - been fixed. - - ++ Other changes: - - * Variables named "data" and "code" have been renamed in order to - avoid name conflicts in certain compilers. - - * Variable++ have in appliciable cases been translated to ++variable - since some compilers generate better code in the latter case. - -(0.4.1) Changes since version 0.4 - - ++ New features: - - * TCP: Connection attempts time out earlier than data - transmissions. Nagle algorithm implemented. Push flag set on the - last segment in a burst. - - * UDP: experimental support for UDP-Lite extensions. - - ++ Bugfixes: - - * TCP: out of order segments were in some cases handled incorrectly, - and this has now been fixed. Delayed acknowledgements was broken - in 0.4, has now been fixed. Binding to an address that is in use - now results in an error. Reset connections sometimes hung an - application; this has been fixed. - - * Checksum calculation sometimes failed for chained pbufs with odd - lengths. This has been fixed. - - * API: a lot of bug fixes in the API. The UDP API has been improved - and tested. Error reporting and handling has been - improved. Logical flaws and race conditions for incoming TCP - connections has been found and removed. - - * Memory manager: alignment issues. Reallocating memory sometimes - failed, this has been fixed. - - * Generic library: bcopy was flawed and has been fixed. - - ++ Other changes: - - * API: all datatypes has been changed from generic ones such as - ints, to specified ones such as u16_t. Functions that return - errors now have the correct type (err_t). - - * General: A lot of code cleaned up and debugging code removed. Many - portability issues have been fixed. - - * The license was changed; the advertising clause was removed. - - * C64 port added. - - * Thanks: Huge thanks go to Dagan Galarneau, Horst Garnetzke, Petri - Kosunen, Mikael Caleres, and Frits Wilmink for reporting and - fixing bugs! - -(0.4) Changes since version 0.3.1 - - * Memory management has been radically changed; instead of - allocating memory from a shared heap, memory for objects that are - rapidly allocated and deallocated is now kept in pools. Allocation - and deallocation from those memory pools is very fast. The shared - heap is still present but is used less frequently. - - * The memory, memory pool, and packet buffer subsystems now support - 4-, 2-, or 1-byte alignment. - - * "Out of memory" situations are handled in a more robust way. - - * Stack usage has been reduced. - - * Easier configuration of lwIP parameters such as memory usage, - TTLs, statistics gathering, etc. All configuration parameters are - now kept in a single header file "lwipopts.h". - - * The directory structure has been changed slightly so that all - architecture specific files are kept under the src/arch - hierarchy. - - * Error propagation has been improved, both in the protocol modules - and in the API. - - * The code for the RTXC architecture has been implemented, tested - and put to use. - - * Bugs have been found and corrected in the TCP, UDP, IP, API, and - the Internet checksum modules. - - * Bugs related to porting between a 32-bit and a 16-bit architecture - have been found and corrected. - - * The license has been changed slightly to conform more with the - original BSD license, including the advertisement clause. - -(0.3.1) Changes since version 0.3 - - * Fix of a fatal bug in the buffer management. Pbufs with allocated - RAM never returned the RAM when the pbuf was deallocated. - - * TCP congestion control, window updates and retransmissions did not - work correctly. This has now been fixed. - - * Bugfixes in the API. - -(0.3) Changes since version 0.2 - - * New and improved directory structure. All include files are now - kept in a dedicated include/ directory. - - * The API now has proper error handling. A new function, - netconn_err(), now returns an error code for the connection in - case of errors. - - * Improvements in the memory management subsystem. The system now - keeps a pointer to the lowest free memory block. A new function, - mem_malloc2() tries to allocate memory once, and if it fails tries - to free some memory and retry the allocation. - - * Much testing has been done with limited memory - configurations. lwIP now does a better job when overloaded. - - * Some bugfixes and improvements to the buffer (pbuf) subsystem. - - * Many bugfixes in the TCP code: - - - Fixed a bug in tcp_close(). - - - The TCP receive window was incorrectly closed when out of - sequence segments was received. This has been fixed. - - - Connections are now timed-out of the FIN-WAIT-2 state. - - - The initial congestion window could in some cases be too - large. This has been fixed. - - - The retransmission queue could in some cases be screwed up. This - has been fixed. - - - TCP RST flag now handled correctly. - - - Out of sequence data was in some cases never delivered to the - application. This has been fixed. - - - Retransmitted segments now contain the correct acknowledgment - number and advertised window. - - - TCP retransmission timeout backoffs are not correctly computed - (ala BSD). After a number of retransmissions, TCP now gives up - the connection. - - * TCP connections now are kept on three lists, one for active - connections, one for listening connections, and one for - connections that are in TIME-WAIT. This greatly speeds up the fast - timeout processing for sending delayed ACKs. - - * TCP now provides proper feedback to the application when a - connection has been successfully set up. - - * More comments have been added to the code. The code has also been - somewhat cleaned up. - -(0.2) Initial public release. diff --git a/ext/lwip/COPYING b/ext/lwip/COPYING deleted file mode 100644 index e23898b..0000000 --- a/ext/lwip/COPYING +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2001, 2002 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - - diff --git a/ext/lwip/FILES b/ext/lwip/FILES deleted file mode 100644 index 6625319..0000000 --- a/ext/lwip/FILES +++ /dev/null @@ -1,4 +0,0 @@ -src/ - The source code for the lwIP TCP/IP stack. -doc/ - The documentation for lwIP. - -See also the FILES file in each subdirectory. diff --git a/ext/lwip/README b/ext/lwip/README deleted file mode 100644 index fb88131..0000000 --- a/ext/lwip/README +++ /dev/null @@ -1,97 +0,0 @@ -INTRODUCTION - -lwIP is a small independent implementation of the TCP/IP protocol -suite that has been developed by Adam Dunkels at the Computer and -Networks Architectures (CNA) lab at the Swedish Institute of Computer -Science (SICS). - -The focus of the lwIP TCP/IP implementation is to reduce the RAM usage -while still having a full scale TCP. This making lwIP suitable for use -in embedded systems with tens of kilobytes of free RAM and room for -around 40 kilobytes of code ROM. - - -FEATURES - - * IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over - multiple network interfaces - * ICMP (Internet Control Message Protocol) for network maintenance and debugging - * IGMP (Internet Group Management Protocol) for multicast traffic management - * MLD (Multicast listener discovery for IPv6). Aims to be compliant with - RFC 2710. No support for MLDv2 - * ND (Neighbor discovery and stateless address autoconfiguration for IPv6). - Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 - (Address autoconfiguration) - * UDP (User Datagram Protocol) including experimental UDP-lite extensions - * TCP (Transmission Control Protocol) with congestion control, RTT estimation - and fast recovery/fast retransmit - * raw/native API for enhanced performance - * Optional Berkeley-like socket API - * DNS (Domain names resolver) - - -APPLICATIONS - - * HTTP server with SSI and CGI - * SNMPv2c agent with MIB compiler (Simple Network Management Protocol) - * SNTP (Simple network time protocol) - - -LICENSE - -lwIP is freely available under a BSD license. - - -DEVELOPMENT - -lwIP has grown into an excellent TCP/IP stack for embedded devices, -and developers using the stack often submit bug fixes, improvements, -and additions to the stack to further increase its usefulness. - -Development of lwIP is hosted on Savannah, a central point for -software development, maintenance and distribution. Everyone can -help improve lwIP by use of Savannah's interface, Git and the -mailing list. A core team of developers will commit changes to the -Git source tree. - -The lwIP TCP/IP stack is maintained in the 'lwip' Git module and -contributions (such as platform ports) are in the 'contrib' Git module. - -See doc/savannah.txt for details on Git server access for users and -developers. - -The current Git trees are web-browsable: - http://git.savannah.gnu.org/cgit/lwip.git - http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git - -Submit patches and bugs via the lwIP project page: - http://savannah.nongnu.org/projects/lwip/ - -Continuous integration builds (GCC, clang): - https://travis-ci.org/yarrick/lwip-merged - - -DOCUMENTATION - -Self documentation of the source code is regularly extracted from the current -Git sources and is available from this web page: - http://www.nongnu.org/lwip/ - -There is now a constantly growin wiki about lwIP at - http://lwip.wikia.com/wiki/LwIP_Wiki - -Also, there are mailing lists you can subscribe at - http://savannah.nongnu.org/mail/?group=lwip -plus searchable archives: - http://lists.nongnu.org/archive/html/lwip-users/ - http://lists.nongnu.org/archive/html/lwip-devel/ - -lwIP was originally written by Adam Dunkels: - http://dunkels.com/adam/ - -Reading Adam's papers, the files in docs/, browsing the source code -documentation and browsing the mailing list archives is a good way to -become familiar with the design of lwIP. - -Adam Dunkels -Leon Woestenberg diff --git a/ext/lwip/UPGRADING b/ext/lwip/UPGRADING deleted file mode 100644 index f44fb48..0000000 --- a/ext/lwip/UPGRADING +++ /dev/null @@ -1,217 +0,0 @@ -This file lists major changes between release versions that require -ports or applications to be changed. Use it to update a port or an -application written for an older version of lwIP to correctly work -with newer versions. - - -(git master) - - * [Enter new changes just after this line - do not remove this line] - - * TODO - -(2.0.0) - - ++ Application changes: - - * Changed netif "up" flag handling to be an administrative flag (as opposed to the previous meaning of - "ip4-address-valid", a netif will now not be used for transmission if not up) -> even a DHCP netif - has to be set "up" before starting the DHCP client - * Added IPv6 support (dual-stack or IPv4/IPv6 only) - * Changed ip_addr_t to be a union in dual-stack mode (use ip4_addr_t where referring to IPv4 only). - * Major rewrite of SNMP (added MIB parser that creates code stubs for custom MIBs); - supports SNMP2vc (experimental v3 support) - * Moved some core applications from contrib repository to src/apps (and include/lwip/apps) - - +++ Raw API: - * Changed TCP listen backlog: removed tcp_accepted(), added the function pair tcp_backlog_delayed()/ - tcp_backlog_accepted() to explicitly delay backlog handling on a connection pcb - - +++ Socket API: - * Added an implementation for posix sendmsg() - * Added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram - - ++ Port changes - - +++ new files: - * MANY new and moved files! - * Continued moving stack-internal parts from abc.h to abc_priv.h in sub-folder "priv" - to let abc.h only contain the actual application programmer's API - - +++ sys layer: - * Made LWIP_TCPIP_CORE_LOCKING==1 the default as it usually performs better than - the traditional message passing (although with LWIP_COMPAT_MUTEX you are still - open to priority inversion, so this is not recommended any more) - * Added LWIP_NETCONN_SEM_PER_THREAD to use one "op_completed" semaphore per thread - instead of using one per netconn (these semaphores are used even with core locking - enabled as some longer lasting functions like big writes still need to delay) - - +++ new options: - * TODO - - +++ new pools: - * Added LWIP_MEMPOOL_* (declare/init/alloc/free) to declare private memp pools - that share memp.c code but do not have to be made global via lwippools.h - * Added pools for IPv6, MPU_COMPATIBLE, dns-api, netif-api, etc. - * added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item - is now available - - * LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp) - or to move buffers to dedicated memory using compiler attributes - - * Standard C headers are used to define sized types and printf formatters - (disable by setting LWIP_NO_STDINT_H=1 or LWIP_NO_INTTYPES_H=1 if your compiler - does not support these) - - - ++ Major bugfixes/improvements - - * Added IPv6 support (dual-stack or IPv4/IPv6 only) - * Major rewrite of PPP (incl. keep-up with apache pppd) - * Major rewrite of SNMP (incl. MIB parser) - * Fixed timing issues that might have lead to losing a DHCP lease - * Made rx processing path more robust against crafted errors - * TCP window scaling support - * modification of api modules to support FreeRTOS-MPU (don't pass stack-pointers to other threads) - * made DNS client more robust - * support PBUF_REF for RX packets - * LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate - threads each (needs LWIP_NETCONN_SEM_PER_THREAD) - * Moved and reorderd stats (mainly memp/mib2) - -(1.4.0) - - ++ Application changes: - - * Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for - compatibility to old applications, but will be removed in the future). - - * Renamed mem_realloc() to mem_trim() to prevent confusion with realloc() - - +++ Raw API: - * Changed the semantics of tcp_close() (since it was rather a - shutdown before): Now the application does *NOT* get any calls to the recv - callback (aside from NULL/closed) after calling tcp_close() - - * When calling tcp_abort() from a raw API TCP callback function, - make sure you return ERR_ABRT to prevent accessing unallocated memory. - (ERR_ABRT now means the applicaiton has called tcp_abort!) - - +++ Netconn API: - * Changed netconn_receive() and netconn_accept() to return - err_t, not a pointer to new data/netconn. - - +++ Socket API: - * LWIP_SO_RCVTIMEO: when accept() or recv() time out, they - now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT. - - * Added a minimal version of posix fctl() to have a - standardised way to set O_NONBLOCK for nonblocking sockets. - - +++ all APIs: - * correctly implemented SO(F)_REUSEADDR - - ++ Port changes - - +++ new files: - - * Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h: - - * Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains - the actual application programmer's API - - * Separated timer implementation from sys.h/.c, moved to timers.h/.c; - Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you - still want to use your own timer implementation for NO_SYS==0 (as before). - - +++ sys layer: - - * Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/ - sys_sem_t; - - * Converted sys_mbox_new/sys_sem_new to take pointers and return err_t; - - * Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use - binary semaphores instead of mutexes - as before) - - +++ new options: - - * Don't waste memory when chaining segments, added option TCP_OVERSIZE to - prevent creating many small pbufs when calling tcp_write with many small - blocks of data. Instead, pbufs are allocated larger than needed and the - space is used for later calls to tcp_write. - - * Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs - in tcp_write/udp_send. - - * Added an additional option LWIP_ETHERNET to support ethernet without ARP - (necessary for pure PPPoE) - - * Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may - be used to place these pools into user-defined memory by using external - declaration. - - * Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT - - +++ new pools: - - * Netdb uses a memp pool for allocating memory when getaddrinfo() is called, - so MEMP_NUM_NETDB has to be set accordingly. - - * DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so - MEMP_NUM_LOCALHOSTLIST has to be set accordingly. - - * Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have - to be set accordingly. - - * PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES - has to be set accordingly - - * Integrated loopif into netif.c - loopif does not have to be created by the - port any more, just define LWIP_HAVE_LOOPIF to 1. - - * Added define LWIP_RAND() for lwip-wide randomization (needs to be defined - in cc.h, e.g. used by igmp) - - * Added printf-formatter X8_F to printf u8_t as hex - - * The heap now may be moved to user-defined memory by defining - LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address - - * added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work - with user-allocated structs instead of calling mem_malloc - - * Added const char* name to mem- and memp-stats for easier debugging. - - * Calculate the TCP/UDP checksum while copying to only fetch data once: - Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum - - * Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to - more than one pcb. - - * Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned - off any more, if this is set to 0, only one packet (the most recent one) is - queued (like demanded by RFC 1122). - - - ++ Major bugfixes/improvements - - * Implemented tcp_shutdown() to only shut down one end of a connection - * Implemented shutdown() at socket- and netconn-level - * Added errorset support to select() + improved select speed overhead - * Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x) - * Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1 - * Use macros defined in ip_addr.h to work with IP addresses - * Implemented many nonblocking socket/netconn functions - * Fixed ARP input processing: only add a new entry if a request was directed as us - * mem_realloc() to mem_trim() to prevent confusion with realloc() - * Some improvements for AutoIP (don't route/forward link-local addresses, don't break - existing connections when assigning a routable address) - * Correctly handle remote side overrunning our rcv_wnd in ooseq case - * Removed packing from ip_addr_t, the packed version is now only used in protocol headers - * Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0 - * Added support for static ARP table entries - -(STABLE-1.3.2) - - * initial version of this file diff --git a/ext/lwip/doc/FILES b/ext/lwip/doc/FILES deleted file mode 100644 index 05d356f..0000000 --- a/ext/lwip/doc/FILES +++ /dev/null @@ -1,6 +0,0 @@ -savannah.txt - How to obtain the current development source code. -contrib.txt - How to contribute to lwIP as a developer. -rawapi.txt - The documentation for the core API of lwIP. - Also provides an overview about the other APIs and multithreading. -snmp_agent.txt - The documentation for the lwIP SNMP agent. -sys_arch.txt - The documentation for a system abstraction layer of lwIP. diff --git a/ext/lwip/doc/contrib.txt b/ext/lwip/doc/contrib.txt deleted file mode 100644 index fa11dfe..0000000 --- a/ext/lwip/doc/contrib.txt +++ /dev/null @@ -1,58 +0,0 @@ -1 Introduction - -This document describes some guidelines for people participating -in lwIP development. - -2 How to contribute to lwIP - -Here is a short list of suggestions to anybody working with lwIP and -trying to contribute bug reports, fixes, enhancements, platform ports etc. -First of all as you may already know lwIP is a volunteer project so feedback -to fixes or questions might often come late. Hopefully the bug and patch tracking -features of Savannah help us not lose users' input. - -2.1 Source code style: - -1. do not use tabs. -2. indentation is two spaces per level (i.e. per tab). -3. end debug messages with a trailing newline (\n). -4. one space between keyword and opening bracket. -5. no space between function and opening bracket. -6. one space and no newline before opening curly braces of a block. -7. closing curly brace on a single line. -8. spaces surrounding assignment and comparisons. -9. don't initialize static and/or global variables to zero, the compiler takes care of that. -10. use current source code style as further reference. - -2.2 Source code documentation style: - -1. JavaDoc compliant and Doxygen compatible. -2. Function documentation above functions in .c files, not .h files. - (This forces you to synchronize documentation and implementation.) -3. Use current documentation style as further reference. - -2.3 Bug reports and patches: - -1. Make sure you are reporting bugs or send patches against the latest - sources. (From the latest release and/or the current Git sources.) -2. If you think you found a bug make sure it's not already filed in the - bugtracker at Savannah. -3. If you have a fix put the patch on Savannah. If it is a patch that affects - both core and arch specific stuff please separate them so that the core can - be applied separately while leaving the other patch 'open'. The prefered way - is to NOT touch archs you can't test and let maintainers take care of them. - This is a good way to see if they are used at all - the same goes for unix - netifs except tapif. -4. Do not file a bug and post a fix to it to the patch area. Either a bug report - or a patch will be enough. - If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area. -5. Patches should be specific to a single change or to related changes. Do not mix bugfixes with spelling and other - trivial fixes unless the bugfix is trivial too. Do not reorganize code and rename identifiers in the same patch you - change behaviour if not necessary. A patch is easier to read and understand if it's to the point and short than - if it's not to the point and long :) so the chances for it to be applied are greater. - -2.4 Platform porters: - -1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and - you think it could benefit others[1] you might want discuss this on the mailing list. You - can also ask for Git access to submit and maintain your port in the contrib Git module. diff --git a/ext/lwip/doc/doxygen/generate.bat b/ext/lwip/doc/doxygen/generate.bat deleted file mode 100644 index 99afb12..0000000 --- a/ext/lwip/doc/doxygen/generate.bat +++ /dev/null @@ -1 +0,0 @@ -doxygen lwip.Doxyfile diff --git a/ext/lwip/doc/doxygen/generate.sh b/ext/lwip/doc/doxygen/generate.sh deleted file mode 100755 index 99afb12..0000000 --- a/ext/lwip/doc/doxygen/generate.sh +++ /dev/null @@ -1 +0,0 @@ -doxygen lwip.Doxyfile diff --git a/ext/lwip/doc/doxygen/main_page.h b/ext/lwip/doc/doxygen/main_page.h deleted file mode 100644 index 9f01d9f..0000000 --- a/ext/lwip/doc/doxygen/main_page.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @defgroup lwip lwIP - * - * @defgroup infrastructure Infrastructure - * - * @defgroup callbackstyle_api Callback-style APIs - * Non thread-safe APIs, callback style for maximum performance and minimum - * memory footprint. - * - * @defgroup threadsafe_api Thread-safe APIs - * Thread-safe APIs, blocking functions. More overhead, but can be called - * from any thread except TCPIP thread. - * - * @defgroup addons Addons - * - * @defgroup apps Applications - */ - -/** - * @mainpage Overview - * @verbinclude "README" - */ - -/** - * @page upgrading Upgrading - * @verbinclude "UPGRADING" - */ - -/** - * @page contrib How to contribute to lwIP - * @verbinclude "contrib.txt" - */ diff --git a/ext/lwip/doc/ppp.txt b/ext/lwip/doc/ppp.txt deleted file mode 100644 index e40c012..0000000 --- a/ext/lwip/doc/ppp.txt +++ /dev/null @@ -1,529 +0,0 @@ -PPP interface for lwIP - -Author: Sylvain Rochet - -Table of Contents: - -1 - Supported PPP protocols and features -2 - Raw API PPP example for all protocols -3 - PPPoS input path (raw API, IRQ safe API, TCPIP API) -4 - Thread safe PPP API (PPPAPI) -5 - Notify phase callback (PPP_NOTIFY_PHASE) -6 - Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x - - - -1 Supported PPP protocols and features -====================================== - -Supported Low level protocols: -* PPP over serial using HDLC-like framing, such as wired dialup modems - or mobile telecommunications GPRS/EDGE/UMTS/HSPA+/LTE modems -* PPP over Ethernet, such as xDSL modems -* PPP over L2TP (Layer 2 Tunneling Protocol) LAC (L2TP Access Concentrator), - IP tunnel over UDP, such as VPN access - -Supported auth protocols: -* PAP, Password Authentication Protocol -* CHAP, Challenge-Handshake Authentication Protocol, also known as CHAP-MD5 -* MSCHAPv1, Microsoft version of CHAP, version 1 -* MSCHAPv2, Microsoft version of CHAP, version 2 -* EAP, Extensible Authentication Protocol - -Supported address protocols: -* IPCP, IP Control Protocol, IPv4 addresses negotiation -* IP6CP, IPv6 Control Protocol, IPv6 link-local addresses negotiation - -Supported encryption protocols: -* MPPE, Microsoft Point-to-Point Encryption - -Supported compression or miscellaneous protocols, for serial links only: -* PFC, Protocol Field Compression -* ACFC, Address-and-Control-Field-Compression -* ACCM, Asynchronous-Control-Character-Map -* VJ, Van Jacobson TCP/IP Header Compression - - - -2 Raw API PPP example for all protocols -======================================= - -As usual, raw API for lwIP means the lightweight API which *MUST* only be used -for NO_SYS=1 systems or called inside lwIP core thread for NO_SYS=0 systems. - -/* - * Globals - * ======= - */ - -/* The PPP control block */ -ppp_pcb *ppp; - -/* The PPP IP interface */ -struct netif ppp_netif; - - -/* - * PPP status callback - * =================== - * - * PPP status callback is called on PPP status change (up, down, …) from lwIP - * core thread - */ - -/* PPP status callback example */ -static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) { - struct netif *pppif = ppp_netif(pcb); - LWIP_UNUSED_ARG(ctx); - - switch(err_code) { - case PPPERR_NONE: { -#if LWIP_DNS - ip_addr_t ns; -#endif /* LWIP_DNS */ - printf("status_cb: Connected\n"); -#if PPP_IPV4_SUPPORT - printf(" our_ipaddr = %s\n", ipaddr_ntoa(&pppif->ip_addr)); - printf(" his_ipaddr = %s\n", ipaddr_ntoa(&pppif->gw)); - printf(" netmask = %s\n", ipaddr_ntoa(&pppif->netmask)); -#if LWIP_DNS - ns = dns_getserver(0); - printf(" dns1 = %s\n", ipaddr_ntoa(&ns)); - ns = dns_getserver(1); - printf(" dns2 = %s\n", ipaddr_ntoa(&ns)); -#endif /* LWIP_DNS */ -#endif /* PPP_IPV4_SUPPORT */ -#if PPP_IPV6_SUPPORT - printf(" our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0))); -#endif /* PPP_IPV6_SUPPORT */ - break; - } - case PPPERR_PARAM: { - printf("status_cb: Invalid parameter\n"); - break; - } - case PPPERR_OPEN: { - printf("status_cb: Unable to open PPP session\n"); - break; - } - case PPPERR_DEVICE: { - printf("status_cb: Invalid I/O device for PPP\n"); - break; - } - case PPPERR_ALLOC: { - printf("status_cb: Unable to allocate resources\n"); - break; - } - case PPPERR_USER: { - printf("status_cb: User interrupt\n"); - break; - } - case PPPERR_CONNECT: { - printf("status_cb: Connection lost\n"); - break; - } - case PPPERR_AUTHFAIL: { - printf("status_cb: Failed authentication challenge\n"); - break; - } - case PPPERR_PROTOCOL: { - printf("status_cb: Failed to meet protocol\n"); - break; - } - case PPPERR_PEERDEAD: { - printf("status_cb: Connection timeout\n"); - break; - } - case PPPERR_IDLETIMEOUT: { - printf("status_cb: Idle Timeout\n"); - break; - } - case PPPERR_CONNECTTIME: { - printf("status_cb: Max connect time reached\n"); - break; - } - case PPPERR_LOOPBACK: { - printf("status_cb: Loopback detected\n"); - break; - } - default: { - printf("status_cb: Unknown error code %d\n", err_code); - break; - } - } - -/* - * This should be in the switch case, this is put outside of the switch - * case for example readability. - */ - - if (err_code == PPPERR_NONE) { - return; - } - - /* ppp_close() was previously called, don't reconnect */ - if (err_code == PPPERR_USER) { - /* ppp_free(); -- can be called here */ - return; - } - - /* - * Try to reconnect in 30 seconds, if you need a modem chatscript you have - * to do a much better signaling here ;-) - */ - ppp_connect(pcb, 30); - /* OR ppp_listen(pcb); */ -} - - -/* - * Creating a new PPPoS session - * ============================ - * - * In lwIP, PPPoS is not PPPoSONET, in lwIP PPPoS is PPPoSerial. - */ - -#include "netif/ppp/pppos.h" - -/* - * PPPoS serial output callback - * - * ppp_pcb, PPP control block - * data, buffer to write to serial port - * len, length of the data buffer - * ctx, optional user-provided callback context pointer - * - * Return value: len if write succeed - */ -static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { - return uart_write(UART, data, len); -} - -/* - * Create a new PPPoS interface - * - * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface - * output_cb, PPPoS serial output callback - * status_cb, PPP status callback, called on PPP status change (up, down, …) - * ctx_cb, optional user-provided callback context pointer - */ -ppp = pppos_create(&ppp_netif, - output_cb, status_cb, ctx_cb); - - -/* - * Creating a new PPPoE session - * ============================ - */ - -#include "netif/ppp/pppoe.h" - -/* - * Create a new PPPoE interface - * - * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface - * ethif, already existing and setup Ethernet interface to use - * service_name, PPPoE service name discriminator (not supported yet) - * concentrator_name, PPPoE concentrator name discriminator (not supported yet) - * status_cb, PPP status callback, called on PPP status change (up, down, …) - * ctx_cb, optional user-provided callback context pointer - */ -ppp = pppoe_create(&ppp_netif, - ðif, - service_name, concentrator_name, - status_cb, ctx_cb); - - -/* - * Creating a new PPPoL2TP session - * =============================== - */ - -#include "netif/ppp/pppol2tp.h" - -/* - * Create a new PPPoL2TP interface - * - * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface - * netif, optional already existing and setup output netif, necessary if you - * want to set this interface as default route to settle the chicken - * and egg problem with VPN links - * ipaddr, IP to connect to - * port, UDP port to connect to (usually 1701) - * secret, L2TP secret to use - * secret_len, size in bytes of the L2TP secret - * status_cb, PPP status callback, called on PPP status change (up, down, …) - * ctx_cb, optional user-provided callback context pointer - */ -ppp = pppol2tp_create(&ppp_netif, - struct netif *netif, ip_addr_t *ipaddr, u16_t port, - u8_t *secret, u8_t secret_len, - ppp_link_status_cb_fn link_status_cb, void *ctx_cb); - - -/* - * Initiate PPP client connection - * ============================== - */ - -/* Set this interface as default route */ -ppp_set_default(ppp); - -/* - * Basic PPP client configuration. Can only be set if PPP session is in the - * dead state (i.e. disconnected). We don't need to provide thread-safe - * equivalents through PPPAPI because those helpers are only changing - * structure members while session is inactive for lwIP core. Configuration - * only need to be done once. - */ - -/* Ask the peer for up to 2 DNS server addresses. */ -ppp_set_usepeerdns(ppp, 1); - -/* Auth configuration, this is pretty self-explanatory */ -ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password"); - -/* - * Initiate PPP negotiation, without waiting (holdoff=0), can only be called - * if PPP session is in the dead state (i.e. disconnected). - */ -u16_t holdoff = 0; -ppp_connect(ppp, holdoff); - - -/* - * Initiate PPP server listener - * ============================ - */ - -/* - * Basic PPP server configuration. Can only be set if PPP session is in the - * dead state (i.e. disconnected). We don't need to provide thread-safe - * equivalents through PPPAPI because those helpers are only changing - * structure members while session is inactive for lwIP core. Configuration - * only need to be done once. - */ -ip4_addr_t addr; - -/* Set our address */ -IP4_ADDR(&addr, 192,168,0,1); -ppp_set_ipcp_ouraddr(ppp, &addr); - -/* Set peer(his) address */ -IP4_ADDR(&addr, 192,168,0,2); -ppp_set_ipcp_hisaddr(ppp, &addr); - -/* Set primary DNS server */ -IP4_ADDR(&addr, 192,168,10,20); -ppp_set_ipcp_dnsaddr(ppp, 0, &addr); - -/* Set secondary DNS server */ -IP4_ADDR(&addr, 192,168,10,21); -ppp_set_ipcp_dnsaddr(ppp, 1, &addr); - -/* Auth configuration, this is pretty self-explanatory */ -ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password"); - -/* Require peer to authenticate */ -ppp_set_auth_required(ppp, 1); - -/* - * Only for PPPoS, the PPP session should be up and waiting for input. - * - * Note: for PPPoS, ppp_connect() and ppp_listen() are actually the same thing. - * The listen call is meant for future support of PPPoE and PPPoL2TP server - * mode, where we will need to negotiate the incoming PPPoE session or L2TP - * session before initiating PPP itself. We need this call because there is - * two passive modes for PPPoS, ppp_set_passive and ppp_set_silent. - */ -ppp_set_silent(pppos, 1); - -/* - * Initiate PPP listener (i.e. wait for an incoming connection), can only - * be called if PPP session is in the dead state (i.e. disconnected). - */ -ppp_listen(ppp); - - -/* - * Closing PPP connection - * ====================== - */ - -/* - * Initiate the end of the PPP session, without carrier lost signal - * (nocarrier=0), meaning a clean shutdown of PPP protocols. - * You can call this function at anytime. - */ -u8_t nocarrier = 0; -ppp_close(ppp, nocarrier); -/* - * Then you must wait your status_cb() to be called, it may takes from a few - * seconds to several tens of seconds depending on the current PPP state. - */ - -/* - * Freeing a PPP connection - * ======================== - */ - -/* - * Free the PPP control block, can only be called if PPP session is in the - * dead state (i.e. disconnected). You need to call ppp_close() before. - */ -ppp_free(ppp); - - - -3 PPPoS input path (raw API, IRQ safe API, TCPIP API) -===================================================== - -Received data on serial port should be sent to lwIP using the pppos_input() -function or the pppos_input_tcpip() function. - -If NO_SYS is 1 and if PPP_INPROC_IRQ_SAFE is 0 (the default), pppos_input() -is not IRQ safe and then *MUST* only be called inside your main loop. - -Whatever the NO_SYS value, if PPP_INPROC_IRQ_SAFE is 1, pppos_input() is IRQ -safe and can be safely called from an interrupt context, using that is going -to reduce your need of buffer if pppos_input() is called byte after byte in -your rx serial interrupt. - -if NO_SYS is 0, the thread safe way outside an interrupt context is to use -the pppos_input_tcpip() function to pass input data to the lwIP core thread -using the TCPIP API. This is thread safe in all cases but you should avoid -passing data byte after byte because it uses heavy locking (mailbox) and it -allocates pbuf, better fill them ! - -if NO_SYS is 0 and if PPP_INPROC_IRQ_SAFE is 1, you may also use pppos_input() -from an RX thread, however pppos_input() is not thread safe by itself. You can -do that *BUT* you should NEVER call pppos_connect(), pppos_listen() and -ppp_free() if pppos_input() can still be running, doing this is NOT thread safe -at all. Using PPP_INPROC_IRQ_SAFE from an RX thread is discouraged unless you -really know what you are doing, your move ;-) - - -/* - * Fonction to call for received data - * - * ppp, PPP control block - * buffer, input buffer - * buffer_len, buffer length in bytes - */ -void pppos_input(ppp, buffer, buffer_len); - -or - -void pppos_input_tcpip(ppp, buffer, buffer_len); - - - -4 Thread safe PPP API (PPPAPI) -============================== - -There is a thread safe API for all corresponding ppp_* functions, you have to -enable LWIP_PPP_API in your lwipopts.h file, then see -include/netif/ppp/pppapi.h, this is actually pretty obvious. - - - -5 Notify phase callback (PPP_NOTIFY_PHASE) -========================================== - -Notify phase callback, enabled using the PPP_NOTIFY_PHASE config option, let -you configure a callback that is called on each PPP internal state change. -This is different from the status callback which only warns you about -up(running) and down(dead) events. - -Notify phase callback can be used, for example, to set a LED pattern depending -on the current phase of the PPP session. Here is a callback example which -tries to mimic what we usually see on xDSL modems while they are negotiating -the link, which should be self-explanatory: - -static void ppp_notify_phase_cb(ppp_pcb *pcb, u8_t phase, void *ctx) { - switch (phase) { - - /* Session is down (either permanently or briefly) */ - case PPP_PHASE_DEAD: - led_set(PPP_LED, LED_OFF); - break; - - /* We are between two sessions */ - case PPP_PHASE_HOLDOFF: - led_set(PPP_LED, LED_SLOW_BLINK); - break; - - /* Session just started */ - case PPP_PHASE_INITIALIZE: - led_set(PPP_LED, LED_FAST_BLINK); - break; - - /* Session is running */ - case PPP_PHASE_RUNNING: - led_set(PPP_LED, LED_ON); - break; - - default: - break; - } -} - - - -6 Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x -=============================================== - -PPP API was fully reworked between 1.4.x and 2.0.x releases. However porting -from previous lwIP version is pretty easy: - -* Previous PPP API used an integer to identify PPP sessions, we are now - using ppp_pcb* control block, therefore all functions changed from "int ppp" - to "ppp_pcb *ppp" - -* struct netif was moved outside the PPP structure, you have to provide a netif - for PPP interface in pppoX_create() functions - -* PPP session are not started automatically after you created them anymore, - you have to call ppp_connect(), this way you can configure the session before - starting it. - -* Previous PPP API used CamelCase, we are now using snake_case. - -* Previous PPP API mixed PPPoS and PPPoE calls, this isn't the case anymore, - PPPoS functions are now prefixed pppos_ and PPPoE functions are now prefixed - pppoe_, common functions are now prefixed ppp_. - -* New PPPERR_ error codes added, check you have all of them in your status - callback function - -* Only the following include files should now be used in user application: - #include "netif/ppp/pppapi.h" - #include "netif/ppp/pppos.h" - #include "netif/ppp/pppoe.h" - #include "netif/ppp/pppol2tp.h" - - Functions from ppp.h can be used, but you don't need to include this header - file as it is already included by above header files. - -* PPP_INPROC_OWNTHREAD was broken by design and was removed, you have to create - your own serial rx thread - -* PPP_INPROC_MULTITHREADED option was misnamed and confusing and was renamed - PPP_INPROC_IRQ_SAFE, please read the "PPPoS input path" documentation above - because you might have been fooled by that - -* If you used tcpip_callback_with_block() on ppp_ functions you may wish to use - the PPPAPI API instead. - -* ppp_sighup and ppp_close functions were merged using an optional argument - "nocarrier" on ppp_close. - -* DNS servers are now only remotely asked if LWIP_DNS is set and if - ppp_set_usepeerdns() is set to true, they are now automatically registered - using the dns_setserver() function so you don't need to do that in the PPP - callback anymore. - -* PPPoS does not use the SIO API anymore, as such it now requires a serial - output callback in place of sio_write - -* PPP_MAXIDLEFLAG is now in ms instead of jiffies diff --git a/ext/lwip/doc/rawapi.txt b/ext/lwip/doc/rawapi.txt deleted file mode 100644 index ce5b42a..0000000 --- a/ext/lwip/doc/rawapi.txt +++ /dev/null @@ -1,506 +0,0 @@ -Raw TCP/IP interface for lwIP - -Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons - -lwIP provides three Application Program's Interfaces (APIs) for programs -to use for communication with the TCP/IP code: -* low-level "core" / "callback" or "raw" API. -* higher-level "sequential" API. -* BSD-style socket API. - -The raw API (sometimes called native API) is an event-driven API designed -to be used without an operating system that implements zero-copy send and -receive. This API is also used by the core stack for interaction between -the various protocols. It is the only API available when running lwIP -without an operating system. - -The sequential API provides a way for ordinary, sequential, programs -to use the lwIP stack. It is quite similar to the BSD socket API. The -model of execution is based on the blocking open-read-write-close -paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP -code and the application program must reside in different execution -contexts (threads). - -The socket API is a compatibility API for existing applications, -currently it is built on top of the sequential API. It is meant to -provide all functions needed to run socket API applications running -on other platforms (e.g. unix / windows etc.). However, due to limitations -in the specification of this API, there might be incompatibilities -that require small modifications of existing programs. - -** Multithreading - -lwIP started targeting single-threaded environments. When adding multi- -threading support, instead of making the core thread-safe, another -approach was chosen: there is one main thread running the lwIP core -(also known as the "tcpip_thread"). When running in a multithreaded -environment, raw API functions MUST only be called from the core thread -since raw API functions are not protected from concurrent access (aside -from pbuf- and memory management functions). Application threads using -the sequential- or socket API communicate with this main thread through -message passing. - - As such, the list of functions that may be called from - other threads or an ISR is very limited! Only functions - from these API header files are thread-safe: - - api.h - - netbuf.h - - netdb.h - - netifapi.h - - pppapi.h - - sockets.h - - sys.h - - Additionaly, memory (de-)allocation functions may be - called from multiple threads (not ISR!) with NO_SYS=0 - since they are protected by SYS_LIGHTWEIGHT_PROT and/or - semaphores. - - Netconn or Socket API functions are thread safe against the - core thread but they are not reentrant at the control block - granularity level. That is, a UDP or TCP control block must - not be shared among multiple threads without proper locking. - - If SYS_LIGHTWEIGHT_PROT is set to 1 and - LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1, - pbuf_free() may also be called from another thread or - an ISR (since only then, mem_free - for PBUF_RAM - may - be called from an ISR: otherwise, the HEAP is only - protected by semaphores). - - -** The remainder of this document discusses the "raw" API. ** - -The raw TCP/IP interface allows the application program to integrate -better with the TCP/IP code. Program execution is event based by -having callback functions being called from within the TCP/IP -code. The TCP/IP code and the application program both run in the same -thread. The sequential API has a much higher overhead and is not very -well suited for small systems since it forces a multithreaded paradigm -on the application. - -The raw TCP/IP interface is not only faster in terms of code execution -time but is also less memory intensive. The drawback is that program -development is somewhat harder and application programs written for -the raw TCP/IP interface are more difficult to understand. Still, this -is the preferred way of writing applications that should be small in -code size and memory usage. - -All APIs can be used simultaneously by different application -programs. In fact, the sequential API is implemented as an application -program using the raw TCP/IP interface. - -Do not confuse the lwIP raw API with raw Ethernet or IP sockets. -The former is a way of interfacing the lwIP network stack (including -TCP and UDP), the later refers to processing raw Ethernet or IP data -instead of TCP connections or UDP packets. - -Raw API applications may never block since all packet processing -(input and output) as well as timer processing (TCP mainly) is done -in a single execution context. - ---- Callbacks - -Program execution is driven by callbacks functions, which are then -invoked by the lwIP core when activity related to that application -occurs. A particular application may register to be notified via a -callback function for events such as incoming data available, outgoing -data sent, error notifications, poll timer expiration, connection -closed, etc. An application can provide a callback function to perform -processing for any or all of these events. Each callback is an ordinary -C function that is called from within the TCP/IP code. Every callback -function is passed the current TCP or UDP connection state as an -argument. Also, in order to be able to keep program specific state, -the callback functions are called with a program specified argument -that is independent of the TCP/IP state. - -The function for setting the application connection state is: - -- void tcp_arg(struct tcp_pcb *pcb, void *arg) - - 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. - - ---- 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. - -- struct tcp_pcb *tcp_new(void) - - Creates a new connection identifier (PCB). If memory is not - available for creating the new pcb, NULL is returned. - -- err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, - u16_t port) - - Binds the pcb to a local IP address and port number. The IP address - can be specified as IP_ADDR_ANY in order to bind the connection 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. - -- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb) - - Commands a pcb to start listening for incoming connections. When an - incoming connection is accepted, the function specified with the - tcp_accept() function will be called. The pcb will have 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. - -- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) - - Same as tcp_listen, but 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. - -- void tcp_accepted(struct tcp_pcb *pcb) - - Inform lwIP that an incoming connection has been accepted. This would - usually be called from the accept callback. This allows lwIP to perform - housekeeping tasks, such as allowing further incoming connections to be - queued in the listen backlog. - ATTENTION: the PCB passed in must be the listening pcb, not the pcb passed - into the accept callback! - -- void tcp_accept(struct tcp_pcb *pcb, - err_t (* accept)(void *arg, struct tcp_pcb *newpcb, - err_t err)) - - Specified the callback function that should be called when a new - connection arrives on a listening connection. - -- err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, - u16_t port, err_t (* connected)(void *arg, - struct tcp_pcb *tpcb, - err_t err)); - - 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. - - ---- Sending TCP data - -TCP data is sent by enqueueing the data with a call to -tcp_write(). When the data is successfully transmitted to the remote -host, the application will be notified with a call to a specified -callback function. - -- err_t tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, - u8_t apiflags) - - Enqueues the data pointed to by the argument dataptr. The length of - the data is passed as the len parameter. The 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. - -- void tcp_sent(struct tcp_pcb *pcb, - err_t (* sent)(void *arg, struct tcp_pcb *tpcb, - u16_t len)) - - 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. - - ---- 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. - -- void tcp_recv(struct tcp_pcb *pcb, - err_t (* recv)(void *arg, struct tcp_pcb *tpcb, - struct pbuf *p, err_t err)) - - 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 - there are no errors and the callback function is to return - ERR_OK, then it must free the pbuf. Otherwise, it must not - free the pbuf so that lwIP core code can store it. - -- void tcp_recved(struct tcp_pcb *pcb, u16_t len) - - Must be called when the application has received the data. The len - argument indicates the length of the received data. - - ---- 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. - -- void tcp_poll(struct tcp_pcb *pcb, - err_t (* poll)(void *arg, struct tcp_pcb *tpcb), - u8_t interval) - - Specifies the polling interval and the callback function that should - be called to poll the application. The interval is specified in - 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. - - ---- Closing and aborting connections - -- err_t tcp_close(struct tcp_pcb *pcb) - - Closes the connection. 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. - - The pcb is deallocated by the TCP code after a call to tcp_close(). - -- void tcp_abort(struct tcp_pcb *pcb) - - Aborts the connection by sending a RST (reset) segment to the remote - host. The pcb is deallocated. This function never fails. - - ATTENTION: When calling this from one of the TCP callbacks, make - sure you always return ERR_ABRT (and never return ERR_ABRT otherwise - or you will risk accessing deallocated memory or memory leaks! - - -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. - -- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, - err_t err)) - - The error callback function does not get the pcb passed to it as a - parameter since the pcb may already have been deallocated. - - ---- UDP interface - -The UDP interface is similar to that of TCP, but due to the lower -level of complexity of UDP, the interface is significantly simpler. - -- struct udp_pcb *udp_new(void) - - 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. - -- void udp_remove(struct udp_pcb *pcb) - - Removes and deallocates the pcb. - -- err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, - u16_t port) - - Binds the pcb to a local address. The IP-address argument "ipaddr" - can be IP_ADDR_ANY to indicate that it should listen to any local IP - address. The function currently always return ERR_OK. - -- err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, - u16_t port) - - Sets the remote end of the pcb. This function does not generate any - network traffic, but only set the remote address of the pcb. - -- err_t udp_disconnect(struct udp_pcb *pcb) - - Remove the remote end of the pcb. This function does not generate - any network traffic, but only removes the remote address of the pcb. - -- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) - - Sends the pbuf p. The pbuf is not deallocated. - -- void udp_recv(struct udp_pcb *pcb, - void (* recv)(void *arg, struct udp_pcb *upcb, - struct pbuf *p, - ip_addr_t *addr, - u16_t port), - void *recv_arg) - - Specifies a callback function that should be called when a UDP - datagram is received. - - ---- System initalization - -A truly complete and generic sequence for initializing the lwIP stack -cannot be given because it depends on additional initializations for -your runtime environment (e.g. timers). - -We can give you some idea on how to proceed when using the raw API. -We assume a configuration using a single Ethernet netif and the -UDP and TCP transport layers, IPv4 and the DHCP client. - -Call these functions in the order of appearance: - -- lwip_init() - - Initialize the lwIP stack and all of its subsystems. - -- 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) - - Adds your network interface to the netif_list. Allocate a struct - netif and pass a pointer to this structure as the first argument. - Give pointers to cleared ip_addr structures when using DHCP, - or fill them with sane numbers otherwise. The state pointer may be NULL. - - The init function pointer must point to a initialization function for - your Ethernet netif interface. The following code illustrates its use. - - err_t netif_if_init(struct netif *netif) - { - u8_t i; - - for (i = 0; i < ETHARP_HWADDR_LEN; i++) { - netif->hwaddr[i] = some_eth_addr[i]; - } - init_my_eth_device(); - return ERR_OK; - } - - For Ethernet drivers, the input function pointer must point to the lwIP - function ethernet_input() declared in "netif/etharp.h". Other drivers - must use ip_input() declared in "lwip/ip.h". - -- netif_set_default(struct netif *netif) - - Registers the default network interface. - -- netif_set_link_up(struct netif *netif) - - This is the hardware link state; e.g. whether cable is plugged for wired - Ethernet interface. This function must be called even if you don't know - the current state. Having link up and link down events is optional but - DHCP and IPv6 discover benefit well from those events. - -- netif_set_up(struct netif *netif) - - This is the administrative (= software) state of the netif, when the - netif is fully configured this function must be called. - -- dhcp_start(struct netif *netif) - - Creates a new DHCP client for this interface on the first call. - - You can peek in the netif->dhcp struct for the actual DHCP status. - -- sys_check_timeouts() - - When the system is running, you have to periodically call - sys_check_timeouts() which will handle all timers for all protocols in - the stack; add this to your main loop or equivalent. - - ---- Optimalization hints - -The first thing you want to optimize is the lwip_standard_checksum() -routine from src/core/inet.c. You can override this standard -function with the #define LWIP_CHKSUM . - -There are C examples given in inet.c or you might want to -craft an assembly function for this. RFC1071 is a good -introduction to this subject. - -Other significant improvements can be made by supplying -assembly or inline replacements for htons() and htonl() -if you're using a little-endian architecture. -#define LWIP_PLATFORM_BYTESWAP 1 -#define LWIP_PLATFORM_HTONS(x) -#define LWIP_PLATFORM_HTONL(x) - -Check your network interface driver if it reads at -a higher speed than the maximum wire-speed. If the -hardware isn't serviced frequently and fast enough -buffer overflows are likely to occur. - -E.g. when using the cs8900 driver, call cs8900if_service(ethif) -as frequently as possible. When using an RTOS let the cs8900 interrupt -wake a high priority task that services your driver using a binary -semaphore or event flag. Some drivers might allow additional tuning -to match your application and network. - -For a production release it is recommended to set LWIP_STATS to 0. -Note that speed performance isn't influenced much by simply setting -high values to the memory options. - -For more optimization hints take a look at the lwIP wiki. - ---- Zero-copy MACs - -To achieve zero-copy on transmit, the data passed to the raw API must -remain unchanged until sent. Because the send- (or write-)functions return -when the packets have been enqueued for sending, data must be kept stable -after that, too. - -This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions -must *not* be reused by the application unless their ref-count is 1. - -For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too, -but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while -PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change). - -Also, data passed to tcp_write without the copy-flag must not be changed! - -Therefore, be careful which type of PBUF you use and if you copy TCP data -or not! diff --git a/ext/lwip/doc/savannah.txt b/ext/lwip/doc/savannah.txt deleted file mode 100644 index d7d19eb..0000000 --- a/ext/lwip/doc/savannah.txt +++ /dev/null @@ -1,120 +0,0 @@ -Daily Use Guide for using Savannah for lwIP - -Table of Contents: - -1 - Obtaining lwIP from the Git repository -2 - Committers/developers Git access using SSH -3 - Merging a development branch to master branch -4 - How to release lwIP - - - -1 Obtaining lwIP from the Git repository ----------------------------------------- - -To perform an anonymous Git clone of the master branch (this is where -bug fixes and incremental enhancements occur), do this: - git clone git://git.savannah.nongnu.org/lwip.git - -Or, obtain a stable branch (updated with bug fixes only) as follows: - git clone --branch DEVEL-1_4_1 git://git.savannah.nongnu.org/lwip.git - -Or, obtain a specific (fixed) release as follows: - git clone --branch STABLE-1_4_1 git://git.savannah.nongnu.org/lwip.git - - -2 Committers/developers Git access using SSH --------------------------------------------- - -The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption. -As such, Git commits to the server occur through a SSH tunnel for project members. -To create a SSH2 key pair in UNIX-like environments, do this: - ssh-keygen -t dsa - -Under Windows, a recommended SSH client is "PuTTY", freely available with good -documentation and a graphic user interface. Use its key generator. - -Now paste the id_dsa.pub contents into your Savannah account public key list. Wait -a while so that Savannah can update its configuration (This can take minutes). - -Try to login using SSH: - ssh -v your_login@git.sv.gnu.org - -If it tells you: - Linux vcs.savannah.gnu.org 2.6.32-5-xen-686 #1 SMP Wed Jun 17 17:10:03 UTC 2015 i686 - - Interactive shell login is not possible for security reasons. - VCS commands are allowed. - Last login: Tue May 15 23:10:12 2012 from 82.245.102.129 - You tried to execute: - Sorry, you are not allowed to execute that command. - Shared connection to git.sv.gnu.org closed. - -then you could login; Savannah refuses to give you a shell - which is OK, as we -are allowed to use SSH for Git only. Now, you should be able to do this: - git clone your_login@git.sv.gnu.org:/srv/git/lwip.git - -After which you can edit your local files with bug fixes or new features and -commit them. Make sure you know what you are doing when using Git to make -changes on the repository. If in doubt, ask on the lwip-members mailing list. - -(If SSH asks about authenticity of the host, you can check the key -fingerprint against https://savannah.nongnu.org/git/?group=lwip - - -3 - Merging a development branch to master branch -------------------------------------------------- - -Merging is a straightforward process in Git. How to merge all changes in a -development branch since our last merge from main: - -Checkout the master branch: - git checkout master - -Merge the development branch to master: - git merge your-development-branch - -Resolve any conflict. - -Commit the merge result. - git commit -a - -Push your commits: - git push - - -4 How to release lwIP ---------------------- - -First, tag the release using Git: (I use release number 1.4.1 throughout -this example). - git tag -a STABLE-1_4_1 - -Share the tag reference by pushing it to remote: - git push origin STABLE-1_4_1 - -Prepare the release: - cp -r lwip lwip-1.4.1 - rm -rf lwip-1.4.1/.git lwip-1.4.1/.gitattributes - -Archive the current directory using tar, gzip'd, bzip2'd and zip'd. - tar czvf lwip-1.4.1.tar.gz lwip-1.4.1 - tar cjvf lwip-1.4.1.tar.bz2 lwip-1.4.1 - zip -r lwip-1.4.1.zip lwip-1.4.1 - -Now, sign the archives with a detached GPG binary signature as follows: - gpg -b lwip-1.4.1.tar.gz - gpg -b lwip-1.4.1.tar.bz2 - gpg -b lwip-1.4.1.zip - -Upload these files using anonymous FTP: - ncftp ftp://savannah.gnu.org/incoming/savannah/lwip - ncftp> mput *1.4.1.* - -Additionally, you may post a news item on Savannah, like this: - -A new 1.4.1 release is now available here: -http://savannah.nongnu.org/files/?group=lwip&highlight=1.4.1 - -You will have to submit this via the user News interface, then approve -this via the Administrator News interface. diff --git a/ext/lwip/doc/sys_arch.txt b/ext/lwip/doc/sys_arch.txt deleted file mode 100644 index 847cd77..0000000 --- a/ext/lwip/doc/sys_arch.txt +++ /dev/null @@ -1,267 +0,0 @@ -sys_arch interface for lwIP 0.6++ - -Author: Adam Dunkels - -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 and mailboxes to lwIP. For the full -lwIP functionality, multiple threads support can be implemented in the -sys_arch, but this is not required for the basic lwIP -functionality. Previous versions of lwIP required the sys_arch to -implement timer scheduling as well but as of lwIP 0.5 this is -implemented in a higher layer. - -In addition to the source file providing the functionality of sys_arch, -the OS emulation layer must provide several header files defining -macros used throughout lwip. The files required and the macros they -must define are listed below the sys_arch description. - -Semaphores can be either counting or binary - lwIP works with both -kinds. Mailboxes are used for message passing and can be implemented -either as a queue which allows multiple messages to be posted to a -mailbox, or as a rendez-vous point where only one message can be -posted at a time. lwIP works with both kinds, but the former type will -be more efficient. A message in a mailbox is just a pointer, nothing -more. - -Semaphores are represented by the type "sys_sem_t" which is typedef'd -in the sys_arch.h file. Mailboxes are equivalently represented by the -type "sys_mbox_t". lwIP does not place any restrictions on how -sys_sem_t or sys_mbox_t are represented internally. - -Since lwIP 1.4.0, semaphore and mailbox functions are prototyped in a way that -allows both using pointers or actual OS structures to be used. This way, memory -required for such types can be either allocated in place (globally or on the -stack) or on the heap (allocated internally in the "*_new()" functions). - -The following functions must be implemented by the sys_arch: - -- void sys_init(void) - - Is called to initialize the sys_arch layer. - -- err_t sys_sem_new(sys_sem_t *sem, u8_t count) - - Creates a new semaphore. The semaphore is allocated to the memory that 'sem' - points to (which can be both a pointer or the actual OS structure). - The "count" argument specifies the initial state of the semaphore (which is - either 0 or 1). - If the semaphore has been created, ERR_OK should be returned. Returning any - other error will provide a hint what went wrong, but except for assertions, - no real error handling is implemented. - -- void sys_sem_free(sys_sem_t *sem) - - Deallocates a semaphore. - -- void sys_sem_signal(sys_sem_t *sem) - - Signals a semaphore. - -- u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) - - Blocks the thread while waiting for the semaphore to be - signaled. If the "timeout" argument is non-zero, the thread should - 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. - - If the timeout argument is non-zero, the return value is the number of - milliseconds spent waiting for the semaphore to be signaled. If the - semaphore wasn't signaled within the specified time, the return value is - SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore - (i.e., it was already signaled), the function may return zero. - - Notice that lwIP implements a function with a similar name, - sys_sem_wait(), that uses the sys_arch_sem_wait() function. - -- int sys_sem_valid(sys_sem_t *sem) - - Returns 1 if the semaphore is valid, 0 if it is not valid. - When using pointers, a simple way is to check the pointer for != NULL. - When directly using OS structures, implementing this may be more complex. - This may also be a define, in which case the function is not prototyped. - -- void sys_sem_set_invalid(sys_sem_t *sem) - - Invalidate a semaphore so that sys_sem_valid() returns 0. - ATTENTION: This does NOT mean that the semaphore shall be deallocated: - sys_sem_free() is always called before calling this function! - This may also be a define, in which case the function is not prototyped. - -- err_t sys_mbox_new(sys_mbox_t *mbox, int size) - - Creates an empty mailbox for maximum "size" elements. Elements stored - in mailboxes are pointers. You have to define macros "_MBOX_SIZE" - in your lwipopts.h, or ignore this parameter in your implementation - and use a default size. - If the mailbox has been created, ERR_OK should be returned. Returning any - other error will provide a hint what went wrong, but except for assertions, - no real error handling is implemented. - -- void sys_mbox_free(sys_mbox_t *mbox) - - Deallocates a mailbox. If there are messages still present in the - mailbox when the mailbox is deallocated, it is an indication of a - programming error in lwIP and the developer should be notified. - -- void sys_mbox_post(sys_mbox_t *mbox, void *msg) - - Posts the "msg" to the mailbox. This function have to block until - the "msg" is really posted. - -- err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) - - Try to post the "msg" to the mailbox. Returns ERR_MEM if this one - is full, else, ERR_OK if the "msg" is posted. - -- u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) - - 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: - Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a - timeout. - - Note that a function with a similar name, sys_mbox_fetch(), is - implemented by lwIP. - -- u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) - - 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. - -- int sys_mbox_valid(sys_mbox_t *mbox) - - Returns 1 if the mailbox is valid, 0 if it is not valid. - When using pointers, a simple way is to check the pointer for != NULL. - When directly using OS structures, implementing this may be more complex. - This may also be a define, in which case the function is not prototyped. - -- void sys_mbox_set_invalid(sys_mbox_t *mbox) - - Invalidate a mailbox so that sys_mbox_valid() returns 0. - ATTENTION: This does NOT mean that the mailbox shall be deallocated: - sys_mbox_free() is always called before calling this function! - This may also be a define, in which case the function is not prototyped. - -If threads are supported by the underlying operating system and if -such functionality is needed in lwIP, the following function will have -to be implemented as well: - -- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) - - 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. - -- sys_prot_t sys_arch_protect(void) - - This optional function does a "fast" critical region protection and returns - the previous protection level. This function is only called during very short - critical regions. An embedded system which supports ISR-based drivers might - want to implement this function by disabling interrupts. Task-based systems - might want to implement this by using a mutex or disabling tasking. This - function should support recursive calls from the same task or interrupt. In - other words, sys_arch_protect() could be called while already protected. In - that case the return value indicates that it is already protected. - - sys_arch_protect() is only required if your port is supporting an operating - system. - -- void sys_arch_unprotect(sys_prot_t pval) - - This optional function does a "fast" set of critical region protection to the - value specified by pval. See the documentation for sys_arch_protect() for - more information. This function is only required if your port is supporting - an operating system. - -For some configurations, you also need: - -- u32_t sys_now(void) - - This optional function returns the current time in milliseconds (don't care - for wraparound, this is only used for time diffs). - Not implementing this function means you cannot use some modules (e.g. TCP - timestamps, internal timeouts for NO_SYS==1). - - -Note: - -Be carefull with using mem_malloc() in sys_arch. When malloc() refers to -mem_malloc() you can run into a circular function call problem. In mem.c -mem_init() tries to allcate a semaphore using mem_malloc, which of course -can't be performed when sys_arch uses mem_malloc. - -------------------------------------------------------------------------------- -Additional files required for the "OS support" emulation layer: -------------------------------------------------------------------------------- - -cc.h - Architecture environment, some compiler specific, some - environment specific (probably should move env stuff - to sys_arch.h.) - - Typedefs for the types used by lwip - - u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t - - Compiler hints for packing lwip's structures - - PACK_STRUCT_FIELD(x) - PACK_STRUCT_STRUCT - PACK_STRUCT_BEGIN - PACK_STRUCT_END - - Platform specific diagnostic output - - LWIP_PLATFORM_DIAG(x) - non-fatal, print a message. - LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution. - Portability defines for printf formatters: - U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F - - "lightweight" synchronization mechanisms - - SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable. - SYS_ARCH_PROTECT(x) - enter protection mode. - SYS_ARCH_UNPROTECT(x) - leave protection mode. - - If the compiler does not provide memset() this file must include a - definition of it, or include a file which defines it. - - This file must either include a system-local which defines - the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO - to make lwip/arch.h define the codes which are used throughout. - - -perf.h - Architecture specific performance measurement. - 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. - -sys_arch.h - Tied to sys_arch.c - - Arch dependent types for the following objects: - sys_sem_t, sys_mbox_t, sys_thread_t, - And, optionally: - sys_prot_t - - Defines to set vars of sys_mbox_t and sys_sem_t to NULL. - SYS_MBOX_NULL NULL - SYS_SEM_NULL NULL diff --git a/ext/lwip/src/FILES b/ext/lwip/src/FILES deleted file mode 100644 index 952aeab..0000000 --- a/ext/lwip/src/FILES +++ /dev/null @@ -1,13 +0,0 @@ -api/ - The code for the high-level wrapper API. Not needed if - you use the lowel-level call-back/raw API. - -core/ - The core of the TPC/IP stack; protocol implementations, - memory and buffer management, and the low-level raw API. - -include/ - lwIP include files. - -netif/ - Generic network interface device drivers are kept here, - as well as the ARP module. - -For more information on the various subdirectories, check the FILES -file in each directory. diff --git a/ext/lwip/src/Filelists.mk b/ext/lwip/src/Filelists.mk deleted file mode 100644 index b3b14eb..0000000 --- a/ext/lwip/src/Filelists.mk +++ /dev/null @@ -1,169 +0,0 @@ -# -# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# 3. The name of the author may not be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -# OF SUCH DAMAGE. -# -# This file is part of the lwIP TCP/IP stack. -# -# Author: Adam Dunkels -# - -# COREFILES, CORE4FILES: The minimum set of files needed for lwIP. -COREFILES=$(LWIPDIR)/core/init.c \ - $(LWIPDIR)/core/def.c \ - $(LWIPDIR)/core/dns.c \ - $(LWIPDIR)/core/inet_chksum.c \ - $(LWIPDIR)/core/ip.c \ - $(LWIPDIR)/core/mem.c \ - $(LWIPDIR)/core/memp.c \ - $(LWIPDIR)/core/netif.c \ - $(LWIPDIR)/core/pbuf.c \ - $(LWIPDIR)/core/raw.c \ - $(LWIPDIR)/core/stats.c \ - $(LWIPDIR)/core/sys.c \ - $(LWIPDIR)/core/tcp.c \ - $(LWIPDIR)/core/tcp_in.c \ - $(LWIPDIR)/core/tcp_out.c \ - $(LWIPDIR)/core/timeouts.c \ - $(LWIPDIR)/core/udp.c - -CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c \ - $(LWIPDIR)/core/ipv4/dhcp.c \ - $(LWIPDIR)/core/ipv4/etharp.c \ - $(LWIPDIR)/core/ipv4/icmp.c \ - $(LWIPDIR)/core/ipv4/igmp.c \ - $(LWIPDIR)/core/ipv4/ip4_frag.c \ - $(LWIPDIR)/core/ipv4/ip4.c \ - $(LWIPDIR)/core/ipv4/ip4_addr.c - -CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c \ - $(LWIPDIR)/core/ipv6/ethip6.c \ - $(LWIPDIR)/core/ipv6/icmp6.c \ - $(LWIPDIR)/core/ipv6/inet6.c \ - $(LWIPDIR)/core/ipv6/ip6.c \ - $(LWIPDIR)/core/ipv6/ip6_addr.c \ - $(LWIPDIR)/core/ipv6/ip6_frag.c \ - $(LWIPDIR)/core/ipv6/mld6.c \ - $(LWIPDIR)/core/ipv6/nd6.c - -# APIFILES: The files which implement the sequential and socket APIs. -APIFILES=$(LWIPDIR)/api/api_lib.c \ - $(LWIPDIR)/api/api_msg.c \ - $(LWIPDIR)/api/err.c \ - $(LWIPDIR)/api/netbuf.c \ - $(LWIPDIR)/api/netdb.c \ - $(LWIPDIR)/api/netifapi.c \ - $(LWIPDIR)/api/sockets.c \ - $(LWIPDIR)/api/tcpip.c - -# NETIFFILES: Files implementing various generic network interface functions -NETIFFILES=$(LWIPDIR)/netif/ethernet.c \ - $(LWIPDIR)/netif/slipif.c - -# SIXLOWPAN: 6LoWPAN -SIXLOWPAN=$(LWIPDIR)/netif/lowpan6.c \ - -# PPPFILES: PPP -PPPFILES=$(LWIPDIR)/netif/ppp/auth.c \ - $(LWIPDIR)/netif/ppp/ccp.c \ - $(LWIPDIR)/netif/ppp/chap-md5.c \ - $(LWIPDIR)/netif/ppp/chap_ms.c \ - $(LWIPDIR)/netif/ppp/chap-new.c \ - $(LWIPDIR)/netif/ppp/demand.c \ - $(LWIPDIR)/netif/ppp/eap.c \ - $(LWIPDIR)/netif/ppp/ecp.c \ - $(LWIPDIR)/netif/ppp/eui64.c \ - $(LWIPDIR)/netif/ppp/fsm.c \ - $(LWIPDIR)/netif/ppp/ipcp.c \ - $(LWIPDIR)/netif/ppp/ipv6cp.c \ - $(LWIPDIR)/netif/ppp/lcp.c \ - $(LWIPDIR)/netif/ppp/magic.c \ - $(LWIPDIR)/netif/ppp/mppe.c \ - $(LWIPDIR)/netif/ppp/multilink.c \ - $(LWIPDIR)/netif/ppp/ppp.c \ - $(LWIPDIR)/netif/ppp/pppapi.c \ - $(LWIPDIR)/netif/ppp/pppcrypt.c \ - $(LWIPDIR)/netif/ppp/pppoe.c \ - $(LWIPDIR)/netif/ppp/pppol2tp.c \ - $(LWIPDIR)/netif/ppp/pppos.c \ - $(LWIPDIR)/netif/ppp/upap.c \ - $(LWIPDIR)/netif/ppp/utils.c \ - $(LWIPDIR)/netif/ppp/vj.c \ - $(LWIPDIR)/netif/ppp/polarssl/arc4.c \ - $(LWIPDIR)/netif/ppp/polarssl/des.c \ - $(LWIPDIR)/netif/ppp/polarssl/md4.c \ - $(LWIPDIR)/netif/ppp/polarssl/md5.c \ - $(LWIPDIR)/netif/ppp/polarssl/sha1.c - -# LWIPNOAPPSFILES: All LWIP files without apps -LWIPNOAPPSFILES=$(COREFILES) \ - $(CORE4FILES) \ - $(CORE6FILES) \ - $(APIFILES) \ - $(NETIFFILES) \ - $(PPPFILES) \ - $(SIXLOWPAN) - -# SNMPFILES: SNMPv2c agent -SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \ - $(LWIPDIR)/apps/snmp/snmp_core.c \ - $(LWIPDIR)/apps/snmp/snmp_mib2.c \ - $(LWIPDIR)/apps/snmp/snmp_mib2_icmp.c \ - $(LWIPDIR)/apps/snmp/snmp_mib2_interfaces.c \ - $(LWIPDIR)/apps/snmp/snmp_mib2_ip.c \ - $(LWIPDIR)/apps/snmp/snmp_mib2_snmp.c \ - $(LWIPDIR)/apps/snmp/snmp_mib2_system.c \ - $(LWIPDIR)/apps/snmp/snmp_mib2_tcp.c \ - $(LWIPDIR)/apps/snmp/snmp_mib2_udp.c \ - $(LWIPDIR)/apps/snmp/snmp_msg.c \ - $(LWIPDIR)/apps/snmp/snmpv3.c \ - $(LWIPDIR)/apps/snmp/snmp_netconn.c \ - $(LWIPDIR)/apps/snmp/snmp_pbuf_stream.c \ - $(LWIPDIR)/apps/snmp/snmp_raw.c \ - $(LWIPDIR)/apps/snmp/snmp_scalar.c \ - $(LWIPDIR)/apps/snmp/snmp_table.c \ - $(LWIPDIR)/apps/snmp/snmp_threadsync.c \ - $(LWIPDIR)/apps/snmp/snmp_traps.c \ - $(LWIPDIR)/apps/snmp/snmpv3_mbedtls.c \ - $(LWIPDIR)/apps/snmp/snmpv3_dummy.c - -# HTTPDFILES: HTTP server -HTTPDFILES=$(LWIPDIR)/apps/httpd/fs.c \ - $(LWIPDIR)/apps/httpd/httpd.c - -# LWIPERFFILES: IPERF server -LWIPERFFILES=$(LWIPDIR)/apps/lwiperf/lwiperf.c - -# SNTPFILES: SNTP client -SNTPFILES=$(LWIPDIR)/apps/sntp/sntp.c - -# NETBIOSNSFILES: NetBIOS name server -NETBIOSNSFILES=$(LWIPDIR)/apps/netbiosns/netbiosns.c - -# LWIPAPPFILES: All LWIP APPs -LWIPAPPFILES=$(SNMPFILES) \ - $(HTTPDFILES) \ - $(LWIPERFFILES) \ - $(SNTPFILES) \ - $(NETBIOSNSFILES) diff --git a/ext/lwip/src/api/api_lib.c b/ext/lwip/src/api/api_lib.c deleted file mode 100644 index 5e696d8..0000000 --- a/ext/lwip/src/api/api_lib.c +++ /dev/null @@ -1,993 +0,0 @@ -/** - * @file - * Sequential API External module - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - */ - -/** - * @defgroup netconn Netconn API - * @ingroup threadsafe_api - * Thread-safe, to be called from non-TCPIP threads only. - * TX/RX handling based on @ref netbuf (containing @ref pbuf) - * to avoid copying data around. - * - * @defgroup netconn_common Common functions - * @ingroup netconn - * For use with TCP and UDP - * - * @defgroup netconn_tcp TCP only - * @ingroup netconn - * TCP only functions - * - * @defgroup netconn_udp UDP only - * @ingroup netconn - * UDP only functions - */ - -/* This is the part of the API that is linked with - the application */ - -#include "lwip/opt.h" - -#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/api.h" -#include "lwip/memp.h" - -#include "lwip/ip.h" -#include "lwip/raw.h" -#include "lwip/udp.h" -#include "lwip/priv/api_msg.h" -#include "lwip/priv/tcp_priv.h" -#include "lwip/priv/tcpip_priv.h" - -#include - -#define API_MSG_VAR_REF(name) API_VAR_REF(name) -#define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name) -#define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM) -#define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL) -#define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name) - -static err_t netconn_close_shutdown(struct netconn *conn, u8_t how); - -/** - * Call the lower part of a netconn_* function - * This function is then running in the thread context - * of tcpip_thread and has exclusive access to lwIP core code. - * - * @param fn function to call - * @param apimsg a struct containing the function to call and its parameters - * @return ERR_OK if the function was called, another err_t if not - */ -static err_t -netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg) -{ - err_t err; - -#ifdef LWIP_DEBUG - /* catch functions that don't set err */ - apimsg->err = ERR_VAL; -#endif /* LWIP_DEBUG */ - -#if LWIP_NETCONN_SEM_PER_THREAD - apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - - err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg)); - if (err == ERR_OK) { - return apimsg->err; - } - return err; -} - -/** - * Create a new netconn (of a specific type) that has a callback function. - * The corresponding pcb is also created. - * - * @param t the type of 'connection' to create (@see enum netconn_type) - * @param proto the IP protocol for RAW IP pcbs - * @param callback a function to call on status changes (RX available, TX'ed) - * @return a newly allocated struct netconn or - * NULL on memory error - */ -struct netconn* -netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) -{ - struct netconn *conn; - API_MSG_VAR_DECLARE(msg); - API_MSG_VAR_ALLOC_RETURN_NULL(msg); - - conn = netconn_alloc(t, callback); - if (conn != NULL) { - err_t err; - - API_MSG_VAR_REF(msg).msg.n.proto = proto; - API_MSG_VAR_REF(msg).conn = conn; - err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg)); - if (err != ERR_OK) { - LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); - LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); -#if LWIP_TCP - LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); -#endif /* LWIP_TCP */ -#if !LWIP_NETCONN_SEM_PER_THREAD - LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); - sys_sem_free(&conn->op_completed); -#endif /* !LWIP_NETCONN_SEM_PER_THREAD */ - sys_mbox_free(&conn->recvmbox); - memp_free(MEMP_NETCONN, conn); - API_MSG_VAR_FREE(msg); - return NULL; - } - } - API_MSG_VAR_FREE(msg); - return conn; -} - -/** - * @ingroup netconn_common - * Close a netconn 'connection' and free its resources. - * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate - * after this returns. - * - * @param conn the netconn to delete - * @return ERR_OK if the connection was deleted - */ -err_t -netconn_delete(struct netconn *conn) -{ - err_t err; - API_MSG_VAR_DECLARE(msg); - - /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ - if (conn == NULL) { - return ERR_OK; - } - - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; -#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER - /* get the time we started, which is later compared to - sys_now() + conn->send_timeout */ - API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); -#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ -#if LWIP_TCP - API_MSG_VAR_REF(msg).msg.sd.polls_left = - ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; -#endif /* LWIP_TCP */ -#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ - err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - - if (err != ERR_OK) { - return err; - } - - netconn_free(conn); - - return ERR_OK; -} - -/** - * Get the local or remote IP address and port of a netconn. - * For RAW netconns, this returns the protocol instead of a port! - * - * @param conn the netconn to query - * @param addr a pointer to which to save the IP address - * @param port a pointer to which to save the port (or protocol for RAW) - * @param local 1 to get the local IP address, 0 to get the remote one - * @return ERR_CONN for invalid connections - * ERR_OK if the information was retrieved - */ -err_t -netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) -{ - API_MSG_VAR_DECLARE(msg); - err_t err; - - LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); - - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.ad.local = local; -#if LWIP_MPU_COMPATIBLE - err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg)); - *addr = msg->msg.ad.ipaddr; - *port = msg->msg.ad.port; -#else /* LWIP_MPU_COMPATIBLE */ - msg.msg.ad.ipaddr = addr; - msg.msg.ad.port = port; - err = netconn_apimsg(lwip_netconn_do_getaddr, &msg); -#endif /* LWIP_MPU_COMPATIBLE */ - API_MSG_VAR_FREE(msg); - - return err; -} - -/** - * @ingroup netconn_common - * Bind a netconn to a specific local IP address and port. - * Binding one netconn twice might not always be checked correctly! - * - * @param conn the netconn to bind - * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY - * to bind to all addresses) - * @param port the local port to bind the netconn to (not used for RAW) - * @return ERR_OK if bound, any other err_t on failure - */ -err_t -netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) -{ - API_MSG_VAR_DECLARE(msg); - err_t err; - - LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); - - /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ - if (addr == NULL) { - addr = IP_ADDR_ANY; - } - - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); - API_MSG_VAR_REF(msg).msg.bc.port = port; - err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - - return err; -} - -/** - * @ingroup netconn_common - * Connect a netconn to a specific remote IP address and port. - * - * @param conn the netconn to connect - * @param addr the remote IP address to connect to - * @param port the remote port to connect to (no used for RAW) - * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise - */ -err_t -netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) -{ - API_MSG_VAR_DECLARE(msg); - err_t err; - - LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); - - /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ - if (addr == NULL) { - addr = IP_ADDR_ANY; - } - - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); - API_MSG_VAR_REF(msg).msg.bc.port = port; - err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - - return err; -} - -/** - * @ingroup netconn_udp - * Disconnect a netconn from its current peer (only valid for UDP netconns). - * - * @param conn the netconn to disconnect - * @return @todo: return value is not set here... - */ -err_t -netconn_disconnect(struct netconn *conn) -{ - API_MSG_VAR_DECLARE(msg); - err_t err; - - LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); - - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; - err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - - return err; -} - -/** - * @ingroup netconn_tcp - * Set a TCP netconn into listen mode - * - * @param conn the tcp netconn to set to listen mode - * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 - * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns - * don't return any error (yet?)) - */ -err_t -netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) -{ -#if LWIP_TCP - API_MSG_VAR_DECLARE(msg); - err_t err; - - /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ - LWIP_UNUSED_ARG(backlog); - - LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); - - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; -#if TCP_LISTEN_BACKLOG - API_MSG_VAR_REF(msg).msg.lb.backlog = backlog; -#endif /* TCP_LISTEN_BACKLOG */ - err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - - return err; -#else /* LWIP_TCP */ - LWIP_UNUSED_ARG(conn); - LWIP_UNUSED_ARG(backlog); - return ERR_ARG; -#endif /* LWIP_TCP */ -} - -/** - * @ingroup netconn_tcp - * Accept a new connection on a TCP listening netconn. - * - * @param conn the TCP listen netconn - * @param new_conn pointer where the new connection is stored - * @return ERR_OK if a new connection has been received or an error - * code otherwise - */ -err_t -netconn_accept(struct netconn *conn, struct netconn **new_conn) -{ -#if LWIP_TCP - void *accept_ptr; - struct netconn *newconn; - err_t err; -#if TCP_LISTEN_BACKLOG - API_MSG_VAR_DECLARE(msg); -#endif /* TCP_LISTEN_BACKLOG */ - - LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); - *new_conn = NULL; - LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); - - err = conn->last_err; - if (ERR_IS_FATAL(err)) { - /* don't recv on fatal errors: this might block the application task - waiting on acceptmbox forever! */ - return err; - } - if (!sys_mbox_valid(&conn->acceptmbox)) { - return ERR_CLSD; - } - -#if TCP_LISTEN_BACKLOG - API_MSG_VAR_ALLOC(msg); -#endif /* TCP_LISTEN_BACKLOG */ - -#if LWIP_SO_RCVTIMEO - if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { -#if TCP_LISTEN_BACKLOG - API_MSG_VAR_FREE(msg); -#endif /* TCP_LISTEN_BACKLOG */ - return ERR_TIMEOUT; - } -#else - sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); -#endif /* LWIP_SO_RCVTIMEO*/ - newconn = (struct netconn *)accept_ptr; - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); - - if (accept_ptr == &netconn_aborted) { - /* a connection has been aborted: out of pcbs or out of netconns during accept */ - /* @todo: set netconn error, but this would be fatal and thus block further accepts */ -#if TCP_LISTEN_BACKLOG - API_MSG_VAR_FREE(msg); -#endif /* TCP_LISTEN_BACKLOG */ - return ERR_ABRT; - } - if (newconn == NULL) { - /* connection has been aborted */ - /* in this special case, we set the netconn error from application thread, as - on a ready-to-accept listening netconn, there should not be anything running - in tcpip_thread */ - NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); -#if TCP_LISTEN_BACKLOG - API_MSG_VAR_FREE(msg); -#endif /* TCP_LISTEN_BACKLOG */ - return ERR_CLSD; - } -#if TCP_LISTEN_BACKLOG - /* Let the stack know that we have accepted the connection. */ - API_MSG_VAR_REF(msg).conn = newconn; - /* don't care for the return value of lwip_netconn_do_recv */ - netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); -#endif /* TCP_LISTEN_BACKLOG */ - - *new_conn = newconn; - /* don't set conn->last_err: it's only ERR_OK, anyway */ - return ERR_OK; -#else /* LWIP_TCP */ - LWIP_UNUSED_ARG(conn); - LWIP_UNUSED_ARG(new_conn); - return ERR_ARG; -#endif /* LWIP_TCP */ -} - -/** - * @ingroup netconn_common - * Receive data: actual implementation that doesn't care whether pbuf or netbuf - * is received - * - * @param conn the netconn from which to receive data - * @param new_buf pointer where a new pbuf/netbuf is stored when received data - * @return ERR_OK if data has been received, an error code otherwise (timeout, - * memory error or another error) - */ -static err_t -netconn_recv_data(struct netconn *conn, void **new_buf) -{ - void *buf = NULL; - u16_t len; - err_t err; -#if LWIP_TCP - API_MSG_VAR_DECLARE(msg); -#if LWIP_MPU_COMPATIBLE - msg = NULL; -#endif -#endif /* LWIP_TCP */ - - LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); - *new_buf = NULL; - LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); -#if LWIP_TCP -#if (LWIP_UDP || LWIP_RAW) - if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) -#endif /* (LWIP_UDP || LWIP_RAW) */ - { - if (!sys_mbox_valid(&conn->recvmbox)) { - /* This happens when calling this function after receiving FIN */ - return sys_mbox_valid(&conn->acceptmbox) ? ERR_CONN : ERR_CLSD; - } - } -#endif /* LWIP_TCP */ - LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); - - err = conn->last_err; - if (ERR_IS_FATAL(err)) { - /* don't recv on fatal errors: this might block the application task - waiting on recvmbox forever! */ - /* @todo: this does not allow us to fetch data that has been put into recvmbox - before the fatal error occurred - is that a problem? */ - return err; - } -#if LWIP_TCP -#if (LWIP_UDP || LWIP_RAW) - if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) -#endif /* (LWIP_UDP || LWIP_RAW) */ - { - API_MSG_VAR_ALLOC(msg); - } -#endif /* LWIP_TCP */ - -#if LWIP_SO_RCVTIMEO - if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { -#if LWIP_TCP -#if (LWIP_UDP || LWIP_RAW) - if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) -#endif /* (LWIP_UDP || LWIP_RAW) */ - { - API_MSG_VAR_FREE(msg); - } -#endif /* LWIP_TCP */ - return ERR_TIMEOUT; - } -#else - sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); -#endif /* LWIP_SO_RCVTIMEO*/ - -#if LWIP_TCP -#if (LWIP_UDP || LWIP_RAW) - if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) -#endif /* (LWIP_UDP || LWIP_RAW) */ - { - /* Let the stack know that we have taken the data. */ - /* @todo: Speedup: Don't block and wait for the answer here - (to prevent multiple thread-switches). */ - API_MSG_VAR_REF(msg).conn = conn; - if (buf != NULL) { - API_MSG_VAR_REF(msg).msg.r.len = ((struct pbuf *)buf)->tot_len; - } else { - API_MSG_VAR_REF(msg).msg.r.len = 1; - } - - /* don't care for the return value of lwip_netconn_do_recv */ - netconn_apimsg(lwip_netconn_do_recv, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - - /* If we are closed, we indicate that we no longer wish to use the socket */ - if (buf == NULL) { - API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); - /* RX side is closed, so deallocate the recvmbox */ - netconn_close_shutdown(conn, NETCONN_SHUT_RD); - /* Don' store ERR_CLSD as conn->err since we are only half-closed */ - return ERR_CLSD; - } - len = ((struct pbuf *)buf)->tot_len; - } -#endif /* LWIP_TCP */ -#if LWIP_TCP && (LWIP_UDP || LWIP_RAW) - else -#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ -#if (LWIP_UDP || LWIP_RAW) - { - LWIP_ASSERT("buf != NULL", buf != NULL); - len = netbuf_len((struct netbuf *)buf); - } -#endif /* (LWIP_UDP || LWIP_RAW) */ - -#if LWIP_SO_RCVBUF - SYS_ARCH_DEC(conn->recv_avail, len); -#endif /* LWIP_SO_RCVBUF */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); - - LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); - - *new_buf = buf; - /* don't set conn->last_err: it's only ERR_OK, anyway */ - return ERR_OK; -} - -/** - * @ingroup netconn_tcp - * Receive data (in form of a pbuf) from a TCP netconn - * - * @param conn the netconn from which to receive data - * @param new_buf pointer where a new pbuf is stored when received data - * @return ERR_OK if data has been received, an error code otherwise (timeout, - * memory error or another error) - * ERR_ARG if conn is not a TCP netconn - */ -err_t -netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) -{ - LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) && - NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); - - return netconn_recv_data(conn, (void **)new_buf); -} - -/** - * @ingroup netconn_common - * Receive data (in form of a netbuf containing a packet buffer) from a netconn - * - * @param conn the netconn from which to receive data - * @param new_buf pointer where a new netbuf is stored when received data - * @return ERR_OK if data has been received, an error code otherwise (timeout, - * memory error or another error) - */ -err_t -netconn_recv(struct netconn *conn, struct netbuf **new_buf) -{ -#if LWIP_TCP - struct netbuf *buf = NULL; - err_t err; -#endif /* LWIP_TCP */ - - LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); - *new_buf = NULL; - LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); - -#if LWIP_TCP -#if (LWIP_UDP || LWIP_RAW) - if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) -#endif /* (LWIP_UDP || LWIP_RAW) */ - { - struct pbuf *p = NULL; - /* This is not a listening netconn, since recvmbox is set */ - - buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); - if (buf == NULL) { - return ERR_MEM; - } - - err = netconn_recv_data(conn, (void **)&p); - if (err != ERR_OK) { - memp_free(MEMP_NETBUF, buf); - return err; - } - LWIP_ASSERT("p != NULL", p != NULL); - - buf->p = p; - buf->ptr = p; - buf->port = 0; - ip_addr_set_zero(&buf->addr); - *new_buf = buf; - /* don't set conn->last_err: it's only ERR_OK, anyway */ - return ERR_OK; - } -#endif /* LWIP_TCP */ -#if LWIP_TCP && (LWIP_UDP || LWIP_RAW) - else -#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ - { -#if (LWIP_UDP || LWIP_RAW) - return netconn_recv_data(conn, (void **)new_buf); -#endif /* (LWIP_UDP || LWIP_RAW) */ - } -} - -/** - * @ingroup netconn_udp - * Send data (in form of a netbuf) to a specific remote IP address and port. - * Only to be used for UDP and RAW netconns (not TCP). - * - * @param conn the netconn over which to send data - * @param buf a netbuf containing the data to send - * @param addr the remote IP address to which to send the data - * @param port the remote port to which to send the data - * @return ERR_OK if data was sent, any other err_t on error - */ -err_t -netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port) -{ - if (buf != NULL) { - ip_addr_set(&buf->addr, addr); - buf->port = port; - return netconn_send(conn, buf); - } - return ERR_VAL; -} - -/** - * @ingroup netconn_udp - * Send data over a UDP or RAW netconn (that is already connected). - * - * @param conn the UDP or RAW netconn over which to send data - * @param buf a netbuf containing the data to send - * @return ERR_OK if data was sent, any other err_t on error - */ -err_t -netconn_send(struct netconn *conn, struct netbuf *buf) -{ - API_MSG_VAR_DECLARE(msg); - err_t err; - - LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); - - LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.b = buf; - err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - - return err; -} - -/** - * @ingroup netconn_tcp - * Send data over a TCP netconn. - * - * @param conn the TCP netconn over which to send data - * @param dataptr pointer to the application buffer that contains the data to send - * @param size size of the application data to send - * @param apiflags combination of following flags : - * - NETCONN_COPY: data will be copied into memory belonging to the stack - * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent - * - NETCONN_DONTBLOCK: only write the data if all data can be written at once - * @param bytes_written pointer to a location that receives the number of written bytes - * @return ERR_OK if data was sent, any other err_t on error - */ -err_t -netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, - u8_t apiflags, size_t *bytes_written) -{ - API_MSG_VAR_DECLARE(msg); - err_t err; - u8_t dontblock; - - LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;); - if (size == 0) { - return ERR_OK; - } - dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); - if (dontblock && !bytes_written) { - /* This implies netconn_write() cannot be used for non-blocking send, since - it has no way to return the number of bytes written. */ - return ERR_VAL; - } - - API_MSG_VAR_ALLOC(msg); - /* non-blocking write sends as much */ - API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.w.dataptr = dataptr; - API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags; - API_MSG_VAR_REF(msg).msg.w.len = size; -#if LWIP_SO_SNDTIMEO - if (conn->send_timeout != 0) { - /* get the time we started, which is later compared to - sys_now() + conn->send_timeout */ - API_MSG_VAR_REF(msg).msg.w.time_started = sys_now(); - } else { - API_MSG_VAR_REF(msg).msg.w.time_started = 0; - } -#endif /* LWIP_SO_SNDTIMEO */ - - /* For locking the core: this _can_ be delayed on low memory/low send buffer, - but if it is, this is done inside api_msg.c:do_write(), so we can use the - non-blocking version here. */ - err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg)); - if ((err == ERR_OK) && (bytes_written != NULL)) { - if (dontblock -#if LWIP_SO_SNDTIMEO - || (conn->send_timeout != 0) -#endif /* LWIP_SO_SNDTIMEO */ - ) { - /* nonblocking write: maybe the data has been sent partly */ - *bytes_written = API_MSG_VAR_REF(msg).msg.w.len; - } else { - /* blocking call succeeded: all data has been sent if it */ - *bytes_written = size; - } - } - API_MSG_VAR_FREE(msg); - - return err; -} - -/** - * @ingroup netconn_tcp - * Close or shutdown a TCP netconn (doesn't delete it). - * - * @param conn the TCP netconn to close or shutdown - * @param how fully close or only shutdown one side? - * @return ERR_OK if the netconn was closed, any other err_t on error - */ -static err_t -netconn_close_shutdown(struct netconn *conn, u8_t how) -{ - API_MSG_VAR_DECLARE(msg); - err_t err; - LWIP_UNUSED_ARG(how); - - LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); - - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; -#if LWIP_TCP - /* shutting down both ends is the same as closing */ - API_MSG_VAR_REF(msg).msg.sd.shut = how; -#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER - /* get the time we started, which is later compared to - sys_now() + conn->send_timeout */ - API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); -#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ - API_MSG_VAR_REF(msg).msg.sd.polls_left = - ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; -#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ -#endif /* LWIP_TCP */ - err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - - return err; -} - -/** - * @ingroup netconn_tcp - * Close a TCP netconn (doesn't delete it). - * - * @param conn the TCP netconn to close - * @return ERR_OK if the netconn was closed, any other err_t on error - */ -err_t -netconn_close(struct netconn *conn) -{ - /* shutting down both ends is the same as closing */ - return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); -} - -/** - * @ingroup netconn_tcp - * Shut down one or both sides of a TCP netconn (doesn't delete it). - * - * @param conn the TCP netconn to shut down - * @param shut_rx shut down the RX side (no more read possible after this) - * @param shut_tx shut down the TX side (no more write possible after this) - * @return ERR_OK if the netconn was closed, any other err_t on error - */ -err_t -netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) -{ - return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)); -} - -#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) -/** - * @ingroup netconn_udp - * Join multicast groups for UDP netconns. - * - * @param conn the UDP netconn for which to change multicast addresses - * @param multiaddr IP address of the multicast group to join or leave - * @param netif_addr the IP address of the network interface on which to send - * the igmp message - * @param join_or_leave flag whether to send a join- or leave-message - * @return ERR_OK if the action was taken, any err_t on error - */ -err_t -netconn_join_leave_group(struct netconn *conn, - const ip_addr_t *multiaddr, - const ip_addr_t *netif_addr, - enum netconn_igmp join_or_leave) -{ - API_MSG_VAR_DECLARE(msg); - err_t err; - - LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); - - API_MSG_VAR_ALLOC(msg); - - /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ - if (multiaddr == NULL) { - multiaddr = IP_ADDR_ANY; - } - if (netif_addr == NULL) { - netif_addr = IP_ADDR_ANY; - } - - API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); - API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr); - API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; - err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - - return err; -} -#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ - -#if LWIP_DNS -/** - * @ingroup netconn_common - * Execute a DNS query, only one IP address is returned - * - * @param name a string representation of the DNS host name to query - * @param addr a preallocated ip_addr_t where to store the resolved IP address - * @param dns_addrtype IP address type (IPv4 / IPv6) - * @return ERR_OK: resolving succeeded - * ERR_MEM: memory error, try again later - * ERR_ARG: dns client not initialized or invalid hostname - * ERR_VAL: dns server response was invalid - */ -#if LWIP_IPV4 && LWIP_IPV6 -err_t -netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) -#else -err_t -netconn_gethostbyname(const char *name, ip_addr_t *addr) -#endif -{ - API_VAR_DECLARE(struct dns_api_msg, msg); -#if !LWIP_MPU_COMPATIBLE - sys_sem_t sem; -#endif /* LWIP_MPU_COMPATIBLE */ - err_t err; - - LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); -#if LWIP_MPU_COMPATIBLE - if (strlen(name) >= DNS_MAX_NAME_LENGTH) { - return ERR_ARG; - } -#endif - - API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM); -#if LWIP_MPU_COMPATIBLE - strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1); - API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0; -#else /* LWIP_MPU_COMPATIBLE */ - msg.err = &err; - msg.sem = &sem; - API_VAR_REF(msg).addr = API_VAR_REF(addr); - API_VAR_REF(msg).name = name; -#endif /* LWIP_MPU_COMPATIBLE */ -#if LWIP_IPV4 && LWIP_IPV6 - API_VAR_REF(msg).dns_addrtype = dns_addrtype; -#endif /* LWIP_IPV4 && LWIP_IPV6 */ -#if LWIP_NETCONN_SEM_PER_THREAD - API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET(); -#else /* LWIP_NETCONN_SEM_PER_THREAD*/ - err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0); - if (err != ERR_OK) { - API_VAR_FREE(MEMP_DNS_API_MSG, msg); - return err; - } -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - - err = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg)); - if (err != ERR_OK) { -#if !LWIP_NETCONN_SEM_PER_THREAD - sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); -#endif /* !LWIP_NETCONN_SEM_PER_THREAD */ - API_VAR_FREE(MEMP_DNS_API_MSG, msg); - return err; - } - sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem)); -#if !LWIP_NETCONN_SEM_PER_THREAD - sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); -#endif /* !LWIP_NETCONN_SEM_PER_THREAD */ - -#if LWIP_MPU_COMPATIBLE - *addr = msg->addr; - err = msg->err; -#endif /* LWIP_MPU_COMPATIBLE */ - - API_VAR_FREE(MEMP_DNS_API_MSG, msg); - return err; -} -#endif /* LWIP_DNS*/ - -#if LWIP_NETCONN_SEM_PER_THREAD -void -netconn_thread_init(void) -{ - sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); - if ((sem == NULL) || !sys_sem_valid(sem)) { - /* call alloc only once */ - LWIP_NETCONN_THREAD_SEM_ALLOC(); - LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET())); - } -} - -void -netconn_thread_cleanup(void) -{ - sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); - if ((sem != NULL) && sys_sem_valid(sem)) { - /* call free only once */ - LWIP_NETCONN_THREAD_SEM_FREE(); - } -} -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - -#endif /* LWIP_NETCONN */ diff --git a/ext/lwip/src/api/api_msg.c b/ext/lwip/src/api/api_msg.c deleted file mode 100644 index 9dfea64..0000000 --- a/ext/lwip/src/api/api_msg.c +++ /dev/null @@ -1,1946 +0,0 @@ -/** - * @file - * Sequential API Internal module - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/opt.h" - -#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/priv/api_msg.h" - -#include "lwip/ip.h" -#include "lwip/udp.h" -#include "lwip/tcp.h" -#include "lwip/raw.h" - -#include "lwip/memp.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" -#include "lwip/mld6.h" -#include "lwip/priv/tcpip_priv.h" - -#include - -/* netconns are polled once per second (e.g. continue write on memory error) */ -#define NETCONN_TCP_POLL_INTERVAL 2 - -#define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \ - (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ -} else { \ - (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0) -#define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0) - -/* forward declarations */ -#if LWIP_TCP -#if LWIP_TCPIP_CORE_LOCKING -#define WRITE_DELAYED , 1 -#define WRITE_DELAYED_PARAM , u8_t delayed -#else /* LWIP_TCPIP_CORE_LOCKING */ -#define WRITE_DELAYED -#define WRITE_DELAYED_PARAM -#endif /* LWIP_TCPIP_CORE_LOCKING */ -static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM); -static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM); -#endif - -#if LWIP_TCPIP_CORE_LOCKING -#define TCPIP_APIMSG_ACK(m) NETCONN_SET_SAFE_ERR((m)->conn, (m)->err) -#else /* LWIP_TCPIP_CORE_LOCKING */ -#define TCPIP_APIMSG_ACK(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0) -#endif /* LWIP_TCPIP_CORE_LOCKING */ - -#if LWIP_TCP -u8_t netconn_aborted; -#endif /* LWIP_TCP */ - -#if LWIP_RAW -/** - * Receive callback function for RAW netconns. - * Doesn't 'eat' the packet, only copies it and sends it to - * conn->recvmbox - * - * @see raw.h (struct raw_pcb.recv) for parameters and return value - */ -static u8_t -recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, - const ip_addr_t *addr) -{ - struct pbuf *q; - struct netbuf *buf; - struct netconn *conn; - - LWIP_UNUSED_ARG(addr); - conn = (struct netconn *)arg; - - if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) { -#if LWIP_SO_RCVBUF - int recv_avail; - SYS_ARCH_GET(conn->recv_avail, recv_avail); - if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { - return 0; - } -#endif /* LWIP_SO_RCVBUF */ - /* copy the whole packet into new pbufs */ - q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if (q != NULL) { - if (pbuf_copy(q, p) != ERR_OK) { - pbuf_free(q); - q = NULL; - } - } - - if (q != NULL) { - u16_t len; - buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); - if (buf == NULL) { - pbuf_free(q); - return 0; - } - - buf->p = q; - buf->ptr = q; - ip_addr_copy(buf->addr, *ip_current_src_addr()); - buf->port = pcb->protocol; - - len = q->tot_len; - if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { - netbuf_delete(buf); - return 0; - } else { -#if LWIP_SO_RCVBUF - SYS_ARCH_INC(conn->recv_avail, len); -#endif /* LWIP_SO_RCVBUF */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); - } - } - } - - return 0; /* do not eat the packet */ -} -#endif /* LWIP_RAW*/ - -#if LWIP_UDP -/** - * Receive callback function for UDP netconns. - * Posts the packet to conn->recvmbox or deletes it on memory error. - * - * @see udp.h (struct udp_pcb.recv) for parameters - */ -static void -recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *addr, u16_t port) -{ - struct netbuf *buf; - struct netconn *conn; - u16_t len; -#if LWIP_SO_RCVBUF - int recv_avail; -#endif /* LWIP_SO_RCVBUF */ - - LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ - LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); - LWIP_ASSERT("recv_udp must have an argument", arg != NULL); - conn = (struct netconn *)arg; - LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); - -#if LWIP_SO_RCVBUF - SYS_ARCH_GET(conn->recv_avail, recv_avail); - if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) || - ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { -#else /* LWIP_SO_RCVBUF */ - if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) { -#endif /* LWIP_SO_RCVBUF */ - pbuf_free(p); - return; - } - - buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); - if (buf == NULL) { - pbuf_free(p); - return; - } else { - buf->p = p; - buf->ptr = p; - ip_addr_set(&buf->addr, addr); - buf->port = port; -#if LWIP_NETBUF_RECVINFO - { - /* get the UDP header - always in the first pbuf, ensured by udp_input */ - const struct udp_hdr* udphdr = (const struct udp_hdr*)ip_next_header_ptr(); -#if LWIP_CHECKSUM_ON_COPY - buf->flags = NETBUF_FLAG_DESTADDR; -#endif /* LWIP_CHECKSUM_ON_COPY */ - ip_addr_set(&buf->toaddr, ip_current_dest_addr()); - buf->toport_chksum = udphdr->dest; - } -#endif /* LWIP_NETBUF_RECVINFO */ - } - - len = p->tot_len; - if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { - netbuf_delete(buf); - return; - } else { -#if LWIP_SO_RCVBUF - SYS_ARCH_INC(conn->recv_avail, len); -#endif /* LWIP_SO_RCVBUF */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); - } -} -#endif /* LWIP_UDP */ - -#if LWIP_TCP -/** - * Receive callback function for TCP netconns. - * Posts the packet to conn->recvmbox, but doesn't delete it on errors. - * - * @see tcp.h (struct tcp_pcb.recv) for parameters and return value - */ -static err_t -recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) -{ - struct netconn *conn; - u16_t len; - - LWIP_UNUSED_ARG(pcb); - LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); - LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); - conn = (struct netconn *)arg; - - if (conn == NULL) { - return ERR_VAL; - } - LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); - - if (!sys_mbox_valid(&conn->recvmbox)) { - /* recvmbox already deleted */ - if (p != NULL) { - tcp_recved(pcb, p->tot_len); - pbuf_free(p); - } - return ERR_OK; - } - /* Unlike for UDP or RAW pcbs, don't check for available space - using recv_avail since that could break the connection - (data is already ACKed) */ - - /* don't overwrite fatal errors! */ - if (err != ERR_OK) { - NETCONN_SET_SAFE_ERR(conn, err); - } - - if (p != NULL) { - len = p->tot_len; - } else { - len = 0; - } - - if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) { - /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ - return ERR_MEM; - } else { -#if LWIP_SO_RCVBUF - SYS_ARCH_INC(conn->recv_avail, len); -#endif /* LWIP_SO_RCVBUF */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); - } - - return ERR_OK; -} - -/** - * Poll callback function for TCP netconns. - * Wakes up an application thread that waits for a connection to close - * or data to be sent. The application thread then takes the - * appropriate action to go on. - * - * Signals the conn->sem. - * netconn_close waits for conn->sem if closing failed. - * - * @see tcp.h (struct tcp_pcb.poll) for parameters and return value - */ -static err_t -poll_tcp(void *arg, struct tcp_pcb *pcb) -{ - struct netconn *conn = (struct netconn *)arg; - - LWIP_UNUSED_ARG(pcb); - LWIP_ASSERT("conn != NULL", (conn != NULL)); - - if (conn->state == NETCONN_WRITE) { - lwip_netconn_do_writemore(conn WRITE_DELAYED); - } else if (conn->state == NETCONN_CLOSE) { -#if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER - if (conn->current_msg && conn->current_msg->msg.sd.polls_left) { - conn->current_msg->msg.sd.polls_left--; - } -#endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */ - lwip_netconn_do_close_internal(conn WRITE_DELAYED); - } - /* @todo: implement connect timeout here? */ - - /* Did a nonblocking write fail before? Then check available write-space. */ - if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { - /* If the queued byte- or pbuf-count drops below the configured low-water limit, - let select mark this pcb as writable again. */ - if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && - (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { - conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; - API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); - } - } - - return ERR_OK; -} - -/** - * Sent callback function for TCP netconns. - * Signals the conn->sem and calls API_EVENT. - * netconn_write waits for conn->sem if send buffer is low. - * - * @see tcp.h (struct tcp_pcb.sent) for parameters and return value - */ -static err_t -sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) -{ - struct netconn *conn = (struct netconn *)arg; - - LWIP_UNUSED_ARG(pcb); - LWIP_ASSERT("conn != NULL", (conn != NULL)); - - if (conn) { - if (conn->state == NETCONN_WRITE) { - lwip_netconn_do_writemore(conn WRITE_DELAYED); - } else if (conn->state == NETCONN_CLOSE) { - lwip_netconn_do_close_internal(conn WRITE_DELAYED); - } - - /* If the queued byte- or pbuf-count drops below the configured low-water limit, - let select mark this pcb as writable again. */ - if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && - (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { - conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; - API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); - } - } - - return ERR_OK; -} - -/** - * Error callback function for TCP netconns. - * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. - * The application thread has then to decide what to do. - * - * @see tcp.h (struct tcp_pcb.err) for parameters - */ -static void -err_tcp(void *arg, err_t err) -{ - struct netconn *conn; - enum netconn_state old_state; - - conn = (struct netconn *)arg; - LWIP_ASSERT("conn != NULL", (conn != NULL)); - - conn->pcb.tcp = NULL; - - /* reset conn->state now before waking up other threads */ - old_state = conn->state; - conn->state = NETCONN_NONE; - - if (old_state == NETCONN_CLOSE) { - /* RST during close: let close return success & dealloc the netconn */ - err = ERR_OK; - NETCONN_SET_SAFE_ERR(conn, ERR_OK); - } else { - /* no check since this is always fatal! */ - SYS_ARCH_SET(conn->last_err, err); - } - - /* @todo: the type of NETCONN_EVT created should depend on 'old_state' */ - - /* Notify the user layer about a connection error. Used to signal select. */ - API_EVENT(conn, NETCONN_EVT_ERROR, 0); - /* Try to release selects pending on 'read' or 'write', too. - They will get an error if they actually try to read or write. */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); - - /* pass NULL-message to recvmbox to wake up pending recv */ - if (sys_mbox_valid(&conn->recvmbox)) { - /* use trypost to prevent deadlock */ - sys_mbox_trypost(&conn->recvmbox, NULL); - } - /* pass NULL-message to acceptmbox to wake up pending accept */ - if (sys_mbox_valid(&conn->acceptmbox)) { - /* use trypost to preven deadlock */ - sys_mbox_trypost(&conn->acceptmbox, NULL); - } - - if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || - (old_state == NETCONN_CONNECT)) { - /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary - since the pcb has already been deleted! */ - int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); - SET_NONBLOCKING_CONNECT(conn, 0); - - if (!was_nonblocking_connect) { - sys_sem_t* op_completed_sem; - /* set error return code */ - LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); - conn->current_msg->err = err; - op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); - LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem)); - conn->current_msg = NULL; - /* wake up the waiting task */ - NETCONN_SET_SAFE_ERR(conn, err); - sys_sem_signal(op_completed_sem); - } - } else { - LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); - } -} - -/** - * Setup a tcp_pcb with the correct callback function pointers - * and their arguments. - * - * @param conn the TCP netconn to setup - */ -static void -setup_tcp(struct netconn *conn) -{ - struct tcp_pcb *pcb; - - pcb = conn->pcb.tcp; - tcp_arg(pcb, conn); - tcp_recv(pcb, recv_tcp); - tcp_sent(pcb, sent_tcp); - tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL); - tcp_err(pcb, err_tcp); -} - -/** - * Accept callback function for TCP netconns. - * Allocates a new netconn and posts that to conn->acceptmbox. - * - * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value - */ -static err_t -accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) -{ - struct netconn *newconn; - struct netconn *conn = (struct netconn *)arg; - - LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state))); - - if (conn == NULL) { - return ERR_VAL; - } - if (!sys_mbox_valid(&conn->acceptmbox)) { - LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); - return ERR_VAL; - } - - if (newpcb == NULL) { - /* out-of-pcbs during connect: pass on this error to the application */ - if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) { - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - } - return ERR_VAL; - } - - /* We have to set the callback here even though - * the new socket is unknown. newconn->socket is marked as -1. */ - newconn = netconn_alloc(conn->type, conn->callback); - if (newconn == NULL) { - /* outof netconns: pass on this error to the application */ - if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) { - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - } - return ERR_MEM; - } - newconn->pcb.tcp = newpcb; - setup_tcp(newconn); - /* no protection: when creating the pcb, the netconn is not yet known - to the application thread */ - newconn->last_err = err; - - /* handle backlog counter */ - tcp_backlog_delayed(newpcb); - - if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { - /* When returning != ERR_OK, the pcb is aborted in tcp_process(), - so do nothing here! */ - /* remove all references to this netconn from the pcb */ - struct tcp_pcb* pcb = newconn->pcb.tcp; - tcp_arg(pcb, NULL); - tcp_recv(pcb, NULL); - tcp_sent(pcb, NULL); - tcp_poll(pcb, NULL, 0); - tcp_err(pcb, NULL); - /* remove reference from to the pcb from this netconn */ - newconn->pcb.tcp = NULL; - /* no need to drain since we know the recvmbox is empty. */ - sys_mbox_free(&newconn->recvmbox); - sys_mbox_set_invalid(&newconn->recvmbox); - netconn_free(newconn); - return ERR_MEM; - } else { - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - } - - return ERR_OK; -} -#endif /* LWIP_TCP */ - -/** - * Create a new pcb of a specific type. - * Called from lwip_netconn_do_newconn(). - * - * @param msg the api_msg_msg describing the connection type - * @return msg->conn->err, but the return value is currently ignored - */ -static void -pcb_new(struct api_msg *msg) -{ - LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); - - /* Allocate a PCB for this connection */ - switch(NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - msg->conn->pcb.raw = raw_new(msg->msg.n.proto); - if (msg->conn->pcb.raw != NULL) { - raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); - } - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - msg->conn->pcb.udp = udp_new(); - if (msg->conn->pcb.udp != NULL) { -#if LWIP_UDPLITE - if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { - udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); - } -#endif /* LWIP_UDPLITE */ - if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { - udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); - } - udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); - } - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - msg->conn->pcb.tcp = tcp_new(); - if (msg->conn->pcb.tcp != NULL) { - setup_tcp(msg->conn); - } - break; -#endif /* LWIP_TCP */ - default: - /* Unsupported netconn type, e.g. protocol disabled */ - msg->err = ERR_VAL; - return; - } - if (msg->conn->pcb.ip == NULL) { - msg->err = ERR_MEM; - } -#if LWIP_IPV4 && LWIP_IPV6 - else { - if (NETCONNTYPE_ISIPV6(msg->conn->type)) { - /* Convert IPv4 PCB manually to an IPv6 PCB */ - IP_SET_TYPE_VAL(msg->conn->pcb.ip->local_ip, IPADDR_TYPE_V6); - IP_SET_TYPE_VAL(msg->conn->pcb.ip->remote_ip, IPADDR_TYPE_V6); - } - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ -} - -/** - * Create a new pcb of a specific type inside a netconn. - * Called from netconn_new_with_proto_and_callback. - * - * @param m the api_msg_msg describing the connection type - */ -void -lwip_netconn_do_newconn(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - msg->err = ERR_OK; - if (msg->conn->pcb.tcp == NULL) { - pcb_new(msg); - } - /* Else? This "new" connection already has a PCB allocated. */ - /* Is this an error condition? Should it be deleted? */ - /* We currently just are happy and return. */ - - TCPIP_APIMSG_ACK(msg); -} - -/** - * Create a new netconn (of a specific type) that has a callback function. - * The corresponding pcb is NOT created! - * - * @param t the type of 'connection' to create (@see enum netconn_type) - * @param callback a function to call on status changes (RX available, TX'ed) - * @return a newly allocated struct netconn or - * NULL on memory error - */ -struct netconn* -netconn_alloc(enum netconn_type t, netconn_callback callback) -{ - struct netconn *conn; - int size; - - conn = (struct netconn *)memp_malloc(MEMP_NETCONN); - if (conn == NULL) { - return NULL; - } - - conn->last_err = ERR_OK; - conn->type = t; - conn->pcb.tcp = NULL; - - /* If all sizes are the same, every compiler should optimize this switch to nothing */ - switch(NETCONNTYPE_GROUP(t)) { -#if LWIP_RAW - case NETCONN_RAW: - size = DEFAULT_RAW_RECVMBOX_SIZE; - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - size = DEFAULT_UDP_RECVMBOX_SIZE; - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - size = DEFAULT_TCP_RECVMBOX_SIZE; - break; -#endif /* LWIP_TCP */ - default: - LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); - goto free_and_return; - } - - if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { - goto free_and_return; - } -#if !LWIP_NETCONN_SEM_PER_THREAD - if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { - sys_mbox_free(&conn->recvmbox); - goto free_and_return; - } -#endif - -#if LWIP_TCP - sys_mbox_set_invalid(&conn->acceptmbox); -#endif - conn->state = NETCONN_NONE; -#if LWIP_SOCKET - /* initialize socket to -1 since 0 is a valid socket */ - conn->socket = -1; -#endif /* LWIP_SOCKET */ - conn->callback = callback; -#if LWIP_TCP - conn->current_msg = NULL; - conn->write_offset = 0; -#endif /* LWIP_TCP */ -#if LWIP_SO_SNDTIMEO - conn->send_timeout = 0; -#endif /* LWIP_SO_SNDTIMEO */ -#if LWIP_SO_RCVTIMEO - conn->recv_timeout = 0; -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF - conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; - conn->recv_avail = 0; -#endif /* LWIP_SO_RCVBUF */ -#if LWIP_SO_LINGER - conn->linger = -1; -#endif /* LWIP_SO_LINGER */ - conn->flags = 0; - return conn; -free_and_return: - memp_free(MEMP_NETCONN, conn); - return NULL; -} - -/** - * Delete a netconn and all its resources. - * The pcb is NOT freed (since we might not be in the right thread context do this). - * - * @param conn the netconn to free - */ -void -netconn_free(struct netconn *conn) -{ - LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); - LWIP_ASSERT("recvmbox must be deallocated before calling this function", - !sys_mbox_valid(&conn->recvmbox)); -#if LWIP_TCP - LWIP_ASSERT("acceptmbox must be deallocated before calling this function", - !sys_mbox_valid(&conn->acceptmbox)); -#endif /* LWIP_TCP */ - -#if !LWIP_NETCONN_SEM_PER_THREAD - sys_sem_free(&conn->op_completed); - sys_sem_set_invalid(&conn->op_completed); -#endif - - memp_free(MEMP_NETCONN, conn); -} - -/** - * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in - * these mboxes - * - * @param conn the netconn to free - * @bytes_drained bytes drained from recvmbox - * @accepts_drained pending connections drained from acceptmbox - */ -static void -netconn_drain(struct netconn *conn) -{ - void *mem; -#if LWIP_TCP - struct pbuf *p; -#endif /* LWIP_TCP */ - - /* This runs in tcpip_thread, so we don't need to lock against rx packets */ - - /* Delete and drain the recvmbox. */ - if (sys_mbox_valid(&conn->recvmbox)) { - while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { -#if LWIP_TCP - if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { - if (mem != NULL) { - p = (struct pbuf*)mem; - /* pcb might be set to NULL already by err_tcp() */ - if (conn->pcb.tcp != NULL) { - tcp_recved(conn->pcb.tcp, p->tot_len); - } - pbuf_free(p); - } - } else -#endif /* LWIP_TCP */ - { - netbuf_delete((struct netbuf *)mem); - } - } - sys_mbox_free(&conn->recvmbox); - sys_mbox_set_invalid(&conn->recvmbox); - } - - /* Delete and drain the acceptmbox. */ -#if LWIP_TCP - if (sys_mbox_valid(&conn->acceptmbox)) { - while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { - struct netconn *newconn = (struct netconn *)mem; - /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ - /* pcb might be set to NULL already by err_tcp() */ - /* drain recvmbox */ - netconn_drain(newconn); - if (newconn->pcb.tcp != NULL) { - tcp_abort(newconn->pcb.tcp); - newconn->pcb.tcp = NULL; - } - netconn_free(newconn); - } - sys_mbox_free(&conn->acceptmbox); - sys_mbox_set_invalid(&conn->acceptmbox); - } -#endif /* LWIP_TCP */ -} - -#if LWIP_TCP -/** - * Internal helper function to close a TCP netconn: since this sometimes - * doesn't work at the first attempt, this function is called from multiple - * places. - * - * @param conn the TCP netconn to close - * [@param delay 1 if called from sent/poll (wake up calling thread on end)] - */ -static err_t -lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM) -{ - err_t err; - u8_t shut, shut_rx, shut_tx, close; - u8_t close_finished = 0; - struct tcp_pcb* tpcb; -#if LWIP_SO_LINGER - u8_t linger_wait_required = 0; -#endif /* LWIP_SO_LINGER */ - - LWIP_ASSERT("invalid conn", (conn != NULL)); - LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)); - LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); - LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); - LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); - - tpcb = conn->pcb.tcp; - shut = conn->current_msg->msg.sd.shut; - shut_rx = shut & NETCONN_SHUT_RD; - shut_tx = shut & NETCONN_SHUT_WR; - /* shutting down both ends is the same as closing - (also if RD or WR side was shut down before already) */ - if (shut == NETCONN_SHUT_RDWR) { - close = 1; - } else if (shut_rx && - ((tpcb->state == FIN_WAIT_1) || - (tpcb->state == FIN_WAIT_2) || - (tpcb->state == CLOSING))) { - close = 1; - } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) { - close = 1; - } else { - close = 0; - } - - /* Set back some callback pointers */ - if (close) { - tcp_arg(tpcb, NULL); - } - if (tpcb->state == LISTEN) { - tcp_accept(tpcb, NULL); - } else { - /* some callbacks have to be reset if tcp_close is not successful */ - if (shut_rx) { - tcp_recv(tpcb, NULL); - tcp_accept(tpcb, NULL); - } - if (shut_tx) { - tcp_sent(tpcb, NULL); - } - if (close) { - tcp_poll(tpcb, NULL, 0); - tcp_err(tpcb, NULL); - } - } - /* Try to close the connection */ - if (close) { -#if LWIP_SO_LINGER - /* check linger possibilites before calling tcp_close */ - err = ERR_OK; - /* linger enabled/required at all? (i.e. is there untransmitted data left?) */ - if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) { - if ((conn->linger == 0)) { - /* data left but linger prevents waiting */ - tcp_abort(tpcb); - tpcb = NULL; - } else if (conn->linger > 0) { - /* data left and linger says we should wait */ - if (netconn_is_nonblocking(conn)) { - /* data left on a nonblocking netconn -> cannot linger */ - err = ERR_WOULDBLOCK; - } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= - (conn->linger * 1000)) { - /* data left but linger timeout has expired (this happens on further - calls to this function through poll_tcp */ - tcp_abort(tpcb); - tpcb = NULL; - } else { - /* data left -> need to wait for ACK after successful close */ - linger_wait_required = 1; - } - } - } - if ((err == ERR_OK) && (tpcb != NULL)) -#endif /* LWIP_SO_LINGER */ - { - err = tcp_close(tpcb); - } - } else { - err = tcp_shutdown(tpcb, shut_rx, shut_tx); - } - if (err == ERR_OK) { - close_finished = 1; -#if LWIP_SO_LINGER - if (linger_wait_required) { - /* wait for ACK of all unsent/unacked data by just getting called again */ - close_finished = 0; - err = ERR_INPROGRESS; - } -#endif /* LWIP_SO_LINGER */ - } else { - if (err == ERR_MEM) { - /* Closing failed because of memory shortage, try again later. Even for - nonblocking netconns, we have to wait since no standard socket application - is prepared for close failing because of resource shortage. - Check the timeout: this is kind of an lwip addition to the standard sockets: - we wait for some time when failing to allocate a segment for the FIN */ -#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER - s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT; -#if LWIP_SO_SNDTIMEO - if (conn->send_timeout > 0) { - close_timeout = conn->send_timeout; - } -#endif /* LWIP_SO_SNDTIMEO */ -#if LWIP_SO_LINGER - if (conn->linger >= 0) { - /* use linger timeout (seconds) */ - close_timeout = conn->linger * 1000U; - } -#endif - if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) { -#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ - if (conn->current_msg->msg.sd.polls_left == 0) { -#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ - close_finished = 1; - if (close) { - /* in this case, we want to RST the connection */ - tcp_abort(tpcb); - err = ERR_OK; - } - } - } else { - /* Closing failed for a non-memory error: give up */ - close_finished = 1; - } - } - if (close_finished) { - /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */ - sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); - conn->current_msg->err = err; - conn->current_msg = NULL; - conn->state = NETCONN_NONE; - if (err == ERR_OK) { - if (close) { - /* Set back some callback pointers as conn is going away */ - conn->pcb.tcp = NULL; - /* Trigger select() in socket layer. Make sure everybody notices activity - on the connection, error first! */ - API_EVENT(conn, NETCONN_EVT_ERROR, 0); - } - if (shut_rx) { - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - } - if (shut_tx) { - API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); - } - } - NETCONN_SET_SAFE_ERR(conn, err); -#if LWIP_TCPIP_CORE_LOCKING - if (delayed) -#endif - { - /* wake up the application task */ - sys_sem_signal(op_completed_sem); - } - return ERR_OK; - } - if (!close_finished) { - /* Closing failed and we want to wait: restore some of the callbacks */ - /* Closing of listen pcb will never fail! */ - LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN)); - if (shut_tx) { - tcp_sent(tpcb, sent_tcp); - } - /* when waiting for close, set up poll interval to 500ms */ - tcp_poll(tpcb, poll_tcp, 1); - tcp_err(tpcb, err_tcp); - tcp_arg(tpcb, conn); - /* don't restore recv callback: we don't want to receive any more data */ - } - /* If closing didn't succeed, we get called again either - from poll_tcp or from sent_tcp */ - LWIP_ASSERT("err != ERR_OK", err != ERR_OK); - return err; -} -#endif /* LWIP_TCP */ - -/** - * Delete the pcb inside a netconn. - * Called from netconn_delete. - * - * @param m the api_msg_msg pointing to the connection - */ -void -lwip_netconn_do_delconn(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - enum netconn_state state = msg->conn->state; - LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */ - (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)); -#if LWIP_NETCONN_FULLDUPLEX - /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */ - if (state != NETCONN_NONE) { - if ((state == NETCONN_WRITE) || - ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { - /* close requested, abort running write/connect */ - sys_sem_t* op_completed_sem; - LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); - op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); - msg->conn->current_msg->err = ERR_CLSD; - msg->conn->current_msg = NULL; - msg->conn->write_offset = 0; - msg->conn->state = NETCONN_NONE; - NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD); - sys_sem_signal(op_completed_sem); - } - } -#else /* LWIP_NETCONN_FULLDUPLEX */ - if (((state != NETCONN_NONE) && - (state != NETCONN_LISTEN) && - (state != NETCONN_CONNECT)) || - ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { - /* This means either a blocking write or blocking connect is running - (nonblocking write returns and sets state to NONE) */ - msg->err = ERR_INPROGRESS; - } else -#endif /* LWIP_NETCONN_FULLDUPLEX */ - { - LWIP_ASSERT("blocking connect in progress", - (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); - msg->err = ERR_OK; - /* Drain and delete mboxes */ - netconn_drain(msg->conn); - - if (msg->conn->pcb.tcp != NULL) { - - switch (NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - raw_remove(msg->conn->pcb.raw); - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - msg->conn->pcb.udp->recv_arg = NULL; - udp_remove(msg->conn->pcb.udp); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && - msg->conn->write_offset == 0); - msg->conn->state = NETCONN_CLOSE; - msg->msg.sd.shut = NETCONN_SHUT_RDWR; - msg->conn->current_msg = msg; -#if LWIP_TCPIP_CORE_LOCKING - if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { - LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); - UNLOCK_TCPIP_CORE(); - sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); - LOCK_TCPIP_CORE(); - LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); - } -#else /* LWIP_TCPIP_CORE_LOCKING */ - lwip_netconn_do_close_internal(msg->conn); -#endif /* LWIP_TCPIP_CORE_LOCKING */ - /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing - the application thread, so we can return at this point! */ - return; -#endif /* LWIP_TCP */ - default: - break; - } - msg->conn->pcb.tcp = NULL; - } - /* tcp netconns don't come here! */ - - /* @todo: this lets select make the socket readable and writable, - which is wrong! errfd instead? */ - API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); - API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); - } - if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) { - TCPIP_APIMSG_ACK(msg); - } -} - -/** - * Bind a pcb contained in a netconn - * Called from netconn_bind. - * - * @param m the api_msg_msg pointing to the connection and containing - * the IP address and port to bind to - */ -void -lwip_netconn_do_bind(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - if (ERR_IS_FATAL(msg->conn->last_err)) { - msg->err = msg->conn->last_err; - } else { - msg->err = ERR_VAL; - if (msg->conn->pcb.tcp != NULL) { - const ip_addr_t *ipaddr = API_EXPR_REF(msg->msg.bc.ipaddr); - -#if LWIP_IPV4 && LWIP_IPV6 - /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY, - * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to bind - */ - if (ip_addr_cmp(ipaddr, IP6_ADDR_ANY) && - (netconn_get_ipv6only(msg->conn) == 0)) { - /* change PCB type to IPADDR_TYPE_ANY */ - IP_SET_TYPE_VAL(msg->conn->pcb.ip->local_ip, IPADDR_TYPE_ANY); - IP_SET_TYPE_VAL(msg->conn->pcb.ip->remote_ip, IPADDR_TYPE_ANY); - - /* bind to IPADDR_TYPE_ANY */ - ipaddr = IP_ANY_TYPE; - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - - switch (NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - msg->err = raw_bind(msg->conn->pcb.raw, ipaddr); - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - msg->err = udp_bind(msg->conn->pcb.udp, ipaddr, msg->msg.bc.port); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - msg->err = tcp_bind(msg->conn->pcb.tcp, ipaddr, msg->msg.bc.port); - break; -#endif /* LWIP_TCP */ - default: - break; - } - } - } - TCPIP_APIMSG_ACK(msg); -} - -#if LWIP_TCP -/** - * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has - * been established (or reset by the remote host). - * - * @see tcp.h (struct tcp_pcb.connected) for parameters and return values - */ -static err_t -lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) -{ - struct netconn *conn; - int was_blocking; - sys_sem_t* op_completed_sem = NULL; - - LWIP_UNUSED_ARG(pcb); - - conn = (struct netconn *)arg; - - if (conn == NULL) { - return ERR_VAL; - } - - LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); - LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", - (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); - - if (conn->current_msg != NULL) { - conn->current_msg->err = err; - op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); - } - if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) { - setup_tcp(conn); - } - was_blocking = !IN_NONBLOCKING_CONNECT(conn); - SET_NONBLOCKING_CONNECT(conn, 0); - LWIP_ASSERT("blocking connect state error", - (was_blocking && op_completed_sem != NULL) || - (!was_blocking && op_completed_sem == NULL)); - conn->current_msg = NULL; - conn->state = NETCONN_NONE; - NETCONN_SET_SAFE_ERR(conn, ERR_OK); - API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); - - if (was_blocking) { - sys_sem_signal(op_completed_sem); - } - return ERR_OK; -} -#endif /* LWIP_TCP */ - -/** - * Connect a pcb contained inside a netconn - * Called from netconn_connect. - * - * @param m the api_msg_msg pointing to the connection and containing - * the IP address and port to connect to - */ -void -lwip_netconn_do_connect(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - if (msg->conn->pcb.tcp == NULL) { - /* This may happen when calling netconn_connect() a second time */ - msg->err = ERR_CLSD; - } else { - switch (NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - /* Prevent connect while doing any other action. */ - if (msg->conn->state == NETCONN_CONNECT) { - msg->err = ERR_ALREADY; - } else if (msg->conn->state != NETCONN_NONE) { - msg->err = ERR_ISCONN; - } else { - setup_tcp(msg->conn); - msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), - msg->msg.bc.port, lwip_netconn_do_connected); - if (msg->err == ERR_OK) { - u8_t non_blocking = netconn_is_nonblocking(msg->conn); - msg->conn->state = NETCONN_CONNECT; - SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); - if (non_blocking) { - msg->err = ERR_INPROGRESS; - } else { - msg->conn->current_msg = msg; - /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()), - when the connection is established! */ -#if LWIP_TCPIP_CORE_LOCKING - LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT); - UNLOCK_TCPIP_CORE(); - sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); - LOCK_TCPIP_CORE(); - LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT); -#endif /* LWIP_TCPIP_CORE_LOCKING */ - return; - } - } - } - break; -#endif /* LWIP_TCP */ - default: - LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); - break; - } - } - /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(), - so use TCPIP_APIMSG_ACK() here. */ - TCPIP_APIMSG_ACK(msg); -} - -/** - * Disconnect a pcb contained inside a netconn - * Only used for UDP netconns. - * Called from netconn_disconnect. - * - * @param m the api_msg_msg pointing to the connection to disconnect - */ -void -lwip_netconn_do_disconnect(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - -#if LWIP_UDP - if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { - udp_disconnect(msg->conn->pcb.udp); - msg->err = ERR_OK; - } else -#endif /* LWIP_UDP */ - { - msg->err = ERR_VAL; - } - TCPIP_APIMSG_ACK(msg); -} - -#if LWIP_TCP -/** - * Set a TCP pcb contained in a netconn into listen mode - * Called from netconn_listen. - * - * @param m the api_msg_msg pointing to the connection - */ -void -lwip_netconn_do_listen(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - if (ERR_IS_FATAL(msg->conn->last_err)) { - msg->err = msg->conn->last_err; - } else { - msg->err = ERR_CONN; - if (msg->conn->pcb.tcp != NULL) { - if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { - if (msg->conn->state == NETCONN_NONE) { - struct tcp_pcb* lpcb; - if (msg->conn->pcb.tcp->state != CLOSED) { - /* connection is not closed, cannot listen */ - msg->err = ERR_VAL; - } else { -#if LWIP_IPV4 && LWIP_IPV6 - /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY, - * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen - */ - if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) && - (netconn_get_ipv6only(msg->conn) == 0)) { - /* change PCB type to IPADDR_TYPE_ANY */ - IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY); - IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY); - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - -#if TCP_LISTEN_BACKLOG - lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); -#else /* TCP_LISTEN_BACKLOG */ - lpcb = tcp_listen(msg->conn->pcb.tcp); -#endif /* TCP_LISTEN_BACKLOG */ - - if (lpcb == NULL) { - /* in this case, the old pcb is still allocated */ - msg->err = ERR_MEM; - } else { - /* delete the recvmbox and allocate the acceptmbox */ - if (sys_mbox_valid(&msg->conn->recvmbox)) { - /** @todo: should we drain the recvmbox here? */ - sys_mbox_free(&msg->conn->recvmbox); - sys_mbox_set_invalid(&msg->conn->recvmbox); - } - msg->err = ERR_OK; - if (!sys_mbox_valid(&msg->conn->acceptmbox)) { - msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); - } - if (msg->err == ERR_OK) { - msg->conn->state = NETCONN_LISTEN; - msg->conn->pcb.tcp = lpcb; - tcp_arg(msg->conn->pcb.tcp, msg->conn); - tcp_accept(msg->conn->pcb.tcp, accept_function); - } else { - /* since the old pcb is already deallocated, free lpcb now */ - tcp_close(lpcb); - msg->conn->pcb.tcp = NULL; - } - } - } - } else if (msg->conn->state == NETCONN_LISTEN) { - /* already listening, allow updating of the backlog */ - msg->err = ERR_OK; - tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog); - } - } else { - msg->err = ERR_ARG; - } - } - } - TCPIP_APIMSG_ACK(msg); -} -#endif /* LWIP_TCP */ - -/** - * Send some data on a RAW or UDP pcb contained in a netconn - * Called from netconn_send - * - * @param m the api_msg_msg pointing to the connection - */ -void -lwip_netconn_do_send(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - if (ERR_IS_FATAL(msg->conn->last_err)) { - msg->err = msg->conn->last_err; - } else { - msg->err = ERR_CONN; - if (msg->conn->pcb.tcp != NULL) { - switch (NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - if (ip_addr_isany(&msg->msg.b->addr)) { - msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); - } else { - msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); - } - break; -#endif -#if LWIP_UDP - case NETCONN_UDP: -#if LWIP_CHECKSUM_ON_COPY - if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { - msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, - msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); - } else { - msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, - &msg->msg.b->addr, msg->msg.b->port, - msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); - } -#else /* LWIP_CHECKSUM_ON_COPY */ - if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { - msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); - } else { - msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); - } -#endif /* LWIP_CHECKSUM_ON_COPY */ - break; -#endif /* LWIP_UDP */ - default: - break; - } - } - } - TCPIP_APIMSG_ACK(msg); -} - -#if LWIP_TCP -/** - * Indicate data has been received from a TCP pcb contained in a netconn - * Called from netconn_recv - * - * @param m the api_msg_msg pointing to the connection - */ -void -lwip_netconn_do_recv(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - msg->err = ERR_OK; - if (msg->conn->pcb.tcp != NULL) { - if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { - u32_t remaining = msg->msg.r.len; - do { - u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; - tcp_recved(msg->conn->pcb.tcp, recved); - remaining -= recved; - } while (remaining != 0); - } - } - TCPIP_APIMSG_ACK(msg); -} - -#if TCP_LISTEN_BACKLOG -/** Indicate that a TCP pcb has been accepted - * Called from netconn_accept - * - * @param m the api_msg_msg pointing to the connection - */ -void -lwip_netconn_do_accepted(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - msg->err = ERR_OK; - if (msg->conn->pcb.tcp != NULL) { - if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { - tcp_backlog_accepted(msg->conn->pcb.tcp); - } - } - TCPIP_APIMSG_ACK(msg); -} -#endif /* TCP_LISTEN_BACKLOG */ - -/** - * See if more data needs to be written from a previous call to netconn_write. - * Called initially from lwip_netconn_do_write. If the first call can't send all data - * (because of low memory or empty send-buffer), this function is called again - * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the - * blocking application thread (waiting in netconn_write) is released. - * - * @param conn netconn (that is currently in state NETCONN_WRITE) to process - * [@param delay 1 if called from sent/poll (wake up calling thread on end)] - * @return ERR_OK - * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished - */ -static err_t -lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) -{ - err_t err; - const void *dataptr; - u16_t len, available; - u8_t write_finished = 0; - size_t diff; - u8_t dontblock; - u8_t apiflags; - - LWIP_ASSERT("conn != NULL", conn != NULL); - LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); - LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); - LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); - LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", - conn->write_offset < conn->current_msg->msg.w.len); - - dontblock = netconn_is_nonblocking(conn) || - (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK); - apiflags = conn->current_msg->msg.w.apiflags; - -#if LWIP_SO_SNDTIMEO - if ((conn->send_timeout != 0) && - ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { - write_finished = 1; - if (conn->write_offset == 0) { - /* nothing has been written */ - err = ERR_WOULDBLOCK; - conn->current_msg->msg.w.len = 0; - } else { - /* partial write */ - err = ERR_OK; - conn->current_msg->msg.w.len = conn->write_offset; - conn->write_offset = 0; - } - } else -#endif /* LWIP_SO_SNDTIMEO */ - { - dataptr = (const u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; - diff = conn->current_msg->msg.w.len - conn->write_offset; - if (diff > 0xffffUL) { /* max_u16_t */ - len = 0xffff; - apiflags |= TCP_WRITE_FLAG_MORE; - } else { - len = (u16_t)diff; - } - available = tcp_sndbuf(conn->pcb.tcp); - if (available < len) { - /* don't try to write more than sendbuf */ - len = available; - if (dontblock) { - if (!len) { - err = ERR_WOULDBLOCK; - goto err_mem; - } - } else { - apiflags |= TCP_WRITE_FLAG_MORE; - } - } - LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); - err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); - /* if OK or memory error, check available space */ - if ((err == ERR_OK) || (err == ERR_MEM)) { -err_mem: - if (dontblock && (len < conn->current_msg->msg.w.len)) { - /* non-blocking write did not write everything: mark the pcb non-writable - and let poll_tcp check writable space to mark the pcb writable again */ - API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); - conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; - } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || - (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { - /* The queued byte- or pbuf-count exceeds the configured low-water limit, - let select mark this pcb as non-writable. */ - API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); - } - } - - if (err == ERR_OK) { - err_t out_err; - conn->write_offset += len; - if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) { - /* return sent length */ - conn->current_msg->msg.w.len = conn->write_offset; - /* everything was written */ - write_finished = 1; - } - out_err = tcp_output(conn->pcb.tcp); - if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) { - /* If tcp_output fails with fatal error or no route is found, - don't try writing any more but return the error - to the application thread. */ - err = out_err; - write_finished = 1; - conn->current_msg->msg.w.len = 0; - } - } else if ((err == ERR_MEM) && !dontblock) { - /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called - we do NOT return to the application thread, since ERR_MEM is - only a temporary error! */ - - /* tcp_write returned ERR_MEM, try tcp_output anyway */ - err_t out_err = tcp_output(conn->pcb.tcp); - if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) { - /* If tcp_output fails with fatal error or no route is found, - don't try writing any more but return the error - to the application thread. */ - err = out_err; - write_finished = 1; - conn->current_msg->msg.w.len = 0; - } else { - } - } else { - /* On errors != ERR_MEM, we don't try writing any more but return - the error to the application thread. */ - write_finished = 1; - conn->current_msg->msg.w.len = 0; - } - } - if (write_finished) { - /* everything was written: set back connection state - and back to application task */ - sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); - conn->current_msg->err = err; - conn->current_msg = NULL; - conn->write_offset = 0; - conn->state = NETCONN_NONE; - NETCONN_SET_SAFE_ERR(conn, err); -#if LWIP_TCPIP_CORE_LOCKING - if (delayed) -#endif - { - sys_sem_signal(op_completed_sem); - } - } -#if LWIP_TCPIP_CORE_LOCKING - else { - return ERR_MEM; - } -#endif - return ERR_OK; -} -#endif /* LWIP_TCP */ - -/** - * Send some data on a TCP pcb contained in a netconn - * Called from netconn_write - * - * @param m the api_msg_msg pointing to the connection - */ -void -lwip_netconn_do_write(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - if (ERR_IS_FATAL(msg->conn->last_err)) { - msg->err = msg->conn->last_err; - } else { - if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { -#if LWIP_TCP - if (msg->conn->state != NETCONN_NONE) { - /* netconn is connecting, closing or in blocking write */ - msg->err = ERR_INPROGRESS; - } else if (msg->conn->pcb.tcp != NULL) { - msg->conn->state = NETCONN_WRITE; - /* set all the variables used by lwip_netconn_do_writemore */ - LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && - msg->conn->write_offset == 0); - LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); - msg->conn->current_msg = msg; - msg->conn->write_offset = 0; -#if LWIP_TCPIP_CORE_LOCKING - if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) { - LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); - UNLOCK_TCPIP_CORE(); - sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); - LOCK_TCPIP_CORE(); - LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE); - } -#else /* LWIP_TCPIP_CORE_LOCKING */ - lwip_netconn_do_writemore(msg->conn); -#endif /* LWIP_TCPIP_CORE_LOCKING */ - /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG - since lwip_netconn_do_writemore ACKs it! */ - return; - } else { - msg->err = ERR_CONN; - } -#else /* LWIP_TCP */ - msg->err = ERR_VAL; -#endif /* LWIP_TCP */ -#if (LWIP_UDP || LWIP_RAW) - } else { - msg->err = ERR_VAL; -#endif /* (LWIP_UDP || LWIP_RAW) */ - } - } - TCPIP_APIMSG_ACK(msg); -} - -/** - * Return a connection's local or remote address - * Called from netconn_getaddr - * - * @param m the api_msg_msg pointing to the connection - */ -void -lwip_netconn_do_getaddr(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - if (msg->conn->pcb.ip != NULL) { - if (msg->msg.ad.local) { - ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), - msg->conn->pcb.ip->local_ip); - } else { - ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), - msg->conn->pcb.ip->remote_ip); - } - msg->err = ERR_OK; - switch (NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - if (msg->msg.ad.local) { - API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; - } else { - /* return an error as connecting is only a helper for upper layers */ - msg->err = ERR_CONN; - } - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - if (msg->msg.ad.local) { - API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; - } else { - if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { - msg->err = ERR_CONN; - } else { - API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; - } - } - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - if ((msg->msg.ad.local == 0) && - ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) { - /* pcb is not connected and remote name is requested */ - msg->err = ERR_CONN; - } else { - API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port); - } - break; -#endif /* LWIP_TCP */ - default: - LWIP_ASSERT("invalid netconn_type", 0); - break; - } - } else { - msg->err = ERR_CONN; - } - TCPIP_APIMSG_ACK(msg); -} - -/** - * Close or half-shutdown a TCP pcb contained in a netconn - * Called from netconn_close - * In contrast to closing sockets, the netconn is not deallocated. - * - * @param m the api_msg_msg pointing to the connection - */ -void -lwip_netconn_do_close(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - -#if LWIP_TCP - enum netconn_state state = msg->conn->state; - /* First check if this is a TCP netconn and if it is in a correct state - (LISTEN doesn't support half shutdown) */ - if ((msg->conn->pcb.tcp != NULL) && - (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) && - ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) { - /* Check if we are in a connected state */ - if (state == NETCONN_CONNECT) { - /* TCP connect in progress: cannot shutdown */ - msg->err = ERR_CONN; - } else if (state == NETCONN_WRITE) { -#if LWIP_NETCONN_FULLDUPLEX - if (msg->msg.sd.shut & NETCONN_SHUT_WR) { - /* close requested, abort running write */ - sys_sem_t* op_completed_sem; - LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); - op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); - msg->conn->current_msg->err = ERR_CLSD; - msg->conn->current_msg = NULL; - msg->conn->write_offset = 0; - msg->conn->state = NETCONN_NONE; - NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD); - sys_sem_signal(op_completed_sem); - } else { - LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD); - /* In this case, let the write continue and do not interfere with - conn->current_msg or conn->state! */ - msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0); - } -#else /* LWIP_NETCONN_FULLDUPLEX */ - msg->err = ERR_INPROGRESS; -#endif /* LWIP_NETCONN_FULLDUPLEX */ - } else { - if (msg->msg.sd.shut & NETCONN_SHUT_RD) { - /* Drain and delete mboxes */ - netconn_drain(msg->conn); - } - LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && - msg->conn->write_offset == 0); - msg->conn->state = NETCONN_CLOSE; - msg->conn->current_msg = msg; -#if LWIP_TCPIP_CORE_LOCKING - if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { - LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); - UNLOCK_TCPIP_CORE(); - sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); - LOCK_TCPIP_CORE(); - LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); - } -#else /* LWIP_TCPIP_CORE_LOCKING */ - lwip_netconn_do_close_internal(msg->conn); -#endif /* LWIP_TCPIP_CORE_LOCKING */ - /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */ - return; - } - } else -#endif /* LWIP_TCP */ - { - msg->err = ERR_CONN; - } - TCPIP_APIMSG_ACK(msg); -} - -#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) -/** - * Join multicast groups for UDP netconns. - * Called from netconn_join_leave_group - * - * @param m the api_msg_msg pointing to the connection - */ -void -lwip_netconn_do_join_leave_group(void *m) -{ - struct api_msg *msg = (struct api_msg*)m; - - if (ERR_IS_FATAL(msg->conn->last_err)) { - msg->err = msg->conn->last_err; - } else { - if (msg->conn->pcb.tcp != NULL) { - if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { -#if LWIP_UDP -#if LWIP_IPV6 && LWIP_IPV6_MLD - if (NETCONNTYPE_ISIPV6(msg->conn->type)) { - if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { - msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), - ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); - } else { - msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), - ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); - } - } - else -#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - { -#if LWIP_IGMP - if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { - msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), - ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); - } else { - msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), - ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); - } -#endif /* LWIP_IGMP */ - } -#endif /* LWIP_UDP */ -#if (LWIP_TCP || LWIP_RAW) - } else { - msg->err = ERR_VAL; -#endif /* (LWIP_TCP || LWIP_RAW) */ - } - } else { - msg->err = ERR_CONN; - } - } - TCPIP_APIMSG_ACK(msg); -} -#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ - -#if LWIP_DNS -/** - * Callback function that is called when DNS name is resolved - * (or on timeout). A waiting application thread is waked up by - * signaling the semaphore. - */ -static void -lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg) -{ - struct dns_api_msg *msg = (struct dns_api_msg*)arg; - - /* we trust the internal implementation to be correct :-) */ - LWIP_UNUSED_ARG(name); - - if (ipaddr == NULL) { - /* timeout or memory error */ - API_EXPR_DEREF(msg->err) = ERR_VAL; - } else { - /* address was resolved */ - API_EXPR_DEREF(msg->err) = ERR_OK; - API_EXPR_DEREF(msg->addr) = *ipaddr; - } - /* wake up the application task waiting in netconn_gethostbyname */ - sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); -} - -/** - * Execute a DNS query - * Called from netconn_gethostbyname - * - * @param arg the dns_api_msg pointing to the query - */ -void -lwip_netconn_do_gethostbyname(void *arg) -{ - struct dns_api_msg *msg = (struct dns_api_msg*)arg; - u8_t addrtype = -#if LWIP_IPV4 && LWIP_IPV6 - msg->dns_addrtype; -#else - LWIP_DNS_ADDRTYPE_DEFAULT; -#endif - - API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, - API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype); - if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) { - /* on error or immediate success, wake up the application - * task waiting in netconn_gethostbyname */ - sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); - } -} -#endif /* LWIP_DNS */ - -#endif /* LWIP_NETCONN */ diff --git a/ext/lwip/src/api/err.c b/ext/lwip/src/api/err.c deleted file mode 100644 index f3650f4..0000000 --- a/ext/lwip/src/api/err.c +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file - * Error Management module - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/err.h" - -#ifdef LWIP_DEBUG - -static const char *err_strerr[] = { - "Ok.", /* ERR_OK 0 */ - "Out of memory error.", /* ERR_MEM -1 */ - "Buffer error.", /* ERR_BUF -2 */ - "Timeout.", /* ERR_TIMEOUT -3 */ - "Routing problem.", /* ERR_RTE -4 */ - "Operation in progress.", /* ERR_INPROGRESS -5 */ - "Illegal value.", /* ERR_VAL -6 */ - "Operation would block.", /* ERR_WOULDBLOCK -7 */ - "Address in use.", /* ERR_USE -8 */ - "Already connecting.", /* ERR_ALREADY -9 */ - "Already connected.", /* ERR_ISCONN -10 */ - "Not connected.", /* ERR_CONN -11 */ - "Low-level netif error.", /* ERR_IF -12 */ - "Connection aborted.", /* ERR_ABRT -13 */ - "Connection reset.", /* ERR_RST -14 */ - "Connection closed.", /* ERR_CLSD -15 */ - "Illegal argument." /* ERR_ARG -16 */ -}; - -/** - * Convert an lwip internal error to a string representation. - * - * @param err an lwip internal err_t - * @return a string representation for err - */ -const char * -lwip_strerr(err_t err) -{ - return err_strerr[-err]; -} - -#endif /* LWIP_DEBUG */ diff --git a/ext/lwip/src/api/netbuf.c b/ext/lwip/src/api/netbuf.c deleted file mode 100644 index 342717b..0000000 --- a/ext/lwip/src/api/netbuf.c +++ /dev/null @@ -1,263 +0,0 @@ -/** - * @file - * Network buffer management - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -/** - * @defgroup netbuf Network buffers - * @ingroup netconn - * Network buffer descriptor for @ref netconn. Based on @ref pbuf internally - * to avoid copying data around.\n - * Buffers must not be shared accross multiple threads, all functions except - * netbuf_new() and netbuf_delete() are not thread-safe. - */ - -#include "lwip/opt.h" - -#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/netbuf.h" -#include "lwip/memp.h" - -#include - -/** - * @ingroup netbuf - * Create (allocate) and initialize a new netbuf. - * The netbuf doesn't yet contain a packet buffer! - * - * @return a pointer to a new netbuf - * NULL on lack of memory - */ -struct -netbuf *netbuf_new(void) -{ - struct netbuf *buf; - - buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); - if (buf != NULL) { - buf->p = NULL; - buf->ptr = NULL; - ip_addr_set_zero(&buf->addr); - buf->port = 0; -#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY -#if LWIP_CHECKSUM_ON_COPY - buf->flags = 0; -#endif /* LWIP_CHECKSUM_ON_COPY */ - buf->toport_chksum = 0; -#if LWIP_NETBUF_RECVINFO - ip_addr_set_zero(&buf->toaddr); -#endif /* LWIP_NETBUF_RECVINFO */ -#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ - return buf; - } else { - return NULL; - } -} - -/** - * @ingroup netbuf - * Deallocate a netbuf allocated by netbuf_new(). - * - * @param buf pointer to a netbuf allocated by netbuf_new() - */ -void -netbuf_delete(struct netbuf *buf) -{ - if (buf != NULL) { - if (buf->p != NULL) { - pbuf_free(buf->p); - buf->p = buf->ptr = NULL; - } - memp_free(MEMP_NETBUF, buf); - } -} - -/** - * @ingroup netbuf - * Allocate memory for a packet buffer for a given netbuf. - * - * @param buf the netbuf for which to allocate a packet buffer - * @param size the size of the packet buffer to allocate - * @return pointer to the allocated memory - * NULL if no memory could be allocated - */ -void * -netbuf_alloc(struct netbuf *buf, u16_t size) -{ - LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;); - - /* Deallocate any previously allocated memory. */ - if (buf->p != NULL) { - pbuf_free(buf->p); - } - buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); - if (buf->p == NULL) { - return NULL; - } - LWIP_ASSERT("check that first pbuf can hold size", - (buf->p->len >= size)); - buf->ptr = buf->p; - return buf->p->payload; -} - -/** - * @ingroup netbuf - * Free the packet buffer included in a netbuf - * - * @param buf pointer to the netbuf which contains the packet buffer to free - */ -void -netbuf_free(struct netbuf *buf) -{ - LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); - if (buf->p != NULL) { - pbuf_free(buf->p); - } - buf->p = buf->ptr = NULL; -} - -/** - * @ingroup netbuf - * Let a netbuf reference existing (non-volatile) data. - * - * @param buf netbuf which should reference the data - * @param dataptr pointer to the data to reference - * @param size size of the data - * @return ERR_OK if data is referenced - * ERR_MEM if data couldn't be referenced due to lack of memory - */ -err_t -netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size) -{ - LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;); - if (buf->p != NULL) { - pbuf_free(buf->p); - } - buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); - if (buf->p == NULL) { - buf->ptr = NULL; - return ERR_MEM; - } - ((struct pbuf_rom*)buf->p)->payload = dataptr; - buf->p->len = buf->p->tot_len = size; - buf->ptr = buf->p; - return ERR_OK; -} - -/** - * @ingroup netbuf - * Chain one netbuf to another (@see pbuf_chain) - * - * @param head the first netbuf - * @param tail netbuf to chain after head, freed by this function, may not be reference after returning - */ -void -netbuf_chain(struct netbuf *head, struct netbuf *tail) -{ - LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;); - LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;); - pbuf_cat(head->p, tail->p); - head->ptr = head->p; - memp_free(MEMP_NETBUF, tail); -} - -/** - * @ingroup netbuf - * Get the data pointer and length of the data inside a netbuf. - * - * @param buf netbuf to get the data from - * @param dataptr pointer to a void pointer where to store the data pointer - * @param len pointer to an u16_t where the length of the data is stored - * @return ERR_OK if the information was retrieved, - * ERR_BUF on error. - */ -err_t -netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len) -{ - LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;); - LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;); - LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;); - - if (buf->ptr == NULL) { - return ERR_BUF; - } - *dataptr = buf->ptr->payload; - *len = buf->ptr->len; - return ERR_OK; -} - -/** - * @ingroup netbuf - * Move the current data pointer of a packet buffer contained in a netbuf - * to the next part. - * The packet buffer itself is not modified. - * - * @param buf the netbuf to modify - * @return -1 if there is no next part - * 1 if moved to the next part but now there is no next part - * 0 if moved to the next part and there are still more parts - */ -s8_t -netbuf_next(struct netbuf *buf) -{ - LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;); - if (buf->ptr->next == NULL) { - return -1; - } - buf->ptr = buf->ptr->next; - if (buf->ptr->next == NULL) { - return 1; - } - return 0; -} - -/** - * @ingroup netbuf - * Move the current data pointer of a packet buffer contained in a netbuf - * to the beginning of the packet. - * The packet buffer itself is not modified. - * - * @param buf the netbuf to modify - */ -void -netbuf_first(struct netbuf *buf) -{ - LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); - buf->ptr = buf->p; -} - -#endif /* LWIP_NETCONN */ diff --git a/ext/lwip/src/api/netdb.c b/ext/lwip/src/api/netdb.c deleted file mode 100644 index f9d63d4..0000000 --- a/ext/lwip/src/api/netdb.c +++ /dev/null @@ -1,417 +0,0 @@ -/** - * @file - * API functions for name resolving - * - */ - -/* - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - - -/** - * @defgroup netdbapi NETDB API - * @ingroup socket - */ - -#include "lwip/netdb.h" - -#if LWIP_DNS && LWIP_SOCKET - -#include "lwip/err.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/ip_addr.h" -#include "lwip/api.h" -#include "lwip/dns.h" - -#include -#include - -/** helper struct for gethostbyname_r to access the char* buffer */ -struct gethostbyname_r_helper { - ip_addr_t *addr_list[2]; - ip_addr_t addr; - char *aliases; -}; - -/** h_errno is exported in netdb.h for access by applications. */ -#if LWIP_DNS_API_DECLARE_H_ERRNO -int h_errno; -#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ - -/** define "hostent" variables storage: 0 if we use a static (but unprotected) - * set of variables for lwip_gethostbyname, 1 if we use a local storage */ -#ifndef LWIP_DNS_API_HOSTENT_STORAGE -#define LWIP_DNS_API_HOSTENT_STORAGE 0 -#endif - -/** define "hostent" variables storage */ -#if LWIP_DNS_API_HOSTENT_STORAGE -#define HOSTENT_STORAGE -#else -#define HOSTENT_STORAGE static -#endif /* LWIP_DNS_API_STATIC_HOSTENT */ - -/** - * Returns an entry containing addresses of address family AF_INET - * for the host with name name. - * Due to dns_gethostbyname limitations, only one address is returned. - * - * @param name the hostname to resolve - * @return an entry containing addresses of address family AF_INET - * for the host with name name - */ -struct hostent* -lwip_gethostbyname(const char *name) -{ - err_t err; - ip_addr_t addr; - - /* buffer variables for lwip_gethostbyname() */ - HOSTENT_STORAGE struct hostent s_hostent; - HOSTENT_STORAGE char *s_aliases; - HOSTENT_STORAGE ip_addr_t s_hostent_addr; - HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; - HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1]; - - /* query host IP address */ - err = netconn_gethostbyname(name, &addr); - if (err != ERR_OK) { - LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); - h_errno = HOST_NOT_FOUND; - return NULL; - } - - /* fill hostent */ - s_hostent_addr = addr; - s_phostent_addr[0] = &s_hostent_addr; - s_phostent_addr[1] = NULL; - strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH); - s_hostname[DNS_MAX_NAME_LENGTH] = 0; - s_hostent.h_name = s_hostname; - s_aliases = NULL; - s_hostent.h_aliases = &s_aliases; - s_hostent.h_addrtype = AF_INET; - s_hostent.h_length = sizeof(ip_addr_t); - s_hostent.h_addr_list = (char**)&s_phostent_addr; - -#if DNS_DEBUG - /* dump hostent */ - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", (void*)s_hostent.h_aliases)); - /* h_aliases are always empty */ - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype)); - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length)); - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", (void*)s_hostent.h_addr_list)); - if (s_hostent.h_addr_list != NULL) { - u8_t idx; - for (idx=0; s_hostent.h_addr_list[idx]; idx++) { - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx])); - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx]))); - } - } -#endif /* DNS_DEBUG */ - -#if LWIP_DNS_API_HOSTENT_STORAGE - /* this function should return the "per-thread" hostent after copy from s_hostent */ - return sys_thread_hostent(&s_hostent); -#else - return &s_hostent; -#endif /* LWIP_DNS_API_HOSTENT_STORAGE */ -} - -/** - * Thread-safe variant of lwip_gethostbyname: instead of using a static - * buffer, this function takes buffer and errno pointers as arguments - * and uses these for the result. - * - * @param name the hostname to resolve - * @param ret pre-allocated struct where to store the result - * @param buf pre-allocated buffer where to store additional data - * @param buflen the size of buf - * @param result pointer to a hostent pointer that is set to ret on success - * and set to zero on error - * @param h_errnop pointer to an int where to store errors (instead of modifying - * the global h_errno) - * @return 0 on success, non-zero on error, additional error information - * is stored in *h_errnop instead of h_errno to be thread-safe - */ -int -lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, - size_t buflen, struct hostent **result, int *h_errnop) -{ - err_t err; - struct gethostbyname_r_helper *h; - char *hostname; - size_t namelen; - int lh_errno; - - if (h_errnop == NULL) { - /* ensure h_errnop is never NULL */ - h_errnop = &lh_errno; - } - - if (result == NULL) { - /* not all arguments given */ - *h_errnop = EINVAL; - return -1; - } - /* first thing to do: set *result to nothing */ - *result = NULL; - if ((name == NULL) || (ret == NULL) || (buf == NULL)) { - /* not all arguments given */ - *h_errnop = EINVAL; - return -1; - } - - namelen = strlen(name); - if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) { - /* buf can't hold the data needed + a copy of name */ - *h_errnop = ERANGE; - return -1; - } - - h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf); - hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper); - - /* query host IP address */ - err = netconn_gethostbyname(name, &h->addr); - if (err != ERR_OK) { - LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); - *h_errnop = HOST_NOT_FOUND; - return -1; - } - - /* copy the hostname into buf */ - MEMCPY(hostname, name, namelen); - hostname[namelen] = 0; - - /* fill hostent */ - h->addr_list[0] = &h->addr; - h->addr_list[1] = NULL; - h->aliases = NULL; - ret->h_name = hostname; - ret->h_aliases = &h->aliases; - ret->h_addrtype = AF_INET; - ret->h_length = sizeof(ip_addr_t); - ret->h_addr_list = (char**)&h->addr_list; - - /* set result != NULL */ - *result = ret; - - /* return success */ - return 0; -} - -/** - * Frees one or more addrinfo structures returned by getaddrinfo(), along with - * any additional storage associated with those structures. If the ai_next field - * of the structure is not null, the entire list of structures is freed. - * - * @param ai struct addrinfo to free - */ -void -lwip_freeaddrinfo(struct addrinfo *ai) -{ - struct addrinfo *next; - - while (ai != NULL) { - next = ai->ai_next; - memp_free(MEMP_NETDB, ai); - ai = next; - } -} - -/** - * Translates the name of a service location (for example, a host name) and/or - * a service name and returns a set of socket addresses and associated - * information to be used in creating a socket with which to address the - * specified service. - * Memory for the result is allocated internally and must be freed by calling - * lwip_freeaddrinfo()! - * - * Due to a limitation in dns_gethostbyname, only the first address of a - * host is returned. - * Also, service names are not supported (only port numbers)! - * - * @param nodename descriptive name or address string of the host - * (may be NULL -> local address) - * @param servname port number as string of NULL - * @param hints structure containing input values that set socktype and protocol - * @param res pointer to a pointer where to store the result (set to NULL on failure) - * @return 0 on success, non-zero on failure - * - * @todo: implement AI_V4MAPPED, AI_ADDRCONFIG - */ -int -lwip_getaddrinfo(const char *nodename, const char *servname, - const struct addrinfo *hints, struct addrinfo **res) -{ - err_t err; - ip_addr_t addr; - struct addrinfo *ai; - struct sockaddr_storage *sa = NULL; - int port_nr = 0; - size_t total_size; - size_t namelen = 0; - int ai_family; - - if (res == NULL) { - return EAI_FAIL; - } - *res = NULL; - if ((nodename == NULL) && (servname == NULL)) { - return EAI_NONAME; - } - - if (hints != NULL) { - ai_family = hints->ai_family; - if ((ai_family != AF_UNSPEC) -#if LWIP_IPV4 - && (ai_family != AF_INET) -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 - && (ai_family != AF_INET6) -#endif /* LWIP_IPV6 */ - ) { - return EAI_FAMILY; - } - } else { - ai_family = AF_UNSPEC; - } - - if (servname != NULL) { - /* service name specified: convert to port number - * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */ - port_nr = atoi(servname); - if ((port_nr <= 0) || (port_nr > 0xffff)) { - return EAI_SERVICE; - } - } - - if (nodename != NULL) { - /* service location specified, try to resolve */ - if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) { - /* no DNS lookup, just parse for an address string */ - if (!ipaddr_aton(nodename, &addr)) { - return EAI_NONAME; - } -#if LWIP_IPV4 && LWIP_IPV6 - if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) || - (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) { - return EAI_NONAME; - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - } else { -#if LWIP_IPV4 && LWIP_IPV6 - /* AF_UNSPEC: prefer IPv4 */ - u8_t type = NETCONN_DNS_IPV4_IPV6; - if (ai_family == AF_INET) { - type = NETCONN_DNS_IPV4; - } else if (ai_family == AF_INET6) { - type = NETCONN_DNS_IPV6; - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - err = netconn_gethostbyname_addrtype(nodename, &addr, type); - if (err != ERR_OK) { - return EAI_FAIL; - } - } - } else { - /* service location specified, use loopback address */ - if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) { - ip_addr_set_any(ai_family == AF_INET6, &addr); - } else { - ip_addr_set_loopback(ai_family == AF_INET6, &addr); - } - } - - total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage); - if (nodename != NULL) { - namelen = strlen(nodename); - if (namelen > DNS_MAX_NAME_LENGTH) { - /* invalid name length */ - return EAI_FAIL; - } - LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size); - total_size += namelen + 1; - } - /* If this fails, please report to lwip-devel! :-) */ - LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", - total_size <= NETDB_ELEM_SIZE); - ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); - if (ai == NULL) { - return EAI_MEMORY; - } - memset(ai, 0, total_size); - /* cast through void* to get rid of alignment warnings */ - sa = (struct sockaddr_storage *)(void*)((u8_t*)ai + sizeof(struct addrinfo)); - if (IP_IS_V6_VAL(addr)) { -#if LWIP_IPV6 - struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)sa; - /* set up sockaddr */ - inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr)); - sa6->sin6_family = AF_INET6; - sa6->sin6_len = sizeof(struct sockaddr_in6); - sa6->sin6_port = htons((u16_t)port_nr); - ai->ai_family = AF_INET6; -#endif /* LWIP_IPV6 */ - } else { -#if LWIP_IPV4 - struct sockaddr_in *sa4 = (struct sockaddr_in*)sa; - /* set up sockaddr */ - inet_addr_from_ipaddr(&sa4->sin_addr, ip_2_ip4(&addr)); - sa4->sin_family = AF_INET; - sa4->sin_len = sizeof(struct sockaddr_in); - sa4->sin_port = htons((u16_t)port_nr); - ai->ai_family = AF_INET; -#endif /* LWIP_IPV4 */ - } - - /* set up addrinfo */ - if (hints != NULL) { - /* copy socktype & protocol from hints if specified */ - ai->ai_socktype = hints->ai_socktype; - ai->ai_protocol = hints->ai_protocol; - } - if (nodename != NULL) { - /* copy nodename to canonname if specified */ - ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); - MEMCPY(ai->ai_canonname, nodename, namelen); - ai->ai_canonname[namelen] = 0; - } - ai->ai_addrlen = sizeof(struct sockaddr_storage); - ai->ai_addr = (struct sockaddr*)sa; - - *res = ai; - - return 0; -} - -#endif /* LWIP_DNS && LWIP_SOCKET */ diff --git a/ext/lwip/src/api/netifapi.c b/ext/lwip/src/api/netifapi.c deleted file mode 100644 index 3a02d52..0000000 --- a/ext/lwip/src/api/netifapi.c +++ /dev/null @@ -1,224 +0,0 @@ -/** - * @file - * Network Interface Sequential API module - * - */ - -/* - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - */ - -/** - * @defgroup netifapi NETIF API - * @ingroup threadsafe_api - * Thread-safe functions to be called from non-TCPIP threads - * - * @defgroup netifapi_netif NETIF related - * @ingroup netifapi - * To be called from non-TCPIP threads - */ - -#include "lwip/opt.h" - -#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/netifapi.h" -#include "lwip/memp.h" -#include "lwip/priv/tcpip_priv.h" - -#define NETIFAPI_VAR_REF(name) API_VAR_REF(name) -#define NETIFAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct netifapi_msg, name) -#define NETIFAPI_VAR_ALLOC(name) API_VAR_ALLOC(struct netifapi_msg, MEMP_NETIFAPI_MSG, name, ERR_MEM) -#define NETIFAPI_VAR_FREE(name) API_VAR_FREE(MEMP_NETIFAPI_MSG, name) - -/** - * Call netif_add() inside the tcpip_thread context. - */ -static err_t -netifapi_do_netif_add(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct netifapi_msg */ - struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m; - - if (!netif_add( msg->netif, -#if LWIP_IPV4 - API_EXPR_REF(msg->msg.add.ipaddr), - API_EXPR_REF(msg->msg.add.netmask), - API_EXPR_REF(msg->msg.add.gw), -#endif /* LWIP_IPV4 */ - msg->msg.add.state, - msg->msg.add.init, - msg->msg.add.input)) { - return ERR_IF; - } else { - return ERR_OK; - } -} - -#if LWIP_IPV4 -/** - * Call netif_set_addr() inside the tcpip_thread context. - */ -static err_t -netifapi_do_netif_set_addr(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct netifapi_msg */ - struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m; - - netif_set_addr( msg->netif, - API_EXPR_REF(msg->msg.add.ipaddr), - API_EXPR_REF(msg->msg.add.netmask), - API_EXPR_REF(msg->msg.add.gw)); - return ERR_OK; -} -#endif /* LWIP_IPV4 */ - -/** - * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the - * tcpip_thread context. - */ -static err_t -netifapi_do_netif_common(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct netifapi_msg */ - struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m; - - if (msg->msg.common.errtfunc != NULL) { - return msg->msg.common.errtfunc(msg->netif); - } else { - msg->msg.common.voidfunc(msg->netif); - return ERR_OK; - } -} - -/** - * @ingroup netifapi_netif - * Call netif_add() in a thread-safe way by running that function inside the - * tcpip_thread context. - * - * @note for params @see netif_add() - */ -err_t -netifapi_netif_add(struct netif *netif, -#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) -{ - err_t err; - NETIFAPI_VAR_DECLARE(msg); - NETIFAPI_VAR_ALLOC(msg); - -#if LWIP_IPV4 - if (ipaddr == NULL) { - ipaddr = IP4_ADDR_ANY; - } - if (netmask == NULL) { - netmask = IP4_ADDR_ANY; - } - if (gw == NULL) { - gw = IP4_ADDR_ANY; - } -#endif /* LWIP_IPV4 */ - - NETIFAPI_VAR_REF(msg).netif = netif; -#if LWIP_IPV4 - NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr); - NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask); - NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw); -#endif /* LWIP_IPV4 */ - NETIFAPI_VAR_REF(msg).msg.add.state = state; - NETIFAPI_VAR_REF(msg).msg.add.init = init; - NETIFAPI_VAR_REF(msg).msg.add.input = input; - err = tcpip_api_call(netifapi_do_netif_add, &API_VAR_REF(msg).call); - NETIFAPI_VAR_FREE(msg); - return err; -} - -#if LWIP_IPV4 -/** - * @ingroup netifapi_netif - * Call netif_set_addr() in a thread-safe way by running that function inside the - * tcpip_thread context. - * - * @note for params @see netif_set_addr() - */ -err_t -netifapi_netif_set_addr(struct netif *netif, - const ip4_addr_t *ipaddr, - const ip4_addr_t *netmask, - const ip4_addr_t *gw) -{ - err_t err; - NETIFAPI_VAR_DECLARE(msg); - NETIFAPI_VAR_ALLOC(msg); - - if (ipaddr == NULL) { - ipaddr = IP4_ADDR_ANY; - } - if (netmask == NULL) { - netmask = IP4_ADDR_ANY; - } - if (gw == NULL) { - gw = IP4_ADDR_ANY; - } - - NETIFAPI_VAR_REF(msg).netif = netif; - NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr); - NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask); - NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw); - err = tcpip_api_call(netifapi_do_netif_set_addr, &API_VAR_REF(msg).call); - NETIFAPI_VAR_FREE(msg); - return err; -} -#endif /* LWIP_IPV4 */ - -/** - * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe - * way by running that function inside the tcpip_thread context. - * - * @note use only for functions where there is only "netif" parameter. - */ -err_t -netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, - netifapi_errt_fn errtfunc) -{ - err_t err; - NETIFAPI_VAR_DECLARE(msg); - NETIFAPI_VAR_ALLOC(msg); - - NETIFAPI_VAR_REF(msg).netif = netif; - NETIFAPI_VAR_REF(msg).msg.common.voidfunc = voidfunc; - NETIFAPI_VAR_REF(msg).msg.common.errtfunc = errtfunc; - err = tcpip_api_call(netifapi_do_netif_common, &API_VAR_REF(msg).call); - NETIFAPI_VAR_FREE(msg); - return err; -} - -#endif /* LWIP_NETIF_API */ diff --git a/ext/lwip/src/api/sockets.c b/ext/lwip/src/api/sockets.c deleted file mode 100644 index 6547182..0000000 --- a/ext/lwip/src/api/sockets.c +++ /dev/null @@ -1,2803 +0,0 @@ -/** - * @file - * Sockets BSD-Like API module - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - * Improved by Marc Boucher and David Haas - * - */ - -/** - * @defgroup socket Socket API - * @ingroup threadsafe_api - * BSD-style socket API.\n - * Thread-safe, to be called from non-TCPIP threads only.\n - * Can be activated by defining LWIP_SOCKET to 1.\n - * Header is in posix/sys/socket.h\b - */ - -#include "lwip/opt.h" - -#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/sockets.h" -#include "lwip/api.h" -#include "lwip/sys.h" -#include "lwip/igmp.h" -#include "lwip/inet.h" -#include "lwip/tcp.h" -#include "lwip/raw.h" -#include "lwip/udp.h" -#include "lwip/memp.h" -#include "lwip/pbuf.h" -#include "lwip/priv/tcpip_priv.h" -#if LWIP_CHECKSUM_ON_COPY -#include "lwip/inet_chksum.h" -#endif - -#include - -/* If the netconn API is not required publicly, then we include the necessary - files here to get the implementation */ -#if !LWIP_NETCONN -#undef LWIP_NETCONN -#define LWIP_NETCONN 1 -#include "api_msg.c" -#include "api_lib.c" -#include "netbuf.c" -#undef LWIP_NETCONN -#define LWIP_NETCONN 0 -#endif - -#if LWIP_IPV4 -#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ - (sin)->sin_len = sizeof(struct sockaddr_in); \ - (sin)->sin_family = AF_INET; \ - (sin)->sin_port = htons((port)); \ - inet_addr_from_ipaddr(&(sin)->sin_addr, ipaddr); \ - memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) -#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ - inet_addr_to_ipaddr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ - (port) = ntohs((sin)->sin_port); }while(0) -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ - (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ - (sin6)->sin6_family = AF_INET6; \ - (sin6)->sin6_port = htons((port)); \ - (sin6)->sin6_flowinfo = 0; \ - inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ - (sin6)->sin6_scope_id = 0; }while(0) -#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \ - inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \ - (port) = ntohs((sin6)->sin6_port); }while(0) -#endif /* LWIP_IPV6 */ - -#if LWIP_IPV4 && LWIP_IPV6 -static void sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port); - -#define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ - ((namelen) == sizeof(struct sockaddr_in6))) -#define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \ - ((name)->sa_family == AF_INET6)) -#define SOCK_ADDR_TYPE_MATCH(name, sock) \ - ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ - (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) -#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \ - if (IP_IS_V6(ipaddr)) { \ - IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \ - } else { \ - IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \ - } } while(0) -#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port)) -#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ - (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) -#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ -#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6)) -#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6) -#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 -#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ - IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port) -#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ - SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port) -#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) -#else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */ -#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) -#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) -#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 -#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ - IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port) -#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ - SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port) -#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) -#endif /* LWIP_IPV6 */ - -#define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \ - IS_SOCK_ADDR_TYPE_VALID(name)) -#define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ - SOCK_ADDR_TYPE_MATCH(name, sock)) -#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) - - -#define LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype) do { if ((optlen) < sizeof(opttype)) { return EINVAL; }}while(0) -#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \ - LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \ - if ((sock)->conn == NULL) { return EINVAL; } }while(0) -#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \ - LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \ - if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { return EINVAL; } }while(0) -#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \ - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \ - if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { return ENOPROTOOPT; } }while(0) - - -#define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name) -#define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name) -#define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name) -#if LWIP_MPU_COMPATIBLE -#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ - name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ - if (name == NULL) { \ - sock_set_errno(sock, ENOMEM); \ - return -1; \ - } }while(0) -#else /* LWIP_MPU_COMPATIBLE */ -#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) -#endif /* LWIP_MPU_COMPATIBLE */ - -#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD -#define LWIP_SO_SNDRCVTIMEO_OPTTYPE int -#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val)) -#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((s32_t)*(const int*)(optval)) -#else -#define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval -#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \ - s32_t loc = (val); \ - ((struct timeval *)(optval))->tv_sec = (loc) / 1000U; \ - ((struct timeval *)(optval))->tv_usec = ((loc) % 1000U) * 1000U; }while(0) -#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U)) -#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 - -/** Contains all internal pointers and states used for a socket */ -struct lwip_sock { - /** sockets currently are built on netconns, each socket has one netconn */ - struct netconn *conn; - /** data that was left from the previous read */ - void *lastdata; - /** offset in the data that was left from the previous read */ - u16_t lastoffset; - /** number of times data was received, set by event_callback(), - tested by the receive and select functions */ - s16_t rcvevent; - /** number of times data was ACKed (free send buffer), set by event_callback(), - tested by select */ - u16_t sendevent; - /** error happened for this socket, set by event_callback(), tested by select */ - u16_t errevent; - /** last error that occurred on this socket (in fact, all our errnos fit into an u8_t) */ - u8_t err; - /** counter of how many threads are waiting for this socket using select */ - SELWAIT_T select_waiting; -}; - -#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; - /** readset passed to select */ - fd_set *readset; - /** writeset passed to select */ - fd_set *writeset; - /** unimplemented: exceptset passed to select */ - fd_set *exceptset; - /** don't signal the same semaphore twice: set to 1 when signalled */ - int sem_signalled; - /** semaphore to wake up a task waiting for select */ - SELECT_SEM_T sem; -}; - -/** A struct sockaddr replacement that has the same alignment as sockaddr_in/ - * sockaddr_in6 if instantiated. - */ -union sockaddr_aligned { - struct sockaddr sa; -#if LWIP_IPV6 - struct sockaddr_in6 sin6; -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 - struct sockaddr_in sin; -#endif /* LWIP_IPV4 */ -}; - -#if LWIP_IGMP -/* Define the number of IPv4 multicast memberships, default is one per socket */ -#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS -#define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS -#endif - -/* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when - a socket is closed */ -struct lwip_socket_multicast_pair { - /** the socket (+1 to not require initialization) */ - int sa; - /** the interface address */ - ip4_addr_t if_addr; - /** the group address */ - ip4_addr_t multi_addr; -}; - -struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; - -static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); -static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); -static void lwip_socket_drop_registered_memberships(int s); -#endif /* LWIP_IGMP */ - -/** The global array of available sockets */ -static struct lwip_sock sockets[NUM_SOCKETS]; -/** The global list of tasks waiting for select */ -static struct lwip_select_cb *select_cb_list; -/** This counter is increased from lwip_select when the list is changed - and checked in event_callback to see if it has changed. */ -static volatile int select_cb_ctr; - -/** Table to quickly map an lwIP error (err_t) to a socket error - * by using -err as an index */ -static const int err_to_errno_table[] = { - 0, /* ERR_OK 0 No error, everything OK. */ - ENOMEM, /* ERR_MEM -1 Out of memory error. */ - ENOBUFS, /* ERR_BUF -2 Buffer error. */ - EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ - EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ - EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ - EINVAL, /* ERR_VAL -6 Illegal value. */ - EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ - EADDRINUSE, /* ERR_USE -8 Address in use. */ - EALREADY, /* ERR_ALREADY -9 Already connecting. */ - EISCONN, /* ERR_ISCONN -10 Conn already established.*/ - ENOTCONN, /* ERR_CONN -11 Not connected. */ - -1, /* ERR_IF -12 Low-level netif error */ - ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */ - ECONNRESET, /* ERR_RST -14 Connection reset. */ - ENOTCONN, /* ERR_CLSD -15 Connection closed. */ - EIO /* ERR_ARG -16 Illegal argument. */ -}; - -#define ERR_TO_ERRNO_TABLE_SIZE LWIP_ARRAYSIZE(err_to_errno_table) - -#define err_to_errno(err) \ - ((unsigned)(-(signed)(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ - err_to_errno_table[-(signed)(err)] : EIO) - -#if LWIP_SOCKET_SET_ERRNO -#ifndef set_errno -#define set_errno(err) do { if (err) { errno = (err); } } while(0) -#endif -#else /* LWIP_SOCKET_SET_ERRNO */ -#define set_errno(err) -#endif /* LWIP_SOCKET_SET_ERRNO */ - -#define sock_set_errno(sk, e) do { \ - const int sockerr = (e); \ - sk->err = (u8_t)sockerr; \ - set_errno(sockerr); \ -} while (0) - -/* Forward declaration of some functions */ -static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); -#if !LWIP_TCPIP_CORE_LOCKING -static void lwip_getsockopt_callback(void *arg); -static void lwip_setsockopt_callback(void *arg); -#endif -static u8_t lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen); -static u8_t lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen); - -#if LWIP_IPV4 && LWIP_IPV6 -static void -sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port) -{ - if ((sockaddr->sa_family) == AF_INET6) { - SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, *port); - ipaddr->type = IPADDR_TYPE_V6; - } else { - SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, *port); - ipaddr->type = IPADDR_TYPE_V4; - } -} -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - -/** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ -void -lwip_socket_thread_init(void) -{ - netconn_thread_init(); -} - -/** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ -void -lwip_socket_thread_cleanup(void) -{ - netconn_thread_cleanup(); -} - -/** - * Map a externally used socket index to the internal socket representation. - * - * @param s externally used socket index - * @return struct lwip_sock for the socket or NULL if not found - */ -static struct lwip_sock * -get_socket(int s) -{ - struct lwip_sock *sock; - - s -= LWIP_SOCKET_OFFSET; - - if ((s < 0) || (s >= NUM_SOCKETS)) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s + LWIP_SOCKET_OFFSET)); - set_errno(EBADF); - return NULL; - } - - sock = &sockets[s]; - - if (!sock->conn) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s + LWIP_SOCKET_OFFSET)); - set_errno(EBADF); - return NULL; - } - - return sock; -} - -/** - * Same as get_socket but doesn't set errno - * - * @param s externally used socket index - * @return struct lwip_sock for the socket or NULL if not found - */ -static struct lwip_sock * -tryget_socket(int s) -{ - s -= LWIP_SOCKET_OFFSET; - if ((s < 0) || (s >= NUM_SOCKETS)) { - return NULL; - } - if (!sockets[s].conn) { - return NULL; - } - return &sockets[s]; -} - -/** - * Allocate a new socket for a given netconn. - * - * @param newconn the netconn for which to allocate a socket - * @param accepted 1 if socket has been created by accept(), - * 0 if socket has been created by socket() - * @return the index of the new socket; -1 on error - */ -static int -alloc_socket(struct netconn *newconn, int accepted) -{ - int i; - SYS_ARCH_DECL_PROTECT(lev); - - /* allocate a new socket identifier */ - for (i = 0; i < NUM_SOCKETS; ++i) { - /* Protect socket array */ - SYS_ARCH_PROTECT(lev); - if (!sockets[i].conn) { - sockets[i].conn = newconn; - /* The socket is not yet known to anyone, so no need to protect - after having marked it as used. */ - SYS_ARCH_UNPROTECT(lev); - sockets[i].lastdata = NULL; - sockets[i].lastoffset = 0; - sockets[i].rcvevent = 0; - /* TCP sendbuf is empty, but the socket is not yet writable until connected - * (unless it has been created by accept()). */ - sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); - sockets[i].errevent = 0; - sockets[i].err = 0; - sockets[i].select_waiting = 0; - return i + LWIP_SOCKET_OFFSET; - } - SYS_ARCH_UNPROTECT(lev); - } - return -1; -} - -/** Free a socket. The socket's netconn must have been - * delete before! - * - * @param sock the socket to free - * @param is_tcp != 0 for TCP sockets, used to free lastdata - */ -static void -free_socket(struct lwip_sock *sock, int is_tcp) -{ - void *lastdata; - - lastdata = sock->lastdata; - sock->lastdata = NULL; - sock->lastoffset = 0; - sock->err = 0; - - /* Protect socket array */ - SYS_ARCH_SET(sock->conn, NULL); - /* don't use 'sock' after this line, as another task might have allocated it */ - - if (lastdata != NULL) { - if (is_tcp) { - pbuf_free((struct pbuf *)lastdata); - } else { - netbuf_delete((struct netbuf *)lastdata); - } - } -} - -/* Below this, the well-known socket functions are implemented. - * Use google.com or opengroup.org to get a good description :-) - * - * Exceptions are documented! - */ - -int -lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) -{ - struct lwip_sock *sock, *nsock; - struct netconn *newconn; - ip_addr_t naddr; - u16_t port = 0; - int newsock; - err_t err; - SYS_ARCH_DECL_PROTECT(lev); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); - sock_set_errno(sock, EWOULDBLOCK); - return -1; - } - - /* wait for a new connection */ - err = netconn_accept(sock->conn, &newconn); - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { - sock_set_errno(sock, EOPNOTSUPP); - } else if (err == ERR_CLSD) { - sock_set_errno(sock, EINVAL); - } else { - sock_set_errno(sock, err_to_errno(err)); - } - return -1; - } - LWIP_ASSERT("newconn != NULL", newconn != NULL); - - newsock = alloc_socket(newconn, 1); - if (newsock == -1) { - netconn_delete(newconn); - sock_set_errno(sock, ENFILE); - return -1; - } - LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); - LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback); - nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; - - /* See event_callback: If data comes in right away after an accept, even - * though the server task might not have created a new socket yet. - * In that case, newconn->socket is counted down (newconn->socket--), - * so nsock->rcvevent is >= 1 here! - */ - SYS_ARCH_PROTECT(lev); - nsock->rcvevent += (s16_t)(-1 - newconn->socket); - newconn->socket = newsock; - SYS_ARCH_UNPROTECT(lev); - - /* Note that POSIX only requires us to check addr is non-NULL. addrlen must - * not be NULL if addr is valid. - */ - if (addr != NULL) { - union sockaddr_aligned tempaddr; - /* get the IP address and port of the remote host */ - err = netconn_peer(newconn, &naddr, &port); - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); - netconn_delete(newconn); - free_socket(nsock, 1); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); - - IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); - if (*addrlen > tempaddr.sa.sa_len) { - *addrlen = tempaddr.sa.sa_len; - } - MEMCPY(addr, &tempaddr, *addrlen); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); - ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); - } else { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); - } - - sock_set_errno(sock, 0); - return newsock; -} - -int -lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) -{ - struct lwip_sock *sock; - ip_addr_t local_addr; - u16_t local_port; - err_t err; - - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { - /* sockaddr does not match socket type (IPv4/IPv6) */ - sock_set_errno(sock, err_to_errno(ERR_VAL)); - return -1; - } - - /* check size, family and alignment of 'name' */ - LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && - IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), - sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - LWIP_UNUSED_ARG(namelen); - - SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); - ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); - - err = netconn_bind(sock->conn, &local_addr, local_port); - - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); - sock_set_errno(sock, 0); - return 0; -} - -int -lwip_close(int s) -{ - struct lwip_sock *sock; - int is_tcp = 0; - err_t err; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); - - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (sock->conn != NULL) { - is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; - } else { - LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); - } - -#if LWIP_IGMP - /* drop all possibly joined IGMP memberships */ - lwip_socket_drop_registered_memberships(s); -#endif /* LWIP_IGMP */ - - err = netconn_delete(sock->conn); - if (err != ERR_OK) { - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - - free_socket(sock, is_tcp); - set_errno(0); - return 0; -} - -int -lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) -{ - struct lwip_sock *sock; - err_t err; - - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { - /* sockaddr does not match socket type (IPv4/IPv6) */ - sock_set_errno(sock, err_to_errno(ERR_VAL)); - return -1; - } - - LWIP_UNUSED_ARG(namelen); - if (name->sa_family == AF_UNSPEC) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); - err = netconn_disconnect(sock->conn); - } else { - ip_addr_t remote_addr; - u16_t remote_port; - - /* check size, family and alignment of 'name' */ - LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && - IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), - sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - - SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); - ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); - - err = netconn_connect(sock->conn, &remote_addr, remote_port); - } - - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); - sock_set_errno(sock, 0); - return 0; -} - -/** - * Set a socket into listen mode. - * The socket may not have been used for another connection previously. - * - * @param s the socket to set to listening mode - * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) - * @return 0 on success, non-zero on failure - */ -int -lwip_listen(int s, int backlog) -{ - struct lwip_sock *sock; - err_t err; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); - - sock = get_socket(s); - if (!sock) { - return -1; - } - - /* limit the "backlog" parameter to fit in an u8_t */ - backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); - - err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); - - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { - sock_set_errno(sock, EOPNOTSUPP); - return -1; - } - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - - sock_set_errno(sock, 0); - return 0; -} - -int -lwip_recvfrom(int s, void *mem, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen) -{ - struct lwip_sock *sock; - void *buf = NULL; - struct pbuf *p; - u16_t buflen, copylen; - int off = 0; - u8_t done = 0; - err_t err; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); - sock = get_socket(s); - if (!sock) { - return -1; - } - - do { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata)); - /* Check if there is data left from the last recv operation. */ - if (sock->lastdata) { - buf = sock->lastdata; - } else { - /* If this is non-blocking call, then check first */ - if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && - (sock->rcvevent <= 0)) { - if (off > 0) { - /* already received data, return that */ - sock_set_errno(sock, 0); - return off; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); - sock_set_errno(sock, EWOULDBLOCK); - return -1; - } - - /* No data was left from the previous operation, so we try to get - some from the network. */ - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { - err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); - } else { - err = netconn_recv(sock->conn, (struct netbuf **)&buf); - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n", - err, buf)); - - if (err != ERR_OK) { - if (off > 0) { - if (err == ERR_CLSD) { - /* closed but already received data, ensure select gets the FIN, too */ - event_callback(sock->conn, NETCONN_EVT_RCVPLUS, 0); - } - /* already received data, return that */ - sock_set_errno(sock, 0); - return off; - } - /* We should really do some error checking here. */ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n", - s, lwip_strerr(err))); - sock_set_errno(sock, err_to_errno(err)); - if (err == ERR_CLSD) { - return 0; - } else { - return -1; - } - } - LWIP_ASSERT("buf != NULL", buf != NULL); - sock->lastdata = buf; - } - - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { - p = (struct pbuf *)buf; - } else { - p = ((struct netbuf *)buf)->p; - } - buflen = p->tot_len; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n", - buflen, len, off, sock->lastoffset)); - - buflen -= sock->lastoffset; - - if (len > buflen) { - copylen = buflen; - } else { - copylen = (u16_t)len; - } - - /* copy the contents of the received buffer into - the supplied memory pointer mem */ - pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset); - - off += copylen; - - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { - LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); - len -= copylen; - if ((len <= 0) || - (p->flags & PBUF_FLAG_PUSH) || - (sock->rcvevent <= 0) || - ((flags & MSG_PEEK) != 0)) { - done = 1; - } - } else { - done = 1; - } - - /* Check to see from where the data was.*/ - if (done) { -#if !SOCKETS_DEBUG - if (from && fromlen) -#endif /* !SOCKETS_DEBUG */ - { - u16_t port; - ip_addr_t tmpaddr; - ip_addr_t *fromaddr; - union sockaddr_aligned saddr; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { - fromaddr = &tmpaddr; - netconn_getaddr(sock->conn, fromaddr, &port, 0); - } else { - port = netbuf_fromport((struct netbuf *)buf); - fromaddr = netbuf_fromaddr((struct netbuf *)buf); - } - IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); - ip_addr_debug_print(SOCKETS_DEBUG, fromaddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); -#if SOCKETS_DEBUG - if (from && fromlen) -#endif /* SOCKETS_DEBUG */ - { - if (*fromlen > saddr.sa.sa_len) { - *fromlen = saddr.sa.sa_len; - } - MEMCPY(from, &saddr, *fromlen); - } - } - } - - /* If we don't peek the incoming message... */ - if ((flags & MSG_PEEK) == 0) { - /* If this is a TCP socket, check if there is data left in the - buffer. If so, it should be saved in the sock structure for next - time around. */ - if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) { - sock->lastdata = buf; - sock->lastoffset += copylen; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); - } else { - sock->lastdata = NULL; - sock->lastoffset = 0; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { - pbuf_free((struct pbuf *)buf); - } else { - netbuf_delete((struct netbuf *)buf); - } - buf = NULL; - } - } - } while (!done); - - sock_set_errno(sock, 0); - return off; -} - -int -lwip_read(int s, void *mem, size_t len) -{ - return lwip_recvfrom(s, mem, len, 0, NULL, NULL); -} - -int -lwip_recv(int s, void *mem, size_t len, int flags) -{ - return lwip_recvfrom(s, mem, len, flags, NULL, NULL); -} - -int -lwip_send(int s, const void *data, size_t size, int flags) -{ - struct lwip_sock *sock; - err_t err; - u8_t write_flags; - size_t written; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", - s, data, size, flags)); - - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { -#if (LWIP_UDP || LWIP_RAW) - return lwip_sendto(s, data, size, flags, NULL, 0); -#else /* (LWIP_UDP || LWIP_RAW) */ - sock_set_errno(sock, err_to_errno(ERR_ARG)); - return -1; -#endif /* (LWIP_UDP || LWIP_RAW) */ - } - - write_flags = NETCONN_COPY | - ((flags & MSG_MORE) ? NETCONN_MORE : 0) | - ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); - written = 0; - err = netconn_write_partly(sock->conn, data, size, write_flags, &written); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); - sock_set_errno(sock, err_to_errno(err)); - return (err == ERR_OK ? (int)written : -1); -} - -int -lwip_sendmsg(int s, const struct msghdr *msg, int flags) -{ - struct lwip_sock *sock; - struct netbuf *chain_buf; - u16_t remote_port; - int i; -#if LWIP_TCP - u8_t write_flags; - size_t written; -#endif - int size = 0; - err_t err = ERR_OK; - - sock = get_socket(s); - if (!sock) { - return -1; - } - - LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL, - sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - - LWIP_UNUSED_ARG(msg->msg_control); - LWIP_UNUSED_ARG(msg->msg_controllen); - LWIP_UNUSED_ARG(msg->msg_flags); - LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", (msg->msg_iov != NULL && msg->msg_iovlen != 0), - sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { -#if LWIP_TCP - write_flags = NETCONN_COPY | - ((flags & MSG_MORE) ? NETCONN_MORE : 0) | - ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); - - for (i = 0; i < msg->msg_iovlen; i++) { - written = 0; - err = netconn_write_partly(sock->conn, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len, write_flags, &written); - if (err == ERR_OK) { - size += written; - /* check that the entire IO vector was accepected, if not return a partial write */ - if (written != msg->msg_iov[i].iov_len) - break; - } - /* none of this IO vector was accepted, but previous was, return partial write and conceal ERR_WOULDBLOCK */ - else if (err == ERR_WOULDBLOCK && size > 0) { - err = ERR_OK; - /* let ERR_WOULDBLOCK persist on the netconn since we are returning ERR_OK */ - break; - } else { - size = -1; - break; - } - } - sock_set_errno(sock, err_to_errno(err)); - return size; -#else /* LWIP_TCP */ - sock_set_errno(sock, err_to_errno(ERR_ARG)); - return -1; -#endif /* LWIP_TCP */ - } - /* else, UDP and RAW NETCONNs */ -#if LWIP_UDP || LWIP_RAW - - LWIP_UNUSED_ARG(flags); - LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || - IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)) , - sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - - /* initialize chain buffer with destination */ - chain_buf = netbuf_new(); - if (!chain_buf) { - sock_set_errno(sock, err_to_errno(ERR_MEM)); - return -1; - } - if (msg->msg_name) { - SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port); - netbuf_fromport(chain_buf) = remote_port; - } -#if LWIP_NETIF_TX_SINGLE_PBUF - for (i = 0; i < msg->msg_iovlen; i++) { - size += msg->msg_iov[i].iov_len; - } - /* Allocate a new netbuf and copy the data into it. */ - if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) { - err = ERR_MEM; - } - else { - /* flatten the IO vectors */ - size_t offset = 0; - for (i = 0; i < msg->msg_iovlen; i++) { - MEMCPY(&((u8_t*)chain_buf->p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); - offset += msg->msg_iov[i].iov_len; - } -#if LWIP_CHECKSUM_ON_COPY - { - /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */ - u16_t chksum = ~inet_chksum_pbuf(chain_buf->p); - netbuf_set_chksum(chain_buf, chksum); - } -#endif /* LWIP_CHECKSUM_ON_COPY */ - err = ERR_OK; - } -#else /* LWIP_NETIF_TX_SINGLE_PBUF */ - /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain - manually to avoid having to allocate, chain, and delete a netbuf for each iov */ - for (i = 0; i < msg->msg_iovlen; i++) { - struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); - if (p == NULL) { - err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ - break; - } - p->payload = msg->msg_iov[i].iov_base; - LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF); - p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; - /* netbuf empty, add new pbuf */ - if (chain_buf->p == NULL) { - chain_buf->p = chain_buf->ptr = p; - /* add pbuf to existing pbuf chain */ - } else { - pbuf_cat(chain_buf->p, p); - } - } - /* save size of total chain */ - if (err == ERR_OK) { - size = netbuf_len(chain_buf); - } -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - - if (err == ERR_OK) { - /* send the data */ - err = netconn_send(sock->conn, chain_buf); - } - - /* deallocated the buffer */ - netbuf_delete(chain_buf); - - sock_set_errno(sock, err_to_errno(err)); - return (err == ERR_OK ? size : -1); -#else /* LWIP_UDP || LWIP_RAW */ - sock_set_errno(sock, err_to_errno(ERR_ARG)); - return -1; -#endif /* LWIP_UDP || LWIP_RAW */ -} - -int -lwip_sendto(int s, const void *data, size_t size, int flags, - const struct sockaddr *to, socklen_t tolen) -{ - struct lwip_sock *sock; - err_t err; - u16_t short_size; - u16_t remote_port; - struct netbuf buf; - - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { -#if LWIP_TCP - return lwip_send(s, data, size, flags); -#else /* LWIP_TCP */ - LWIP_UNUSED_ARG(flags); - sock_set_errno(sock, err_to_errno(ERR_ARG)); - return -1; -#endif /* LWIP_TCP */ - } - - if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) { - /* sockaddr does not match socket type (IPv4/IPv6) */ - sock_set_errno(sock, err_to_errno(ERR_VAL)); - return -1; - } - - /* @todo: split into multiple sendto's? */ - LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); - short_size = (u16_t)size; - LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || - (IS_SOCK_ADDR_LEN_VALID(tolen) && - IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))), - sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - LWIP_UNUSED_ARG(tolen); - - /* initialize a buffer */ - buf.p = buf.ptr = NULL; -#if LWIP_CHECKSUM_ON_COPY - buf.flags = 0; -#endif /* LWIP_CHECKSUM_ON_COPY */ - if (to) { - SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); - } else { - remote_port = 0; - ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); - } - netbuf_fromport(&buf) = remote_port; - - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", - s, data, short_size, flags)); - ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); - - /* make the buffer point to the data that should be sent */ -#if LWIP_NETIF_TX_SINGLE_PBUF - /* Allocate a new netbuf and copy the data into it. */ - if (netbuf_alloc(&buf, short_size) == NULL) { - err = ERR_MEM; - } else { -#if LWIP_CHECKSUM_ON_COPY - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { - u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); - netbuf_set_chksum(&buf, chksum); - } else -#endif /* LWIP_CHECKSUM_ON_COPY */ - { - MEMCPY(buf.p->payload, data, short_size); - } - err = ERR_OK; - } -#else /* LWIP_NETIF_TX_SINGLE_PBUF */ - err = netbuf_ref(&buf, data, short_size); -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - if (err == ERR_OK) { - /* send the data */ - err = netconn_send(sock->conn, &buf); - } - - /* deallocated the buffer */ - netbuf_free(&buf); - - sock_set_errno(sock, err_to_errno(err)); - return (err == ERR_OK ? short_size : -1); -} - -int -lwip_socket(int domain, int type, int protocol) -{ - struct netconn *conn; - int i; - -#if !LWIP_IPV6 - LWIP_UNUSED_ARG(domain); /* @todo: check this */ -#endif /* LWIP_IPV6 */ - - /* create a netconn */ - switch (type) { - case SOCK_RAW: - conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), - (u8_t)protocol, event_callback); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", - domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); - break; - case SOCK_DGRAM: - conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, - ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) , - event_callback); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", - domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); - break; - case SOCK_STREAM: - conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", - domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", - domain, type, protocol)); - set_errno(EINVAL); - return -1; - } - - if (!conn) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); - set_errno(ENOBUFS); - return -1; - } - - i = alloc_socket(conn, 0); - - if (i == -1) { - netconn_delete(conn); - set_errno(ENFILE); - return -1; - } - conn->socket = i; - LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); - set_errno(0); - return i; -} - -int -lwip_write(int s, const void *data, size_t size) -{ - return lwip_send(s, data, size, 0); -} - -int -lwip_writev(int s, const struct iovec *iov, int iovcnt) -{ - struct msghdr msg; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - /* Hack: we have to cast via number to cast from 'const' pointer to non-const. - Blame the opengroup standard for this inconsistency. */ - msg.msg_iov = (struct iovec *)(size_t)iov; - msg.msg_iovlen = iovcnt; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - return lwip_sendmsg(s, &msg, 0); -} - -/** - * Go through the readset and writeset lists and see which socket of the sockets - * set in the sets has events. On return, readset, writeset and exceptset have - * the sockets enabled that had events. - * - * @param maxfdp1 the highest socket index in the sets - * @param readset_in: set of sockets to check for read events - * @param writeset_in: set of sockets to check for write events - * @param exceptset_in: set of sockets to check for error events - * @param readset_out: set of sockets that had read events - * @param writeset_out: set of sockets that had write events - * @param exceptset_out: set os sockets that had error events - * @return number of sockets that had events (read/write/exception) (>= 0) - */ -static int -lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, - fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) -{ - int i, nready = 0; - fd_set lreadset, lwriteset, lexceptset; - struct lwip_sock *sock; - SYS_ARCH_DECL_PROTECT(lev); - - FD_ZERO(&lreadset); - FD_ZERO(&lwriteset); - FD_ZERO(&lexceptset); - - /* Go through each socket in each list to count number of sockets which - currently match */ - for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { - /* if this FD is not in the set, continue */ - if (!(readset_in && FD_ISSET(i, readset_in)) && - !(writeset_in && FD_ISSET(i, writeset_in)) && - !(exceptset_in && FD_ISSET(i, exceptset_in))) { - continue; - } - /* First get the socket's status (protected)... */ - SYS_ARCH_PROTECT(lev); - sock = tryget_socket(i); - if (sock != NULL) { - void* lastdata = sock->lastdata; - s16_t rcvevent = sock->rcvevent; - u16_t sendevent = sock->sendevent; - u16_t errevent = sock->errevent; - SYS_ARCH_UNPROTECT(lev); - - /* ... then examine it: */ - /* See if netconn of this socket is ready for read */ - if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { - FD_SET(i, &lreadset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); - nready++; - } - /* See if netconn of this socket is ready for write */ - if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { - FD_SET(i, &lwriteset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); - nready++; - } - /* See if netconn of this socket had an error */ - if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { - FD_SET(i, &lexceptset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); - nready++; - } - } else { - SYS_ARCH_UNPROTECT(lev); - /* continue on to next FD in list */ - } - } - /* copy local sets to the ones provided as arguments */ - *readset_out = lreadset; - *writeset_out = lwriteset; - *exceptset_out = lexceptset; - - LWIP_ASSERT("nready >= 0", nready >= 0); - return nready; -} - -int -lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, - struct timeval *timeout) -{ - u32_t waitres = 0; - int nready; - fd_set lreadset, lwriteset, lexceptset; - u32_t msectimeout; - struct lwip_select_cb select_cb; - int i; - int maxfdp2; -#if LWIP_NETCONN_SEM_PER_THREAD - int waited = 0; -#endif - SYS_ARCH_DECL_PROTECT(lev); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", - maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, - timeout ? (s32_t)timeout->tv_sec : (s32_t)-1, - timeout ? (s32_t)timeout->tv_usec : (s32_t)-1)); - - /* Go through each socket in each list to count number of sockets which - currently match */ - nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); - - /* If we don't have any current events, then suspend if we are supposed to */ - if (!nready) { - if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); - /* This is OK as the local fdsets are empty and nready is zero, - or we would have returned earlier. */ - goto return_copy_fdsets; - } - - /* None ready: add our semaphore to list: - We don't actually need any dynamic memory. Our entry on the - list is only valid while we are in this function, so it's ok - to use local variables. */ - - select_cb.next = NULL; - select_cb.prev = NULL; - select_cb.readset = readset; - select_cb.writeset = writeset; - select_cb.exceptset = exceptset; - select_cb.sem_signalled = 0; -#if LWIP_NETCONN_SEM_PER_THREAD - select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET(); -#else /* LWIP_NETCONN_SEM_PER_THREAD */ - if (sys_sem_new(&select_cb.sem, 0) != ERR_OK) { - /* failed to create semaphore */ - set_errno(ENOMEM); - return -1; - } -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - - /* Protect the select_cb_list */ - SYS_ARCH_PROTECT(lev); - - /* Put this select_cb on top of list */ - select_cb.next = select_cb_list; - if (select_cb_list != NULL) { - select_cb_list->prev = &select_cb; - } - select_cb_list = &select_cb; - /* Increasing this counter tells event_callback that the list has changed. */ - select_cb_ctr++; - - /* Now we can safely unprotect */ - SYS_ARCH_UNPROTECT(lev); - - /* Increase select_waiting for each socket we are interested in */ - maxfdp2 = maxfdp1; - for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { - if ((readset && FD_ISSET(i, readset)) || - (writeset && FD_ISSET(i, writeset)) || - (exceptset && FD_ISSET(i, exceptset))) { - struct lwip_sock *sock; - SYS_ARCH_PROTECT(lev); - sock = tryget_socket(i); - if (sock != NULL) { - sock->select_waiting++; - LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); - } else { - /* Not a valid socket */ - nready = -1; - maxfdp2 = i; - SYS_ARCH_UNPROTECT(lev); - break; - } - SYS_ARCH_UNPROTECT(lev); - } - } - - if (nready >= 0) { - /* Call lwip_selscan again: there could have been events between - the last scan (without us on the list) and putting us on the list! */ - nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); - if (!nready) { - /* Still none ready, just wait to be woken */ - if (timeout == 0) { - /* Wait forever */ - msectimeout = 0; - } else { - msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); - if (msectimeout == 0) { - /* Wait 1ms at least (0 means wait forever) */ - msectimeout = 1; - } - } - - waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout); -#if LWIP_NETCONN_SEM_PER_THREAD - waited = 1; -#endif - } - } - - /* Decrease select_waiting for each socket we are interested in */ - for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) { - if ((readset && FD_ISSET(i, readset)) || - (writeset && FD_ISSET(i, writeset)) || - (exceptset && FD_ISSET(i, exceptset))) { - struct lwip_sock *sock; - SYS_ARCH_PROTECT(lev); - sock = tryget_socket(i); - if (sock != NULL) { - /* @todo: what if this is a new socket (reallocated?) in this case, - select_waiting-- would be wrong (a global 'sockalloc' counter, - stored per socket could help) */ - LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); - if (sock->select_waiting > 0) { - sock->select_waiting--; - } - } else { - /* Not a valid socket */ - nready = -1; - } - SYS_ARCH_UNPROTECT(lev); - } - } - /* Take us off the list */ - SYS_ARCH_PROTECT(lev); - if (select_cb.next != NULL) { - select_cb.next->prev = select_cb.prev; - } - if (select_cb_list == &select_cb) { - LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); - select_cb_list = select_cb.next; - } else { - LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); - select_cb.prev->next = select_cb.next; - } - /* Increasing this counter tells event_callback that the list has changed. */ - select_cb_ctr++; - SYS_ARCH_UNPROTECT(lev); - -#if LWIP_NETCONN_SEM_PER_THREAD - if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { - /* don't leave the thread-local semaphore signalled */ - sys_arch_sem_wait(select_cb.sem, 1); - } -#else /* LWIP_NETCONN_SEM_PER_THREAD */ - sys_sem_free(&select_cb.sem); -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - - if (nready < 0) { - /* This happens when a socket got closed while waiting */ - set_errno(EBADF); - return -1; - } - - if (waitres == SYS_ARCH_TIMEOUT) { - /* Timeout */ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); - /* This is OK as the local fdsets are empty and nready is zero, - or we would have returned earlier. */ - goto return_copy_fdsets; - } - - /* See what's set */ - nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); -return_copy_fdsets: - set_errno(0); - if (readset) { - *readset = lreadset; - } - if (writeset) { - *writeset = lwriteset; - } - if (exceptset) { - *exceptset = lexceptset; - } - return nready; -} - -/** - * Callback registered in the netconn layer for each socket-netconn. - * Processes recvevent (data available) and wakes up tasks waiting for select. - */ -static void -event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) -{ - int s; - struct lwip_sock *sock; - struct lwip_select_cb *scb; - int last_select_cb_ctr; - SYS_ARCH_DECL_PROTECT(lev); - - LWIP_UNUSED_ARG(len); - - /* Get socket */ - if (conn) { - s = conn->socket; - if (s < 0) { - /* Data comes in right away after an accept, even though - * the server task might not have created a new socket yet. - * Just count down (or up) if that's the case and we - * will use the data later. Note that only receive events - * can happen before the new socket is set up. */ - SYS_ARCH_PROTECT(lev); - if (conn->socket < 0) { - if (evt == NETCONN_EVT_RCVPLUS) { - conn->socket--; - } - SYS_ARCH_UNPROTECT(lev); - return; - } - s = conn->socket; - SYS_ARCH_UNPROTECT(lev); - } - - sock = get_socket(s); - if (!sock) { - return; - } - } else { - return; - } - - SYS_ARCH_PROTECT(lev); - /* Set event as required */ - switch (evt) { - case NETCONN_EVT_RCVPLUS: - sock->rcvevent++; - break; - case NETCONN_EVT_RCVMINUS: - sock->rcvevent--; - break; - case NETCONN_EVT_SENDPLUS: - sock->sendevent = 1; - break; - case NETCONN_EVT_SENDMINUS: - sock->sendevent = 0; - break; - case NETCONN_EVT_ERROR: - sock->errevent = 1; - break; - default: - LWIP_ASSERT("unknown event", 0); - break; - } - - if (sock->select_waiting == 0) { - /* noone is waiting for this socket, no need to check select_cb_list */ - SYS_ARCH_UNPROTECT(lev); - return; - } - - /* Now decide if anyone is waiting for this socket */ - /* NOTE: This code goes through the select_cb_list list multiple times - ONLY IF a select was actually waiting. We go through the list the number - of waiting select calls + 1. This list is expected to be small. */ - - /* At this point, SYS_ARCH is still protected! */ -again: - for (scb = select_cb_list; scb != NULL; scb = scb->next) { - /* remember the state of select_cb_list to detect changes */ - last_select_cb_ctr = select_cb_ctr; - if (scb->sem_signalled == 0) { - /* semaphore not signalled yet */ - int do_signal = 0; - /* Test this select call for our socket */ - if (sock->rcvevent > 0) { - if (scb->readset && FD_ISSET(s, scb->readset)) { - do_signal = 1; - } - } - if (sock->sendevent != 0) { - if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { - do_signal = 1; - } - } - if (sock->errevent != 0) { - if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { - do_signal = 1; - } - } - if (do_signal) { - scb->sem_signalled = 1; - /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might - lead to the select thread taking itself off the list, invalidating the semaphore. */ - sys_sem_signal(SELECT_SEM_PTR(scb->sem)); - } - } - /* unlock interrupts with each step */ - SYS_ARCH_UNPROTECT(lev); - /* this makes sure interrupt protection time is short */ - SYS_ARCH_PROTECT(lev); - if (last_select_cb_ctr != select_cb_ctr) { - /* someone has changed select_cb_list, restart at the beginning */ - goto again; - } - } - SYS_ARCH_UNPROTECT(lev); -} - -/** - * Unimplemented: Close one end of a full-duplex connection. - * Currently, the full connection is closed. - */ -int -lwip_shutdown(int s, int how) -{ - struct lwip_sock *sock; - err_t err; - u8_t shut_rx = 0, shut_tx = 0; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); - - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (sock->conn != NULL) { - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { - sock_set_errno(sock, EOPNOTSUPP); - return -1; - } - } else { - sock_set_errno(sock, ENOTCONN); - return -1; - } - - if (how == SHUT_RD) { - shut_rx = 1; - } else if (how == SHUT_WR) { - shut_tx = 1; - } else if (how == SHUT_RDWR) { - shut_rx = 1; - shut_tx = 1; - } else { - sock_set_errno(sock, EINVAL); - return -1; - } - err = netconn_shutdown(sock->conn, shut_rx, shut_tx); - - sock_set_errno(sock, err_to_errno(err)); - return (err == ERR_OK ? 0 : -1); -} - -static int -lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) -{ - struct lwip_sock *sock; - union sockaddr_aligned saddr; - ip_addr_t naddr; - u16_t port; - err_t err; - - sock = get_socket(s); - if (!sock) { - return -1; - } - - /* get the IP address and port */ - /* @todo: this does not work for IPv6, yet */ - err = netconn_getaddr(sock->conn, &naddr, &port, local); - if (err != ERR_OK) { - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); - ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); - - if (*namelen > saddr.sa.sa_len) { - *namelen = saddr.sa.sa_len; - } - MEMCPY(name, &saddr, *namelen); - - sock_set_errno(sock, 0); - return 0; -} - -int -lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) -{ - return lwip_getaddrname(s, name, namelen, 0); -} - -int -lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) -{ - return lwip_getaddrname(s, name, namelen, 1); -} - -int -lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) -{ - u8_t err; - struct lwip_sock *sock = get_socket(s); -#if !LWIP_TCPIP_CORE_LOCKING - LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); -#endif /* !LWIP_TCPIP_CORE_LOCKING */ - - if (!sock) { - return -1; - } - - if ((NULL == optval) || (NULL == optlen)) { - sock_set_errno(sock, EFAULT); - return -1; - } - -#if LWIP_TCPIP_CORE_LOCKING - /* core-locking can just call the -impl function */ - LOCK_TCPIP_CORE(); - err = lwip_getsockopt_impl(s, level, optname, optval, optlen); - UNLOCK_TCPIP_CORE(); - -#else /* LWIP_TCPIP_CORE_LOCKING */ - -#if LWIP_MPU_COMPATIBLE - /* MPU_COMPATIBLE copies the optval data, so check for max size here */ - if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { - sock_set_errno(sock, ENOBUFS); - return -1; - } -#endif /* LWIP_MPU_COMPATIBLE */ - - LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen; -#if !LWIP_MPU_COMPATIBLE - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval; -#endif /* !LWIP_MPU_COMPATIBLE */ - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; -#if LWIP_NETCONN_SEM_PER_THREAD - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); -#else - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; -#endif - err = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); - if (err != ERR_OK) { - LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); - - /* write back optlen and optval */ - *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen; -#if LWIP_MPU_COMPATIBLE - memcpy(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen); -#endif /* LWIP_MPU_COMPATIBLE */ - - /* maybe lwip_getsockopt_internal has changed err */ - err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; - LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); -#endif /* LWIP_TCPIP_CORE_LOCKING */ - - sock_set_errno(sock, err); - return err ? -1 : 0; -} - -#if !LWIP_TCPIP_CORE_LOCKING -/** lwip_getsockopt_callback: only used without CORE_LOCKING - * to get into the tcpip_thread - */ -static void -lwip_getsockopt_callback(void *arg) -{ - struct lwip_setgetsockopt_data *data; - LWIP_ASSERT("arg != NULL", arg != NULL); - data = (struct lwip_setgetsockopt_data*)arg; - - data->err = lwip_getsockopt_impl(data->s, data->level, data->optname, -#if LWIP_MPU_COMPATIBLE - data->optval, -#else /* LWIP_MPU_COMPATIBLE */ - data->optval.p, -#endif /* LWIP_MPU_COMPATIBLE */ - &data->optlen); - - sys_sem_signal((sys_sem_t*)(data->completed_sem)); -} -#endif /* LWIP_TCPIP_CORE_LOCKING */ - -/** lwip_getsockopt_impl: the actual implementation of getsockopt: - * same argument as lwip_getsockopt, either called directly or through callback - */ -static u8_t -lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen) -{ - u8_t err = 0; - struct lwip_sock *sock = tryget_socket(s); - if (!sock) { - return EBADF; - } - - switch (level) { - -/* Level: SOL_SOCKET */ - case SOL_SOCKET: - switch (optname) { - -#if LWIP_TCP - case SO_ACCEPTCONN: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) { - return ENOPROTOOPT; - } - if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) { - *(int*)optval = 1; - } else { - *(int*)optval = 0; - } - break; -#endif /* LWIP_TCP */ - - /* The option flags */ - case SO_BROADCAST: - case SO_KEEPALIVE: -#if SO_REUSE - case SO_REUSEADDR: -#endif /* SO_REUSE */ - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); - *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", - s, optname, (*(int*)optval?"on":"off"))); - break; - - case SO_TYPE: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); - switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { - case NETCONN_RAW: - *(int*)optval = SOCK_RAW; - break; - case NETCONN_TCP: - *(int*)optval = SOCK_STREAM; - break; - case NETCONN_UDP: - *(int*)optval = SOCK_DGRAM; - break; - default: /* unrecognized socket type */ - *(int*)optval = netconn_type(sock->conn); - LWIP_DEBUGF(SOCKETS_DEBUG, - ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", - s, *(int *)optval)); - } /* switch (netconn_type(sock->conn)) */ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", - s, *(int *)optval)); - break; - - case SO_ERROR: - LWIP_SOCKOPT_CHECK_OPTLEN(*optlen, int); - /* only overwrite ERR_OK or temporary errors */ - if (((sock->err == 0) || (sock->err == EINPROGRESS)) && (sock->conn != NULL)) { - sock_set_errno(sock, err_to_errno(sock->conn->last_err)); - } - *(int *)optval = (sock->err == 0xFF ? (int)-1 : (int)sock->err); - sock->err = 0; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", - s, *(int *)optval)); - break; - -#if LWIP_SO_SNDTIMEO - case SO_SNDTIMEO: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); - LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn)); - break; -#endif /* LWIP_SO_SNDTIMEO */ -#if LWIP_SO_RCVTIMEO - case SO_RCVTIMEO: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); - LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn)); - break; -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF - case SO_RCVBUF: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); - *(int *)optval = netconn_get_recvbufsize(sock->conn); - break; -#endif /* LWIP_SO_RCVBUF */ -#if LWIP_SO_LINGER - case SO_LINGER: - { - s16_t conn_linger; - struct linger* linger = (struct linger*)optval; - LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger); - conn_linger = sock->conn->linger; - if (conn_linger >= 0) { - linger->l_onoff = 1; - linger->l_linger = (int)conn_linger; - } else { - linger->l_onoff = 0; - linger->l_linger = 0; - } - } - break; -#endif /* LWIP_SO_LINGER */ -#if LWIP_UDP - case SO_NO_CHECK: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP); -#if LWIP_UDPLITE - if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) { - /* this flag is only available for UDP, not for UDP lite */ - return EAFNOSUPPORT; - } -#endif /* LWIP_UDPLITE */ - *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; - break; -#endif /* LWIP_UDP*/ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; - -/* Level: IPPROTO_IP */ - case IPPROTO_IP: - switch (optname) { - case IP_TTL: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); - *(int*)optval = sock->conn->pcb.ip->ttl; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", - s, *(int *)optval)); - break; - case IP_TOS: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); - *(int*)optval = sock->conn->pcb.ip->tos; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", - s, *(int *)optval)); - break; -#if LWIP_MULTICAST_TX_OPTIONS - case IP_MULTICAST_TTL: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { - return ENOPROTOOPT; - } - *(u8_t*)optval = sock->conn->pcb.udp->mcast_ttl; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", - s, *(int *)optval)); - break; - case IP_MULTICAST_IF: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr); - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { - return ENOPROTOOPT; - } - inet_addr_from_ipaddr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp)); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", - s, *(u32_t *)optval)); - break; - case IP_MULTICAST_LOOP: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); - if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { - *(u8_t*)optval = 1; - } else { - *(u8_t*)optval = 0; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", - s, *(int *)optval)); - break; -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; - -#if LWIP_TCP -/* Level: IPPROTO_TCP */ - case IPPROTO_TCP: - /* Special case: all IPPROTO_TCP option take an int */ - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP); - switch (optname) { - case TCP_NODELAY: - *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", - s, (*(int*)optval)?"on":"off") ); - break; - case TCP_KEEPALIVE: - *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n", - s, *(int *)optval)); - break; - -#if LWIP_TCP_KEEPALIVE - case TCP_KEEPIDLE: - *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n", - s, *(int *)optval)); - break; - case TCP_KEEPINTVL: - *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n", - s, *(int *)optval)); - break; - case TCP_KEEPCNT: - *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n", - s, *(int *)optval)); - break; -#endif /* LWIP_TCP_KEEPALIVE */ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; -#endif /* LWIP_TCP */ - -#if LWIP_IPV6 -/* Level: IPPROTO_IPV6 */ - case IPPROTO_IPV6: - switch (optname) { - case IPV6_V6ONLY: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); - /* @todo: this does not work for datagram sockets, yet */ - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { - return ENOPROTOOPT; - } - *(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", - s, *(int *)optval)); - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; -#endif /* LWIP_IPV6 */ - -#if LWIP_UDP && LWIP_UDPLITE - /* Level: IPPROTO_UDPLITE */ - case IPPROTO_UDPLITE: - /* Special case: all IPPROTO_UDPLITE option take an int */ - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); - /* If this is no UDP lite socket, ignore any options. */ - if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { - return ENOPROTOOPT; - } - switch (optname) { - case UDPLITE_SEND_CSCOV: - *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", - s, (*(int*)optval)) ); - break; - case UDPLITE_RECV_CSCOV: - *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", - s, (*(int*)optval)) ); - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; -#endif /* LWIP_UDP */ - /* Level: IPPROTO_RAW */ - case IPPROTO_RAW: - switch (optname) { -#if LWIP_IPV6 && LWIP_RAW - case IPV6_CHECKSUM: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW); - if (sock->conn->pcb.raw->chksum_reqd == 0) { - *(int *)optval = -1; - } else { - *(int *)optval = sock->conn->pcb.raw->chksum_offset; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", - s, (*(int*)optval)) ); - break; -#endif /* LWIP_IPV6 && LWIP_RAW */ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", - s, level, optname)); - err = ENOPROTOOPT; - break; - } /* switch (level) */ - - return err; -} - -int -lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) -{ - u8_t err = 0; - struct lwip_sock *sock = get_socket(s); -#if !LWIP_TCPIP_CORE_LOCKING - LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); -#endif /* !LWIP_TCPIP_CORE_LOCKING */ - - if (!sock) { - return -1; - } - - if (NULL == optval) { - sock_set_errno(sock, EFAULT); - return -1; - } - -#if LWIP_TCPIP_CORE_LOCKING - /* core-locking can just call the -impl function */ - LOCK_TCPIP_CORE(); - err = lwip_setsockopt_impl(s, level, optname, optval, optlen); - UNLOCK_TCPIP_CORE(); - -#else /* LWIP_TCPIP_CORE_LOCKING */ - -#if LWIP_MPU_COMPATIBLE - /* MPU_COMPATIBLE copies the optval data, so check for max size here */ - if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { - sock_set_errno(sock, ENOBUFS); - return -1; - } -#endif /* LWIP_MPU_COMPATIBLE */ - - LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; -#if LWIP_MPU_COMPATIBLE - memcpy(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen); -#else /* LWIP_MPU_COMPATIBLE */ - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void*)optval; -#endif /* LWIP_MPU_COMPATIBLE */ - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; -#if LWIP_NETCONN_SEM_PER_THREAD - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); -#else - LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; -#endif - err = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); - if (err != ERR_OK) { - LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); - - /* maybe lwip_getsockopt_internal has changed err */ - err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; - LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); -#endif /* LWIP_TCPIP_CORE_LOCKING */ - - sock_set_errno(sock, err); - return err ? -1 : 0; -} - -#if !LWIP_TCPIP_CORE_LOCKING -/** lwip_setsockopt_callback: only used without CORE_LOCKING - * to get into the tcpip_thread - */ -static void -lwip_setsockopt_callback(void *arg) -{ - struct lwip_setgetsockopt_data *data; - LWIP_ASSERT("arg != NULL", arg != NULL); - data = (struct lwip_setgetsockopt_data*)arg; - - data->err = lwip_setsockopt_impl(data->s, data->level, data->optname, -#if LWIP_MPU_COMPATIBLE - data->optval, -#else /* LWIP_MPU_COMPATIBLE */ - data->optval.pc, -#endif /* LWIP_MPU_COMPATIBLE */ - data->optlen); - - sys_sem_signal((sys_sem_t*)(data->completed_sem)); -} -#endif /* LWIP_TCPIP_CORE_LOCKING */ - -/** lwip_setsockopt_impl: the actual implementation of setsockopt: - * same argument as lwip_setsockopt, either called directly or through callback - */ -static u8_t -lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen) -{ - u8_t err = 0; - struct lwip_sock *sock = tryget_socket(s); - if (!sock) { - return EBADF; - } - - switch (level) { - -/* Level: SOL_SOCKET */ - case SOL_SOCKET: - switch (optname) { - - /* SO_ACCEPTCONN is get-only */ - - /* The option flags */ - case SO_BROADCAST: - case SO_KEEPALIVE: -#if SO_REUSE - case SO_REUSEADDR: -#endif /* SO_REUSE */ - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); - if (*(const int*)optval) { - ip_set_option(sock->conn->pcb.ip, optname); - } else { - ip_reset_option(sock->conn->pcb.ip, optname); - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", - s, optname, (*(const int*)optval?"on":"off"))); - break; - - /* SO_TYPE is get-only */ - /* SO_ERROR is get-only */ - -#if LWIP_SO_SNDTIMEO - case SO_SNDTIMEO: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); - netconn_set_sendtimeout(sock->conn, LWIP_SO_SNDRCVTIMEO_GET_MS(optval)); - break; -#endif /* LWIP_SO_SNDTIMEO */ -#if LWIP_SO_RCVTIMEO - case SO_RCVTIMEO: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); - netconn_set_recvtimeout(sock->conn, (int)LWIP_SO_SNDRCVTIMEO_GET_MS(optval)); - break; -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF - case SO_RCVBUF: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int); - netconn_set_recvbufsize(sock->conn, *(const int*)optval); - break; -#endif /* LWIP_SO_RCVBUF */ -#if LWIP_SO_LINGER - case SO_LINGER: - { - const struct linger* linger = (const struct linger*)optval; - LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger); - if (linger->l_onoff) { - int lingersec = linger->l_linger; - if (lingersec < 0) { - return EINVAL; - } - if (lingersec > 0xFFFF) { - lingersec = 0xFFFF; - } - sock->conn->linger = (s16_t)lingersec; - } else { - sock->conn->linger = -1; - } - } - break; -#endif /* LWIP_SO_LINGER */ -#if LWIP_UDP - case SO_NO_CHECK: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); -#if LWIP_UDPLITE - if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) { - /* this flag is only available for UDP, not for UDP lite */ - return EAFNOSUPPORT; - } -#endif /* LWIP_UDPLITE */ - if (*(const int*)optval) { - udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); - } else { - udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); - } - break; -#endif /* LWIP_UDP */ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; - -/* Level: IPPROTO_IP */ - case IPPROTO_IP: - switch (optname) { - case IP_TTL: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); - sock->conn->pcb.ip->ttl = (u8_t)(*(const int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", - s, sock->conn->pcb.ip->ttl)); - break; - case IP_TOS: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); - sock->conn->pcb.ip->tos = (u8_t)(*(const int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", - s, sock->conn->pcb.ip->tos)); - break; -#if LWIP_MULTICAST_TX_OPTIONS - case IP_MULTICAST_TTL: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); - sock->conn->pcb.udp->mcast_ttl = (u8_t)(*(const u8_t*)optval); - break; - case IP_MULTICAST_IF: - { - ip4_addr_t if_addr; - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP); - inet_addr_to_ipaddr(&if_addr, (const struct in_addr*)optval); - udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr); - } - break; - case IP_MULTICAST_LOOP: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); - if (*(const u8_t*)optval) { - udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); - } else { - udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); - } - break; -#endif /* LWIP_MULTICAST_TX_OPTIONS */ -#if LWIP_IGMP - case IP_ADD_MEMBERSHIP: - case IP_DROP_MEMBERSHIP: - { - /* If this is a TCP or a RAW socket, ignore these options. */ - /* @todo: assign membership to this socket so that it is dropped when closing the socket */ - err_t igmp_err; - const struct ip_mreq *imr = (const struct ip_mreq *)optval; - ip4_addr_t if_addr; - ip4_addr_t multi_addr; - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP); - inet_addr_to_ipaddr(&if_addr, &imr->imr_interface); - inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr); - if (optname == IP_ADD_MEMBERSHIP) { - if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) { - /* cannot track membership (out of memory) */ - err = ENOMEM; - igmp_err = ERR_OK; - } else { - igmp_err = igmp_joingroup(&if_addr, &multi_addr); - } - } else { - igmp_err = igmp_leavegroup(&if_addr, &multi_addr); - lwip_socket_unregister_membership(s, &if_addr, &multi_addr); - } - if (igmp_err != ERR_OK) { - err = EADDRNOTAVAIL; - } - } - break; -#endif /* LWIP_IGMP */ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; - -#if LWIP_TCP -/* Level: IPPROTO_TCP */ - case IPPROTO_TCP: - /* Special case: all IPPROTO_TCP option take an int */ - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); - switch (optname) { - case TCP_NODELAY: - if (*(const int*)optval) { - tcp_nagle_disable(sock->conn->pcb.tcp); - } else { - tcp_nagle_enable(sock->conn->pcb.tcp); - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", - s, (*(const int *)optval)?"on":"off") ); - break; - case TCP_KEEPALIVE: - sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", - s, sock->conn->pcb.tcp->keep_idle)); - break; - -#if LWIP_TCP_KEEPALIVE - case TCP_KEEPIDLE: - sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(const int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", - s, sock->conn->pcb.tcp->keep_idle)); - break; - case TCP_KEEPINTVL: - sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(const int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", - s, sock->conn->pcb.tcp->keep_intvl)); - break; - case TCP_KEEPCNT: - sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", - s, sock->conn->pcb.tcp->keep_cnt)); - break; -#endif /* LWIP_TCP_KEEPALIVE */ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; -#endif /* LWIP_TCP*/ - -#if LWIP_IPV6 -/* Level: IPPROTO_IPV6 */ - case IPPROTO_IPV6: - switch (optname) { - case IPV6_V6ONLY: - /* @todo: this does not work for datagram sockets, yet */ - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); - if (*(const int*)optval) { - netconn_set_ipv6only(sock->conn, 1); - } else { - netconn_set_ipv6only(sock->conn, 0); - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", - s, (netconn_get_ipv6only(sock->conn) ? 1 : 0))); - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; -#endif /* LWIP_IPV6 */ - -#if LWIP_UDP && LWIP_UDPLITE - /* Level: IPPROTO_UDPLITE */ - case IPPROTO_UDPLITE: - /* Special case: all IPPROTO_UDPLITE option take an int */ - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); - /* If this is no UDP lite socket, ignore any options. */ - if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { - return ENOPROTOOPT; - } - switch (optname) { - case UDPLITE_SEND_CSCOV: - if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) { - /* don't allow illegal values! */ - sock->conn->pcb.udp->chksum_len_tx = 8; - } else { - sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(const int*)optval; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", - s, (*(const int*)optval)) ); - break; - case UDPLITE_RECV_CSCOV: - if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) { - /* don't allow illegal values! */ - sock->conn->pcb.udp->chksum_len_rx = 8; - } else { - sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(const int*)optval; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", - s, (*(const int*)optval)) ); - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; -#endif /* LWIP_UDP */ - /* Level: IPPROTO_RAW */ - case IPPROTO_RAW: - switch (optname) { -#if LWIP_IPV6 && LWIP_RAW - case IPV6_CHECKSUM: - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); - if (*(const int *)optval < 0) { - sock->conn->pcb.raw->chksum_reqd = 0; - } else if (*(const int *)optval & 1) { - /* Per RFC3542, odd offsets are not allowed */ - return EINVAL; - } else { - sock->conn->pcb.raw->chksum_reqd = 1; - sock->conn->pcb.raw->chksum_offset = (u16_t)*(const int *)optval; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", - s, sock->conn->pcb.raw->chksum_reqd)); - break; -#endif /* LWIP_IPV6 && LWIP_RAW */ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - break; - } /* switch (optname) */ - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", - s, level, optname)); - err = ENOPROTOOPT; - break; - } /* switch (level) */ - - return err; -} - -int -lwip_ioctl(int s, long cmd, void *argp) -{ - struct lwip_sock *sock = get_socket(s); - u8_t val; -#if LWIP_SO_RCVBUF - u16_t buflen = 0; - int recv_avail; -#endif /* LWIP_SO_RCVBUF */ - - if (!sock) { - return -1; - } - - switch (cmd) { -#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE - case FIONREAD: - if (!argp) { - sock_set_errno(sock, EINVAL); - return -1; - } -#if LWIP_FIONREAD_LINUXMODE - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { - struct pbuf *p; - if (sock->lastdata) { - p = ((struct netbuf *)sock->lastdata)->p; - *((int*)argp) = p->tot_len - sock->lastoffset; - } else { - struct netbuf *rxbuf; - err_t err; - if (sock->rcvevent <= 0) { - *((int*)argp) = 0; - } else { - err = netconn_recv(sock->conn, &rxbuf); - if (err != ERR_OK) { - *((int*)argp) = 0; - } else { - sock->lastdata = rxbuf; - sock->lastoffset = 0; - *((int*)argp) = rxbuf->p->tot_len; - } - } - } - return 0; - } -#endif /* LWIP_FIONREAD_LINUXMODE */ - -#if LWIP_SO_RCVBUF - /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ - SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); - if (recv_avail < 0) { - recv_avail = 0; - } - *((int*)argp) = recv_avail; - - /* Check if there is data left from the last recv operation. /maq 041215 */ - if (sock->lastdata) { - struct pbuf *p = (struct pbuf *)sock->lastdata; - if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { - p = ((struct netbuf *)p)->p; - } - buflen = p->tot_len; - buflen -= sock->lastoffset; - - *((int*)argp) += buflen; - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); - sock_set_errno(sock, 0); - return 0; -#else /* LWIP_SO_RCVBUF */ - break; -#endif /* LWIP_SO_RCVBUF */ -#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ - - case (long)FIONBIO: - val = 0; - if (argp && *(u32_t*)argp) { - val = 1; - } - netconn_set_nonblocking(sock->conn, val); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); - sock_set_errno(sock, 0); - return 0; - - default: - break; - } /* switch (cmd) */ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); - sock_set_errno(sock, ENOSYS); /* not yet implemented */ - return -1; -} - -/** A minimal implementation of fcntl. - * Currently only the commands F_GETFL and F_SETFL are implemented. - * Only the flag O_NONBLOCK is implemented. - */ -int -lwip_fcntl(int s, int cmd, int val) -{ - struct lwip_sock *sock = get_socket(s); - int ret = -1; - - if (!sock) { - return -1; - } - - switch (cmd) { - case F_GETFL: - ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; - sock_set_errno(sock, 0); - break; - case F_SETFL: - if ((val & ~O_NONBLOCK) == 0) { - /* only O_NONBLOCK, all other bits are zero */ - netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); - ret = 0; - sock_set_errno(sock, 0); - } else { - sock_set_errno(sock, ENOSYS); /* not yet implemented */ - } - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); - sock_set_errno(sock, ENOSYS); /* not yet implemented */ - break; - } - return ret; -} - -#if LWIP_IGMP -/** Register a new IGMP membership. On socket close, the membership is dropped automatically. - * - * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). - * - * @return 1 on success, 0 on failure - */ -static int -lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) -{ - /* s+1 is stored in the array to prevent having to initialize the array - (default initialization is to 0) */ - int sa = s + 1; - int i; - - for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { - if (socket_ipv4_multicast_memberships[i].sa == 0) { - socket_ipv4_multicast_memberships[i].sa = sa; - ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr); - ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); - return 1; - } - } - return 0; -} - -/** Unregister a previously registered membership. This prevents dropping the membership - * on socket close. - * - * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). - */ -static void -lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) -{ - /* s+1 is stored in the array to prevent having to initialize the array - (default initialization is to 0) */ - int sa = s + 1; - int i; - - for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { - if ((socket_ipv4_multicast_memberships[i].sa == sa) && - ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && - ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { - socket_ipv4_multicast_memberships[i].sa = 0; - ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); - ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); - return; - } - } -} - -/** Drop all memberships of a socket that were not dropped explicitly via setsockopt. - * - * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). - */ -static void lwip_socket_drop_registered_memberships(int s) -{ - /* s+1 is stored in the array to prevent having to initialize the array - (default initialization is to 0) */ - int sa = s + 1; - int i; - - LWIP_ASSERT("socket has no netconn", sockets[s].conn != NULL); - - for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { - if (socket_ipv4_multicast_memberships[i].sa == sa) { - ip_addr_t multi_addr, if_addr; - ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr); - ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr); - socket_ipv4_multicast_memberships[i].sa = 0; - ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); - ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); - - netconn_join_leave_group(sockets[s].conn, &multi_addr, &if_addr, NETCONN_LEAVE); - } - } -} -#endif /* LWIP_IGMP */ -#endif /* LWIP_SOCKET */ diff --git a/ext/lwip/src/api/tcpip.c b/ext/lwip/src/api/tcpip.c deleted file mode 100644 index 5ab2658..0000000 --- a/ext/lwip/src/api/tcpip.c +++ /dev/null @@ -1,511 +0,0 @@ -/** - * @file - * Sequential API Main thread module - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/opt.h" - -#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/priv/tcpip_priv.h" -#include "lwip/sys.h" -#include "lwip/memp.h" -#include "lwip/mem.h" -#include "lwip/init.h" -#include "lwip/ip.h" -#include "lwip/pbuf.h" -#include "lwip/etharp.h" - -#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) -#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) -#define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM) -#define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name) - -/* global variables */ -static tcpip_init_done_fn tcpip_init_done; -static void *tcpip_init_done_arg; -static sys_mbox_t mbox; - -#if LWIP_TCPIP_CORE_LOCKING -/** The global semaphore to lock the stack. */ -sys_mutex_t lock_tcpip_core; -#endif /* LWIP_TCPIP_CORE_LOCKING */ - - -/** - * The main lwIP thread. This thread has exclusive access to lwIP core functions - * (unless access to them is not locked). Other threads communicate with this - * thread using message boxes. - * - * It also starts all the timers to make sure they are running in the right - * thread context. - * - * @param arg unused argument - */ -static void -tcpip_thread(void *arg) -{ - struct tcpip_msg *msg; - LWIP_UNUSED_ARG(arg); - - if (tcpip_init_done != NULL) { - tcpip_init_done(tcpip_init_done_arg); - } - - LOCK_TCPIP_CORE(); - while (1) { /* MAIN Loop */ - UNLOCK_TCPIP_CORE(); - LWIP_TCPIP_THREAD_ALIVE(); - /* wait for a message, timeouts are processed while waiting */ - sys_timeouts_mbox_fetch(&mbox, (void **)&msg); - LOCK_TCPIP_CORE(); - if (msg == NULL) { - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); - LWIP_ASSERT("tcpip_thread: invalid message", 0); - continue; - } - switch (msg->type) { -#if !LWIP_TCPIP_CORE_LOCKING - case TCPIP_MSG_API: - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); - msg->msg.api_msg.function(msg->msg.api_msg.msg); - break; - case TCPIP_MSG_API_CALL: - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg)); - msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg); - sys_sem_signal(msg->msg.api_call.sem); - break; -#endif /* !LWIP_TCPIP_CORE_LOCKING */ - -#if !LWIP_TCPIP_CORE_LOCKING_INPUT - case TCPIP_MSG_INPKT: - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); - msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif); - memp_free(MEMP_TCPIP_MSG_INPKT, msg); - break; -#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ - -#if LWIP_TCPIP_TIMEOUT - case TCPIP_MSG_TIMEOUT: - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); - sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); - memp_free(MEMP_TCPIP_MSG_API, msg); - break; - case TCPIP_MSG_UNTIMEOUT: - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); - sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); - memp_free(MEMP_TCPIP_MSG_API, msg); - break; -#endif /* LWIP_TCPIP_TIMEOUT */ - - case TCPIP_MSG_CALLBACK: - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); - msg->msg.cb.function(msg->msg.cb.ctx); - memp_free(MEMP_TCPIP_MSG_API, msg); - break; - - case TCPIP_MSG_CALLBACK_STATIC: - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); - msg->msg.cb.function(msg->msg.cb.ctx); - break; - - default: - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); - LWIP_ASSERT("tcpip_thread: invalid message", 0); - break; - } - } -} - -/** - * Pass a received packet to tcpip_thread for input processing - * - * @param p the received packet - * @param inp the network interface on which the packet was received - * @param input_fn input function to call - */ -err_t -tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) -{ -#if LWIP_TCPIP_CORE_LOCKING_INPUT - err_t ret; - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); - LOCK_TCPIP_CORE(); - ret = input_fn(p, inp); - UNLOCK_TCPIP_CORE(); - return ret; -#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ - struct tcpip_msg *msg; - - LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); - - msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); - if (msg == NULL) { - return ERR_MEM; - } - - msg->type = TCPIP_MSG_INPKT; - msg->msg.inp.p = p; - msg->msg.inp.netif = inp; - msg->msg.inp.input_fn = input_fn; - if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { - memp_free(MEMP_TCPIP_MSG_INPKT, msg); - return ERR_MEM; - } - return ERR_OK; -#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ -} - -/** - * @ingroup lwip_os - * Pass a received packet to tcpip_thread for input processing with - * ethernet_input or ip_input. Don't call directly, pass to netif_add() - * and call netif->input(). - * - * @param p the received packet, p->payload pointing to the Ethernet header or - * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or - * NETIF_FLAG_ETHERNET flags) - * @param inp the network interface on which the packet was received - */ -err_t -tcpip_input(struct pbuf *p, struct netif *inp) -{ -#if LWIP_ETHERNET - if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { - return tcpip_inpkt(p, inp, ethernet_input); - } else -#endif /* LWIP_ETHERNET */ - return tcpip_inpkt(p, inp, ip_input); -} - -/** - * Call a specific function in the thread context of - * tcpip_thread for easy access synchronization. - * A function called in that way may access lwIP core code - * without fearing concurrent access. - * - * @param function the function to call - * @param ctx parameter passed to f - * @param block 1 to block until the request is posted, 0 to non-blocking mode - * @return ERR_OK if the function was called, another err_t if not - */ -err_t -tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) -{ - struct tcpip_msg *msg; - - LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); - - msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); - if (msg == NULL) { - return ERR_MEM; - } - - msg->type = TCPIP_MSG_CALLBACK; - msg->msg.cb.function = function; - msg->msg.cb.ctx = ctx; - if (block) { - sys_mbox_post(&mbox, msg); - } else { - if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { - memp_free(MEMP_TCPIP_MSG_API, msg); - return ERR_MEM; - } - } - return ERR_OK; -} - -#if LWIP_TCPIP_TIMEOUT -/** - * call sys_timeout in tcpip_thread - * - * @param msec time in milliseconds for timeout - * @param h function to be called on timeout - * @param arg argument to pass to timeout function h - * @return ERR_MEM on memory error, ERR_OK otherwise - */ -err_t -tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) -{ - struct tcpip_msg *msg; - - LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); - - msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); - if (msg == NULL) { - return ERR_MEM; - } - - msg->type = TCPIP_MSG_TIMEOUT; - msg->msg.tmo.msecs = msecs; - msg->msg.tmo.h = h; - msg->msg.tmo.arg = arg; - sys_mbox_post(&mbox, msg); - return ERR_OK; -} - -/** - * call sys_untimeout in tcpip_thread - * - * @param msec time in milliseconds for timeout - * @param h function to be called on timeout - * @param arg argument to pass to timeout function h - * @return ERR_MEM on memory error, ERR_OK otherwise - */ -err_t -tcpip_untimeout(sys_timeout_handler h, void *arg) -{ - struct tcpip_msg *msg; - - LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); - - msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); - if (msg == NULL) { - return ERR_MEM; - } - - msg->type = TCPIP_MSG_UNTIMEOUT; - msg->msg.tmo.h = h; - msg->msg.tmo.arg = arg; - sys_mbox_post(&mbox, msg); - return ERR_OK; -} -#endif /* LWIP_TCPIP_TIMEOUT */ - - -/** - * Sends a message to TCPIP thread to call a function. Caller thread blocks on - * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread, - * this has to be done by the user. - * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way - * with least runtime overhead. - * - * @param fn function to be called from TCPIP thread - * @param apimsg argument to API function - * @param sem semaphore to wait on - * @return ERR_OK if the function was called, another err_t if not - */ -err_t -tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem) -{ -#if LWIP_TCPIP_CORE_LOCKING - LWIP_UNUSED_ARG(sem); - LOCK_TCPIP_CORE(); - fn(apimsg); - UNLOCK_TCPIP_CORE(); - return ERR_OK; -#else /* LWIP_TCPIP_CORE_LOCKING */ - TCPIP_MSG_VAR_DECLARE(msg); - - LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem)); - LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); - - TCPIP_MSG_VAR_ALLOC(msg); - TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; - TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn; - TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg; - sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); - sys_arch_sem_wait(sem, 0); - TCPIP_MSG_VAR_FREE(msg); - return ERR_OK; -#endif /* LWIP_TCPIP_CORE_LOCKING */ -} - -/** - * Synchronously calls function in TCPIP thread and waits for its completion. - * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or - * LWIP_NETCONN_SEM_PER_THREAD. - * If not, a semaphore is created and destroyed on every call which is usually - * an expensive/slow operation. - * @param fn Function to call - * @param call Call parameters - * @return Return value from tcpip_api_call_fn - */ -err_t -tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) -{ -#if LWIP_TCPIP_CORE_LOCKING - err_t err; - LOCK_TCPIP_CORE(); - err = fn(call); - UNLOCK_TCPIP_CORE(); - return err; -#else /* LWIP_TCPIP_CORE_LOCKING */ - TCPIP_MSG_VAR_DECLARE(msg); - -#if !LWIP_NETCONN_SEM_PER_THREAD - err_t err = sys_sem_new(&call->sem, 0); - if (err != ERR_OK) { - return err; - } -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - - LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); - - TCPIP_MSG_VAR_ALLOC(msg); - TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL; - TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call; - TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn; -#if LWIP_NETCONN_SEM_PER_THREAD - TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET(); -#else /* LWIP_NETCONN_SEM_PER_THREAD */ - TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem; -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); - sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0); - TCPIP_MSG_VAR_FREE(msg); - -#if !LWIP_NETCONN_SEM_PER_THREAD - sys_sem_free(&call->sem); -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - - return call->err; -#endif /* LWIP_TCPIP_CORE_LOCKING */ -} - -/** - * Allocate a structure for a static callback message and initialize it. - * This is intended to be used to send "static" messages from interrupt context. - * - * @param function the function to call - * @param ctx parameter passed to function - * @return a struct pointer to pass to tcpip_trycallback(). - */ -struct tcpip_callback_msg* -tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) -{ - struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); - if (msg == NULL) { - return NULL; - } - msg->type = TCPIP_MSG_CALLBACK_STATIC; - msg->msg.cb.function = function; - msg->msg.cb.ctx = ctx; - return (struct tcpip_callback_msg*)msg; -} - -/** - * Free a callback message allocated by tcpip_callbackmsg_new(). - * - * @param msg the message to free - */ -void -tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg) -{ - memp_free(MEMP_TCPIP_MSG_API, msg); -} - -/** - * Try to post a callback-message to the tcpip_thread mbox - * This is intended to be used to send "static" messages from interrupt context. - * - * @param msg pointer to the message to post - * @return sys_mbox_trypost() return code - */ -err_t -tcpip_trycallback(struct tcpip_callback_msg* msg) -{ - LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); - return sys_mbox_trypost(&mbox, msg); -} - -/** - * @ingroup lwip_os - * Initialize this module: - * - initialize all sub modules - * - start the tcpip_thread - * - * @param initfunc a function to call when tcpip_thread is running and finished initializing - * @param arg argument to pass to initfunc - */ -void -tcpip_init(tcpip_init_done_fn initfunc, void *arg) -{ - lwip_init(); - - tcpip_init_done = initfunc; - tcpip_init_done_arg = arg; - if (sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) { - LWIP_ASSERT("failed to create tcpip_thread mbox", 0); - } -#if LWIP_TCPIP_CORE_LOCKING - if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) { - LWIP_ASSERT("failed to create lock_tcpip_core", 0); - } -#endif /* LWIP_TCPIP_CORE_LOCKING */ - - sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); -} - -/** - * Simple callback function used with tcpip_callback to free a pbuf - * (pbuf_free has a wrong signature for tcpip_callback) - * - * @param p The pbuf (chain) to be dereferenced. - */ -static void -pbuf_free_int(void *p) -{ - struct pbuf *q = (struct pbuf *)p; - pbuf_free(q); -} - -/** - * A simple wrapper function that allows you to free a pbuf from interrupt context. - * - * @param p The pbuf (chain) to be dereferenced. - * @return ERR_OK if callback could be enqueued, an err_t if not - */ -err_t -pbuf_free_callback(struct pbuf *p) -{ - return tcpip_callback_with_block(pbuf_free_int, p, 0); -} - -/** - * A simple wrapper function that allows you to free heap memory from - * interrupt context. - * - * @param m the heap memory to free - * @return ERR_OK if callback could be enqueued, an err_t if not - */ -err_t -mem_free_callback(void *m) -{ - return tcpip_callback_with_block(mem_free, m, 0); -} - -#endif /* !NO_SYS */ diff --git a/ext/lwip/src/apps/httpd/fs.c b/ext/lwip/src/apps/httpd/fs.c deleted file mode 100644 index 35b5e31..0000000 --- a/ext/lwip/src/apps/httpd/fs.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/apps/httpd_opts.h" -#include "lwip/def.h" -#include "lwip/apps/fs.h" -#include "fsdata.h" -#include - - -#if HTTPD_USE_CUSTOM_FSDATA -#include "fsdata_custom.c" -#else /* HTTPD_USE_CUSTOM_FSDATA */ -#include "fsdata.c" -#endif /* HTTPD_USE_CUSTOM_FSDATA */ - -/*-----------------------------------------------------------------------------------*/ - -#if LWIP_HTTPD_CUSTOM_FILES -int fs_open_custom(struct fs_file *file, const char *name); -void fs_close_custom(struct fs_file *file); -#if LWIP_HTTPD_FS_ASYNC_READ -u8_t fs_canread_custom(struct fs_file *file); -u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); -int fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg); -#else /* LWIP_HTTPD_FS_ASYNC_READ */ -int fs_read_custom(struct fs_file *file, char *buffer, int count); -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ -#endif /* LWIP_HTTPD_CUSTOM_FILES */ - -/*-----------------------------------------------------------------------------------*/ -err_t -fs_open(struct fs_file *file, const char *name) -{ - const struct fsdata_file *f; - - if ((file == NULL) || (name == NULL)) { - return ERR_ARG; - } - -#if LWIP_HTTPD_CUSTOM_FILES - if (fs_open_custom(file, name)) { - file->is_custom_file = 1; - return ERR_OK; - } - file->is_custom_file = 0; -#endif /* LWIP_HTTPD_CUSTOM_FILES */ - - for (f = FS_ROOT; f != NULL; f = f->next) { - if (!strcmp(name, (const char *)f->name)) { - file->data = (const char *)f->data; - file->len = f->len; - file->index = f->len; - file->pextension = NULL; - file->flags = f->flags; -#if HTTPD_PRECALCULATED_CHECKSUM - file->chksum_count = f->chksum_count; - file->chksum = f->chksum; -#endif /* HTTPD_PRECALCULATED_CHECKSUM */ -#if LWIP_HTTPD_FILE_STATE - file->state = fs_state_init(file, name); -#endif /* #if LWIP_HTTPD_FILE_STATE */ - return ERR_OK; - } - } - /* file not found */ - return ERR_VAL; -} - -/*-----------------------------------------------------------------------------------*/ -void -fs_close(struct fs_file *file) -{ -#if LWIP_HTTPD_CUSTOM_FILES - if (file->is_custom_file) { - fs_close_custom(file); - } -#endif /* LWIP_HTTPD_CUSTOM_FILES */ -#if LWIP_HTTPD_FILE_STATE - fs_state_free(file, file->state); -#endif /* #if LWIP_HTTPD_FILE_STATE */ - LWIP_UNUSED_ARG(file); -} -/*-----------------------------------------------------------------------------------*/ -#if LWIP_HTTPD_DYNAMIC_FILE_READ -#if LWIP_HTTPD_FS_ASYNC_READ -int -fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg) -#else /* LWIP_HTTPD_FS_ASYNC_READ */ -int -fs_read(struct fs_file *file, char *buffer, int count) -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ -{ - int read; - if(file->index == file->len) { - return FS_READ_EOF; - } -#if LWIP_HTTPD_FS_ASYNC_READ - LWIP_UNUSED_ARG(callback_fn); - LWIP_UNUSED_ARG(callback_arg); -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ -#if LWIP_HTTPD_CUSTOM_FILES - if (file->is_custom_file) { -#if LWIP_HTTPD_FS_ASYNC_READ - return fs_read_async_custom(file, buffer, count, callback_fn, callback_arg); -#else /* LWIP_HTTPD_FS_ASYNC_READ */ - return fs_read_custom(file, buffer, count); -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ - } -#endif /* LWIP_HTTPD_CUSTOM_FILES */ - - read = file->len - file->index; - if(read > count) { - read = count; - } - - MEMCPY(buffer, (file->data + file->index), read); - file->index += read; - - return(read); -} -#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ -/*-----------------------------------------------------------------------------------*/ -#if LWIP_HTTPD_FS_ASYNC_READ -int -fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg) -{ - if (file != NULL) { -#if LWIP_HTTPD_FS_ASYNC_READ -#if LWIP_HTTPD_CUSTOM_FILES - if (!fs_canread_custom(file)) { - if (fs_wait_read_custom(file, callback_fn, callback_arg)) { - return 0; - } - } -#else /* LWIP_HTTPD_CUSTOM_FILES */ - LWIP_UNUSED_ARG(callback_fn); - LWIP_UNUSED_ARG(callback_arg); -#endif /* LWIP_HTTPD_CUSTOM_FILES */ -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ - } - return 1; -} -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ -/*-----------------------------------------------------------------------------------*/ -int -fs_bytes_left(struct fs_file *file) -{ - return file->len - file->index; -} diff --git a/ext/lwip/src/apps/httpd/fs/404.html b/ext/lwip/src/apps/httpd/fs/404.html deleted file mode 100644 index 40b343a..0000000 --- a/ext/lwip/src/apps/httpd/fs/404.html +++ /dev/null @@ -1,21 +0,0 @@ - -lwIP - A Lightweight TCP/IP Stack - - - - -
- SICS logo - -

lwIP - A Lightweight TCP/IP Stack

-

404 - Page not found

-

- Sorry, the page you are requesting was not found on this - server. -

-
-   -
- - diff --git a/ext/lwip/src/apps/httpd/fs/img/sics.gif b/ext/lwip/src/apps/httpd/fs/img/sics.gif deleted file mode 100644 index 0a4fc7bb07050eec9226ca93bc9ad237f35502c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 724 zcmZ?wbhEHbbYoCrSjxa~Q`<5tD{KG${gWq8=I7_%uwlcpWy=~G8p_Jb4zT=SA;^3z!7uBu>UZ()&> z+r1;Oh0mFly?klC)5cAV$sD}98F{LBUHERS_hGGKac5`W-mvIltqUt73*&`X?UVf< z%Uqmm^}K~z9MaFS-jwgVGIUF9Z77P_s7Vc}y?@_XT+GT)AcZF$6%$qQsA+Q0bF z!Mss%ktc&>+n*qp2aIzy6-8A8zNf3ovHkU%wPnH@(O;*7g5`QX{a~M@%VFg!JaWkVUk6yFE1wL^V{({yi?^s!by^W;pXIz%mY}~L;uBR^JK|)kW|Avap zVzxyL+2N;b1q1f77^T<4c)gUoN8c;6;F^+^0^VN o#HPS7gPr3^SVM!%(d|c@c+6frXclnOc-SHmma$O4k%7S)08~d;ZvX%Q diff --git a/ext/lwip/src/apps/httpd/fs/index.html b/ext/lwip/src/apps/httpd/fs/index.html deleted file mode 100644 index ab575ef..0000000 --- a/ext/lwip/src/apps/httpd/fs/index.html +++ /dev/null @@ -1,47 +0,0 @@ - -lwIP - A Lightweight TCP/IP Stack - - - - -
- SICS logo - -

lwIP - A Lightweight TCP/IP Stack

-

- The web page you are watching was served by a simple web - server running on top of the lightweight TCP/IP stack lwIP. -

-

- lwIP is an open source implementation of the TCP/IP - protocol suite that was originally written by Adam Dunkels - of the Swedish Institute of Computer Science but now is - being actively developed by a team of developers - distributed world-wide. Since it's release, lwIP has - spurred a lot of interest and has been ported to several - platforms and operating systems. lwIP can be used either - with or without an underlying OS. -

-

- The focus of the lwIP TCP/IP implementation is to reduce - the RAM usage while still having a full scale TCP. This - makes lwIP suitable for use in embedded systems with tens - of kilobytes of free RAM and room for around 40 kilobytes - of code ROM. -

-

- More information about lwIP can be found at the lwIP - homepage at http://savannah.nongnu.org/projects/lwip/ - or at the lwIP wiki at http://lwip.wikia.com/. -

-
-   -
- - - diff --git a/ext/lwip/src/apps/httpd/fsdata.c b/ext/lwip/src/apps/httpd/fsdata.c deleted file mode 100644 index 6170ce6..0000000 --- a/ext/lwip/src/apps/httpd/fsdata.c +++ /dev/null @@ -1,298 +0,0 @@ -#include "lwip/apps/fs.h" -#include "lwip/def.h" -#include "fsdata.h" - - -#define file_NULL (struct fsdata_file *) NULL - - -static const unsigned int dummy_align__img_sics_gif = 0; -static const unsigned char data__img_sics_gif[] = { -/* /img/sics.gif (14 chars) */ -0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x00,0x00,0x00, - -/* HTTP header */ -/* "HTTP/1.0 200 OK -" (17 bytes) */ -0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, -0x0a, -/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip) -" (63 bytes) */ -0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33, -0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e, -0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70, -0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, -/* "Content-type: image/gif - -" (27 bytes) */ -0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d, -0x61,0x67,0x65,0x2f,0x67,0x69,0x66,0x0d,0x0a,0x0d,0x0a, -/* raw file data (724 bytes) */ -0x47,0x49,0x46,0x38,0x39,0x61,0x46,0x00,0x22,0x00,0xa5,0x00,0x00,0xd9,0x2b,0x39, -0x6a,0x6a,0x6a,0xbf,0xbf,0xbf,0x93,0x93,0x93,0x0f,0x0f,0x0f,0xb0,0xb0,0xb0,0xa6, -0xa6,0xa6,0x80,0x80,0x80,0x76,0x76,0x76,0x1e,0x1e,0x1e,0x9d,0x9d,0x9d,0x2e,0x2e, -0x2e,0x49,0x49,0x49,0x54,0x54,0x54,0x8a,0x8a,0x8a,0x60,0x60,0x60,0xc6,0xa6,0x99, -0xbd,0xb5,0xb2,0xc2,0xab,0xa1,0xd9,0x41,0x40,0xd5,0x67,0x55,0xc0,0xb0,0xaa,0xd5, -0x5e,0x4e,0xd6,0x50,0x45,0xcc,0x93,0x7d,0xc8,0xa1,0x90,0xce,0x8b,0x76,0xd2,0x7b, -0x65,0xd1,0x84,0x6d,0xc9,0x99,0x86,0x3a,0x3a,0x3a,0x00,0x00,0x00,0xb8,0xb8,0xb8, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2c,0x00,0x00, -0x00,0x00,0x46,0x00,0x22,0x00,0x00,0x06,0xfe,0x40,0x90,0x70,0x48,0x2c,0x1a,0x8f, -0xc8,0xa4,0x72,0xc9,0x6c,0x3a,0x9f,0xd0,0xa8,0x74,0x4a,0xad,0x5a,0xaf,0xd8,0xac, -0x76,0xa9,0x40,0x04,0xbe,0x83,0xe2,0x60,0x3c,0x50,0x20,0x0d,0x8e,0x6f,0x00,0x31, -0x28,0x1c,0x0d,0x07,0xb5,0xc3,0x60,0x75,0x24,0x3e,0xf8,0xfc,0x87,0x11,0x06,0xe9, -0x3d,0x46,0x07,0x0b,0x7a,0x7a,0x7c,0x43,0x06,0x1e,0x84,0x78,0x0b,0x07,0x6e,0x51, -0x01,0x8a,0x84,0x08,0x7e,0x79,0x80,0x87,0x89,0x91,0x7a,0x93,0x0a,0x04,0x99,0x78, -0x96,0x4f,0x03,0x9e,0x79,0x01,0x94,0x9f,0x43,0x9c,0xa3,0xa4,0x05,0x77,0xa3,0xa0, -0x4e,0x98,0x79,0x0b,0x1e,0x83,0xa4,0xa6,0x1f,0x96,0x05,0x9d,0xaa,0x78,0x01,0x07, -0x84,0x04,0x1e,0x1e,0xbb,0xb8,0x51,0x84,0x0e,0x43,0x05,0x07,0x77,0xa5,0x7f,0x42, -0xb1,0xb2,0x01,0x63,0x08,0x0d,0xbb,0x01,0x0c,0x7a,0x0d,0x44,0x0e,0xd8,0xaf,0x4c, -0x05,0x7a,0x04,0x47,0x07,0x07,0xb7,0x80,0xa2,0xe1,0x7d,0x44,0x05,0x01,0x04,0x01, -0xd0,0xea,0x87,0x93,0x4f,0xe0,0x9a,0x49,0xce,0xd8,0x79,0x04,0x66,0x20,0x15,0x10, -0x10,0x11,0x92,0x29,0x80,0xb6,0xc0,0x91,0x15,0x45,0x1e,0x90,0x19,0x71,0x46,0xa8, -0x5c,0x04,0x0e,0x00,0x22,0x4e,0xe8,0x40,0x24,0x9f,0x3e,0x04,0x06,0xa7,0x58,0xd4, -0x93,0xa0,0x1c,0x91,0x3f,0xe8,0xf0,0x88,0x03,0xb1,0x21,0xa2,0x49,0x00,0x19,0x86, -0xfc,0x52,0x44,0xe0,0x01,0x9d,0x29,0x21,0x15,0x25,0x50,0xf7,0x67,0x25,0x1e,0x06, -0xfd,0x4e,0x9a,0xb4,0x90,0xac,0x15,0xfa,0xcb,0x52,0x53,0x1e,0x8c,0xf2,0xf8,0x07, -0x92,0x2d,0x08,0x3a,0x4d,0x12,0x49,0x95,0x49,0xdb,0x14,0x04,0xc4,0x14,0x85,0x29, -0xaa,0xe7,0x01,0x08,0xa4,0x49,0x01,0x14,0x51,0xe0,0x53,0x91,0xd5,0x29,0x06,0x1a, -0x64,0x02,0xf4,0xc7,0x81,0x9e,0x05,0x20,0x22,0x64,0xa5,0x30,0xae,0xab,0x9e,0x97, -0x53,0xd8,0xb9,0xfd,0x50,0xef,0x93,0x02,0x42,0x74,0x34,0xe8,0x9c,0x20,0x21,0xc9, -0x01,0x68,0x78,0xe6,0x55,0x29,0x20,0x56,0x4f,0x4c,0x40,0x51,0x71,0x82,0xc0,0x70, -0x21,0x22,0x85,0xbe,0x4b,0x1c,0x44,0x05,0xea,0xa4,0x01,0xbf,0x22,0xb5,0xf0,0x1c, -0x06,0x51,0x38,0x8f,0xe0,0x22,0xec,0x18,0xac,0x39,0x22,0xd4,0xd6,0x93,0x44,0x01, -0x32,0x82,0xc8,0xfc,0x61,0xb3,0x01,0x45,0x0c,0x2e,0x83,0x30,0xd0,0x0e,0x17,0x24, -0x0f,0x70,0x85,0x94,0xee,0x05,0x05,0x53,0x4b,0x32,0x1b,0x3f,0x98,0xd3,0x1d,0x29, -0x81,0xb0,0xae,0x1e,0x8c,0x7e,0x68,0xe0,0x60,0x5a,0x54,0x8f,0xb0,0x78,0x69,0x73, -0x06,0xa2,0x00,0x6b,0x57,0xca,0x3d,0x11,0x50,0xbd,0x04,0x30,0x4b,0x3a,0xd4,0xab, -0x5f,0x1f,0x9b,0x3d,0x13,0x74,0x27,0x88,0x3c,0x25,0xe0,0x17,0xbe,0x7a,0x79,0x45, -0x0d,0x0c,0xb0,0x8b,0xda,0x90,0xca,0x80,0x06,0x5d,0x17,0x60,0x1c,0x22,0x4c,0xd8, -0x57,0x22,0x06,0x20,0x00,0x98,0x07,0x08,0xe4,0x56,0x80,0x80,0x1c,0xc5,0xb7,0xc5, -0x82,0x0c,0x36,0xe8,0xe0,0x83,0x10,0x46,0x28,0xe1,0x84,0x14,0x56,0x68,0xa1,0x10, -0x41,0x00,0x00,0x3b,}; - -static const unsigned int dummy_align__404_html = 1; -static const unsigned char data__404_html[] = { -/* /404.html (10 chars) */ -0x2f,0x34,0x30,0x34,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00, - -/* HTTP header */ -/* "HTTP/1.0 404 File not found -" (29 bytes) */ -0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x34,0x30,0x34,0x20,0x46,0x69,0x6c, -0x65,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x0d,0x0a, -/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip) -" (63 bytes) */ -0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33, -0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e, -0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70, -0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, -/* "Content-type: text/html - -" (27 bytes) */ -0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, -0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, -/* raw file data (565 bytes) */ -0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, -0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69, -0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, -0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f, -0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63, -0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78, -0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20, -0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22, -0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74, -0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c, -0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20, -0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, -0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, -0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69, -0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20, -0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d, -0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c, -0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f, -0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69, -0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09, -0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c, -0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49, -0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20, -0x20,0x3c,0x68,0x32,0x3e,0x34,0x30,0x34,0x20,0x2d,0x20,0x50,0x61,0x67,0x65,0x20, -0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3c,0x2f,0x68,0x32,0x3e,0x0d,0x0a, -0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x53,0x6f,0x72, -0x72,0x79,0x2c,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75, -0x20,0x61,0x72,0x65,0x20,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x69,0x6e,0x67,0x20, -0x77,0x61,0x73,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x6f,0x6e, -0x20,0x74,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76, -0x65,0x72,0x2e,0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09, -0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e, -0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72, -0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65, -0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74, -0x6d,0x6c,0x3e,0x0d,0x0a,}; - -static const unsigned int dummy_align__index_html = 2; -static const unsigned char data__index_html[] = { -/* /index.html (12 chars) */ -0x2f,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x00, - -/* HTTP header */ -/* "HTTP/1.0 200 OK -" (17 bytes) */ -0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, -0x0a, -/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip) -" (63 bytes) */ -0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33, -0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e, -0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70, -0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, -/* "Content-type: text/html - -" (27 bytes) */ -0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, -0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, -/* raw file data (1751 bytes) */ -0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, -0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69, -0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, -0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f, -0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63, -0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78, -0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20, -0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22, -0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74, -0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c, -0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20, -0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, -0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, -0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69, -0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20, -0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d, -0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c, -0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f, -0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69, -0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09, -0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c, -0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49, -0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20, -0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x77, -0x65,0x62,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,0x20,0x61,0x72,0x65,0x20, -0x77,0x61,0x74,0x63,0x68,0x69,0x6e,0x67,0x20,0x77,0x61,0x73,0x20,0x73,0x65,0x72, -0x76,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x73,0x69,0x6d,0x70,0x6c,0x65,0x20, -0x77,0x65,0x62,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,0x65,0x72, -0x20,0x72,0x75,0x6e,0x6e,0x69,0x6e,0x67,0x20,0x6f,0x6e,0x20,0x74,0x6f,0x70,0x20, -0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67, -0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20,0x73,0x74,0x61,0x63,0x6b,0x20, -0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, -0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, -0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x6c, -0x77,0x49,0x50,0x3c,0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70, -0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, -0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20, -0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74, -0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50, -0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63, -0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61, -0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69, -0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20, -0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77, -0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f, -0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b, -0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65, -0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75, -0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53, -0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e, -0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e, -0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c, -0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f, -0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20, -0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77, -0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65, -0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c, -0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70, -0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69, -0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20, -0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73, -0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61, -0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61, -0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77, -0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65, -0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68, -0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75, -0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09, -0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a, -0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x66,0x6f,0x63,0x75,0x73,0x20,0x6f, -0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x54,0x43,0x50,0x2f,0x49, -0x50,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e, -0x20,0x69,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x0d,0x0a,0x09, -0x20,0x20,0x20,0x20,0x74,0x68,0x65,0x20,0x52,0x41,0x4d,0x20,0x75,0x73,0x61,0x67, -0x65,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x73,0x74,0x69,0x6c,0x6c,0x20,0x68,0x61, -0x76,0x69,0x6e,0x67,0x20,0x61,0x20,0x66,0x75,0x6c,0x6c,0x20,0x73,0x63,0x61,0x6c, -0x65,0x20,0x54,0x43,0x50,0x2e,0x20,0x54,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20, -0x20,0x20,0x6d,0x61,0x6b,0x65,0x73,0x20,0x6c,0x77,0x49,0x50,0x20,0x73,0x75,0x69, -0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,0x72,0x20,0x75,0x73,0x65,0x20,0x69,0x6e, -0x20,0x65,0x6d,0x62,0x65,0x64,0x64,0x65,0x64,0x20,0x73,0x79,0x73,0x74,0x65,0x6d, -0x73,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x65,0x6e,0x73,0x0d,0x0a,0x09,0x20,0x20, -0x20,0x20,0x6f,0x66,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x20,0x6f, -0x66,0x20,0x66,0x72,0x65,0x65,0x20,0x52,0x41,0x4d,0x20,0x61,0x6e,0x64,0x20,0x72, -0x6f,0x6f,0x6d,0x20,0x66,0x6f,0x72,0x20,0x61,0x72,0x6f,0x75,0x6e,0x64,0x20,0x34, -0x30,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x0d,0x0a,0x09,0x20,0x20, -0x20,0x20,0x6f,0x66,0x20,0x63,0x6f,0x64,0x65,0x20,0x52,0x4f,0x4d,0x2e,0x0d,0x0a, -0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d, -0x0a,0x09,0x20,0x20,0x20,0x20,0x4d,0x6f,0x72,0x65,0x20,0x69,0x6e,0x66,0x6f,0x72, -0x6d,0x61,0x74,0x69,0x6f,0x6e,0x20,0x61,0x62,0x6f,0x75,0x74,0x20,0x6c,0x77,0x49, -0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x61, -0x74,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20, -0x20,0x68,0x6f,0x6d,0x65,0x70,0x61,0x67,0x65,0x20,0x61,0x74,0x20,0x3c,0x61,0x0d, -0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70, -0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67, -0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f, -0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61, -0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72, -0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x2f, -0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x72,0x20,0x61,0x74, -0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x77,0x69,0x6b,0x69,0x20,0x61, -0x74,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d, -0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b, -0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f, -0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x3c, -0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09, -0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e, -0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72, -0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65, -0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74, -0x6d,0x6c,0x3e,0x0d,0x0a,0x0d,0x0a,}; - - - -const struct fsdata_file file__img_sics_gif[] = { { -file_NULL, -data__img_sics_gif, -data__img_sics_gif + 16, -sizeof(data__img_sics_gif) - 16, -1, -}}; - -const struct fsdata_file file__404_html[] = { { -file__img_sics_gif, -data__404_html, -data__404_html + 12, -sizeof(data__404_html) - 12, -1, -}}; - -const struct fsdata_file file__index_html[] = { { -file__404_html, -data__index_html, -data__index_html + 12, -sizeof(data__index_html) - 12, -1, -}}; - -#define FS_ROOT file__index_html -#define FS_NUMFILES 3 - diff --git a/ext/lwip/src/apps/httpd/fsdata.h b/ext/lwip/src/apps/httpd/fsdata.h deleted file mode 100644 index ac4548c..0000000 --- a/ext/lwip/src/apps/httpd/fsdata.h +++ /dev/null @@ -1,50 +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_FSDATA_H -#define LWIP_FSDATA_H - -#include "lwip/apps/httpd_opts.h" -#include "lwip/apps/fs.h" - -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 */ -}; - -#endif /* LWIP_FSDATA_H */ diff --git a/ext/lwip/src/apps/httpd/httpd.c b/ext/lwip/src/apps/httpd/httpd.c deleted file mode 100644 index 6be2573..0000000 --- a/ext/lwip/src/apps/httpd/httpd.c +++ /dev/null @@ -1,2693 +0,0 @@ -/** - * @file - * LWIP HTTP server implementation - */ - -/* - * 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 - * Simon Goldschmidt - * - */ - -/** - * @defgroup httpd HTTP server - * @ingroup apps - * - * This httpd supports for a - * rudimentary server-side-include facility which will replace tags of the form - * in any file whose extension is .shtml, .shtm or .ssi with - * strings provided by an include handler whose pointer is provided to the - * module via function http_set_ssi_handler(). - * Additionally, a simple common - * gateway interface (CGI) handling mechanism has been added to allow clients - * to hook functions to particular request URIs. - * - * To enable SSI support, define label LWIP_HTTPD_SSI in lwipopts.h. - * To enable CGI support, define label LWIP_HTTPD_CGI in lwipopts.h. - * - * By default, the server assumes that HTTP headers are already present in - * each file stored in the file system. By defining LWIP_HTTPD_DYNAMIC_HEADERS in - * lwipopts.h, this behavior can be changed such that the server inserts the - * headers automatically based on the extension of the file being served. If - * this mode is used, be careful to ensure that the file system image used - * does not already contain the header information. - * - * File system images without headers can be created using the makefsfile - * tool with the -h command line option. - * - * - * Notes about valid SSI tags - * -------------------------- - * - * The following assumptions are made about tags used in SSI markers: - * - * 1. No tag may contain '-' or whitespace characters within the tag name. - * 2. Whitespace is allowed between the tag leadin "". - * 3. The maximum tag name length is LWIP_HTTPD_MAX_TAG_NAME_LEN, currently 8 characters. - * - * Notes on CGI usage - * ------------------ - * - * The simple CGI support offered here works with GET method requests only - * and can handle up to 16 parameters encoded into the URI. The handler - * function may not write directly to the HTTP output but must return a - * filename that the HTTP server will send to the browser as a response to - * the incoming CGI request. - * - * - * - * The list of supported file types is quite short, so if makefsdata complains - * about an unknown extension, make sure to add it (and its doctype) to - * the 'g_psHTTPHeaders' list. - */ -#include "lwip/init.h" -#include "lwip/apps/httpd.h" -#include "lwip/debug.h" -#include "lwip/stats.h" -#include "lwip/apps/fs.h" -#include "httpd_structs.h" -#include "lwip/def.h" -#include "lwip/ip.h" -#include "lwip/tcp.h" - -#include -#include -#include - -#if LWIP_TCP - -/** Minimum length for a valid HTTP/0.9 request: "GET /\r\n" -> 7 bytes */ -#define MIN_REQ_LEN 7 - -#define CRLF "\r\n" -#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE -#define HTTP11_CONNECTIONKEEPALIVE "Connection: keep-alive" -#define HTTP11_CONNECTIONKEEPALIVE2 "Connection: Keep-Alive" -#endif - -/** These defines check whether tcp_write has to copy data or not */ - -/** This was TI's check whether to let TCP copy data or not - * \#define HTTP_IS_DATA_VOLATILE(hs) ((hs->file < (char *)0x20000000) ? 0 : TCP_WRITE_FLAG_COPY) - */ -#ifndef HTTP_IS_DATA_VOLATILE -#if LWIP_HTTPD_SSI -/* Copy for SSI files, no copy for non-SSI files */ -#define HTTP_IS_DATA_VOLATILE(hs) ((hs)->ssi ? TCP_WRITE_FLAG_COPY : 0) -#else /* LWIP_HTTPD_SSI */ -/** Default: don't copy if the data is sent from file-system directly */ -#define HTTP_IS_DATA_VOLATILE(hs) (((hs->file != NULL) && (hs->handle != NULL) && (hs->file == \ - (const char*)hs->handle->data + hs->handle->len - hs->left)) \ - ? 0 : TCP_WRITE_FLAG_COPY) -#endif /* LWIP_HTTPD_SSI */ -#endif - -/** Default: headers are sent from ROM */ -#ifndef HTTP_IS_HDR_VOLATILE -#define HTTP_IS_HDR_VOLATILE(hs, ptr) 0 -#endif - -/* Return values for http_send_*() */ -#define HTTP_DATA_TO_SEND_BREAK 2 -#define HTTP_DATA_TO_SEND_CONTINUE 1 -#define HTTP_NO_DATA_TO_SEND 0 - -typedef struct -{ - const char *name; - u8_t shtml; -} default_filename; - -const default_filename g_psDefaultFilenames[] = { - {"/index.shtml", 1 }, - {"/index.ssi", 1 }, - {"/index.shtm", 1 }, - {"/index.html", 0 }, - {"/index.htm", 0 } -}; - -#define NUM_DEFAULT_FILENAMES (sizeof(g_psDefaultFilenames) / \ - sizeof(default_filename)) - -#if LWIP_HTTPD_SUPPORT_REQUESTLIST -/** HTTP request is copied here from pbufs for simple parsing */ -static char httpd_req_buf[LWIP_HTTPD_MAX_REQ_LENGTH+1]; -#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ - -#if LWIP_HTTPD_SUPPORT_POST -#if LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN > LWIP_HTTPD_MAX_REQUEST_URI_LEN -#define LWIP_HTTPD_URI_BUF_LEN LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN -#endif -#endif -#ifndef LWIP_HTTPD_URI_BUF_LEN -#define LWIP_HTTPD_URI_BUF_LEN LWIP_HTTPD_MAX_REQUEST_URI_LEN -#endif -#if LWIP_HTTPD_URI_BUF_LEN -/* Filename for response file to send when POST is finished or - * search for default files when a directory is requested. */ -static char http_uri_buf[LWIP_HTTPD_URI_BUF_LEN+1]; -#endif - -#if LWIP_HTTPD_DYNAMIC_HEADERS -/* The number of individual strings that comprise the headers sent before each - * requested file. - */ -#define NUM_FILE_HDR_STRINGS 5 -#define HDR_STRINGS_IDX_HTTP_STATUS 0 /* e.g. "HTTP/1.0 200 OK\r\n" */ -#define HDR_STRINGS_IDX_SERVER_NAME 1 /* e.g. "Server: "HTTPD_SERVER_AGENT"\r\n" */ -#define HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE 2 /* e.g. "Content-Length: xy\r\n" and/or "Connection: keep-alive\r\n" */ -#define HDR_STRINGS_IDX_CONTENT_LEN_NR 3 /* the byte count, when content-length is used */ -#define HDR_STRINGS_IDX_CONTENT_TYPE 4 /* the content type (or default answer content type including default document) */ - -/* The dynamically generated Content-Length buffer needs space for CRLF + NULL */ -#define LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET 3 -#ifndef LWIP_HTTPD_MAX_CONTENT_LEN_SIZE -/* The dynamically generated Content-Length buffer shall be able to work with - ~953 MB (9 digits) */ -#define LWIP_HTTPD_MAX_CONTENT_LEN_SIZE (9 + LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET) -#endif -#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ - -#if LWIP_HTTPD_SSI - -#define HTTPD_LAST_TAG_PART 0xFFFF - -enum tag_check_state { - TAG_NONE, /* Not processing an SSI tag */ - TAG_LEADIN, /* Tag lead in "" being processed */ - TAG_SENDING /* Sending tag replacement string */ -}; - -struct http_ssi_state { - const char *parsed; /* Pointer to the first unparsed byte in buf. */ -#if !LWIP_HTTPD_SSI_INCLUDE_TAG - const char *tag_started;/* Pointer to the first opening '<' of the tag. */ -#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */ - const char *tag_end; /* Pointer to char after the closing '>' of the tag. */ - u32_t parse_left; /* Number of unparsed bytes in buf. */ - u16_t tag_index; /* Counter used by tag parsing state machine */ - u16_t tag_insert_len; /* Length of insert in string tag_insert */ -#if LWIP_HTTPD_SSI_MULTIPART - u16_t tag_part; /* Counter passed to and changed by tag insertion function to insert multiple times */ -#endif /* LWIP_HTTPD_SSI_MULTIPART */ - u8_t tag_name_len; /* Length of the tag name in string tag_name */ - char tag_name[LWIP_HTTPD_MAX_TAG_NAME_LEN + 1]; /* Last tag name extracted */ - char tag_insert[LWIP_HTTPD_MAX_TAG_INSERT_LEN + 1]; /* Insert string for tag_name */ - enum tag_check_state tag_state; /* State of the tag processor */ -}; -#endif /* LWIP_HTTPD_SSI */ - -struct http_state { -#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED - struct http_state *next; -#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ - struct fs_file file_handle; - struct fs_file *handle; - const char *file; /* Pointer to first unsent byte in buf. */ - - struct tcp_pcb *pcb; -#if LWIP_HTTPD_SUPPORT_REQUESTLIST - struct pbuf *req; -#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ - -#if LWIP_HTTPD_DYNAMIC_FILE_READ - char *buf; /* File read buffer. */ - int buf_len; /* Size of file read buffer, buf. */ -#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ - u32_t left; /* Number of unsent bytes in buf. */ - u8_t retries; -#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE - u8_t keepalive; -#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */ -#if LWIP_HTTPD_SSI - struct http_ssi_state *ssi; -#endif /* LWIP_HTTPD_SSI */ -#if LWIP_HTTPD_CGI - char *params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */ - char *param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */ -#endif /* LWIP_HTTPD_CGI */ -#if LWIP_HTTPD_DYNAMIC_HEADERS - const char *hdrs[NUM_FILE_HDR_STRINGS]; /* HTTP headers to be sent. */ - char hdr_content_len[LWIP_HTTPD_MAX_CONTENT_LEN_SIZE]; - u16_t hdr_pos; /* The position of the first unsent header byte in the - current string */ - u16_t hdr_index; /* The index of the hdr string currently being sent. */ -#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ -#if LWIP_HTTPD_TIMING - u32_t time_started; -#endif /* LWIP_HTTPD_TIMING */ -#if LWIP_HTTPD_SUPPORT_POST - u32_t post_content_len_left; -#if LWIP_HTTPD_POST_MANUAL_WND - u32_t unrecved_bytes; - u8_t no_auto_wnd; - u8_t post_finished; -#endif /* LWIP_HTTPD_POST_MANUAL_WND */ -#endif /* LWIP_HTTPD_SUPPORT_POST*/ -}; - -#if HTTPD_USE_MEM_POOL -LWIP_MEMPOOL_DECLARE(HTTPD_STATE, MEMP_NUM_PARALLEL_HTTPD_CONNS, sizeof(struct http_state), "HTTPD_STATE") -#if LWIP_HTTPD_SSI -LWIP_MEMPOOL_DECLARE(HTTPD_SSI_STATE, MEMP_NUM_PARALLEL_HTTPD_SSI_CONNS, sizeof(struct http_ssi_state), "HTTPD_SSI_STATE") -#define HTTP_FREE_SSI_STATE(x) LWIP_MEMPOOL_FREE(HTTPD_SSI_STATE, (x)) -#define HTTP_ALLOC_SSI_STATE() (struct http_ssi_state *)LWIP_MEMPOOL_ALLOC(HTTPD_SSI_STATE) -#endif /* LWIP_HTTPD_SSI */ -#define HTTP_ALLOC_HTTP_STATE() (struct http_state *)LWIP_MEMPOOL_ALLOC(HTTPD_STATE) -#define HTTP_FREE_HTTP_STATE(x) LWIP_MEMPOOL_FREE(HTTPD_STATE, (x)) -#else /* HTTPD_USE_MEM_POOL */ -#define HTTP_ALLOC_HTTP_STATE() (struct http_state *)mem_malloc(sizeof(struct http_state)) -#define HTTP_FREE_HTTP_STATE(x) mem_free(x) -#if LWIP_HTTPD_SSI -#define HTTP_ALLOC_SSI_STATE() (struct http_ssi_state *)mem_malloc(sizeof(struct http_ssi_state)) -#define HTTP_FREE_SSI_STATE(x) mem_free(x) -#endif /* LWIP_HTTPD_SSI */ -#endif /* HTTPD_USE_MEM_POOL */ - -static err_t http_close_conn(struct tcp_pcb *pcb, struct http_state *hs); -static err_t http_close_or_abort_conn(struct tcp_pcb *pcb, struct http_state *hs, u8_t abort_conn); -static err_t http_find_file(struct http_state *hs, const char *uri, int is_09); -static err_t http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri, u8_t tag_check, char* params); -static err_t http_poll(void *arg, struct tcp_pcb *pcb); -static u8_t http_check_eof(struct tcp_pcb *pcb, struct http_state *hs); -#if LWIP_HTTPD_FS_ASYNC_READ -static void http_continue(void *connection); -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ - -#if LWIP_HTTPD_SSI -/* SSI insert handler function pointer. */ -tSSIHandler g_pfnSSIHandler; -#if !LWIP_HTTPD_SSI_RAW -int g_iNumTags; -const char **g_ppcTags; -#endif /* !LWIP_HTTPD_SSI_RAW */ - -#define LEN_TAG_LEAD_IN 5 -const char * const g_pcTagLeadIn = ""; -#endif /* LWIP_HTTPD_SSI */ - -#if LWIP_HTTPD_CGI -/* CGI handler information */ -const tCGI *g_pCGIs; -int g_iNumCGIs; -int http_cgi_paramcount; -#define http_cgi_params hs->params -#define http_cgi_param_vals hs->param_vals -#elif LWIP_HTTPD_CGI_SSI -char *http_cgi_params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */ -char *http_cgi_param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */ -#endif /* LWIP_HTTPD_CGI */ - -#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED -/** global list of active HTTP connections, use to kill the oldest when - running out of memory */ -static struct http_state *http_connections; -#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ - -#if LWIP_HTTPD_STRNSTR_PRIVATE -/** Like strstr but does not need 'buffer' to be NULL-terminated */ -static char* -strnstr(const char* buffer, const char* token, size_t n) -{ - const char* p; - int tokenlen = (int)strlen(token); - if (tokenlen == 0) { - return (char *)(size_t)buffer; - } - for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) { - if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) { - return (char *)(size_t)p; - } - } - return NULL; -} -#endif /* LWIP_HTTPD_STRNSTR_PRIVATE */ - -#if LWIP_HTTPD_STRICMP_PRIVATE -static int -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 /* LWIP_HTTPD_STRICMP_PRIVATE */ - -#if LWIP_HTTPD_ITOA_PRIVATE && LWIP_HTTPD_DYNAMIC_HEADERS -static void -httpd_itoa(int value, char* result) -{ - const int base = 10; - char* ptr = result, *ptr1 = result, tmp_char; - int tmp_value; - - do { - tmp_value = value; - value /= base; - *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)]; - } while(value); - - /* Apply negative sign */ - if (tmp_value < 0) { - *ptr++ = '-'; - } - *ptr-- = '\0'; - while(ptr1 < ptr) { - tmp_char = *ptr; - *ptr--= *ptr1; - *ptr1++ = tmp_char; - } -} -#endif - -#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED -static void -http_kill_oldest_connection(u8_t ssi_required) -{ - struct http_state *hs = http_connections; - struct http_state *hs_free_next = NULL; - while(hs && hs->next) { -#if LWIP_HTTPD_SSI - if (ssi_required) { - if (hs->next->ssi != NULL) { - hs_free_next = hs; - } - } else -#else /* LWIP_HTTPD_SSI */ - LWIP_UNUSED_ARG(ssi_required); -#endif /* LWIP_HTTPD_SSI */ - { - hs_free_next = hs; - } - LWIP_ASSERT("broken list", hs != hs->next); - hs = hs->next; - } - if (hs_free_next != NULL) { - LWIP_ASSERT("hs_free_next->next != NULL", hs_free_next->next != NULL); - LWIP_ASSERT("hs_free_next->next->pcb != NULL", hs_free_next->next->pcb != NULL); - /* send RST when killing a connection because of memory shortage */ - http_close_or_abort_conn(hs_free_next->next->pcb, hs_free_next->next, 1); /* this also unlinks the http_state from the list */ - } -} -#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ - -#if LWIP_HTTPD_SSI -/** Allocate as struct http_ssi_state. */ -static struct http_ssi_state* -http_ssi_state_alloc(void) -{ - struct http_ssi_state *ret = HTTP_ALLOC_SSI_STATE(); -#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED - if (ret == NULL) { - http_kill_oldest_connection(1); - ret = HTTP_ALLOC_SSI_STATE(); - } -#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ - if (ret != NULL) { - memset(ret, 0, sizeof(struct http_ssi_state)); - } - return ret; -} - -/** Free a struct http_ssi_state. */ -static void -http_ssi_state_free(struct http_ssi_state *ssi) -{ - if (ssi != NULL) { - HTTP_FREE_SSI_STATE(ssi); - } -} -#endif /* LWIP_HTTPD_SSI */ - -/** Initialize a struct http_state. - */ -static void -http_state_init(struct http_state* hs) -{ - /* Initialize the structure. */ - memset(hs, 0, sizeof(struct http_state)); -#if LWIP_HTTPD_DYNAMIC_HEADERS - /* Indicate that the headers are not yet valid */ - hs->hdr_index = NUM_FILE_HDR_STRINGS; -#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ -} - -/** Allocate a struct http_state. */ -static struct http_state* -http_state_alloc(void) -{ - struct http_state *ret = HTTP_ALLOC_HTTP_STATE(); -#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED - if (ret == NULL) { - http_kill_oldest_connection(0); - ret = HTTP_ALLOC_HTTP_STATE(); - } -#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ - if (ret != NULL) { - http_state_init(ret); -#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED - /* add the connection to the list */ - if (http_connections == NULL) { - http_connections = ret; - } else { - struct http_state *last; - for(last = http_connections; last->next != NULL; last = last->next); - LWIP_ASSERT("last != NULL", last != NULL); - last->next = ret; - } -#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ - } - return ret; -} - -/** Free a struct http_state. - * Also frees the file data if dynamic. - */ -static void -http_state_eof(struct http_state *hs) -{ - if(hs->handle) { -#if LWIP_HTTPD_TIMING - u32_t ms_needed = sys_now() - hs->time_started; - u32_t needed = LWIP_MAX(1, (ms_needed/100)); - LWIP_DEBUGF(HTTPD_DEBUG_TIMING, ("httpd: needed %"U32_F" ms to send file of %d bytes -> %"U32_F" bytes/sec\n", - ms_needed, hs->handle->len, ((((u32_t)hs->handle->len) * 10) / needed))); -#endif /* LWIP_HTTPD_TIMING */ - fs_close(hs->handle); - hs->handle = NULL; - } -#if LWIP_HTTPD_DYNAMIC_FILE_READ - if (hs->buf != NULL) { - mem_free(hs->buf); - hs->buf = NULL; - } -#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ -#if LWIP_HTTPD_SSI - if (hs->ssi) { - http_ssi_state_free(hs->ssi); - hs->ssi = NULL; - } -#endif /* LWIP_HTTPD_SSI */ -#if LWIP_HTTPD_SUPPORT_REQUESTLIST - if (hs->req) { - pbuf_free(hs->req); - hs->req = NULL; - } -#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ -} - -/** Free a struct http_state. - * Also frees the file data if dynamic. - */ -static void -http_state_free(struct http_state *hs) -{ - if (hs != NULL) { - http_state_eof(hs); -#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED - /* take the connection off the list */ - if (http_connections) { - if (http_connections == hs) { - http_connections = hs->next; - } else { - struct http_state *last; - for(last = http_connections; last->next != NULL; last = last->next) { - if (last->next == hs) { - last->next = hs->next; - break; - } - } - } - } -#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ - HTTP_FREE_HTTP_STATE(hs); - } -} - -/** Call tcp_write() in a loop trying smaller and smaller length - * - * @param pcb tcp_pcb to send - * @param ptr Data to send - * @param length Length of data to send (in/out: on return, contains the - * amount of data sent) - * @param apiflags directly passed to tcp_write - * @return the return value of tcp_write - */ -static err_t -http_write(struct tcp_pcb *pcb, const void* ptr, u16_t *length, u8_t apiflags) -{ - u16_t len, max_len; - err_t err; - LWIP_ASSERT("length != NULL", length != NULL); - len = *length; - if (len == 0) { - return ERR_OK; - } - /* We cannot send more data than space available in the send buffer. */ - max_len = tcp_sndbuf(pcb); - if (max_len < len) { - len = max_len; - } -#ifdef HTTPD_MAX_WRITE_LEN - /* Additional limitation: e.g. don't enqueue more than 2*mss at once */ - max_len = HTTPD_MAX_WRITE_LEN(pcb); - if(len > max_len) { - len = max_len; - } -#endif /* HTTPD_MAX_WRITE_LEN */ - do { - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Trying go send %d bytes\n", len)); - err = tcp_write(pcb, ptr, len, apiflags); - if (err == ERR_MEM) { - if ((tcp_sndbuf(pcb) == 0) || - (tcp_sndqueuelen(pcb) >= TCP_SND_QUEUELEN)) { - /* no need to try smaller sizes */ - len = 1; - } else { - len /= 2; - } - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, - ("Send failed, trying less (%d bytes)\n", len)); - } - } while ((err == ERR_MEM) && (len > 1)); - - if (err == ERR_OK) { - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Sent %d bytes\n", len)); - *length = len; - } else { - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Send failed with err %d (\"%s\")\n", err, lwip_strerr(err))); - *length = 0; - } - -#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE - /* ensure nagle is normally enabled (only disabled for persistent connections - when all data has been enqueued but the connection stays open for the next - request */ - tcp_nagle_enable(pcb); -#endif - - return err; -} - -/** - * The connection shall be actively closed (using RST to close from fault states). - * Reset the sent- and recv-callbacks. - * - * @param pcb the tcp pcb to reset callbacks - * @param hs connection state to free - */ -static err_t -http_close_or_abort_conn(struct tcp_pcb *pcb, struct http_state *hs, u8_t abort_conn) -{ - err_t err; - LWIP_DEBUGF(HTTPD_DEBUG, ("Closing connection %p\n", (void*)pcb)); - -#if LWIP_HTTPD_SUPPORT_POST - if (hs != NULL) { - if ((hs->post_content_len_left != 0) -#if LWIP_HTTPD_POST_MANUAL_WND - || ((hs->no_auto_wnd != 0) && (hs->unrecved_bytes != 0)) -#endif /* LWIP_HTTPD_POST_MANUAL_WND */ - ) { - /* make sure the post code knows that the connection is closed */ - http_uri_buf[0] = 0; - httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN); - } - } -#endif /* LWIP_HTTPD_SUPPORT_POST*/ - - - tcp_arg(pcb, NULL); - tcp_recv(pcb, NULL); - tcp_err(pcb, NULL); - tcp_poll(pcb, NULL, 0); - tcp_sent(pcb, NULL); - if (hs != NULL) { - http_state_free(hs); - } - - if (abort_conn) { - tcp_abort(pcb); - return ERR_OK; - } - err = tcp_close(pcb); - if (err != ERR_OK) { - LWIP_DEBUGF(HTTPD_DEBUG, ("Error %d closing %p\n", err, (void*)pcb)); - /* error closing, try again later in poll */ - tcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL); - } - return err; -} - -/** - * The connection shall be actively closed. - * Reset the sent- and recv-callbacks. - * - * @param pcb the tcp pcb to reset callbacks - * @param hs connection state to free - */ -static err_t -http_close_conn(struct tcp_pcb *pcb, struct http_state *hs) -{ - return http_close_or_abort_conn(pcb, hs, 0); -} - -/** End of file: either close the connection (Connection: close) or - * close the file (Connection: keep-alive) - */ -static void -http_eof(struct tcp_pcb *pcb, struct http_state *hs) -{ - /* HTTP/1.1 persistent connection? (Not supported for SSI) */ -#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE - if (hs->keepalive) { -#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED - struct http_state* next = hs->next; -#endif - http_state_eof(hs); - http_state_init(hs); - /* restore state: */ -#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED - hs->next = next; -#endif - hs->pcb = pcb; - hs->keepalive = 1; - /* ensure nagle doesn't interfere with sending all data as fast as possible: */ - tcp_nagle_disable(pcb); - } else -#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */ - { - http_close_conn(pcb, hs); - } -} - -#if LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI -/** - * Extract URI parameters from the parameter-part of an URI in the form - * "test.cgi?x=y" @todo: better explanation! - * Pointers to the parameters are stored in hs->param_vals. - * - * @param hs http connection state - * @param params pointer to the NULL-terminated parameter string from the URI - * @return number of parameters extracted - */ -static int -extract_uri_parameters(struct http_state *hs, char *params) -{ - char *pair; - char *equals; - int loop; - - LWIP_UNUSED_ARG(hs); - - /* If we have no parameters at all, return immediately. */ - if(!params || (params[0] == '\0')) { - return(0); - } - - /* Get a pointer to our first parameter */ - pair = params; - - /* Parse up to LWIP_HTTPD_MAX_CGI_PARAMETERS from the passed string and ignore the - * remainder (if any) */ - for(loop = 0; (loop < LWIP_HTTPD_MAX_CGI_PARAMETERS) && pair; loop++) { - - /* Save the name of the parameter */ - http_cgi_params[loop] = pair; - - /* Remember the start of this name=value pair */ - equals = pair; - - /* Find the start of the next name=value pair and replace the delimiter - * with a 0 to terminate the previous pair string. */ - pair = strchr(pair, '&'); - if(pair) { - *pair = '\0'; - pair++; - } else { - /* We didn't find a new parameter so find the end of the URI and - * replace the space with a '\0' */ - pair = strchr(equals, ' '); - if(pair) { - *pair = '\0'; - } - - /* Revert to NULL so that we exit the loop as expected. */ - pair = NULL; - } - - /* Now find the '=' in the previous pair, replace it with '\0' and save - * the parameter value string. */ - equals = strchr(equals, '='); - if(equals) { - *equals = '\0'; - http_cgi_param_vals[loop] = equals + 1; - } else { - http_cgi_param_vals[loop] = NULL; - } - } - - return loop; -} -#endif /* LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI */ - -#if LWIP_HTTPD_SSI -/** - * Insert a tag (found in an shtml in the form of "" into the file. - * The tag's name is stored in ssi->tag_name (NULL-terminated), the replacement - * should be written to hs->tag_insert (up to a length of LWIP_HTTPD_MAX_TAG_INSERT_LEN). - * The amount of data written is stored to ssi->tag_insert_len. - * - * @todo: return tag_insert_len - maybe it can be removed from struct http_state? - * - * @param hs http connection state - */ -static void -get_tag_insert(struct http_state *hs) -{ -#if LWIP_HTTPD_SSI_RAW - const char* tag; -#else /* LWIP_HTTPD_SSI_RAW */ - int tag; -#endif /* LWIP_HTTPD_SSI_RAW */ - size_t len; - struct http_ssi_state *ssi; -#if LWIP_HTTPD_SSI_MULTIPART - u16_t current_tag_part; -#endif /* LWIP_HTTPD_SSI_MULTIPART */ - - LWIP_ASSERT("hs != NULL", hs != NULL); - ssi = hs->ssi; - LWIP_ASSERT("ssi != NULL", ssi != NULL); -#if LWIP_HTTPD_SSI_MULTIPART - current_tag_part = ssi->tag_part; - ssi->tag_part = HTTPD_LAST_TAG_PART; -#endif /* LWIP_HTTPD_SSI_MULTIPART */ -#if LWIP_HTTPD_SSI_RAW - tag = ssi->tag_name; -#endif - - if(g_pfnSSIHandler -#if !LWIP_HTTPD_SSI_RAW - && g_ppcTags && g_iNumTags -#endif /* !LWIP_HTTPD_SSI_RAW */ - ) { - - /* Find this tag in the list we have been provided. */ -#if LWIP_HTTPD_SSI_RAW - { -#else /* LWIP_HTTPD_SSI_RAW */ - for(tag = 0; tag < g_iNumTags; tag++) { - if(strcmp(ssi->tag_name, g_ppcTags[tag]) == 0) -#endif /* LWIP_HTTPD_SSI_RAW */ - { - ssi->tag_insert_len = g_pfnSSIHandler(tag, ssi->tag_insert, - LWIP_HTTPD_MAX_TAG_INSERT_LEN -#if LWIP_HTTPD_SSI_MULTIPART - , current_tag_part, &ssi->tag_part -#endif /* LWIP_HTTPD_SSI_MULTIPART */ -#if LWIP_HTTPD_FILE_STATE - , (hs->handle ? hs->handle->state : NULL) -#endif /* LWIP_HTTPD_FILE_STATE */ - ); -#if LWIP_HTTPD_SSI_RAW - if (ssi->tag_insert_len != HTTPD_SSI_TAG_UNKNOWN) -#endif /* LWIP_HTTPD_SSI_RAW */ - { - return; - } - } - } - } - - /* If we drop out, we were asked to serve a page which contains tags that - * we don't have a handler for. Merely echo back the tags with an error - * marker. */ -#define UNKNOWN_TAG1_TEXT "***UNKNOWN TAG " -#define UNKNOWN_TAG1_LEN 18 -#define UNKNOWN_TAG2_TEXT "***" -#define UNKNOWN_TAG2_LEN 7 - len = LWIP_MIN(sizeof(ssi->tag_name), LWIP_MIN(strlen(ssi->tag_name), - LWIP_HTTPD_MAX_TAG_INSERT_LEN - (UNKNOWN_TAG1_LEN + UNKNOWN_TAG2_LEN))); - MEMCPY(ssi->tag_insert, UNKNOWN_TAG1_TEXT, UNKNOWN_TAG1_LEN); - MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN], ssi->tag_name, len); - MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN + len], UNKNOWN_TAG2_TEXT, UNKNOWN_TAG2_LEN); - ssi->tag_insert[UNKNOWN_TAG1_LEN + len + UNKNOWN_TAG2_LEN] = 0; - - len = strlen(ssi->tag_insert); - LWIP_ASSERT("len <= 0xffff", len <= 0xffff); - ssi->tag_insert_len = (u16_t)len; -} -#endif /* LWIP_HTTPD_SSI */ - -#if LWIP_HTTPD_DYNAMIC_HEADERS -/** - * Generate the relevant HTTP headers for the given filename and write - * them into the supplied buffer. - */ -static void -get_http_headers(struct http_state *hs, const char *uri) -{ - size_t content_type; - char *tmp; - char *ext; - char *vars; - u8_t add_content_len; - - /* In all cases, the second header we send is the server identification - so set it here. */ - hs->hdrs[HDR_STRINGS_IDX_SERVER_NAME] = g_psHTTPHeaderStrings[HTTP_HDR_SERVER]; - hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = NULL; - hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_NR] = NULL; - - /* Is this a normal file or the special case we use to send back the - default "404: Page not found" response? */ - if (uri == NULL) { - hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND]; -#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE - if (hs->keepalive) { - hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaderStrings[DEFAULT_404_HTML_PERSISTENT]; - } else -#endif - { - hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaderStrings[DEFAULT_404_HTML]; - } - - /* Set up to send the first header string. */ - hs->hdr_index = 0; - hs->hdr_pos = 0; - return; - } - /* We are dealing with a particular filename. Look for one other - special case. We assume that any filename with "404" in it must be - indicative of a 404 server error whereas all other files require - the 200 OK header. */ - if (strstr(uri, "404")) { - hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND]; - } else if (strstr(uri, "400")) { - hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_BAD_REQUEST]; - } else if (strstr(uri, "501")) { - hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_IMPL]; - } else { - hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_OK]; - } - - /* Determine if the URI has any variables and, if so, temporarily remove - them. */ - vars = strchr(uri, '?'); - if(vars) { - *vars = '\0'; - } - - /* Get a pointer to the file extension. We find this by looking for the - last occurrence of "." in the filename passed. */ - ext = NULL; - tmp = strchr(uri, '.'); - while (tmp) { - ext = tmp + 1; - tmp = strchr(ext, '.'); - } - if (ext != NULL) { - /* Now determine the content type and add the relevant header for that. */ - for (content_type = 0; content_type < NUM_HTTP_HEADERS; content_type++) { - /* Have we found a matching extension? */ - if(!stricmp(g_psHTTPHeaders[content_type].extension, ext)) { - break; - } - } - } else { - content_type = NUM_HTTP_HEADERS; - } - - /* Reinstate the parameter marker if there was one in the original URI. */ - if (vars) { - *vars = '?'; - } - -#if LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI - /* Does the URL passed have any file extension? If not, we assume it - is a special-case URL used for control state notification and we do - not send any HTTP headers with the response. */ - if (!ext) { - /* Force the header index to a value indicating that all headers - have already been sent. */ - hs->hdr_index = NUM_FILE_HDR_STRINGS; - return; - } -#endif /* LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI */ - add_content_len = 1; - /* Did we find a matching extension? */ - if(content_type < NUM_HTTP_HEADERS) { - /* yes, store it */ - hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaders[content_type].content_type; - } else if (!ext) { - /* no, no extension found -> use binary transfer to prevent the browser adding '.txt' on save */ - hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = HTTP_HDR_APP; - } else { - /* No - use the default, plain text file type. */ - hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = HTTP_HDR_DEFAULT_TYPE; - } - /* Add content-length header? */ -#if LWIP_HTTPD_SSI - if (hs->ssi != NULL) { - add_content_len = 0; /* @todo: get maximum file length from SSI */ - } else -#endif /* LWIP_HTTPD_SSI */ - if ((hs->handle == NULL) || - ((hs->handle->flags & (FS_FILE_FLAGS_HEADER_INCLUDED|FS_FILE_FLAGS_HEADER_PERSISTENT)) == FS_FILE_FLAGS_HEADER_INCLUDED)) { - add_content_len = 0; - } - if (add_content_len) { - size_t len; - LWIP_HTTPD_ITOA(hs->hdr_content_len, (size_t)LWIP_HTTPD_MAX_CONTENT_LEN_SIZE, - hs->handle->len); - len = strlen(hs->hdr_content_len); - if (len <= LWIP_HTTPD_MAX_CONTENT_LEN_SIZE - LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET) { - SMEMCPY(&hs->hdr_content_len[len], CRLF "\0", 3); - hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_NR] = hs->hdr_content_len; - } else { - add_content_len = 0; - } - } -#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE - if (add_content_len) { - hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_KEEPALIVE_LEN]; - } else { - hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE]; - } -#else /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */ - if (add_content_len) { - hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH]; - } -#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */ - - /* Set up to send the first header string. */ - hs->hdr_index = 0; - hs->hdr_pos = 0; -} - -/** Sub-function of http_send(): send dynamic headers - * - * @returns: - HTTP_NO_DATA_TO_SEND: no new data has been enqueued - * - HTTP_DATA_TO_SEND_CONTINUE: continue with sending HTTP body - * - HTTP_DATA_TO_SEND_BREAK: data has been enqueued, headers pending, - * so don't send HTTP body yet - */ -static u8_t -http_send_headers(struct tcp_pcb *pcb, struct http_state *hs) -{ - err_t err; - u16_t len; - u8_t data_to_send = HTTP_NO_DATA_TO_SEND; - u16_t hdrlen, sendlen; - - /* How much data can we send? */ - len = tcp_sndbuf(pcb); - sendlen = len; - - while(len && (hs->hdr_index < NUM_FILE_HDR_STRINGS) && sendlen) { - const void *ptr; - u16_t old_sendlen; - u8_t apiflags; - /* How much do we have to send from the current header? */ - hdrlen = (u16_t)strlen(hs->hdrs[hs->hdr_index]); - - /* How much of this can we send? */ - sendlen = (len < (hdrlen - hs->hdr_pos)) ? len : (hdrlen - hs->hdr_pos); - - /* Send this amount of data or as much as we can given memory - * constraints. */ - ptr = (const void *)(hs->hdrs[hs->hdr_index] + hs->hdr_pos); - old_sendlen = sendlen; - apiflags = HTTP_IS_HDR_VOLATILE(hs, ptr); - if (hs->hdr_index == HDR_STRINGS_IDX_CONTENT_LEN_NR) { - /* content-length is always volatile */ - apiflags |= TCP_WRITE_FLAG_COPY; - } - if (hs->hdr_index < NUM_FILE_HDR_STRINGS - 1) { - apiflags |= TCP_WRITE_FLAG_MORE; - } - err = http_write(pcb, ptr, &sendlen, apiflags); - if ((err == ERR_OK) && (old_sendlen != sendlen)) { - /* Remember that we added some more data to be transmitted. */ - data_to_send = HTTP_DATA_TO_SEND_CONTINUE; - } else if (err != ERR_OK) { - /* special case: http_write does not try to send 1 byte */ - sendlen = 0; - } - - /* Fix up the header position for the next time round. */ - hs->hdr_pos += sendlen; - len -= sendlen; - - /* Have we finished sending this string? */ - if(hs->hdr_pos == hdrlen) { - /* Yes - move on to the next one */ - hs->hdr_index++; - /* skip headers that are NULL (not all headers are required) */ - while ((hs->hdr_index < NUM_FILE_HDR_STRINGS) && - (hs->hdrs[hs->hdr_index] == NULL)) { - hs->hdr_index++; - } - hs->hdr_pos = 0; - } - } - - if ((hs->hdr_index >= NUM_FILE_HDR_STRINGS) && (hs->file == NULL)) { - /* When we are at the end of the headers, check for data to send - * instead of waiting for ACK from remote side to continue - * (which would happen when sending files from async read). */ - if(http_check_eof(pcb, hs)) { - data_to_send = HTTP_DATA_TO_SEND_CONTINUE; - } - } - /* If we get here and there are still header bytes to send, we send - * the header information we just wrote immediately. If there are no - * more headers to send, but we do have file data to send, drop through - * to try to send some file data too. */ - if((hs->hdr_index < NUM_FILE_HDR_STRINGS) || !hs->file) { - LWIP_DEBUGF(HTTPD_DEBUG, ("tcp_output\n")); - return HTTP_DATA_TO_SEND_BREAK; - } - return data_to_send; -} -#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ - -/** Sub-function of http_send(): end-of-file (or block) is reached, - * either close the file or read the next block (if supported). - * - * @returns: 0 if the file is finished or no data has been read - * 1 if the file is not finished and data has been read - */ -static u8_t -http_check_eof(struct tcp_pcb *pcb, struct http_state *hs) -{ - int bytes_left; -#if LWIP_HTTPD_DYNAMIC_FILE_READ - int count; -#ifdef HTTPD_MAX_WRITE_LEN - int max_write_len; -#endif /* HTTPD_MAX_WRITE_LEN */ -#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ - - /* Do we have a valid file handle? */ - if (hs->handle == NULL) { - /* No - close the connection. */ - http_eof(pcb, hs); - return 0; - } - bytes_left = fs_bytes_left(hs->handle); - if (bytes_left <= 0) { - /* We reached the end of the file so this request is done. */ - LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n")); - http_eof(pcb, hs); - return 0; - } -#if LWIP_HTTPD_DYNAMIC_FILE_READ - /* Do we already have a send buffer allocated? */ - if(hs->buf) { - /* Yes - get the length of the buffer */ - count = LWIP_MIN(hs->buf_len, bytes_left); - } else { - /* We don't have a send buffer so allocate one now */ - count = tcp_sndbuf(pcb); - if(bytes_left < count) { - count = bytes_left; - } -#ifdef HTTPD_MAX_WRITE_LEN - /* Additional limitation: e.g. don't enqueue more than 2*mss at once */ - max_write_len = HTTPD_MAX_WRITE_LEN(pcb); - if (count > max_write_len) { - count = max_write_len; - } -#endif /* HTTPD_MAX_WRITE_LEN */ - do { - hs->buf = (char*)mem_malloc((mem_size_t)count); - if (hs->buf != NULL) { - hs->buf_len = count; - break; - } - count = count / 2; - } while (count > 100); - - /* Did we get a send buffer? If not, return immediately. */ - if (hs->buf == NULL) { - LWIP_DEBUGF(HTTPD_DEBUG, ("No buff\n")); - return 0; - } - } - - /* Read a block of data from the file. */ - LWIP_DEBUGF(HTTPD_DEBUG, ("Trying to read %d bytes.\n", count)); - -#if LWIP_HTTPD_FS_ASYNC_READ - count = fs_read_async(hs->handle, hs->buf, count, http_continue, hs); -#else /* LWIP_HTTPD_FS_ASYNC_READ */ - count = fs_read(hs->handle, hs->buf, count); -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ - if (count < 0) { - if (count == FS_READ_DELAYED) { - /* Delayed read, wait for FS to unblock us */ - return 0; - } - /* We reached the end of the file so this request is done. - * @todo: close here for HTTP/1.1 when reading file fails */ - LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n")); - http_eof(pcb, hs); - return 0; - } - - /* Set up to send the block of data we just read */ - LWIP_DEBUGF(HTTPD_DEBUG, ("Read %d bytes.\n", count)); - hs->left = count; - hs->file = hs->buf; -#if LWIP_HTTPD_SSI - if (hs->ssi) { - hs->ssi->parse_left = count; - hs->ssi->parsed = hs->buf; - } -#endif /* LWIP_HTTPD_SSI */ -#else /* LWIP_HTTPD_DYNAMIC_FILE_READ */ - LWIP_ASSERT("SSI and DYNAMIC_HEADERS turned off but eof not reached", 0); -#endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */ - return 1; -} - -/** Sub-function of http_send(): This is the normal send-routine for non-ssi files - * - * @returns: - 1: data has been written (so call tcp_ouput) - * - 0: no data has been written (no need to call tcp_output) - */ -static u8_t -http_send_data_nonssi(struct tcp_pcb *pcb, struct http_state *hs) -{ - err_t err; - u16_t len; - u8_t data_to_send = 0; - - /* We are not processing an SHTML file so no tag checking is necessary. - * Just send the data as we received it from the file. */ - len = (u16_t)LWIP_MIN(hs->left, 0xffff); - - err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); - if (err == ERR_OK) { - data_to_send = 1; - hs->file += len; - hs->left -= len; - } - - return data_to_send; -} - -#if LWIP_HTTPD_SSI -/** Sub-function of http_send(): This is the send-routine for ssi files - * - * @returns: - 1: data has been written (so call tcp_ouput) - * - 0: no data has been written (no need to call tcp_output) - */ -static u8_t -http_send_data_ssi(struct tcp_pcb *pcb, struct http_state *hs) -{ - err_t err = ERR_OK; - u16_t len; - u8_t data_to_send = 0; - - struct http_ssi_state *ssi = hs->ssi; - LWIP_ASSERT("ssi != NULL", ssi != NULL); - /* We are processing an SHTML file so need to scan for tags and replace - * them with insert strings. We need to be careful here since a tag may - * straddle the boundary of two blocks read from the file and we may also - * have to split the insert string between two tcp_write operations. */ - - /* How much data could we send? */ - len = tcp_sndbuf(pcb); - - /* Do we have remaining data to send before parsing more? */ - if(ssi->parsed > hs->file) { - len = (u16_t)LWIP_MIN(ssi->parsed - hs->file, 0xffff); - - err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); - if (err == ERR_OK) { - data_to_send = 1; - hs->file += len; - hs->left -= len; - } - - /* If the send buffer is full, return now. */ - if(tcp_sndbuf(pcb) == 0) { - return data_to_send; - } - } - - LWIP_DEBUGF(HTTPD_DEBUG, ("State %d, %d left\n", ssi->tag_state, (int)ssi->parse_left)); - - /* We have sent all the data that was already parsed so continue parsing - * the buffer contents looking for SSI tags. */ - while((ssi->parse_left) && (err == ERR_OK)) { - if (len == 0) { - return data_to_send; - } - switch(ssi->tag_state) { - case TAG_NONE: - /* We are not currently processing an SSI tag so scan for the - * start of the lead-in marker. */ - if(*ssi->parsed == g_pcTagLeadIn[0]) { - /* We found what could be the lead-in for a new tag so change - * state appropriately. */ - ssi->tag_state = TAG_LEADIN; - ssi->tag_index = 1; -#if !LWIP_HTTPD_SSI_INCLUDE_TAG - ssi->tag_started = ssi->parsed; -#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */ - } - - /* Move on to the next character in the buffer */ - ssi->parse_left--; - ssi->parsed++; - break; - - case TAG_LEADIN: - /* We are processing the lead-in marker, looking for the start of - * the tag name. */ - - /* Have we reached the end of the leadin? */ - if(ssi->tag_index == LEN_TAG_LEAD_IN) { - ssi->tag_index = 0; - ssi->tag_state = TAG_FOUND; - } else { - /* Have we found the next character we expect for the tag leadin? */ - if(*ssi->parsed == g_pcTagLeadIn[ssi->tag_index]) { - /* Yes - move to the next one unless we have found the complete - * leadin, in which case we start looking for the tag itself */ - ssi->tag_index++; - } else { - /* We found an unexpected character so this is not a tag. Move - * back to idle state. */ - ssi->tag_state = TAG_NONE; - } - - /* Move on to the next character in the buffer */ - ssi->parse_left--; - ssi->parsed++; - } - break; - - case TAG_FOUND: - /* We are reading the tag name, looking for the start of the - * lead-out marker and removing any whitespace found. */ - - /* Remove leading whitespace between the tag leading and the first - * tag name character. */ - if((ssi->tag_index == 0) && ((*ssi->parsed == ' ') || - (*ssi->parsed == '\t') || (*ssi->parsed == '\n') || - (*ssi->parsed == '\r'))) { - /* Move on to the next character in the buffer */ - ssi->parse_left--; - ssi->parsed++; - break; - } - - /* Have we found the end of the tag name? This is signalled by - * us finding the first leadout character or whitespace */ - if((*ssi->parsed == g_pcTagLeadOut[0]) || - (*ssi->parsed == ' ') || (*ssi->parsed == '\t') || - (*ssi->parsed == '\n') || (*ssi->parsed == '\r')) { - - if(ssi->tag_index == 0) { - /* We read a zero length tag so ignore it. */ - ssi->tag_state = TAG_NONE; - } else { - /* We read a non-empty tag so go ahead and look for the - * leadout string. */ - ssi->tag_state = TAG_LEADOUT; - LWIP_ASSERT("ssi->tag_index <= 0xff", ssi->tag_index <= 0xff); - ssi->tag_name_len = (u8_t)ssi->tag_index; - ssi->tag_name[ssi->tag_index] = '\0'; - if(*ssi->parsed == g_pcTagLeadOut[0]) { - ssi->tag_index = 1; - } else { - ssi->tag_index = 0; - } - } - } else { - /* This character is part of the tag name so save it */ - if(ssi->tag_index < LWIP_HTTPD_MAX_TAG_NAME_LEN) { - ssi->tag_name[ssi->tag_index++] = *ssi->parsed; - } else { - /* The tag was too long so ignore it. */ - ssi->tag_state = TAG_NONE; - } - } - - /* Move on to the next character in the buffer */ - ssi->parse_left--; - ssi->parsed++; - - break; - - /* We are looking for the end of the lead-out marker. */ - case TAG_LEADOUT: - /* Remove leading whitespace between the tag leading and the first - * tag leadout character. */ - if((ssi->tag_index == 0) && ((*ssi->parsed == ' ') || - (*ssi->parsed == '\t') || (*ssi->parsed == '\n') || - (*ssi->parsed == '\r'))) { - /* Move on to the next character in the buffer */ - ssi->parse_left--; - ssi->parsed++; - break; - } - - /* Have we found the next character we expect for the tag leadout? */ - if(*ssi->parsed == g_pcTagLeadOut[ssi->tag_index]) { - /* Yes - move to the next one unless we have found the complete - * leadout, in which case we need to call the client to process - * the tag. */ - - /* Move on to the next character in the buffer */ - ssi->parse_left--; - ssi->parsed++; - - if(ssi->tag_index == (LEN_TAG_LEAD_OUT - 1)) { - /* Call the client to ask for the insert string for the - * tag we just found. */ -#if LWIP_HTTPD_SSI_MULTIPART - ssi->tag_part = 0; /* start with tag part 0 */ -#endif /* LWIP_HTTPD_SSI_MULTIPART */ - get_tag_insert(hs); - - /* Next time through, we are going to be sending data - * immediately, either the end of the block we start - * sending here or the insert string. */ - ssi->tag_index = 0; - ssi->tag_state = TAG_SENDING; - ssi->tag_end = ssi->parsed; -#if !LWIP_HTTPD_SSI_INCLUDE_TAG - ssi->parsed = ssi->tag_started; -#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ - - /* If there is any unsent data in the buffer prior to the - * tag, we need to send it now. */ - if (ssi->tag_end > hs->file) { - /* How much of the data can we send? */ -#if LWIP_HTTPD_SSI_INCLUDE_TAG - len = (u16_t)LWIP_MIN(ssi->tag_end - hs->file, 0xffff); -#else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ - /* we would include the tag in sending */ - len = (u16_t)LWIP_MIN(ssi->tag_started - hs->file, 0xffff); -#endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ - - err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); - if (err == ERR_OK) { - data_to_send = 1; -#if !LWIP_HTTPD_SSI_INCLUDE_TAG - if(ssi->tag_started <= hs->file) { - /* pretend to have sent the tag, too */ - len += ssi->tag_end - ssi->tag_started; - } -#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ - hs->file += len; - hs->left -= len; - } - } - } else { - ssi->tag_index++; - } - } else { - /* We found an unexpected character so this is not a tag. Move - * back to idle state. */ - ssi->parse_left--; - ssi->parsed++; - ssi->tag_state = TAG_NONE; - } - break; - - /* - * We have found a valid tag and are in the process of sending - * data as a result of that discovery. We send either remaining data - * from the file prior to the insert point or the insert string itself. - */ - case TAG_SENDING: - /* Do we have any remaining file data to send from the buffer prior - * to the tag? */ - if(ssi->tag_end > hs->file) { - /* How much of the data can we send? */ -#if LWIP_HTTPD_SSI_INCLUDE_TAG - len = (u16_t)LWIP_MIN(ssi->tag_end - hs->file, 0xffff); -#else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ - LWIP_ASSERT("hs->started >= hs->file", ssi->tag_started >= hs->file); - /* we would include the tag in sending */ - len = (u16_t)LWIP_MIN(ssi->tag_started - hs->file, 0xffff); -#endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ - if (len != 0) { - err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); - } else { - err = ERR_OK; - } - if (err == ERR_OK) { - data_to_send = 1; -#if !LWIP_HTTPD_SSI_INCLUDE_TAG - if(ssi->tag_started <= hs->file) { - /* pretend to have sent the tag, too */ - len += ssi->tag_end - ssi->tag_started; - } -#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ - hs->file += len; - hs->left -= len; - } - } else { -#if LWIP_HTTPD_SSI_MULTIPART - if(ssi->tag_index >= ssi->tag_insert_len) { - /* Did the last SSIHandler have more to send? */ - if (ssi->tag_part != HTTPD_LAST_TAG_PART) { - /* If so, call it again */ - ssi->tag_index = 0; - get_tag_insert(hs); - } - } -#endif /* LWIP_HTTPD_SSI_MULTIPART */ - - /* Do we still have insert data left to send? */ - if(ssi->tag_index < ssi->tag_insert_len) { - /* We are sending the insert string itself. How much of the - * insert can we send? */ - len = (ssi->tag_insert_len - ssi->tag_index); - - /* Note that we set the copy flag here since we only have a - * single tag insert buffer per connection. If we don't do - * this, insert corruption can occur if more than one insert - * is processed before we call tcp_output. */ - err = http_write(pcb, &(ssi->tag_insert[ssi->tag_index]), &len, - HTTP_IS_TAG_VOLATILE(hs)); - if (err == ERR_OK) { - data_to_send = 1; - ssi->tag_index += len; - /* Don't return here: keep on sending data */ - } - } else { -#if LWIP_HTTPD_SSI_MULTIPART - if (ssi->tag_part == HTTPD_LAST_TAG_PART) -#endif /* LWIP_HTTPD_SSI_MULTIPART */ - { - /* We have sent all the insert data so go back to looking for - * a new tag. */ - LWIP_DEBUGF(HTTPD_DEBUG, ("Everything sent.\n")); - ssi->tag_index = 0; - ssi->tag_state = TAG_NONE; -#if !LWIP_HTTPD_SSI_INCLUDE_TAG - ssi->parsed = ssi->tag_end; -#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ - } - } - break; - } - } - } - - /* If we drop out of the end of the for loop, this implies we must have - * file data to send so send it now. In TAG_SENDING state, we've already - * handled this so skip the send if that's the case. */ - if((ssi->tag_state != TAG_SENDING) && (ssi->parsed > hs->file)) { - len = (u16_t)LWIP_MIN(ssi->parsed - hs->file, 0xffff); - - err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); - if (err == ERR_OK) { - data_to_send = 1; - hs->file += len; - hs->left -= len; - } - } - return data_to_send; -} -#endif /* LWIP_HTTPD_SSI */ - -/** - * Try to send more data on this pcb. - * - * @param pcb the pcb to send data - * @param hs connection state - */ -static u8_t -http_send(struct tcp_pcb *pcb, struct http_state *hs) -{ - u8_t data_to_send = HTTP_NO_DATA_TO_SEND; - - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_send: pcb=%p hs=%p left=%d\n", (void*)pcb, - (void*)hs, hs != NULL ? (int)hs->left : 0)); - -#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND - if (hs->unrecved_bytes != 0) { - return 0; - } -#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */ - - /* If we were passed a NULL state structure pointer, ignore the call. */ - if (hs == NULL) { - return 0; - } - -#if LWIP_HTTPD_FS_ASYNC_READ - /* Check if we are allowed to read from this file. - (e.g. SSI might want to delay sending until data is available) */ - if (!fs_is_file_ready(hs->handle, http_continue, hs)) { - return 0; - } -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ - -#if LWIP_HTTPD_DYNAMIC_HEADERS - /* Do we have any more header data to send for this file? */ - if (hs->hdr_index < NUM_FILE_HDR_STRINGS) { - data_to_send = http_send_headers(pcb, hs); - if ((data_to_send != HTTP_DATA_TO_SEND_CONTINUE) && - (hs->hdr_index < NUM_FILE_HDR_STRINGS)) { - return data_to_send; - } - } -#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ - - /* Have we run out of file data to send? If so, we need to read the next - * block from the file. */ - if (hs->left == 0) { - if (!http_check_eof(pcb, hs)) { - return 0; - } - } - -#if LWIP_HTTPD_SSI - if(hs->ssi) { - data_to_send = http_send_data_ssi(pcb, hs); - } else -#endif /* LWIP_HTTPD_SSI */ - { - data_to_send = http_send_data_nonssi(pcb, hs); - } - - if((hs->left == 0) && (fs_bytes_left(hs->handle) <= 0)) { - /* We reached the end of the file so this request is done. - * This adds the FIN flag right into the last data segment. */ - LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n")); - http_eof(pcb, hs); - return 0; - } - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("send_data end.\n")); - return data_to_send; -} - -#if LWIP_HTTPD_SUPPORT_EXTSTATUS -/** Initialize a http connection with a file to send for an error message - * - * @param hs http connection state - * @param error_nr HTTP error number - * @return ERR_OK if file was found and hs has been initialized correctly - * another err_t otherwise - */ -static err_t -http_find_error_file(struct http_state *hs, u16_t error_nr) -{ - const char *uri1, *uri2, *uri3; - err_t err; - - if (error_nr == 501) { - uri1 = "/501.html"; - uri2 = "/501.htm"; - uri3 = "/501.shtml"; - } else { - /* 400 (bad request is the default) */ - uri1 = "/400.html"; - uri2 = "/400.htm"; - uri3 = "/400.shtml"; - } - err = fs_open(&hs->file_handle, uri1); - if (err != ERR_OK) { - err = fs_open(&hs->file_handle, uri2); - if (err != ERR_OK) { - err = fs_open(&hs->file_handle, uri3); - if (err != ERR_OK) { - LWIP_DEBUGF(HTTPD_DEBUG, ("Error page for error %"U16_F" not found\n", - error_nr)); - return ERR_ARG; - } - } - } - return http_init_file(hs, &hs->file_handle, 0, NULL, 0, NULL); -} -#else /* LWIP_HTTPD_SUPPORT_EXTSTATUS */ -#define http_find_error_file(hs, error_nr) ERR_ARG -#endif /* LWIP_HTTPD_SUPPORT_EXTSTATUS */ - -/** - * Get the file struct for a 404 error page. - * Tries some file names and returns NULL if none found. - * - * @param uri pointer that receives the actual file name URI - * @return file struct for the error page or NULL no matching file was found - */ -static struct fs_file * -http_get_404_file(struct http_state *hs, const char **uri) -{ - err_t err; - - *uri = "/404.html"; - err = fs_open(&hs->file_handle, *uri); - if (err != ERR_OK) { - /* 404.html doesn't exist. Try 404.htm instead. */ - *uri = "/404.htm"; - err = fs_open(&hs->file_handle, *uri); - if (err != ERR_OK) { - /* 404.htm doesn't exist either. Try 404.shtml instead. */ - *uri = "/404.shtml"; - err = fs_open(&hs->file_handle, *uri); - if (err != ERR_OK) { - /* 404.htm doesn't exist either. Indicate to the caller that it should - * send back a default 404 page. - */ - *uri = NULL; - return NULL; - } - } - } - - return &hs->file_handle; -} - -#if LWIP_HTTPD_SUPPORT_POST -static err_t -http_handle_post_finished(struct http_state *hs) -{ -#if LWIP_HTTPD_POST_MANUAL_WND - /* Prevent multiple calls to httpd_post_finished, since it might have already - been called before from httpd_post_data_recved(). */ - if (hs->post_finished) { - return ERR_OK; - } - hs->post_finished = 1; -#endif /* LWIP_HTTPD_POST_MANUAL_WND */ - /* application error or POST finished */ - /* NULL-terminate the buffer */ - http_uri_buf[0] = 0; - httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN); - return http_find_file(hs, http_uri_buf, 0); -} - -/** Pass received POST body data to the application and correctly handle - * returning a response document or closing the connection. - * ATTENTION: The application is responsible for the pbuf now, so don't free it! - * - * @param hs http connection state - * @param p pbuf to pass to the application - * @return ERR_OK if passed successfully, another err_t if the response file - * hasn't been found (after POST finished) - */ -static err_t -http_post_rxpbuf(struct http_state *hs, struct pbuf *p) -{ - err_t err; - - if (p != NULL) { - /* adjust remaining Content-Length */ - if (hs->post_content_len_left < p->tot_len) { - hs->post_content_len_left = 0; - } else { - hs->post_content_len_left -= p->tot_len; - } - } - err = httpd_post_receive_data(hs, p); - if (err != ERR_OK) { - /* Ignore remaining content in case of application error */ - hs->post_content_len_left = 0; - } - if (hs->post_content_len_left == 0) { -#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND - if (hs->unrecved_bytes != 0) { - return ERR_OK; - } -#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */ - /* application error or POST finished */ - return http_handle_post_finished(hs); - } - - return ERR_OK; -} - -/** Handle a post request. Called from http_parse_request when method 'POST' - * is found. - * - * @param p The input pbuf (containing the POST header and body). - * @param hs The http connection state. - * @param data HTTP request (header and part of body) from input pbuf(s). - * @param data_len Size of 'data'. - * @param uri The HTTP URI parsed from input pbuf(s). - * @param uri_end Pointer to the end of 'uri' (here, the rest of the HTTP - * header starts). - * @return ERR_OK: POST correctly parsed and accepted by the application. - * ERR_INPROGRESS: POST not completely parsed (no error yet) - * another err_t: Error parsing POST or denied by the application - */ -static err_t -http_post_request(struct pbuf *inp, struct http_state *hs, - char *data, u16_t data_len, char *uri, char *uri_end) -{ - err_t err; - /* search for end-of-header (first double-CRLF) */ - char* crlfcrlf = strnstr(uri_end + 1, CRLF CRLF, data_len - (uri_end + 1 - data)); - - if (crlfcrlf != NULL) { - /* search for "Content-Length: " */ -#define HTTP_HDR_CONTENT_LEN "Content-Length: " -#define HTTP_HDR_CONTENT_LEN_LEN 16 -#define HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN 10 - char *scontent_len = strnstr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1)); - if (scontent_len != NULL) { - char *scontent_len_end = strnstr(scontent_len + HTTP_HDR_CONTENT_LEN_LEN, CRLF, HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN); - if (scontent_len_end != NULL) { - int content_len; - char *content_len_num = scontent_len + HTTP_HDR_CONTENT_LEN_LEN; - content_len = atoi(content_len_num); - if (content_len == 0) { - /* if atoi returns 0 on error, fix this */ - if ((content_len_num[0] != '0') || (content_len_num[1] != '\r')) { - content_len = -1; - } - } - if (content_len >= 0) { - /* adjust length of HTTP header passed to application */ - const char *hdr_start_after_uri = uri_end + 1; - u16_t hdr_len = LWIP_MIN(data_len, crlfcrlf + 4 - data); - u16_t hdr_data_len = LWIP_MIN(data_len, crlfcrlf + 4 - hdr_start_after_uri); - u8_t post_auto_wnd = 1; - http_uri_buf[0] = 0; - /* trim http header */ - *crlfcrlf = 0; - err = httpd_post_begin(hs, uri, hdr_start_after_uri, hdr_data_len, content_len, - http_uri_buf, LWIP_HTTPD_URI_BUF_LEN, &post_auto_wnd); - if (err == ERR_OK) { - /* try to pass in data of the first pbuf(s) */ - struct pbuf *q = inp; - u16_t start_offset = hdr_len; -#if LWIP_HTTPD_POST_MANUAL_WND - hs->no_auto_wnd = !post_auto_wnd; -#endif /* LWIP_HTTPD_POST_MANUAL_WND */ - /* set the Content-Length to be received for this POST */ - hs->post_content_len_left = (u32_t)content_len; - - /* get to the pbuf where the body starts */ - while((q != NULL) && (q->len <= start_offset)) { - start_offset -= q->len; - q = q->next; - } - if (q != NULL) { - /* hide the remaining HTTP header */ - pbuf_header(q, -(s16_t)start_offset); -#if LWIP_HTTPD_POST_MANUAL_WND - if (!post_auto_wnd) { - /* already tcp_recved() this data... */ - hs->unrecved_bytes = q->tot_len; - } -#endif /* LWIP_HTTPD_POST_MANUAL_WND */ - pbuf_ref(q); - return http_post_rxpbuf(hs, q); - } else if (hs->post_content_len_left == 0) { - q = pbuf_alloc(PBUF_RAW, 0, PBUF_REF); - return http_post_rxpbuf(hs, q); - } else { - return ERR_OK; - } - } else { - /* return file passed from application */ - return http_find_file(hs, http_uri_buf, 0); - } - } else { - LWIP_DEBUGF(HTTPD_DEBUG, ("POST received invalid Content-Length: %s\n", - content_len_num)); - return ERR_ARG; - } - } - } - /* If we come here, headers are fully received (double-crlf), but Content-Length - was not included. Since this is currently the only supported method, we have - to fail in this case! */ - LWIP_DEBUGF(HTTPD_DEBUG, ("Error when parsing Content-Length\n")); - return ERR_ARG; - } - /* if we come here, the POST is incomplete */ -#if LWIP_HTTPD_SUPPORT_REQUESTLIST - return ERR_INPROGRESS; -#else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ - return ERR_ARG; -#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ -} - -#if LWIP_HTTPD_POST_MANUAL_WND -/** A POST implementation can call this function to update the TCP window. - * This can be used to throttle data reception (e.g. when received data is - * programmed to flash and data is received faster than programmed). - * - * @param connection A connection handle passed to httpd_post_begin for which - * httpd_post_finished has *NOT* been called yet! - * @param recved_len Length of data received (for window update) - */ -void httpd_post_data_recved(void *connection, u16_t recved_len) -{ - struct http_state *hs = (struct http_state*)connection; - if (hs != NULL) { - if (hs->no_auto_wnd) { - u16_t len = recved_len; - if (hs->unrecved_bytes >= recved_len) { - hs->unrecved_bytes -= recved_len; - } else { - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_LEVEL_WARNING, ("httpd_post_data_recved: recved_len too big\n")); - len = (u16_t)hs->unrecved_bytes; - hs->unrecved_bytes = 0; - } - if (hs->pcb != NULL) { - if (len != 0) { - tcp_recved(hs->pcb, len); - } - if ((hs->post_content_len_left == 0) && (hs->unrecved_bytes == 0)) { - /* finished handling POST */ - http_handle_post_finished(hs); - http_send(hs->pcb, hs); - } - } - } - } -} -#endif /* LWIP_HTTPD_POST_MANUAL_WND */ - -#endif /* LWIP_HTTPD_SUPPORT_POST */ - -#if LWIP_HTTPD_FS_ASYNC_READ -/** Try to send more data if file has been blocked before - * This is a callback function passed to fs_read_async(). - */ -static void -http_continue(void *connection) -{ - struct http_state *hs = (struct http_state*)connection; - if (hs && (hs->pcb) && (hs->handle)) { - LWIP_ASSERT("hs->pcb != NULL", hs->pcb != NULL); - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("httpd_continue: try to send more data\n")); - if (http_send(hs->pcb, hs)) { - /* If we wrote anything to be sent, go ahead and send it now. */ - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n")); - tcp_output(hs->pcb); - } - } -} -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ - -/** - * When data has been received in the correct state, try to parse it - * as a HTTP request. - * - * @param p the received pbuf - * @param hs the connection state - * @param pcb the tcp_pcb which received this packet - * @return ERR_OK if request was OK and hs has been initialized correctly - * ERR_INPROGRESS if request was OK so far but not fully received - * another err_t otherwise - */ -static err_t -http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb) -{ - char *data; - char *crlf; - u16_t data_len; - struct pbuf *p = inp; -#if LWIP_HTTPD_SUPPORT_REQUESTLIST - u16_t clen; -#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ -#if LWIP_HTTPD_SUPPORT_POST - err_t err; -#endif /* LWIP_HTTPD_SUPPORT_POST */ - - LWIP_UNUSED_ARG(pcb); /* only used for post */ - LWIP_ASSERT("p != NULL", p != NULL); - LWIP_ASSERT("hs != NULL", hs != NULL); - - if ((hs->handle != NULL) || (hs->file != NULL)) { - LWIP_DEBUGF(HTTPD_DEBUG, ("Received data while sending a file\n")); - /* already sending a file */ - /* @todo: abort? */ - return ERR_USE; - } - -#if LWIP_HTTPD_SUPPORT_REQUESTLIST - - LWIP_DEBUGF(HTTPD_DEBUG, ("Received %"U16_F" bytes\n", p->tot_len)); - - /* first check allowed characters in this pbuf? */ - - /* enqueue the pbuf */ - if (hs->req == NULL) { - LWIP_DEBUGF(HTTPD_DEBUG, ("First pbuf\n")); - hs->req = p; - } else { - LWIP_DEBUGF(HTTPD_DEBUG, ("pbuf enqueued\n")); - pbuf_cat(hs->req, p); - } - /* increase pbuf ref counter as it is freed when we return but we want to - keep it on the req list */ - pbuf_ref(p); - - if (hs->req->next != NULL) { - data_len = LWIP_MIN(hs->req->tot_len, LWIP_HTTPD_MAX_REQ_LENGTH); - pbuf_copy_partial(hs->req, httpd_req_buf, data_len, 0); - data = httpd_req_buf; - } else -#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ - { - data = (char *)p->payload; - data_len = p->len; - if (p->len != p->tot_len) { - LWIP_DEBUGF(HTTPD_DEBUG, ("Warning: incomplete header due to chained pbufs\n")); - } - } - - /* received enough data for minimal request? */ - if (data_len >= MIN_REQ_LEN) { - /* wait for CRLF before parsing anything */ - crlf = strnstr(data, CRLF, data_len); - if (crlf != NULL) { -#if LWIP_HTTPD_SUPPORT_POST - int is_post = 0; -#endif /* LWIP_HTTPD_SUPPORT_POST */ - int is_09 = 0; - char *sp1, *sp2; - u16_t left_len, uri_len; - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("CRLF received, parsing request\n")); - /* parse method */ - if (!strncmp(data, "GET ", 4)) { - sp1 = data + 3; - /* received GET request */ - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received GET request\"\n")); -#if LWIP_HTTPD_SUPPORT_POST - } else if (!strncmp(data, "POST ", 5)) { - /* store request type */ - is_post = 1; - sp1 = data + 4; - /* received GET request */ - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received POST request\n")); -#endif /* LWIP_HTTPD_SUPPORT_POST */ - } else { - /* null-terminate the METHOD (pbuf is freed anyway wen returning) */ - data[4] = 0; - /* unsupported method! */ - LWIP_DEBUGF(HTTPD_DEBUG, ("Unsupported request method (not implemented): \"%s\"\n", - data)); - return http_find_error_file(hs, 501); - } - /* if we come here, method is OK, parse URI */ - left_len = (u16_t)(data_len - ((sp1 +1) - data)); - sp2 = strnstr(sp1 + 1, " ", left_len); -#if LWIP_HTTPD_SUPPORT_V09 - if (sp2 == NULL) { - /* HTTP 0.9: respond with correct protocol version */ - sp2 = strnstr(sp1 + 1, CRLF, left_len); - is_09 = 1; -#if LWIP_HTTPD_SUPPORT_POST - if (is_post) { - /* HTTP/0.9 does not support POST */ - goto badrequest; - } -#endif /* LWIP_HTTPD_SUPPORT_POST */ - } -#endif /* LWIP_HTTPD_SUPPORT_V09 */ - uri_len = (u16_t)(sp2 - (sp1 + 1)); - if ((sp2 != 0) && (sp2 > sp1)) { - /* wait for CRLFCRLF (indicating end of HTTP headers) before parsing anything */ - if (strnstr(data, CRLF CRLF, data_len) != NULL) { - char *uri = sp1 + 1; -#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE - /* This is HTTP/1.0 compatible: for strict 1.1, a connection - would always be persistent unless "close" was specified. */ - if (!is_09 && (strnstr(data, HTTP11_CONNECTIONKEEPALIVE, data_len) || - strnstr(data, HTTP11_CONNECTIONKEEPALIVE2, data_len))) { - hs->keepalive = 1; - } else { - hs->keepalive = 0; - } -#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */ - /* null-terminate the METHOD (pbuf is freed anyway wen returning) */ - *sp1 = 0; - uri[uri_len] = 0; - LWIP_DEBUGF(HTTPD_DEBUG, ("Received \"%s\" request for URI: \"%s\"\n", - data, uri)); -#if LWIP_HTTPD_SUPPORT_POST - if (is_post) { -#if LWIP_HTTPD_SUPPORT_REQUESTLIST - struct pbuf *q = hs->req; -#else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ - struct pbuf *q = inp; -#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ - err = http_post_request(q, hs, data, data_len, uri, sp2); - if (err != ERR_OK) { - /* restore header for next try */ - *sp1 = ' '; - *sp2 = ' '; - uri[uri_len] = ' '; - } - if (err == ERR_ARG) { - goto badrequest; - } - return err; - } else -#endif /* LWIP_HTTPD_SUPPORT_POST */ - { - return http_find_file(hs, uri, is_09); - } - } - } else { - LWIP_DEBUGF(HTTPD_DEBUG, ("invalid URI\n")); - } - } - } - -#if LWIP_HTTPD_SUPPORT_REQUESTLIST - clen = pbuf_clen(hs->req); - if ((hs->req->tot_len <= LWIP_HTTPD_REQ_BUFSIZE) && - (clen <= LWIP_HTTPD_REQ_QUEUELEN)) { - /* request not fully received (too short or CRLF is missing) */ - return ERR_INPROGRESS; - } else -#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ - { -#if LWIP_HTTPD_SUPPORT_POST -badrequest: -#endif /* LWIP_HTTPD_SUPPORT_POST */ - LWIP_DEBUGF(HTTPD_DEBUG, ("bad request\n")); - /* could not parse request */ - return http_find_error_file(hs, 400); - } -} - -/** Try to find the file specified by uri and, if found, initialize hs - * accordingly. - * - * @param hs the connection state - * @param uri the HTTP header URI - * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response) - * @return ERR_OK if file was found and hs has been initialized correctly - * another err_t otherwise - */ -static err_t -http_find_file(struct http_state *hs, const char *uri, int is_09) -{ - size_t loop; - struct fs_file *file = NULL; - char *params = NULL; - err_t err; -#if LWIP_HTTPD_CGI - int i; -#endif /* LWIP_HTTPD_CGI */ -#if !LWIP_HTTPD_SSI - const -#endif /* !LWIP_HTTPD_SSI */ - /* By default, assume we will not be processing server-side-includes tags */ - u8_t tag_check = 0; - - /* Have we been asked for the default file (in root or a directory) ? */ -#if LWIP_HTTPD_MAX_REQUEST_URI_LEN - size_t uri_len = strlen(uri); - if ((uri_len > 0) && (uri[uri_len-1] == '/') && - ((uri != http_uri_buf) || (uri_len == 1))) { - size_t copy_len = LWIP_MIN(sizeof(http_uri_buf) - 1, uri_len - 1); - if (copy_len > 0) { - MEMCPY(http_uri_buf, uri, copy_len); - http_uri_buf[copy_len] = 0; - } -#else /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */ - if ((uri[0] == '/') && (uri[1] == 0)) { -#endif /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */ - /* Try each of the configured default filenames until we find one - that exists. */ - for (loop = 0; loop < NUM_DEFAULT_FILENAMES; loop++) { - const char* file_name; -#if LWIP_HTTPD_MAX_REQUEST_URI_LEN - if (copy_len > 0) { - size_t len_left = sizeof(http_uri_buf) - copy_len - 1; - if (len_left > 0) { - size_t name_len = strlen(g_psDefaultFilenames[loop].name); - size_t name_copy_len = LWIP_MIN(len_left, name_len); - MEMCPY(&http_uri_buf[copy_len], g_psDefaultFilenames[loop].name, name_copy_len); - } - file_name = http_uri_buf; - } else -#endif /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */ - { - file_name = g_psDefaultFilenames[loop].name; - } - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Looking for %s...\n", file_name)); - err = fs_open(&hs->file_handle, file_name); - if(err == ERR_OK) { - uri = file_name; - file = &hs->file_handle; - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opened.\n")); -#if LWIP_HTTPD_SSI - tag_check = g_psDefaultFilenames[loop].shtml; -#endif /* LWIP_HTTPD_SSI */ - break; - } - } - } - if (file == NULL) { - /* No - we've been asked for a specific file. */ - /* First, isolate the base URI (without any parameters) */ - params = (char *)strchr(uri, '?'); - if (params != NULL) { - /* URI contains parameters. NULL-terminate the base URI */ - *params = '\0'; - params++; - } - -#if LWIP_HTTPD_CGI - http_cgi_paramcount = -1; - /* Does the base URI we have isolated correspond to a CGI handler? */ - if (g_iNumCGIs && g_pCGIs) { - for (i = 0; i < g_iNumCGIs; i++) { - if (strcmp(uri, g_pCGIs[i].pcCGIName) == 0) { - /* - * We found a CGI that handles this URI so extract the - * parameters and call the handler. - */ - http_cgi_paramcount = extract_uri_parameters(hs, params); - uri = g_pCGIs[i].pfnCGIHandler(i, http_cgi_paramcount, hs->params, - hs->param_vals); - break; - } - } - } -#endif /* LWIP_HTTPD_CGI */ - - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opening %s\n", uri)); - - err = fs_open(&hs->file_handle, uri); - if (err == ERR_OK) { - file = &hs->file_handle; - } else { - file = http_get_404_file(hs, &uri); - } -#if LWIP_HTTPD_SSI - if (file != NULL) { - /* See if we have been asked for an shtml file and, if so, - enable tag checking. */ - const char* ext = NULL, *sub; - char* param = (char*)strstr(uri, "?"); - if (param != NULL) { - /* separate uri from parameters for now, set back later */ - *param = 0; - } - sub = uri; - ext = uri; - for (sub = strstr(sub, "."); sub != NULL; sub = strstr(sub, ".")) - { - ext = sub; - sub++; - } - tag_check = 0; - for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) { - if (!stricmp(ext, g_pcSSIExtensions[loop])) { - tag_check = 1; - break; - } - } - if (param != NULL) { - *param = '?'; - } - } -#endif /* LWIP_HTTPD_SSI */ - } - if (file == NULL) { - /* None of the default filenames exist so send back a 404 page */ - file = http_get_404_file(hs, &uri); - } - return http_init_file(hs, file, is_09, uri, tag_check, params); -} - -/** Initialize a http connection with a file to send (if found). - * Called by http_find_file and http_find_error_file. - * - * @param hs http connection state - * @param file file structure to send (or NULL if not found) - * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response) - * @param uri the HTTP header URI - * @param tag_check enable SSI tag checking - * @param uri_has_params != NULL if URI has parameters (separated by '?') - * @return ERR_OK if file was found and hs has been initialized correctly - * another err_t otherwise - */ -static err_t -http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri, - u8_t tag_check, char* params) -{ - if (file != NULL) { - /* file opened, initialise struct http_state */ -#if LWIP_HTTPD_SSI - if (tag_check) { - struct http_ssi_state *ssi = http_ssi_state_alloc(); - if (ssi != NULL) { - ssi->tag_index = 0; - ssi->tag_state = TAG_NONE; - ssi->parsed = file->data; - ssi->parse_left = file->len; - ssi->tag_end = file->data; - hs->ssi = ssi; - } - } -#else /* LWIP_HTTPD_SSI */ - LWIP_UNUSED_ARG(tag_check); -#endif /* LWIP_HTTPD_SSI */ - hs->handle = file; - hs->file = file->data; - LWIP_ASSERT("File length must be positive!", (file->len >= 0)); -#if LWIP_HTTPD_CUSTOM_FILES - if (file->is_custom_file && (file->data == NULL)) { - /* custom file, need to read data first (via fs_read_custom) */ - hs->left = 0; - } else -#endif /* LWIP_HTTPD_CUSTOM_FILES */ - { - hs->left = file->len; - } - hs->retries = 0; -#if LWIP_HTTPD_TIMING - hs->time_started = sys_now(); -#endif /* LWIP_HTTPD_TIMING */ -#if !LWIP_HTTPD_DYNAMIC_HEADERS - LWIP_ASSERT("HTTP headers not included in file system", - (hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) != 0); -#endif /* !LWIP_HTTPD_DYNAMIC_HEADERS */ -#if LWIP_HTTPD_SUPPORT_V09 - if (is_09 && ((hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) != 0)) { - /* HTTP/0.9 responses are sent without HTTP header, - search for the end of the header. */ - char *file_start = strnstr(hs->file, CRLF CRLF, hs->left); - if (file_start != NULL) { - size_t diff = file_start + 4 - hs->file; - hs->file += diff; - hs->left -= (u32_t)diff; - } - } -#endif /* LWIP_HTTPD_SUPPORT_V09*/ -#if LWIP_HTTPD_CGI_SSI - if (params != NULL) { - /* URI contains parameters, call generic CGI handler */ - int count; -#if LWIP_HTTPD_CGI - if (http_cgi_paramcount >= 0) { - count = http_cgi_paramcount; - } else -#endif - { - count = extract_uri_parameters(hs, params); - } - httpd_cgi_handler(uri, count, http_cgi_params, http_cgi_param_vals -#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE - , hs->handle->state -#endif /* LWIP_HTTPD_FILE_STATE */ - ); - } -#else /* LWIP_HTTPD_CGI_SSI */ - LWIP_UNUSED_ARG(params); -#endif /* LWIP_HTTPD_CGI_SSI */ - } else { - hs->handle = NULL; - hs->file = NULL; - hs->left = 0; - hs->retries = 0; - } -#if LWIP_HTTPD_DYNAMIC_HEADERS - /* Determine the HTTP headers to send based on the file extension of - * the requested URI. */ - if ((hs->handle == NULL) || ((hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) == 0)) { - get_http_headers(hs, uri); - } -#else /* LWIP_HTTPD_DYNAMIC_HEADERS */ - LWIP_UNUSED_ARG(uri); -#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ -#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE - if (hs->keepalive) { -#if LWIP_HTTPD_SSI - if (hs->ssi != NULL) { - hs->keepalive = 0; - } else -#endif /* LWIP_HTTPD_SSI */ - { - if ((hs->handle != NULL) && - ((hs->handle->flags & (FS_FILE_FLAGS_HEADER_INCLUDED|FS_FILE_FLAGS_HEADER_PERSISTENT)) == FS_FILE_FLAGS_HEADER_INCLUDED)) { - hs->keepalive = 0; - } - } - } -#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */ - return ERR_OK; -} - -/** - * The pcb had an error and is already deallocated. - * The argument might still be valid (if != NULL). - */ -static void -http_err(void *arg, err_t err) -{ - struct http_state *hs = (struct http_state *)arg; - LWIP_UNUSED_ARG(err); - - LWIP_DEBUGF(HTTPD_DEBUG, ("http_err: %s", lwip_strerr(err))); - - if (hs != NULL) { - http_state_free(hs); - } -} - -/** - * Data has been sent and acknowledged by the remote host. - * This means that more data can be sent. - */ -static err_t -http_sent(void *arg, struct tcp_pcb *pcb, u16_t len) -{ - struct http_state *hs = (struct http_state *)arg; - - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_sent %p\n", (void*)pcb)); - - LWIP_UNUSED_ARG(len); - - if (hs == NULL) { - return ERR_OK; - } - - hs->retries = 0; - - http_send(pcb, hs); - - return ERR_OK; -} - -/** - * The poll function is called every 2nd second. - * If there has been no data sent (which resets the retries) in 8 seconds, close. - * If the last portion of a file has not been sent in 2 seconds, close. - * - * This could be increased, but we don't want to waste resources for bad connections. - */ -static err_t -http_poll(void *arg, struct tcp_pcb *pcb) -{ - struct http_state *hs = (struct http_state *)arg; - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: pcb=%p hs=%p pcb_state=%s\n", - (void*)pcb, (void*)hs, tcp_debug_state_str(pcb->state))); - - if (hs == NULL) { - err_t closed; - /* arg is null, close. */ - LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: arg is NULL, close\n")); - closed = http_close_conn(pcb, NULL); - LWIP_UNUSED_ARG(closed); -#if LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR - if (closed == ERR_MEM) { - tcp_abort(pcb); - return ERR_ABRT; - } -#endif /* LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR */ - return ERR_OK; - } else { - hs->retries++; - if (hs->retries == HTTPD_MAX_RETRIES) { - LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: too many retries, close\n")); - http_close_conn(pcb, hs); - return ERR_OK; - } - - /* If this connection has a file open, try to send some more data. If - * it has not yet received a GET request, don't do this since it will - * cause the connection to close immediately. */ - if(hs && (hs->handle)) { - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: try to send more data\n")); - if(http_send(pcb, hs)) { - /* If we wrote anything to be sent, go ahead and send it now. */ - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n")); - tcp_output(pcb); - } - } - } - - return ERR_OK; -} - -/** - * Data has been received on this pcb. - * For HTTP 1.0, this should normally only happen once (if the request fits in one packet). - */ -static err_t -http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) -{ - struct http_state *hs = (struct http_state *)arg; - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: pcb=%p pbuf=%p err=%s\n", (void*)pcb, - (void*)p, lwip_strerr(err))); - - if ((err != ERR_OK) || (p == NULL) || (hs == NULL)) { - /* error or closed by other side? */ - if (p != NULL) { - /* Inform TCP that we have taken the data. */ - tcp_recved(pcb, p->tot_len); - pbuf_free(p); - } - if (hs == NULL) { - /* this should not happen, only to be robust */ - LWIP_DEBUGF(HTTPD_DEBUG, ("Error, http_recv: hs is NULL, close\n")); - } - http_close_conn(pcb, hs); - return ERR_OK; - } - -#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND - if (hs->no_auto_wnd) { - hs->unrecved_bytes += p->tot_len; - } else -#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */ - { - /* Inform TCP that we have taken the data. */ - tcp_recved(pcb, p->tot_len); - } - -#if LWIP_HTTPD_SUPPORT_POST - if (hs->post_content_len_left > 0) { - /* reset idle counter when POST data is received */ - hs->retries = 0; - /* this is data for a POST, pass the complete pbuf to the application */ - http_post_rxpbuf(hs, p); - /* pbuf is passed to the application, don't free it! */ - if (hs->post_content_len_left == 0) { - /* all data received, send response or close connection */ - http_send(pcb, hs); - } - return ERR_OK; - } else -#endif /* LWIP_HTTPD_SUPPORT_POST */ - { - if (hs->handle == NULL) { - err_t parsed = http_parse_request(p, hs, pcb); - LWIP_ASSERT("http_parse_request: unexpected return value", parsed == ERR_OK - || parsed == ERR_INPROGRESS ||parsed == ERR_ARG || parsed == ERR_USE); -#if LWIP_HTTPD_SUPPORT_REQUESTLIST - if (parsed != ERR_INPROGRESS) { - /* request fully parsed or error */ - if (hs->req != NULL) { - pbuf_free(hs->req); - hs->req = NULL; - } - } -#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ - pbuf_free(p); - if (parsed == ERR_OK) { -#if LWIP_HTTPD_SUPPORT_POST - if (hs->post_content_len_left == 0) -#endif /* LWIP_HTTPD_SUPPORT_POST */ - { - LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: data %p len %"S32_F"\n", (const void*)hs->file, hs->left)); - http_send(pcb, hs); - } - } else if (parsed == ERR_ARG) { - /* @todo: close on ERR_USE? */ - http_close_conn(pcb, hs); - } - } else { - LWIP_DEBUGF(HTTPD_DEBUG, ("http_recv: already sending data\n")); - /* already sending but still receiving data, we might want to RST here? */ - pbuf_free(p); - } - } - return ERR_OK; -} - -/** - * A new incoming connection has been accepted. - */ -static err_t -http_accept(void *arg, struct tcp_pcb *pcb, err_t err) -{ - struct http_state *hs; - LWIP_UNUSED_ARG(err); - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept %p / %p\n", (void*)pcb, arg)); - - if ((err != ERR_OK) || (pcb == NULL)) { - return ERR_VAL; - } - - /* Set priority */ - tcp_setprio(pcb, HTTPD_TCP_PRIO); - - /* Allocate memory for the structure that holds the state of the - connection - initialized by that function. */ - hs = http_state_alloc(); - if (hs == NULL) { - LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept: Out of memory, RST\n")); - return ERR_MEM; - } - hs->pcb = pcb; - - /* Tell TCP that this is the structure we wish to be passed for our - callbacks. */ - tcp_arg(pcb, hs); - - /* Set up the various callback functions */ - tcp_recv(pcb, http_recv); - tcp_err(pcb, http_err); - tcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL); - tcp_sent(pcb, http_sent); - - return ERR_OK; -} - -/** - * @ingroup httpd - * Initialize the httpd: set up a listening PCB and bind it to the defined port - */ -void -httpd_init(void) -{ - struct tcp_pcb *pcb; - err_t err; - -#if HTTPD_USE_MEM_POOL - LWIP_MEMPOOL_INIT(HTTPD_STATE); -#if LWIP_HTTPD_SSI - LWIP_MEMPOOL_INIT(HTTPD_SSI_STATE); -#endif -#endif - LWIP_DEBUGF(HTTPD_DEBUG, ("httpd_init\n")); - - pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); - LWIP_ASSERT("httpd_init: tcp_new failed", pcb != NULL); - tcp_setprio(pcb, HTTPD_TCP_PRIO); - /* set SOF_REUSEADDR here to explicitly bind httpd to multiple interfaces */ - err = tcp_bind(pcb, IP_ANY_TYPE, HTTPD_SERVER_PORT); - LWIP_ASSERT("httpd_init: tcp_bind failed", err == ERR_OK); - pcb = tcp_listen(pcb); - LWIP_ASSERT("httpd_init: tcp_listen failed", pcb != NULL); - tcp_accept(pcb, http_accept); -} - -#if LWIP_HTTPD_SSI -/** - * Set the SSI handler function. - * - * @param ssi_handler the SSI handler function - * @param tags an array of SSI tag strings to search for in SSI-enabled files - * @param num_tags number of tags in the 'tags' array - */ -void -http_set_ssi_handler(tSSIHandler ssi_handler, const char **tags, int num_tags) -{ - LWIP_DEBUGF(HTTPD_DEBUG, ("http_set_ssi_handler\n")); - - LWIP_ASSERT("no ssi_handler given", ssi_handler != NULL); - g_pfnSSIHandler = ssi_handler; - -#if LWIP_HTTPD_SSI_RAW - LWIP_UNUSED_ARG(tags); - LWIP_UNUSED_ARG(num_tags); -#else /* LWIP_HTTPD_SSI_RAW */ - LWIP_ASSERT("no tags given", tags != NULL); - LWIP_ASSERT("invalid number of tags", num_tags > 0); - - g_ppcTags = tags; - g_iNumTags = num_tags; -#endif /* !LWIP_HTTPD_SSI_RAW */ -} -#endif /* LWIP_HTTPD_SSI */ - -#if LWIP_HTTPD_CGI -/** - * Set an array of CGI filenames/handler functions - * - * @param cgis an array of CGI filenames/handler functions - * @param num_handlers number of elements in the 'cgis' array - */ -void -http_set_cgi_handlers(const tCGI *cgis, int num_handlers) -{ - LWIP_ASSERT("no cgis given", cgis != NULL); - LWIP_ASSERT("invalid number of handlers", num_handlers > 0); - - g_pCGIs = cgis; - g_iNumCGIs = num_handlers; -} -#endif /* LWIP_HTTPD_CGI */ - -#endif /* LWIP_TCP */ diff --git a/ext/lwip/src/apps/httpd/httpd_structs.h b/ext/lwip/src/apps/httpd/httpd_structs.h deleted file mode 100644 index fbd135a..0000000 --- a/ext/lwip/src/apps/httpd/httpd_structs.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef LWIP_HTTPD_STRUCTS_H -#define LWIP_HTTPD_STRUCTS_H - -#include "lwip/apps/httpd.h" - -#if LWIP_HTTPD_DYNAMIC_HEADERS -/** This struct is used for a list of HTTP header strings for various - * filename extensions. */ -typedef struct -{ - const char *extension; - const char *content_type; -} tHTTPHeader; - -/** A list of strings used in HTTP headers (see RFC 1945 HTTP/1.0 and - * RFC 2616 HTTP/1.1 for header field definitions) */ -static const char * const g_psHTTPHeaderStrings[] = -{ - "HTTP/1.0 200 OK\r\n", - "HTTP/1.0 404 File not found\r\n", - "HTTP/1.0 400 Bad Request\r\n", - "HTTP/1.0 501 Not Implemented\r\n", - "HTTP/1.1 200 OK\r\n", - "HTTP/1.1 404 File not found\r\n", - "HTTP/1.1 400 Bad Request\r\n", - "HTTP/1.1 501 Not Implemented\r\n", - "Content-Length: ", - "Connection: Close\r\n", - "Connection: keep-alive\r\n", - "Connection: keep-alive\r\nContent-Length: ", - "Server: "HTTPD_SERVER_AGENT"\r\n", - "\r\n

404: The requested file cannot be found.

\r\n" -#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE - ,"Connection: keep-alive\r\nContent-Length: 77\r\n\r\n

404: The requested file cannot be found.

\r\n" -#endif -}; - -/* Indexes into the g_psHTTPHeaderStrings array */ -#define HTTP_HDR_OK 0 /* 200 OK */ -#define HTTP_HDR_NOT_FOUND 1 /* 404 File not found */ -#define HTTP_HDR_BAD_REQUEST 2 /* 400 Bad request */ -#define HTTP_HDR_NOT_IMPL 3 /* 501 Not Implemented */ -#define HTTP_HDR_OK_11 4 /* 200 OK */ -#define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */ -#define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */ -#define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */ -#define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.0)*/ -#define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */ -#define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */ -#define HTTP_HDR_KEEPALIVE_LEN 11 /* Connection: keep-alive + Content-Length: (HTTP 1.1)*/ -#define HTTP_HDR_SERVER 12 /* Server: HTTPD_SERVER_AGENT */ -#define DEFAULT_404_HTML 13 /* default 404 body */ -#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE -#define DEFAULT_404_HTML_PERSISTENT 14 /* default 404 body, but including Connection: keep-alive */ -#endif - - -#define HTTP_HDR_HTML "Content-type: text/html\r\n\r\n" -#define HTTP_HDR_SSI "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n" -#define HTTP_HDR_GIF "Content-type: image/gif\r\n\r\n" -#define HTTP_HDR_PNG "Content-type: image/png\r\n\r\n" -#define HTTP_HDR_JPG "Content-type: image/jpeg\r\n\r\n" -#define HTTP_HDR_BMP "Content-type: image/bmp\r\n\r\n" -#define HTTP_HDR_ICO "Content-type: image/x-icon\r\n\r\n" -#define HTTP_HDR_APP "Content-type: application/octet-stream\r\n\r\n" -#define HTTP_HDR_JS "Content-type: application/javascript\r\n\r\n" -#define HTTP_HDR_RA "Content-type: application/javascript\r\n\r\n" -#define HTTP_HDR_CSS "Content-type: text/css\r\n\r\n" -#define HTTP_HDR_SWF "Content-type: application/x-shockwave-flash\r\n\r\n" -#define HTTP_HDR_XML "Content-type: text/xml\r\n\r\n" -#define HTTP_HDR_PDF "Content-type: application/pdf\r\n\r\n" -#define HTTP_HDR_JSON "Content-type: application/json\r\n\r\n" - -#define HTTP_HDR_DEFAULT_TYPE "Content-type: text/plain\r\n\r\n" - -/** A list of extension-to-HTTP header strings (see outdated RFC 1700 MEDIA TYPES - * and http://www.iana.org/assignments/media-types for registered content types - * and subtypes) */ -static const tHTTPHeader g_psHTTPHeaders[] = -{ - { "html", HTTP_HDR_HTML}, - { "htm", HTTP_HDR_HTML}, - { "shtml",HTTP_HDR_SSI}, - { "shtm", HTTP_HDR_SSI}, - { "ssi", HTTP_HDR_SSI}, - { "gif", HTTP_HDR_GIF}, - { "png", HTTP_HDR_PNG}, - { "jpg", HTTP_HDR_JPG}, - { "bmp", HTTP_HDR_BMP}, - { "ico", HTTP_HDR_ICO}, - { "class",HTTP_HDR_APP}, - { "cls", HTTP_HDR_APP}, - { "js", HTTP_HDR_JS}, - { "ram", HTTP_HDR_RA}, - { "css", HTTP_HDR_CSS}, - { "swf", HTTP_HDR_SWF}, - { "xml", HTTP_HDR_XML}, - { "xsl", HTTP_HDR_XML}, - { "pdf", HTTP_HDR_PDF}, - { "json", HTTP_HDR_JSON} -}; - -#define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader)) - -#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ - -#if LWIP_HTTPD_SSI -static const char * const g_pcSSIExtensions[] = { - ".shtml", ".shtm", ".ssi", ".xml" -}; -#define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *)) -#endif /* LWIP_HTTPD_SSI */ - -#endif /* LWIP_HTTPD_STRUCTS_H */ diff --git a/ext/lwip/src/apps/httpd/makefsdata/makefsdata b/ext/lwip/src/apps/httpd/makefsdata/makefsdata deleted file mode 100644 index 37b4203..0000000 --- a/ext/lwip/src/apps/httpd/makefsdata/makefsdata +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/perl - -open(OUTPUT, "> fsdata.c"); - -chdir("fs"); -open(FILES, "find . -type f |"); - -while($file = ) { - - # Do not include files in CVS directories nor backup files. - if($file =~ /(CVS|~)/) { - next; - } - - chop($file); - - open(HEADER, "> /tmp/header") || die $!; - if($file =~ /404/) { - print(HEADER "HTTP/1.0 404 File not found\r\n"); - } else { - print(HEADER "HTTP/1.0 200 OK\r\n"); - } - print(HEADER "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n"); - if($file =~ /\.html$/) { - print(HEADER "Content-type: text/html\r\n"); - } elsif($file =~ /\.gif$/) { - print(HEADER "Content-type: image/gif\r\n"); - } elsif($file =~ /\.png$/) { - print(HEADER "Content-type: image/png\r\n"); - } elsif($file =~ /\.jpg$/) { - print(HEADER "Content-type: image/jpeg\r\n"); - } elsif($file =~ /\.class$/) { - print(HEADER "Content-type: application/octet-stream\r\n"); - } elsif($file =~ /\.ram$/) { - print(HEADER "Content-type: audio/x-pn-realaudio\r\n"); - } else { - print(HEADER "Content-type: text/plain\r\n"); - } - print(HEADER "\r\n"); - close(HEADER); - - unless($file =~ /\.plain$/ || $file =~ /cgi/) { - system("cat /tmp/header $file > /tmp/file"); - } else { - system("cp $file /tmp/file"); - } - - open(FILE, "/tmp/file"); - unlink("/tmp/file"); - unlink("/tmp/header"); - - $file =~ s/\.//; - $fvar = $file; - $fvar =~ s-/-_-g; - $fvar =~ s-\.-_-g; - print(OUTPUT "static const unsigned char data".$fvar."[] = {\n"); - print(OUTPUT "\t/* $file */\n\t"); - for($j = 0; $j < length($file); $j++) { - printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1))); - } - printf(OUTPUT "0,\n"); - - - $i = 0; - while(read(FILE, $data, 1)) { - if($i == 0) { - print(OUTPUT "\t"); - } - printf(OUTPUT "%#02x, ", unpack("C", $data)); - $i++; - if($i == 10) { - print(OUTPUT "\n"); - $i = 0; - } - } - print(OUTPUT "};\n\n"); - close(FILE); - push(@fvars, $fvar); - push(@files, $file); -} - -for($i = 0; $i < @fvars; $i++) { - $file = $files[$i]; - $fvar = $fvars[$i]; - - if($i == 0) { - $prevfile = "NULL"; - } else { - $prevfile = "file" . $fvars[$i - 1]; - } - print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, "); - print(OUTPUT "data$fvar + ". (length($file) + 1) .", "); - print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n"); -} - -print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n"); -print(OUTPUT "#define FS_NUMFILES $i\n"); diff --git a/ext/lwip/src/apps/httpd/makefsdata/makefsdata.c b/ext/lwip/src/apps/httpd/makefsdata/makefsdata.c deleted file mode 100644 index 34101a4..0000000 --- a/ext/lwip/src/apps/httpd/makefsdata/makefsdata.c +++ /dev/null @@ -1,1033 +0,0 @@ -/** - * makefsdata: Converts a directory structure for use with the lwIP httpd. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Jim Pettinato - * Simon Goldschmidt - * - * @todo: - * - take TCP_MSS, LWIP_TCP_TIMESTAMPS and - * PAYLOAD_ALIGN_TYPE/PAYLOAD_ALIGNMENT as arguments - */ - -#include -#include -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include "windows.h" -#else -#include -#endif -#include -#include -#include -#include - -/** Makefsdata can generate *all* files deflate-compressed (where file size shrinks). - * Since nearly all browsers support this, this is a good way to reduce ROM size. - * To compress the files, "miniz.c" must be downloaded seperately. - */ -#ifndef MAKEFS_SUPPORT_DEFLATE -#define MAKEFS_SUPPORT_DEFLATE 0 -#endif - -#define COPY_BUFSIZE (1024*1024) /* 1 MByte */ - -#if MAKEFS_SUPPORT_DEFLATE -#include "../miniz.c" - -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint; - -#define my_max(a,b) (((a) > (b)) ? (a) : (b)) -#define my_min(a,b) (((a) < (b)) ? (a) : (b)) - -/* COMP_OUT_BUF_SIZE is the size of the output buffer used during compression. - COMP_OUT_BUF_SIZE must be >= 1 and <= OUT_BUF_SIZE */ -#define COMP_OUT_BUF_SIZE COPY_BUFSIZE - -/* OUT_BUF_SIZE is the size of the output buffer used during decompression. - OUT_BUF_SIZE must be a power of 2 >= TINFL_LZ_DICT_SIZE (because the low-level decompressor not only writes, but reads from the output buffer as it decompresses) */ -#define OUT_BUF_SIZE COPY_BUFSIZE -static uint8 s_outbuf[OUT_BUF_SIZE]; -static uint8 s_checkbuf[OUT_BUF_SIZE]; - -/* tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k). - This example makes it a global vs. putting it on the stack, of course in real-world usage you'll probably malloc() or new it. */ -tdefl_compressor g_deflator; -tinfl_decompressor g_inflator; - -int deflate_level = 10; /* default compression level, can be changed via command line */ -#define USAGE_ARG_DEFLATE " [-defl<:compr_level>]" -#else /* MAKEFS_SUPPORT_DEFLATE */ -#define USAGE_ARG_DEFLATE "" -#endif /* MAKEFS_SUPPORT_DEFLATE */ - -/* Compatibility defines Win32 vs. DOS */ -#ifdef WIN32 - -#define FIND_T WIN32_FIND_DATAA -#define FIND_T_FILENAME(fInfo) (fInfo.cFileName) -#define FIND_T_IS_DIR(fInfo) ((fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) -#define FIND_T_IS_FILE(fInfo) ((fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) -#define FIND_RET_T HANDLE -#define FINDFIRST_FILE(path, result) FindFirstFileA(path, result) -#define FINDFIRST_DIR(path, result) FindFirstFileA(path, result) -#define FINDNEXT(ff_res, result) FindNextFileA(ff_res, result) -#define FINDFIRST_SUCCEEDED(ret) (ret != INVALID_HANDLE_VALUE) -#define FINDNEXT_SUCCEEDED(ret) (ret == TRUE) - -#define GETCWD(path, len) GetCurrentDirectoryA(len, path) -#define CHDIR(path) SetCurrentDirectoryA(path) -#define CHDIR_SUCCEEDED(ret) (ret == TRUE) - -#else - -#define FIND_T struct ffblk -#define FIND_T_FILENAME(fInfo) (fInfo.ff_name) -#define FIND_T_IS_DIR(fInfo) ((fInfo.ff_attrib & FA_DIREC) == FA_DIREC) -#define FIND_T_IS_FILE(fInfo) (1) -#define FIND_RET_T int -#define FINDFIRST_FILE(path, result) findfirst(path, result, FA_ARCH) -#define FINDFIRST_DIR(path, result) findfirst(path, result, FA_DIREC) -#define FINDNEXT(ff_res, result) FindNextFileA(ff_res, result) -#define FINDFIRST_SUCCEEDED(ret) (ret == 0) -#define FINDNEXT_SUCCEEDED(ret) (ret == 0) - -#define GETCWD(path, len) getcwd(path, len) -#define CHDIR(path) chdir(path) -#define CHDIR_SUCCEEDED(ret) (ret == 0) - -#endif - -#define NEWLINE "\r\n" -#define NEWLINE_LEN 2 - -/* define this to get the header variables we use to build HTTP headers */ -#define LWIP_HTTPD_DYNAMIC_HEADERS 1 -#define LWIP_HTTPD_SSI 1 -#include "lwip/init.h" -#include "../httpd_structs.h" -#include "lwip/apps/fs.h" - -#include "../core/inet_chksum.c" -#include "../core/def.c" - -/** (Your server name here) */ -const char *serverID = "Server: "HTTPD_SERVER_AGENT"\r\n"; -char serverIDBuffer[1024]; - -/* change this to suit your MEM_ALIGNMENT */ -#define PAYLOAD_ALIGNMENT 4 -/* set this to 0 to prevent aligning payload */ -#define ALIGN_PAYLOAD 1 -/* define this to a type that has the required alignment */ -#define PAYLOAD_ALIGN_TYPE "unsigned int" -static int payload_alingment_dummy_counter = 0; - -#define HEX_BYTES_PER_LINE 16 - -#define MAX_PATH_LEN 256 - -struct file_entry -{ - struct file_entry* next; - const char* filename_c; -}; - -int process_sub(FILE *data_file, FILE *struct_file); -int process_file(FILE *data_file, FILE *struct_file, const char *filename); -int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, - u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed); -int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i); -int s_put_ascii(char *buf, const char *ascii_string, int len, int *i); -void concat_files(const char *file1, const char *file2, const char *targetfile); -int check_path(char* path, size_t size); - -/* 5 bytes per char + 3 bytes per line */ -static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)]; - -char curSubdir[MAX_PATH_LEN]; -char lastFileVar[MAX_PATH_LEN]; -char hdr_buf[4096]; - -unsigned char processSubs = 1; -unsigned char includeHttpHeader = 1; -unsigned char useHttp11 = 0; -unsigned char supportSsi = 1; -unsigned char precalcChksum = 0; -unsigned char includeLastModified = 0; -#if MAKEFS_SUPPORT_DEFLATE -unsigned char deflateNonSsiFiles = 0; -size_t deflatedBytesReduced = 0; -size_t overallDataBytes = 0; -#endif - -struct file_entry* first_file = NULL; -struct file_entry* last_file = NULL; - -static void print_usage(void) -{ - printf(" Usage: htmlgen [targetdir] [-s] [-e] [-i] [-11] [-nossi] [-c] [-f:] [-m] [-svr:]" USAGE_ARG_DEFLATE NEWLINE NEWLINE); - printf(" targetdir: relative or absolute path to files to convert" NEWLINE); - printf(" switch -s: toggle processing of subdirectories (default is on)" NEWLINE); - printf(" switch -e: exclude HTTP header from file (header is created at runtime, default is off)" NEWLINE); - printf(" switch -11: include HTTP 1.1 header (1.0 is default)" NEWLINE); - printf(" switch -nossi: no support for SSI (cannot calculate Content-Length for SSI)" NEWLINE); - printf(" switch -c: precalculate checksums for all pages (default is off)" NEWLINE); - printf(" switch -f: target filename (default is \"fsdata.c\")" NEWLINE); - printf(" switch -m: include \"Last-Modified\" header based on file time" NEWLINE); - printf(" switch -svr: server identifier sent in HTTP response header ('Server' field)" NEWLINE); -#if MAKEFS_SUPPORT_DEFLATE - printf(" switch -defl: deflate-compress all non-SSI files (with opt. compr.-level, default=10)" NEWLINE); - printf(" ATTENTION: browser has to support \"Content-Encoding: deflate\"!" NEWLINE); -#endif - printf(" if targetdir not specified, htmlgen will attempt to" NEWLINE); - printf(" process files in subdirectory 'fs'" NEWLINE); -} - -int main(int argc, char *argv[]) -{ - char path[MAX_PATH_LEN]; - char appPath[MAX_PATH_LEN]; - FILE *data_file; - FILE *struct_file; - int filesProcessed; - int i; - char targetfile[MAX_PATH_LEN]; - strcpy(targetfile, "fsdata.c"); - - memset(path, 0, sizeof(path)); - memset(appPath, 0, sizeof(appPath)); - - printf(NEWLINE " makefsdata - HTML to C source converter" NEWLINE); - printf(" by Jim Pettinato - circa 2003 " NEWLINE); - printf(" extended by Simon Goldschmidt - 2009 " NEWLINE NEWLINE); - - strcpy(path, "fs"); - for (i = 1; i < argc; i++) { - if (argv[i] == NULL) { - continue; - } - if (argv[i][0] == '-') { - if (strstr(argv[i], "-svr:") == argv[i]) { - snprintf(serverIDBuffer, sizeof(serverIDBuffer), "Server: %s\r\n", &argv[i][5]); - serverID = serverIDBuffer; - printf("Using Server-ID: \"%s\"\n", serverID); - } else if (strstr(argv[i], "-s") == argv[i]) { - processSubs = 0; - } else if (strstr(argv[i], "-e") == argv[i]) { - includeHttpHeader = 0; - } else if (strstr(argv[i], "-11") == argv[i]) { - useHttp11 = 1; - } else if (strstr(argv[i], "-nossi") == argv[i]) { - supportSsi = 0; - } else if (strstr(argv[i], "-c") == argv[i]) { - precalcChksum = 1; - } else if (strstr(argv[i], "-f:") == argv[i]) { - strncpy(targetfile, &argv[i][3], sizeof(targetfile) - 1); - targetfile[sizeof(targetfile) - 1] = 0; - printf("Writing to file \"%s\"\n", targetfile); - } else if (strstr(argv[i], "-m") == argv[i]) { - includeLastModified = 1; - } else if (strstr(argv[i], "-defl") == argv[i]) { -#if MAKEFS_SUPPORT_DEFLATE - char* colon = strstr(argv[i], ":"); - if (colon) { - if (colon[1] != 0) { - int defl_level = atoi(&colon[1]); - if ((defl_level >= 0) && (defl_level <= 10)) { - deflate_level = defl_level; - } else { - printf("ERROR: deflate level must be [0..10]" NEWLINE); - exit(0); - } - } - } - deflateNonSsiFiles = 1; - printf("Deflating all non-SSI files with level %d (but only if size is reduced)" NEWLINE, deflate_level); -#else - printf("WARNING: Deflate support is disabled\n"); -#endif - } else if ((strstr(argv[i], "-?")) || (strstr(argv[i], "-h"))) { - print_usage(); - exit(0); - } - } else if ((argv[i][0] == '/') && (argv[i][1] == '?') && (argv[i][2] == 0)) { - print_usage(); - exit(0); - } else { - strncpy(path, argv[i], sizeof(path)-1); - path[sizeof(path)-1] = 0; - } - } - - if (!check_path(path, sizeof(path))) { - printf("Invalid path: \"%s\"." NEWLINE, path); - exit(-1); - } - - GETCWD(appPath, MAX_PATH_LEN); - /* if command line param or subdir named 'fs' not found spout usage verbiage */ - if (!CHDIR_SUCCEEDED(CHDIR(path))) { - /* if no subdir named 'fs' (or the one which was given) exists, spout usage verbiage */ - printf(" Failed to open directory \"%s\"." NEWLINE NEWLINE, path); - print_usage(); - exit(-1); - } - CHDIR(appPath); - - printf("HTTP %sheader will %s statically included." NEWLINE, - (includeHttpHeader ? (useHttp11 ? "1.1 " : "1.0 ") : ""), - (includeHttpHeader ? "be" : "not be")); - - sprintf(curSubdir, ""); /* start off in web page's root directory - relative paths */ - printf(" Processing all files in directory %s", path); - if (processSubs) { - printf(" and subdirectories..." NEWLINE NEWLINE); - } else { - printf("..." NEWLINE NEWLINE); - } - - data_file = fopen("fsdata.tmp", "wb"); - if (data_file == NULL) { - printf("Failed to create file \"fsdata.tmp\"\n"); - exit(-1); - } - struct_file = fopen("fshdr.tmp", "wb"); - if (struct_file == NULL) { - printf("Failed to create file \"fshdr.tmp\"\n"); - fclose(data_file); - exit(-1); - } - - CHDIR(path); - - fprintf(data_file, "#include \"lwip/apps/fs.h\"" NEWLINE); - fprintf(data_file, "#include \"lwip/def.h\"" NEWLINE); - fprintf(data_file, "#include \"fsdata.h\"" NEWLINE NEWLINE NEWLINE); - - fprintf(data_file, "#define file_NULL (struct fsdata_file *) NULL" NEWLINE NEWLINE NEWLINE); - /* define FS_FILE_FLAGS_HEADER_INCLUDED to 1 if not defined (compatibility with older httpd/fs) */ - fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_INCLUDED" NEWLINE "#define FS_FILE_FLAGS_HEADER_INCLUDED 1" NEWLINE "#endif" NEWLINE); - /* define FS_FILE_FLAGS_HEADER_PERSISTENT to 0 if not defined (compatibility with older httpd/fs: wasn't supported back then) */ - fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT" NEWLINE "#define FS_FILE_FLAGS_HEADER_PERSISTENT 0" NEWLINE "#endif" NEWLINE); - - /* define alignment defines */ -#if ALIGN_PAYLOAD - fprintf(data_file, "/* FSDATA_FILE_ALIGNMENT: 0=off, 1=by variable, 2=by include */" NEWLINE "#ifndef FSDATA_FILE_ALIGNMENT" NEWLINE "#define FSDATA_FILE_ALIGNMENT 0" NEWLINE "#endif" NEWLINE); -#endif - fprintf(data_file, "#ifndef FSDATA_ALIGN_PRE" NEWLINE "#define FSDATA_ALIGN_PRE" NEWLINE "#endif" NEWLINE); - fprintf(data_file, "#ifndef FSDATA_ALIGN_POST" NEWLINE "#define FSDATA_ALIGN_POST" NEWLINE "#endif" NEWLINE); -#if ALIGN_PAYLOAD - fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==2" NEWLINE "#include \"fsdata_alignment.h\"" NEWLINE "#endif" NEWLINE); -#endif - - sprintf(lastFileVar, "NULL"); - - filesProcessed = process_sub(data_file, struct_file); - - /* data_file now contains all of the raw data.. now append linked list of - * file header structs to allow embedded app to search for a file name */ - fprintf(data_file, NEWLINE NEWLINE); - fprintf(struct_file, "#define FS_ROOT file_%s" NEWLINE, lastFileVar); - fprintf(struct_file, "#define FS_NUMFILES %d" NEWLINE NEWLINE, filesProcessed); - - fclose(data_file); - fclose(struct_file); - - CHDIR(appPath); - /* append struct_file to data_file */ - printf(NEWLINE "Creating target file..." NEWLINE NEWLINE); - concat_files("fsdata.tmp", "fshdr.tmp", targetfile); - - /* if succeeded, delete the temporary files */ - if (remove("fsdata.tmp") != 0) { - printf("Warning: failed to delete fsdata.tmp\n"); - } - if (remove("fshdr.tmp") != 0) { - printf("Warning: failed to delete fshdr.tmp\n"); - } - - printf(NEWLINE "Processed %d files - done." NEWLINE, filesProcessed); -#if MAKEFS_SUPPORT_DEFLATE - if (deflateNonSsiFiles) { - printf("(Deflated total byte reduction: %d bytes -> %d bytes (%.02f%%)" NEWLINE, - (int)overallDataBytes, (int)deflatedBytesReduced, (float)((deflatedBytesReduced*100.0)/overallDataBytes)); - } -#endif - printf(NEWLINE); - - while (first_file != NULL) { - struct file_entry* fe = first_file; - first_file = fe->next; - free(fe); - } - - return 0; -} - -int check_path(char* path, size_t size) -{ - size_t slen; - if (path[0] == 0) { - /* empty */ - return 0; - } - slen = strlen(path); - if (slen >= size) { - /* not NULL-terminated */ - return 0; - } - while ((slen > 0) && ((path[slen] == '\\') || (path[slen] == '/'))) { - /* path should not end with trailing backslash */ - path[slen] = 0; - slen--; - } - if (slen == 0) { - return 0; - } - return 1; -} - -static void copy_file(const char *filename_in, FILE *fout) -{ - FILE *fin; - size_t len; - void* buf; - fin = fopen(filename_in, "rb"); - if (fin == NULL) { - printf("Failed to open file \"%s\"\n", filename_in); - exit(-1); - } - buf = malloc(COPY_BUFSIZE); - while ((len = fread(buf, 1, COPY_BUFSIZE, fin)) > 0) { - fwrite(buf, 1, len, fout); - } - free(buf); - fclose(fin); -} - -void concat_files(const char *file1, const char *file2, const char *targetfile) -{ - FILE *fout; - fout = fopen(targetfile, "wb"); - if (fout == NULL) { - printf("Failed to open file \"%s\"\n", targetfile); - exit(-1); - } - copy_file(file1, fout); - copy_file(file2, fout); - fclose(fout); -} - -int process_sub(FILE *data_file, FILE *struct_file) -{ - FIND_T fInfo; - FIND_RET_T fret; - int filesProcessed = 0; - - if (processSubs) { - /* process subs recursively */ - size_t sublen = strlen(curSubdir); - size_t freelen = sizeof(curSubdir) - sublen - 1; - LWIP_ASSERT("sublen < sizeof(curSubdir)", sublen < sizeof(curSubdir)); - fret = FINDFIRST_DIR("*", &fInfo); - if (FINDFIRST_SUCCEEDED(fret)) { - do { - const char *curName = FIND_T_FILENAME(fInfo); - if ((curName[0] == '.') || (strcmp(curName, "CVS") == 0)) { - continue; - } - if (!FIND_T_IS_DIR(fInfo)) { - continue; - } - if (freelen > 0) { - CHDIR(curName); - strncat(curSubdir, "/", freelen); - strncat(curSubdir, curName, freelen - 1); - curSubdir[sizeof(curSubdir) - 1] = 0; - printf("processing subdirectory %s/..." NEWLINE, curSubdir); - filesProcessed += process_sub(data_file, struct_file); - CHDIR(".."); - curSubdir[sublen] = 0; - } else { - printf("WARNING: cannot process sub due to path length restrictions: \"%s/%s\"\n", curSubdir, curName); - } - } while (FINDNEXT_SUCCEEDED(FINDNEXT(fret, &fInfo))); - } - } - - fret = FINDFIRST_FILE("*.*", &fInfo); - if (FINDFIRST_SUCCEEDED(fret)) { - /* at least one file in directory */ - do { - if (FIND_T_IS_FILE(fInfo)) { - const char *curName = FIND_T_FILENAME(fInfo); - printf("processing %s/%s..." NEWLINE, curSubdir, curName); - if (process_file(data_file, struct_file, curName) < 0) { - printf(NEWLINE "Error... aborting" NEWLINE); - return -1; - } - filesProcessed++; - } - } while (FINDNEXT_SUCCEEDED(FINDNEXT(fret, &fInfo))); - } - return filesProcessed; -} - -u8_t* get_file_data(const char* filename, int* file_size, int can_be_compressed, int* is_compressed) -{ - FILE *inFile; - size_t fsize = 0; - u8_t* buf; - size_t r; - int rs; - inFile = fopen(filename, "rb"); - if (inFile == NULL) { - printf("Failed to open file \"%s\"\n", filename); - exit(-1); - } - fseek(inFile, 0, SEEK_END); - rs = ftell(inFile); - if (rs < 0) { - printf("ftell failed with %d\n", errno); - exit(-1); - } - fsize = (size_t)rs; - fseek(inFile, 0, SEEK_SET); - buf = (u8_t*)malloc(fsize); - LWIP_ASSERT("buf != NULL", buf != NULL); - r = fread(buf, 1, fsize, inFile); - *file_size = fsize; - *is_compressed = 0; -#if MAKEFS_SUPPORT_DEFLATE - overallDataBytes += fsize; - if (deflateNonSsiFiles) { - if (can_be_compressed) { - if (fsize < OUT_BUF_SIZE) { - u8_t* ret_buf; - tdefl_status status; - size_t in_bytes = fsize; - size_t out_bytes = OUT_BUF_SIZE; - const void *next_in = buf; - void *next_out = s_outbuf; - /* create tdefl() compatible flags (we have to compose the low-level flags ourselves, or use tdefl_create_comp_flags_from_zip_params() but that means MINIZ_NO_ZLIB_APIS can't be defined). */ - mz_uint comp_flags = s_tdefl_num_probes[MZ_MIN(10, deflate_level)] | ((deflate_level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); - if (!deflate_level) { - comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; - } - status = tdefl_init(&g_deflator, NULL, NULL, comp_flags); - if (status != TDEFL_STATUS_OKAY) { - printf("tdefl_init() failed!\n"); - exit(-1); - } - memset(s_outbuf, 0, sizeof(s_outbuf)); - status = tdefl_compress(&g_deflator, next_in, &in_bytes, next_out, &out_bytes, TDEFL_FINISH); - if (status != TDEFL_STATUS_DONE) { - printf("deflate failed: %d\n", status); - exit(-1); - } - LWIP_ASSERT("out_bytes <= COPY_BUFSIZE", out_bytes <= OUT_BUF_SIZE); - if (out_bytes < fsize) { - ret_buf = (u8_t*)malloc(out_bytes); - LWIP_ASSERT("ret_buf != NULL", ret_buf != NULL); - memcpy(ret_buf, s_outbuf, out_bytes); - { - /* sanity-check compression be inflating and comparing to the original */ - tinfl_status dec_status; - tinfl_decompressor inflator; - size_t dec_in_bytes = out_bytes; - size_t dec_out_bytes = OUT_BUF_SIZE; - next_out = s_checkbuf; - - tinfl_init(&inflator); - memset(s_checkbuf, 0, sizeof(s_checkbuf)); - dec_status = tinfl_decompress(&inflator, (const mz_uint8 *)ret_buf, &dec_in_bytes, s_checkbuf, (mz_uint8 *)next_out, &dec_out_bytes, 0); - LWIP_ASSERT("tinfl_decompress failed", dec_status == TINFL_STATUS_DONE); - LWIP_ASSERT("tinfl_decompress size mismatch", fsize == dec_out_bytes); - LWIP_ASSERT("decompressed memcmp failed", !memcmp(s_checkbuf, buf, fsize)); - } - /* free original buffer, use compressed data + size */ - free(buf); - buf = ret_buf; - *file_size = out_bytes; - printf(" - deflate: %d bytes -> %d bytes (%.02f%%)" NEWLINE, (int)fsize, (int)out_bytes, (float)((out_bytes*100.0)/fsize)); - deflatedBytesReduced += (size_t)(fsize - out_bytes); - *is_compressed = 1; - } else { - printf(" - uncompressed: (would be %d bytes larger using deflate)" NEWLINE, (int)(out_bytes - fsize)); - } - } else { - printf(" - uncompressed: (file is larger than deflate bufer)" NEWLINE); - } - } else { - printf(" - SSI file, cannot be compressed" NEWLINE); - } - } -#else - LWIP_UNUSED_ARG(can_be_compressed); -#endif - fclose(inFile); - return buf; -} - -void process_file_data(FILE* data_file, u8_t* file_data, size_t file_size) -{ - size_t written, i, src_off=0; - - size_t off = 0; - for (i = 0; i < file_size; i++) { - LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - 5); - sprintf(&file_buffer_c[off], "0x%02.2x,", file_data[i]); - off += 5; - if ((++src_off % HEX_BYTES_PER_LINE) == 0) { - LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - NEWLINE_LEN); - memcpy(&file_buffer_c[off], NEWLINE, NEWLINE_LEN); - off += NEWLINE_LEN; - } - if (off + 20 >= sizeof(file_buffer_c)) { - written = fwrite(file_buffer_c, 1, off, data_file); - LWIP_ASSERT("written == off", written == off); - off = 0; - } - } - written = fwrite(file_buffer_c, 1, off, data_file); - LWIP_ASSERT("written == off", written == off); -} - -int write_checksums(FILE *struct_file, const char *varname, - u16_t hdr_len, u16_t hdr_chksum, const u8_t* file_data, size_t file_size) -{ - int chunk_size = TCP_MSS; - int offset, src_offset; - size_t len; - int i = 0; -#if LWIP_TCP_TIMESTAMPS - /* when timestamps are used, usable space is 12 bytes less per segment */ - chunk_size -= 12; -#endif - - fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); - fprintf(struct_file, "const struct fsdata_chksum chksums_%s[] = {" NEWLINE, varname); - - if (hdr_len > 0) { - /* add checksum for HTTP header */ - fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, 0, hdr_chksum, hdr_len); - i++; - } - src_offset = 0; - for (offset = hdr_len; ; offset += len) { - unsigned short chksum; - void* data = (void*)&file_data[src_offset]; - len = LWIP_MIN(chunk_size, (int)file_size - src_offset); - if (len == 0) { - break; - } - chksum = ~inet_chksum(data, (u16_t)len); - /* add checksum for data */ - fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, offset, chksum, len); - i++; - } - fprintf(struct_file, "};" NEWLINE); - fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); - return i; -} - -static int is_valid_char_for_c_var(char x) -{ - if (((x >= 'A') && (x <= 'Z')) || - ((x >= 'a') && (x <= 'z')) || - ((x >= '0') && (x <= '9')) || - (x == '_')) { - return 1; - } - return 0; -} - -static void fix_filename_for_c(char* qualifiedName, size_t max_len) -{ - struct file_entry* f; - size_t len = strlen(qualifiedName); - char *new_name = (char*)malloc(len + 2); - int filename_ok; - int cnt = 0; - size_t i; - if (len + 3 == max_len) { - printf("File name too long: \"%s\"\n", qualifiedName); - exit(-1); - } - strcpy(new_name, qualifiedName); - for (i = 0; i < len; i++) { - if (!is_valid_char_for_c_var(new_name[i])) { - new_name[i] = '_'; - } - } - do { - filename_ok = 1; - for (f = first_file; f != NULL; f = f->next) { - if (!strcmp(f->filename_c, new_name)) { - filename_ok = 0; - cnt++; - /* try next unique file name */ - sprintf(&new_name[len], "%d", cnt); - break; - } - } - } while (!filename_ok && (cnt < 999)); - if (!filename_ok) { - printf("Failed to get unique file name: \"%s\"\n", qualifiedName); - exit(-1); - } - strcpy(qualifiedName, new_name); - free(new_name); -} - -static void register_filename(const char* qualifiedName) -{ - struct file_entry* fe = (struct file_entry*)malloc(sizeof(struct file_entry)); - fe->filename_c = strdup(qualifiedName); - fe->next = NULL; - if (first_file == NULL) { - first_file = last_file = fe; - } else { - last_file->next = fe; - last_file = fe; - } -} - -int is_ssi_file(const char* filename) -{ - size_t loop; - for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) { - if (strstr(filename, g_pcSSIExtensions[loop])) { - return 1; - } - } - return 0; -} - -int process_file(FILE *data_file, FILE *struct_file, const char *filename) -{ - char varname[MAX_PATH_LEN]; - int i = 0; - char qualifiedName[MAX_PATH_LEN]; - int file_size; - u16_t http_hdr_chksum = 0; - u16_t http_hdr_len = 0; - int chksum_count = 0; - u8_t flags = 0; - const char* flags_str; - u8_t has_content_len; - u8_t* file_data; - int is_compressed = 0; - - /* create qualified name (@todo: prepend slash or not?) */ - sprintf(qualifiedName,"%s/%s", curSubdir, filename); - /* create C variable name */ - strcpy(varname, qualifiedName); - /* convert slashes & dots to underscores */ - fix_filename_for_c(varname, MAX_PATH_LEN); - register_filename(varname); -#if ALIGN_PAYLOAD - /* to force even alignment of array, type 1 */ - fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==1" NEWLINE); - fprintf(data_file, "static const " PAYLOAD_ALIGN_TYPE " dummy_align_%s = %d;" NEWLINE, varname, payload_alingment_dummy_counter++); - fprintf(data_file, "#endif" NEWLINE); -#endif /* ALIGN_PAYLOAD */ - fprintf(data_file, "static const unsigned char FSDATA_ALIGN_PRE data_%s[] FSDATA_ALIGN_POST = {" NEWLINE, varname); - /* encode source file name (used by file system, not returned to browser) */ - fprintf(data_file, "/* %s (%d chars) */" NEWLINE, qualifiedName, strlen(qualifiedName)+1); - file_put_ascii(data_file, qualifiedName, strlen(qualifiedName)+1, &i); -#if ALIGN_PAYLOAD - /* pad to even number of bytes to assure payload is on aligned boundary */ - while(i % PAYLOAD_ALIGNMENT != 0) { - fprintf(data_file, "0x%02.2x,", 0); - i++; - } -#endif /* ALIGN_PAYLOAD */ - fprintf(data_file, NEWLINE); - - has_content_len = !is_ssi_file(filename); - file_data = get_file_data(filename, &file_size, includeHttpHeader && has_content_len, &is_compressed); - if (includeHttpHeader) { - file_write_http_header(data_file, filename, file_size, &http_hdr_len, &http_hdr_chksum, has_content_len, is_compressed); - flags = FS_FILE_FLAGS_HEADER_INCLUDED; - if (has_content_len) { - flags |= FS_FILE_FLAGS_HEADER_PERSISTENT; - } - } - if (precalcChksum) { - chksum_count = write_checksums(struct_file, varname, http_hdr_len, http_hdr_chksum, file_data, file_size); - } - - /* build declaration of struct fsdata_file in temp file */ - fprintf(struct_file, "const struct fsdata_file file_%s[] = { {" NEWLINE, varname); - fprintf(struct_file, "file_%s," NEWLINE, lastFileVar); - fprintf(struct_file, "data_%s," NEWLINE, varname); - fprintf(struct_file, "data_%s + %d," NEWLINE, varname, i); - fprintf(struct_file, "sizeof(data_%s) - %d," NEWLINE, varname, i); - switch(flags) - { - case(FS_FILE_FLAGS_HEADER_INCLUDED): - flags_str = "FS_FILE_FLAGS_HEADER_INCLUDED"; - break; - case(FS_FILE_FLAGS_HEADER_PERSISTENT): - flags_str = "FS_FILE_FLAGS_HEADER_PERSISTENT"; - break; - case(FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT): - flags_str = "FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT"; - break; - default: - flags_str = "0"; - break; - } - fprintf(struct_file, "%s," NEWLINE, flags_str); - if (precalcChksum) { - fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); - fprintf(struct_file, "%d, chksums_%s," NEWLINE, chksum_count, varname); - fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); - } - fprintf(struct_file, "}};" NEWLINE NEWLINE); - strcpy(lastFileVar, varname); - - /* write actual file contents */ - i = 0; - fprintf(data_file, NEWLINE "/* raw file data (%d bytes) */" NEWLINE, file_size); - process_file_data(data_file, file_data, file_size); - fprintf(data_file, "};" NEWLINE NEWLINE); - free(file_data); - return 0; -} - -int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, - u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed) -{ - int i = 0; - int response_type = HTTP_HDR_OK; - const char* file_type; - const char *cur_string; - size_t cur_len; - int written = 0; - size_t hdr_len = 0; - u16_t acc; - const char *file_ext; - int j; - u8_t provide_last_modified = includeLastModified; - - memset(hdr_buf, 0, sizeof(hdr_buf)); - - if (useHttp11) { - response_type = HTTP_HDR_OK_11; - } - - fprintf(data_file, NEWLINE "/* HTTP header */"); - if (strstr(filename, "404") == filename) { - response_type = HTTP_HDR_NOT_FOUND; - if (useHttp11) { - response_type = HTTP_HDR_NOT_FOUND_11; - } - } else if (strstr(filename, "400") == filename) { - response_type = HTTP_HDR_BAD_REQUEST; - if (useHttp11) { - response_type = HTTP_HDR_BAD_REQUEST_11; - } - } else if (strstr(filename, "501") == filename) { - response_type = HTTP_HDR_NOT_IMPL; - if (useHttp11) { - response_type = HTTP_HDR_NOT_IMPL_11; - } - } - cur_string = g_psHTTPHeaderStrings[response_type]; - cur_len = strlen(cur_string); - fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); - written += file_put_ascii(data_file, cur_string, cur_len, &i); - i = 0; - if (precalcChksum) { - memcpy(&hdr_buf[hdr_len], cur_string, cur_len); - hdr_len += cur_len; - } - - cur_string = serverID; - cur_len = strlen(cur_string); - fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); - written += file_put_ascii(data_file, cur_string, cur_len, &i); - i = 0; - if (precalcChksum) { - memcpy(&hdr_buf[hdr_len], cur_string, cur_len); - hdr_len += cur_len; - } - - file_ext = filename; - if (file_ext != NULL) { - while(strstr(file_ext, ".") != NULL) { - file_ext = strstr(file_ext, "."); - file_ext++; - } - } - if ((file_ext == NULL) || (*file_ext == 0)) { - printf("failed to get extension for file \"%s\", using default.\n", filename); - file_type = HTTP_HDR_DEFAULT_TYPE; - } else { - file_type = NULL; - for (j = 0; j < NUM_HTTP_HEADERS; j++) { - if (!strcmp(file_ext, g_psHTTPHeaders[j].extension)) { - file_type = g_psHTTPHeaders[j].content_type; - break; - } - } - if (file_type == NULL) { - printf("failed to get file type for extension \"%s\", using default.\n", file_ext); - file_type = HTTP_HDR_DEFAULT_TYPE; - } - } - - /* Content-Length is used for persistent connections in HTTP/1.1 but also for - download progress in older versions - @todo: just use a big-enough buffer and let the HTTPD send spaces? */ - if (provide_content_len) { - char intbuf[MAX_PATH_LEN]; - int content_len = file_size; - memset(intbuf, 0, sizeof(intbuf)); - cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH]; - cur_len = strlen(cur_string); - fprintf(data_file, NEWLINE "/* \"%s%d\r\n\" (%d+ bytes) */" NEWLINE, cur_string, content_len, cur_len+2); - written += file_put_ascii(data_file, cur_string, cur_len, &i); - if (precalcChksum) { - memcpy(&hdr_buf[hdr_len], cur_string, cur_len); - hdr_len += cur_len; - } - - _itoa(content_len, intbuf, 10); - strcat(intbuf, "\r\n"); - cur_len = strlen(intbuf); - written += file_put_ascii(data_file, intbuf, cur_len, &i); - i = 0; - if (precalcChksum) { - memcpy(&hdr_buf[hdr_len], intbuf, cur_len); - hdr_len += cur_len; - } - } - if (provide_last_modified) { - char modbuf[256]; - struct stat stat_data; - struct tm* t; - memset(modbuf, 0, sizeof(modbuf)); - memset(&stat_data, 0, sizeof(stat_data)); - cur_string = modbuf; - strcpy(modbuf, "Last-Modified: "); - if (stat(filename, &stat_data) != 0) { - printf("stat(%s) failed with error %d\n", filename, errno); - exit(-1); - } - t = gmtime(&stat_data.st_mtime); - if (t == NULL) { - printf("gmtime() failed with error %d\n", errno); - exit(-1); - } - strftime(&modbuf[15], sizeof(modbuf)-15, "%a, %d %b %Y %H:%M:%S GMT", t); - cur_len = strlen(cur_string); - fprintf(data_file, NEWLINE "/* \"%s\"\r\n\" (%d+ bytes) */" NEWLINE, cur_string, cur_len+2); - written += file_put_ascii(data_file, cur_string, cur_len, &i); - if (precalcChksum) { - memcpy(&hdr_buf[hdr_len], cur_string, cur_len); - hdr_len += cur_len; - } - - modbuf[0] = 0; - strcat(modbuf, "\r\n"); - cur_len = strlen(modbuf); - written += file_put_ascii(data_file, modbuf, cur_len, &i); - i = 0; - if (precalcChksum) { - memcpy(&hdr_buf[hdr_len], modbuf, cur_len); - hdr_len += cur_len; - } - } - - /* HTTP/1.1 implements persistent connections */ - if (useHttp11) { - if (provide_content_len) { - cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_KEEPALIVE]; - } else { - /* no Content-Length available, so a persistent connection is no possible - because the client does not know the data length */ - cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE]; - } - cur_len = strlen(cur_string); - fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); - written += file_put_ascii(data_file, cur_string, cur_len, &i); - i = 0; - if (precalcChksum) { - memcpy(&hdr_buf[hdr_len], cur_string, cur_len); - hdr_len += cur_len; - } - } - -#if MAKEFS_SUPPORT_DEFLATE - if (is_compressed) { - /* tell the client about the deflate encoding */ - LWIP_ASSERT("error", deflateNonSsiFiles); - cur_string = "Content-Encoding: deflate\r\n"; - cur_len = strlen(cur_string); - fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); - written += file_put_ascii(data_file, cur_string, cur_len, &i); - i = 0; - } -#else - LWIP_UNUSED_ARG(is_compressed); -#endif - - /* write content-type, ATTENTION: this includes the double-CRLF! */ - cur_string = file_type; - cur_len = strlen(cur_string); - fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); - written += file_put_ascii(data_file, cur_string, cur_len, &i); - i = 0; - - /* ATTENTION: headers are done now (double-CRLF has been written!) */ - - if (precalcChksum) { - memcpy(&hdr_buf[hdr_len], cur_string, cur_len); - hdr_len += cur_len; - - LWIP_ASSERT("hdr_len <= 0xffff", hdr_len <= 0xffff); - LWIP_ASSERT("strlen(hdr_buf) == hdr_len", strlen(hdr_buf) == hdr_len); - acc = ~inet_chksum(hdr_buf, (u16_t)hdr_len); - *http_hdr_len = (u16_t)hdr_len; - *http_hdr_chksum = acc; - } - - return written; -} - -int file_put_ascii(FILE *file, const char* ascii_string, int len, int *i) -{ - int x; - for (x = 0; x < len; x++) { - unsigned char cur = ascii_string[x]; - fprintf(file, "0x%02.2x,", cur); - if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { - fprintf(file, NEWLINE); - } - } - return len; -} - -int s_put_ascii(char *buf, const char *ascii_string, int len, int *i) -{ - int x; - int idx = 0; - for (x = 0; x < len; x++) { - unsigned char cur = ascii_string[x]; - sprintf(&buf[idx], "0x%02.2x,", cur); - idx += 5; - if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { - sprintf(&buf[idx], NEWLINE); - idx += NEWLINE_LEN; - } - } - return len; -} diff --git a/ext/lwip/src/apps/httpd/makefsdata/readme.txt b/ext/lwip/src/apps/httpd/makefsdata/readme.txt deleted file mode 100644 index 3768585..0000000 --- a/ext/lwip/src/apps/httpd/makefsdata/readme.txt +++ /dev/null @@ -1,13 +0,0 @@ -This directory contains a script ('makefsdata') to create C code suitable for -httpd for given html pages (or other files) in a directory. - -There is also a plain C console application doing the same and extended a bit. - -Usage: htmlgen [targetdir] [-s] [-i]s - targetdir: relative or absolute path to files to convert - switch -s: toggle processing of subdirectories (default is on) - switch -e: exclude HTTP header from file (header is created at runtime, default is on) - switch -11: include HTTP 1.1 header (1.0 is default) - - if targetdir not specified, makefsdata will attempt to - process files in subdirectory 'fs'. diff --git a/ext/lwip/src/apps/lwiperf/lwiperf.c b/ext/lwip/src/apps/lwiperf/lwiperf.c deleted file mode 100644 index 0686867..0000000 --- a/ext/lwip/src/apps/lwiperf/lwiperf.c +++ /dev/null @@ -1,662 +0,0 @@ -/** - * @file - * lwIP iPerf server implementation - */ - -/** - * @defgroup iperf Iperf server - * @ingroup apps - * - * This is a simple performance measuring server to check your bandwith using - * iPerf2 on a PC as client. - * It is currently a minimal implementation providing an IPv4 TCP server only. - * - * @todo: implement UDP mode and IPv6 - */ - -/* - * Copyright (c) 2014 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - */ - -#include "lwip/apps/lwiperf.h" - -#include "lwip/tcp.h" -#include "lwip/sys.h" - -#include - -/* Currently, only TCP-over-IPv4 is implemented (does iperf support IPv6 anyway?) */ -#if LWIP_IPV4 && LWIP_TCP - -/** Specify the idle timeout (in seconds) after that the test fails */ -#ifndef LWIPERF_TCP_MAX_IDLE_SEC -#define LWIPERF_TCP_MAX_IDLE_SEC 10U -#endif -#if LWIPERF_TCP_MAX_IDLE_SEC > 255 -#error LWIPERF_TCP_MAX_IDLE_SEC must fit into an u8_t -#endif - -/* File internal memory allocation (struct lwiperf_*): this defaults to - the heap */ -#ifndef LWIPERF_ALLOC -#define LWIPERF_ALLOC(type) mem_malloc(sizeof(type)) -#define LWIPERF_FREE(type, item) mem_free(item) -#endif - -/** If this is 1, check that received data has the correct format */ -#ifndef LWIPERF_CHECK_RX_DATA -#define LWIPERF_CHECK_RX_DATA 0 -#endif - -/** This is the Iperf settings struct sent from the client */ -typedef struct _lwiperf_settings { -#define LWIPERF_FLAGS_ANSWER_TEST 0x80000000 -#define LWIPERF_FLAGS_ANSWER_NOW 0x00000001 - u32_t flags; - u32_t num_threads; /* unused for now */ - u32_t remote_port; - u32_t buffer_len; /* unused for now */ - u32_t win_band; /* TCP window / UDP rate: unused for now */ - u32_t amount; /* pos. value: bytes?; neg. values: time (unit is 10ms: 1/100 second) */ -} lwiperf_settings_t; - -/** Basic connection handle */ -struct _lwiperf_state_base; -typedef struct _lwiperf_state_base lwiperf_state_base_t; -struct _lwiperf_state_base { - /* 1=tcp, 0=udp */ - u8_t tcp; - /* 1=server, 0=client */ - u8_t server; - lwiperf_state_base_t* next; - lwiperf_state_base_t* related_server_state; -}; - -/** Connection handle for a TCP iperf session */ -typedef struct _lwiperf_state_tcp { - lwiperf_state_base_t base; - struct tcp_pcb* server_pcb; - struct tcp_pcb* conn_pcb; - u32_t time_started; - lwiperf_report_fn report_fn; - void* report_arg; - u8_t poll_count; - u8_t next_num; - u32_t bytes_transferred; - lwiperf_settings_t settings; - u8_t have_settings_buf; -} lwiperf_state_tcp_t; - -/** List of active iperf sessions */ -static lwiperf_state_base_t* lwiperf_all_connections; -/** A const buffer to send from: we want to measure sending, not copying! */ -static const u8_t lwiperf_txbuf_const[1600] = { - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', - '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', -}; - -static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb); -static void lwiperf_tcp_err(void *arg, err_t err); - -/** Add an iperf session to the 'active' list */ -static void -lwiperf_list_add(lwiperf_state_base_t* item) -{ - if (lwiperf_all_connections == NULL) { - lwiperf_all_connections = item; - } else { - item = lwiperf_all_connections; - } -} - -/** Remove an iperf session from the 'active' list */ -static void -lwiperf_list_remove(lwiperf_state_base_t* item) -{ - lwiperf_state_base_t* prev = NULL; - lwiperf_state_base_t* iter; - for (iter = lwiperf_all_connections; iter != NULL; prev = iter, iter = iter->next) { - if (iter == item) { - if (prev == NULL) { - lwiperf_all_connections = iter->next; - } else { - prev->next = item; - } - /* @debug: ensure this item is listed only once */ - for (iter = iter->next; iter != NULL; iter = iter->next) { - LWIP_ASSERT("duplicate entry", iter != item); - } - break; - } - } -} - -/** Call the report function of an iperf tcp session */ -static void -lwip_tcp_conn_report(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type) -{ - if ((conn != NULL) && (conn->report_fn != NULL)) { - u32_t now, duration_ms, bandwidth_kbitpsec; - now = sys_now(); - duration_ms = now - conn->time_started; - if (duration_ms == 0) { - bandwidth_kbitpsec = 0; - } else { - bandwidth_kbitpsec = (conn->bytes_transferred / duration_ms) * 8U; - } - conn->report_fn(conn->report_arg, report_type, - &conn->conn_pcb->local_ip, conn->conn_pcb->local_port, - &conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port, - conn->bytes_transferred, duration_ms, bandwidth_kbitpsec); - } -} - -/** Close an iperf tcp session */ -static void -lwiperf_tcp_close(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type) -{ - err_t err; - - lwip_tcp_conn_report(conn, report_type); - lwiperf_list_remove(&conn->base); - if (conn->conn_pcb != NULL) { - tcp_arg(conn->conn_pcb, NULL); - tcp_poll(conn->conn_pcb, NULL, 0); - tcp_sent(conn->conn_pcb, NULL); - tcp_recv(conn->conn_pcb, NULL); - tcp_err(conn->conn_pcb, NULL); - err = tcp_close(conn->conn_pcb); - if (err != ERR_OK) { - /* don't want to wait for free memory here... */ - tcp_abort(conn->conn_pcb); - } - } else { - /* no conn pcb, this is the server pcb */ - err = tcp_close(conn->server_pcb); - LWIP_ASSERT("error", err != ERR_OK); - } - LWIPERF_FREE(lwiperf_state_tcp_t, conn); -} - -/** Try to send more data on an iperf tcp session */ -static err_t -lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn) -{ - int send_more; - err_t err; - u16_t txlen; - u16_t txlen_max; - void* txptr; - u8_t apiflags; - - LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0)); - - do { - send_more = 0; - if (conn->settings.amount & PP_HTONL(0x80000000)) { - /* this session is time-limited */ - u32_t now = sys_now(); - u32_t diff_ms = now - conn->time_started; - u32_t time = (u32_t)-(s32_t)htonl(conn->settings.amount); - u32_t time_ms = time * 10; - if (diff_ms >= time_ms) { - /* time specified by the client is over -> close the connection */ - lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); - return ERR_OK; - } - } else { - /* this session is byte-limited */ - u32_t amount_bytes = htonl(conn->settings.amount); - /* @todo: this can send up to 1*MSS more than requested... */ - if (amount_bytes >= conn->bytes_transferred) { - /* all requested bytes transferred -> close the connection */ - lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); - return ERR_OK; - } - } - - if (conn->bytes_transferred < 24) { - /* transmit the settings a first time */ - txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred]; - txlen_max = (u16_t)(24 - conn->bytes_transferred); - apiflags = TCP_WRITE_FLAG_COPY; - } else if (conn->bytes_transferred < 48) { - /* transmit the settings a second time */ - txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred - 24]; - txlen_max = (u16_t)(48 - conn->bytes_transferred); - apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE; - send_more = 1; - } else { - /* transmit data */ - /* @todo: every x bytes, transmit the settings again */ - txptr = (void*)(size_t)&lwiperf_txbuf_const[conn->bytes_transferred % 10]; - txlen_max = TCP_MSS; - if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */ - txlen_max = TCP_MSS - 24; - } - apiflags = 0; /* no copying needed */ - send_more = 1; - } - txlen = txlen_max; - do { - err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags); - if (err == ERR_MEM) { - txlen /= 2; - } - } while ((err == ERR_MEM) && (txlen >= (TCP_MSS/2))); - - if (err == ERR_OK) { - conn->bytes_transferred += txlen; - } else { - send_more = 0; - } - } while(send_more); - - tcp_output(conn->conn_pcb); - return ERR_OK; -} - -/** TCP sent callback, try to send more data */ -static err_t -lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) -{ - lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; - /* @todo: check 'len' (e.g. to time ACK of all data)? for now, we just send more... */ - LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb); - LWIP_UNUSED_ARG(tpcb); - LWIP_UNUSED_ARG(len); - - conn->poll_count = 0; - - return lwiperf_tcp_client_send_more(conn); -} - -/** TCP connected callback (active connection), send data now */ -static err_t -lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err) -{ - lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; - LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb); - LWIP_UNUSED_ARG(tpcb); - if (err != ERR_OK) { - lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); - return ERR_OK; - } - conn->poll_count = 0; - conn->time_started = sys_now(); - return lwiperf_tcp_client_send_more(conn); -} - -/** Start TCP connection back to the client (either parallel or after the - * receive test has finished. - */ -static err_t -lwiperf_tx_start(lwiperf_state_tcp_t* conn) -{ - err_t err; - lwiperf_state_tcp_t* client_conn; - struct tcp_pcb* newpcb; - ip_addr_t remote_addr; - u16_t remote_port; - - client_conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); - if (client_conn == NULL) { - return ERR_MEM; - } - newpcb = tcp_new(); - if (newpcb == NULL) { - LWIPERF_FREE(lwiperf_state_tcp_t, client_conn); - return ERR_MEM; - } - - memcpy(client_conn, conn, sizeof(lwiperf_state_tcp_t)); - client_conn->base.server = 0; - client_conn->server_pcb = NULL; - client_conn->conn_pcb = newpcb; - client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */ - client_conn->poll_count = 0; - client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */ - client_conn->bytes_transferred = 0; - client_conn->settings.flags = 0; /* prevent the remote side starting back as client again */ - - tcp_arg(newpcb, client_conn); - tcp_sent(newpcb, lwiperf_tcp_client_sent); - tcp_poll(newpcb, lwiperf_tcp_poll, 2U); - tcp_err(newpcb, lwiperf_tcp_err); - - ip_addr_copy(remote_addr, conn->conn_pcb->remote_ip); - remote_port = (u16_t)htonl(client_conn->settings.remote_port); - - err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected); - if (err != ERR_OK) { - lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL); - return err; - } - lwiperf_list_add(&client_conn->base); - return ERR_OK; -} - -/** Receive data on an iperf tcp session */ -static err_t -lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) -{ - u16_t tot_len; - u32_t packet_idx; - struct pbuf* q; - lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; - - LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); - LWIP_UNUSED_ARG(tpcb); - - if (err != ERR_OK) { - lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); - return ERR_OK; - } - if (p == NULL) { - /* connection closed -> test done */ - if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) == - PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) { - /* client requested transmission after end of test */ - lwiperf_tx_start(conn); - } - lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER); - return ERR_OK; - } - tot_len = p->tot_len; - - conn->poll_count = 0; - - if ((!conn->have_settings_buf) || ((conn->bytes_transferred -24) % (1024*128) == 0)) { - /* wait for 24-byte header */ - if (p->tot_len < sizeof(lwiperf_settings_t)) { - lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); - pbuf_free(p); - return ERR_VAL; - } - if (!conn->have_settings_buf) { - if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) { - lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); - pbuf_free(p); - return ERR_VAL; - } - conn->have_settings_buf = 1; - if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) == - PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) { - /* client requested parallel transmission test */ - err_t err2 = lwiperf_tx_start(conn); - if (err2 != ERR_OK) { - lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR); - pbuf_free(p); - return err2; - } - } - } else { - if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) { - lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); - pbuf_free(p); - return ERR_VAL; - } - } - conn->bytes_transferred += sizeof(lwiperf_settings_t); - if (conn->bytes_transferred <= 24) { - conn->time_started = sys_now(); - tcp_recved(tpcb, p->tot_len); - pbuf_free(p); - return ERR_OK; - } - conn->next_num = 4; /* 24 bytes received... */ - err = pbuf_header(p, -24); - LWIP_ASSERT("pbuf_header failed", err == ERR_OK); - } - - packet_idx = 0; - for (q = p; q != NULL; q = q->next) { -#if LWIPERF_CHECK_RX_DATA - const u8_t* payload = (const u8_t*)q->payload; - u16_t i; - for (i = 0; i < q->len; i++) { - u8_t val = payload[i]; - u8_t num = val - '0'; - if (num == conn->next_num) { - conn->next_num++; - if (conn->next_num == 10) { - conn->next_num = 0; - } - } else { - lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); - pbuf_free(p); - return ERR_VAL; - } - } - packet_idx += i; -#else - packet_idx += q->len; -#endif - } - LWIP_ASSERT("count mismatch", packet_idx == p->tot_len); - conn->bytes_transferred += packet_idx; - tcp_recved(tpcb, tot_len); - pbuf_free(p); - return ERR_OK; -} - -/** Error callback, iperf tcp session aborted */ -static void -lwiperf_tcp_err(void *arg, err_t err) -{ - lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; - LWIP_UNUSED_ARG(err); - lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); -} - -/** TCP poll callback, try to send more data */ -static err_t -lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb) -{ - lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; - LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); - LWIP_UNUSED_ARG(tpcb); - if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) { - lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); - return ERR_OK; /* lwiperf_tcp_close frees conn */ - } - - if (!conn->base.server) { - lwiperf_tcp_client_send_more(conn); - } - - return ERR_OK; -} - -/** This is called when a new client connects for an iperf tcp session */ -static err_t -lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) -{ - lwiperf_state_tcp_t *s, *conn; - if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) { - return ERR_VAL; - } - - s = (lwiperf_state_tcp_t*)arg; - conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); - if (conn == NULL) { - return ERR_MEM; - } - memset(conn, 0, sizeof(lwiperf_state_tcp_t)); - conn->base.tcp = 1; - conn->base.server = 1; - conn->base.related_server_state = &s->base; - conn->server_pcb = s->server_pcb; - conn->conn_pcb = newpcb; - conn->time_started = sys_now(); - conn->report_fn = s->report_fn; - conn->report_arg = s->report_arg; - - /* setup the tcp rx connection */ - tcp_arg(newpcb, conn); - tcp_recv(newpcb, lwiperf_tcp_recv); - tcp_poll(newpcb, lwiperf_tcp_poll, 2U); - tcp_err(conn->conn_pcb, lwiperf_tcp_err); - - lwiperf_list_add(&conn->base); - return ERR_OK; -} - -/** - * @ingroup iperf - * Start a TCP iperf server on the default TCP port (5001) and listen for - * incoming connections from iperf clients. - * - * @returns a connection handle that can be used to abort the server - * by calling @ref lwiperf_abort() - */ -void* -lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg) -{ - return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT, - report_fn, report_arg); -} - -/** - * @ingroup iperf - * Start a TCP iperf server on a specific IP address and port and listen for - * incoming connections from iperf clients. - * - * @returns a connection handle that can be used to abort the server - * by calling @ref lwiperf_abort() - */ -void* -lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port, - lwiperf_report_fn report_fn, void* report_arg) -{ - err_t err; - struct tcp_pcb* pcb; - lwiperf_state_tcp_t* s; - - if (local_addr == NULL) { - return NULL; - } - - s = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); - if (s == NULL) { - return NULL; - } - memset(s, 0, sizeof(lwiperf_state_tcp_t)); - s->base.tcp = 1; - s->base.server = 1; - s->report_fn = report_fn; - s->report_arg = report_arg; - - pcb = tcp_new(); - if (pcb != NULL) { - err = tcp_bind(pcb, local_addr, local_port); - if (err == ERR_OK) { - s->server_pcb = tcp_listen_with_backlog(pcb, 1); - } - } - if (s->server_pcb == NULL) { - if (pcb != NULL) { - tcp_close(pcb); - } - LWIPERF_FREE(lwiperf_state_tcp_t, s); - return NULL; - } - pcb = NULL; - - tcp_arg(s->server_pcb, s); - tcp_accept(s->server_pcb, lwiperf_tcp_accept); - - lwiperf_list_add(&s->base); - return s; -} - -/** - * @ingroup iperf - * Abort an iperf session (handle returned by lwiperf_start_tcp_server*()) - */ -void -lwiperf_abort(void* lwiperf_session) -{ - lwiperf_state_base_t* i, *dealloc, *last = NULL; - - for (i = lwiperf_all_connections; i != NULL; ) { - if ((i == lwiperf_session) || (i->related_server_state == lwiperf_session)) { - dealloc = i; - i = i->next; - if (last != NULL) { - last->next = i; - } - LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */ - } else { - last = i; - i = i->next; - } - } -} - -#endif /* LWIP_IPV4 && LWIP_TCP */ diff --git a/ext/lwip/src/apps/netbiosns/netbiosns.c b/ext/lwip/src/apps/netbiosns/netbiosns.c deleted file mode 100644 index dd01c02..0000000 --- a/ext/lwip/src/apps/netbiosns/netbiosns.c +++ /dev/null @@ -1,366 +0,0 @@ -/** - * @file - * NetBIOS name service responder - */ - -/** - * @defgroup netbiosns NETBIOS responder - * @ingroup apps - * - * This is an example implementation of a NetBIOS name server. - * It responds to name queries for a configurable name. - * Name resolving is not supported. - * - * Note that the device doesn't broadcast it's own name so can't - * detect duplicate names! - */ - -/* - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - */ - -#include "lwip/apps/netbiosns.h" - -#if LWIP_IPV4 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/udp.h" -#include "lwip/netif.h" - -#include - -/** default port number for "NetBIOS Name service */ -#define NETBIOS_PORT 137 - -/** size of a NetBIOS name */ -#define NETBIOS_NAME_LEN 16 - -/** The Time-To-Live for NetBIOS name responds (in seconds) - * Default is 300000 seconds (3 days, 11 hours, 20 minutes) */ -#define NETBIOS_NAME_TTL 300000u - -/** NetBIOS header flags */ -#define NETB_HFLAG_RESPONSE 0x8000U -#define NETB_HFLAG_OPCODE 0x7800U -#define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U -#define NETB_HFLAG_AUTHORATIVE 0x0400U -#define NETB_HFLAG_TRUNCATED 0x0200U -#define NETB_HFLAG_RECURS_DESIRED 0x0100U -#define NETB_HFLAG_RECURS_AVAILABLE 0x0080U -#define NETB_HFLAG_BROADCAST 0x0010U -#define NETB_HFLAG_REPLYCODE 0x0008U -#define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U - -/** NetBIOS name flags */ -#define NETB_NFLAG_UNIQUE 0x8000U -#define NETB_NFLAG_NODETYPE 0x6000U -#define NETB_NFLAG_NODETYPE_HNODE 0x6000U -#define NETB_NFLAG_NODETYPE_MNODE 0x4000U -#define NETB_NFLAG_NODETYPE_PNODE 0x2000U -#define NETB_NFLAG_NODETYPE_BNODE 0x0000U - -/** NetBIOS message header */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct netbios_hdr { - PACK_STRUCT_FIELD(u16_t trans_id); - PACK_STRUCT_FIELD(u16_t flags); - PACK_STRUCT_FIELD(u16_t questions); - PACK_STRUCT_FIELD(u16_t answerRRs); - PACK_STRUCT_FIELD(u16_t authorityRRs); - PACK_STRUCT_FIELD(u16_t additionalRRs); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** NetBIOS message name part */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct netbios_name_hdr { - PACK_STRUCT_FLD_8(u8_t nametype); - PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN*2)+1]); - PACK_STRUCT_FIELD(u16_t type); - PACK_STRUCT_FIELD(u16_t cls); - PACK_STRUCT_FIELD(u32_t ttl); - PACK_STRUCT_FIELD(u16_t datalen); - PACK_STRUCT_FIELD(u16_t flags); - PACK_STRUCT_FLD_S(ip4_addr_p_t addr); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** NetBIOS message */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct netbios_resp -{ - struct netbios_hdr resp_hdr; - struct netbios_name_hdr resp_name; -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#ifdef NETBIOS_LWIP_NAME -#define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME -#else -static char netbiosns_local_name[NETBIOS_NAME_LEN]; -#define NETBIOS_LOCAL_NAME netbiosns_local_name -#endif - -struct udp_pcb *netbiosns_pcb; - -/** Decode a NetBIOS name (from packet to string) */ -static int -netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len) -{ - char *pname; - char cname; - char cnbname; - int idx = 0; - - LWIP_UNUSED_ARG(name_dec_len); - - /* Start decoding netbios name. */ - pname = name_enc; - for (;;) { - /* Every two characters of the first level-encoded name - * turn into one character in the decoded name. */ - cname = *pname; - if (cname == '\0') - break; /* no more characters */ - if (cname == '.') - break; /* scope ID follows */ - if (cname < 'A' || cname > 'Z') { - /* Not legal. */ - return -1; - } - cname -= 'A'; - cnbname = cname << 4; - pname++; - - cname = *pname; - if (cname == '\0' || cname == '.') { - /* No more characters in the name - but we're in - * the middle of a pair. Not legal. */ - return -1; - } - if (cname < 'A' || cname > 'Z') { - /* Not legal. */ - return -1; - } - cname -= 'A'; - cnbname |= cname; - pname++; - - /* Do we have room to store the character? */ - if (idx < NETBIOS_NAME_LEN) { - /* Yes - store the character. */ - name_dec[idx++] = (cnbname!=' '?cnbname:'\0'); - } - } - - return 0; -} - -#if 0 /* function currently unused */ -/** Encode a NetBIOS name (from string to packet) - currently unused because - we don't ask for names. */ -static int -netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len) -{ - char *pname; - char cname; - unsigned char ucname; - int idx = 0; - - /* Start encoding netbios name. */ - pname = name_enc; - - for (;;) { - /* Every two characters of the first level-encoded name - * turn into one character in the decoded name. */ - cname = *pname; - if (cname == '\0') - break; /* no more characters */ - if (cname == '.') - break; /* scope ID follows */ - if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) { - /* Not legal. */ - return -1; - } - - /* Do we have room to store the character? */ - if (idx >= name_dec_len) { - return -1; - } - - /* Yes - store the character. */ - ucname = cname; - name_dec[idx++] = ('A'+((ucname>>4) & 0x0F)); - name_dec[idx++] = ('A'+( ucname & 0x0F)); - pname++; - } - - /* Fill with "space" coding */ - for (;idx < name_dec_len - 1;) { - name_dec[idx++] = 'C'; - name_dec[idx++] = 'A'; - } - - /* Terminate string */ - name_dec[idx] = '\0'; - - return 0; -} -#endif /* 0 */ - -/** NetBIOS Name service recv callback */ -static void -netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) -{ - LWIP_UNUSED_ARG(arg); - - /* if packet is valid */ - if (p != NULL) { - char netbios_name[NETBIOS_NAME_LEN+1]; - struct netbios_hdr* netbios_hdr = (struct netbios_hdr*)p->payload; - struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1); - - /* we only answer if we got a default interface */ - if (netif_default != NULL) { - /* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */ - /* if the packet is a NetBIOS name query question */ - if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) && - ((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) && - (netbios_hdr->questions == PP_NTOHS(1))) { - /* decode the NetBIOS name */ - netbiosns_name_decode((char*)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name)); - /* if the packet is for us */ - if (NETBIOS_STRCMP(netbios_name, NETBIOS_LOCAL_NAME) == 0) { - struct pbuf *q; - struct netbios_resp *resp; - - q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM); - if (q != NULL) { - resp = (struct netbios_resp*)q->payload; - - /* prepare NetBIOS header response */ - resp->resp_hdr.trans_id = netbios_hdr->trans_id; - resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE | - NETB_HFLAG_OPCODE_NAME_QUERY | - NETB_HFLAG_AUTHORATIVE | - NETB_HFLAG_RECURS_DESIRED); - resp->resp_hdr.questions = 0; - resp->resp_hdr.answerRRs = PP_HTONS(1); - resp->resp_hdr.authorityRRs = 0; - resp->resp_hdr.additionalRRs = 0; - - /* prepare NetBIOS header datas */ - MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname)); - resp->resp_name.nametype = netbios_name_hdr->nametype; - resp->resp_name.type = netbios_name_hdr->type; - resp->resp_name.cls = netbios_name_hdr->cls; - resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL); - resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr)); - resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE); - ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default)); - - /* send the NetBIOS response */ - udp_sendto(upcb, q, addr, port); - - /* free the "reference" pbuf */ - pbuf_free(q); - } - } - } - } - /* free the pbuf */ - pbuf_free(p); - } -} - -/** - * @ingroup netbiosns - * Init netbios responder - */ -void -netbiosns_init(void) -{ -#ifdef NETBIOS_LWIP_NAME - LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN); -#endif - - netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); - if (netbiosns_pcb != NULL) { - /* we have to be allowed to send broadcast packets! */ - netbiosns_pcb->so_options |= SOF_BROADCAST; - udp_bind(netbiosns_pcb, IP_ANY_TYPE, NETBIOS_PORT); - udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb); - } -} - -#ifndef NETBIOS_LWIP_NAME -/** - * @ingroup netbiosns - * Set netbios name. ATTENTION: the hostname must be less than 15 characters! - */ -void -netbiosns_set_name(const char* hostname) -{ - size_t copy_len = strlen(hostname); - LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN); - if (copy_len >= NETBIOS_NAME_LEN) { - copy_len = NETBIOS_NAME_LEN - 1; - } - memcpy(netbiosns_local_name, hostname, copy_len + 1); -} -#endif - -/** - * @ingroup netbiosns - * Stop netbios responder - */ -void -netbiosns_stop(void) -{ - if (netbiosns_pcb != NULL) { - udp_remove(netbiosns_pcb); - netbiosns_pcb = NULL; - } -} - -#endif /* LWIP_IPV4 && LWIP_UDP */ diff --git a/ext/lwip/src/apps/snmp/README b/ext/lwip/src/apps/snmp/README deleted file mode 100644 index d2815ec..0000000 --- a/ext/lwip/src/apps/snmp/README +++ /dev/null @@ -1,38 +0,0 @@ -lwIP SNMPv2c agent -================== - -Based on SNMP stack written by Christiaan Simons - -Rewritten by Martin Hentschel and -Dirk Ziegelmeier - -Features: - - SNMPv2c support. - - Low RAM usage - no memory pools, stack only. - - MIB2 implementation is separated from SNMP stack. - - Support for multiple MIBs (snmp_set_mibs() call) - e.g. for private MIB. - - Simple and generic API for MIB implementation. - - Comfortable node types and helper functions for scalar arrays and tables. - - Counter64, bit and truthvalue datatype support. - - Callbacks for SNMP writes e.g. to implement persistency. - - Runs on two APIs: RAW and netconn. - - Async API is gone - the stack now supports netconn API instead, - so blocking operations can be done in MIB calls. - SNMP runs in a worker thread when netconn API is used. - - Simplified thread sync support for MIBs - useful when MIBs - need to access variables shared with other threads where no locking is - possible. Used in MIB2 to access lwIP stats from lwIP thread. - -MIB compiler (code generator): - - Written in C#. MIB viewer used Windows Forms. - - Developed on Windows with Visual Studio 2010. - - Can be compiled and used under Linux with http://www.monodevelop.com/. - - Based on a heavily modified version of of SharpSnmpLib (a4bd05c6afb4) - (https://sharpsnmplib.codeplex.com/SourceControl/network/forks/Nemo157/MIBParserUpdate). - - MIB parser, C file generation framework and LWIP code generation are cleanly - separated, which means the code may be useful as a base for code generation - of other SNMP agents. - -Notes: - - Stack and MIB compiler were used to implement a Profinet device. - Compiled/implemented MIBs: LLDP-MIB, LLDP-EXT-DOT3-MIB, LLDP-EXT-PNO-MIB. diff --git a/ext/lwip/src/apps/snmp/snmp_asn1.c b/ext/lwip/src/apps/snmp/snmp_asn1.c deleted file mode 100644 index e2cb02c..0000000 --- a/ext/lwip/src/apps/snmp/snmp_asn1.c +++ /dev/null @@ -1,749 +0,0 @@ -/** - * @file - * Abstract Syntax Notation One (ISO 8824, 8825) encoding - * - * @todo not optimised (yet), favor correctness over speed, favor speed over size - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons - * Martin Hentschel - */ - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "snmp_asn1.h" - -#define PBUF_OP_EXEC(code) \ - if ((code) != ERR_OK) { \ - return ERR_BUF; \ - } - -/** - * Encodes a TLV into a pbuf stream. - * - * @param pbuf_stream points to a pbuf stream - * @param tlv TLV to encode - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode - */ -err_t -snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv) -{ - u8_t data; - u8_t length_bytes_required; - - /* write type */ - if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) { - /* extended format is not used by SNMP so we do not accept those values */ - return ERR_ARG; - } - if (tlv->type_len != 0) { - /* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */ - return ERR_ARG; - } - - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type)); - tlv->type_len = 1; - - /* write length */ - if (tlv->value_len <= 127) { - length_bytes_required = 1; - } else if (tlv->value_len <= 255) { - length_bytes_required = 2; - } else { - length_bytes_required = 3; - } - - /* check for forced min length */ - if (tlv->length_len > 0) { - if (tlv->length_len < length_bytes_required) { - /* unable to code requested length in requested number of bytes */ - return ERR_ARG; - } - - length_bytes_required = tlv->length_len; - } else { - tlv->length_len = length_bytes_required; - } - - if (length_bytes_required > 1) { - /* multi byte representation required */ - length_bytes_required--; - data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */ - - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data)); - - while (length_bytes_required > 1) { - if (length_bytes_required == 2) { - /* append high byte */ - data = (u8_t)(tlv->value_len >> 8); - } else { - /* append leading 0x00 */ - data = 0x00; - } - - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data)); - length_bytes_required--; - } - } - - /* append low byte */ - data = (u8_t)(tlv->value_len & 0xFF); - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data)); - - return ERR_OK; -} - -/** - * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg. - * - * @param pbuf_stream points to a pbuf stream - * @param raw_len raw data length - * @param raw points raw data - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode - */ -err_t -snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len) -{ - PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len)); - - return ERR_OK; -} - -/** - * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg. - * - * @param pbuf_stream points to a pbuf stream - * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) - * @param value is the host order u32_t value to be encoded - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode - * - * @see snmp_asn1_enc_u32t_cnt() - */ -err_t -snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value) -{ - if (octets_needed > 5) { - return ERR_ARG; - } - if (octets_needed == 5) { - /* not enough bits in 'value' add leading 0x00 */ - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00)); - octets_needed--; - } - - while (octets_needed > 1) { - octets_needed--; - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3)))); - } - - /* (only) one least significant octet */ - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value)); - - return ERR_OK; -} - -/** - * Encodes u64_t (counter64) into a pbuf chained ASN1 msg. - * - * @param pbuf_stream points to a pbuf stream - * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) - * @param value is the host order u32_t value to be encoded - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode - * - * @see snmp_asn1_enc_u64t_cnt() - */ -err_t -snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value) -{ - if (octets_needed > 9) { - return ERR_ARG; - } - if (octets_needed == 9) { - /* not enough bits in 'value' add leading 0x00 */ - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00)); - octets_needed--; - } - - while (octets_needed > 4) { - octets_needed--; - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3)))); - } - - /* skip to low u32 */ - value++; - - while (octets_needed > 1) { - octets_needed--; - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3)))); - } - - /* always write at least one octet (also in case of value == 0) */ - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value))); - - return ERR_OK; -} - -/** - * Encodes s32_t integer into a pbuf chained ASN1 msg. - * - * @param pbuf_stream points to a pbuf stream - * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt()) - * @param value is the host order s32_t value to be encoded - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode - * - * @see snmp_asn1_enc_s32t_cnt() - */ -err_t -snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value) -{ - while (octets_needed > 1) { - octets_needed--; - - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3)))); - } - - /* (only) one least significant octet */ - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value)); - - return ERR_OK; -} - -/** - * Encodes object identifier into a pbuf chained ASN1 msg. - * - * @param pbuf_stream points to a pbuf stream - * @param oid points to object identifier array - * @param oid_len object identifier array length - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode - */ -err_t -snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len) -{ - if (oid_len > 1) { - /* write compressed first two sub id's */ - u32_t compressed_byte = ((oid[0] * 40) + oid[1]); - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte)); - oid_len -= 2; - oid += 2; - } else { - /* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */ - /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */ - return ERR_ARG; - } - - while (oid_len > 0) { - u32_t sub_id; - u8_t shift, tail; - - oid_len--; - sub_id = *oid; - tail = 0; - shift = 28; - while (shift > 0) { - u8_t code; - - code = (u8_t)(sub_id >> shift); - if ((code != 0) || (tail != 0)) { - tail = 1; - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80)); - } - shift -= 7; - } - PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F)); - - /* proceed to next sub-identifier */ - oid++; - } - return ERR_OK; -} - -/** - * Returns octet count for length. - * - * @param length - * @param octets_needed points to the return value - */ -void -snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed) -{ - if (length < 0x80U) { - *octets_needed = 1; - } else if (length < 0x100U) { - *octets_needed = 2; - } else { - *octets_needed = 3; - } -} - -/** - * Returns octet count for an u32_t. - * - * @param value - * @param octets_needed points to the return value - * - * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded - * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value - * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! - */ -void -snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed) -{ - if (value < 0x80UL) { - *octets_needed = 1; - } else if (value < 0x8000UL) { - *octets_needed = 2; - } else if (value < 0x800000UL) { - *octets_needed = 3; - } else if (value < 0x80000000UL) { - *octets_needed = 4; - } else { - *octets_needed = 5; - } -} - -/** - * Returns octet count for an u64_t. - * - * @param value - * @param octets_needed points to the return value - * - * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded - * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value - * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! - */ -void -snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed) -{ - /* check if high u32 is 0 */ - if (*value == 0x00) { - /* only low u32 is important */ - value++; - snmp_asn1_enc_u32t_cnt(*value, octets_needed); - } else { - /* low u32 does not matter for length determination */ - snmp_asn1_enc_u32t_cnt(*value, octets_needed); - *octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */ - } -} - -/** - * Returns octet count for an s32_t. - * - * @param value - * @param octets_needed points to the return value - * - * @note ASN coded integers are _always_ signed. - */ -void -snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed) -{ - if (value < 0) { - value = ~value; - } - if (value < 0x80L) { - *octets_needed = 1; - } else if (value < 0x8000L) { - *octets_needed = 2; - } else if (value < 0x800000L) { - *octets_needed = 3; - } else { - *octets_needed = 4; - } -} - -/** - * Returns octet count for an object identifier. - * - * @param oid points to object identifier array - * @param oid_len object identifier array length - * @param octets_needed points to the return value - */ -void -snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed) -{ - u32_t sub_id; - - *octets_needed = 0; - if (oid_len > 1) { - /* compressed prefix in one octet */ - (*octets_needed)++; - oid_len -= 2; - oid += 2; - } - while (oid_len > 0) { - oid_len--; - sub_id = *oid; - - sub_id >>= 7; - (*octets_needed)++; - while (sub_id > 0) { - sub_id >>= 7; - (*octets_needed)++; - } - oid++; - } -} - -/** - * Decodes a TLV from a pbuf stream. - * - * @param pbuf_stream points to a pbuf stream - * @param tlv returns decoded TLV - * @return ERR_OK if successful, ERR_VAL if we can't decode - */ -err_t -snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv) -{ - u8_t data; - - /* decode type first */ - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - tlv->type = data; - - if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) { - /* extended format is not used by SNMP so we do not accept those values */ - return ERR_VAL; - } - tlv->type_len = 1; - - /* now, decode length */ - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - - if (data < 0x80) { /* short form */ - tlv->length_len = 1; - tlv->value_len = data; - } else if (data > 0x80) { /* long form */ - u8_t length_bytes = data - 0x80; - tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */ - tlv->value_len = 0; - - while (length_bytes > 0) { - /* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */ - if (tlv->value_len > 0xFF) { - return ERR_VAL; - } - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - tlv->value_len <<= 8; - tlv->value_len |= data; - - /* take care for special value used for indefinite length */ - if (tlv->value_len == 0xFFFF) { - return ERR_VAL; - } - - length_bytes--; - } - } else { /* data == 0x80 indefinite length form */ - /* (not allowed for SNMP; RFC 1157, 3.2.2) */ - return ERR_VAL; - } - - return ERR_OK; -} - -/** - * Decodes positive integer (counter, gauge, timeticks) into u32_t. - * - * @param pbuf_stream points to a pbuf stream - * @param len length of the coded integer field - * @param value return host order integer - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode - * - * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded - * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value - * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! - */ -err_t -snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value) -{ - u8_t data; - - if ((len > 0) && (len <= 5)) { - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - - /* expecting sign bit to be zero, only unsigned please! */ - if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) { - *value = data; - len--; - - while (len > 0) { - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - len--; - - *value <<= 8; - *value |= data; - } - - return ERR_OK; - } - } - - return ERR_VAL; -} - -/** - * Decodes large positive integer (counter64) into 2x u32_t. - * - * @param pbuf_stream points to a pbuf stream - * @param len length of the coded integer field - * @param value return host order integer - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode - * - * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded - * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value - * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! - */ -err_t -snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value) -{ - u8_t data; - - if (len <= 4) { - /* high u32 is 0 */ - *value = 0; - /* directly skip to low u32 */ - value++; - } - - if ((len > 0) && (len <= 9)) { - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - - /* expecting sign bit to be zero, only unsigned please! */ - if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) { - *value = data; - len--; - - while (len > 0) { - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - - if (len == 4) { - /* skip to low u32 */ - value++; - *value = 0; - } else { - *value <<= 8; - } - - *value |= data; - len--; - } - - return ERR_OK; - } - } - - return ERR_VAL; -} - -/** - * Decodes integer into s32_t. - * - * @param pbuf_stream points to a pbuf stream - * @param len length of the coded integer field - * @param value return host order integer - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode - * - * @note ASN coded integers are _always_ signed! - */ -err_t -snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value) -{ -#if BYTE_ORDER == LITTLE_ENDIAN - u8_t *lsb_ptr = (u8_t*)value; -#endif -#if BYTE_ORDER == BIG_ENDIAN - u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1; -#endif - u8_t sign; - u8_t data; - - if ((len > 0) && (len < 5)) { - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - len--; - - if (data & 0x80) { - /* negative, start from -1 */ - *value = -1; - sign = 1; - *lsb_ptr &= data; - } else { - /* positive, start from 0 */ - *value = 0; - sign = 0; - *lsb_ptr |= data; - } - - /* OR/AND octets with value */ - while (len > 0) { - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - len--; - -#if BYTE_ORDER == LITTLE_ENDIAN - *value <<= 8; -#endif -#if BYTE_ORDER == BIG_ENDIAN - *value >>= 8; -#endif - - if (sign) { - *lsb_ptr |= 255; - *lsb_ptr &= data; - } else { - *lsb_ptr |= data; - } - } - - return ERR_OK; - } - - return ERR_VAL; -} - -/** - * Decodes object identifier from incoming message into array of u32_t. - * - * @param pbuf_stream points to a pbuf stream - * @param len length of the coded object identifier - * @param oid return decoded object identifier - * @param oid_len return decoded object identifier length - * @param oid_max_len size of oid buffer - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode - */ -err_t -snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len) -{ - u32_t *oid_ptr; - u8_t data; - - *oid_len = 0; - oid_ptr = oid; - if (len > 0) { - if (oid_max_len < 2) { - return ERR_MEM; - } - - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - len--; - - /* first compressed octet */ - if (data == 0x2B) { - /* (most) common case 1.3 (iso.org) */ - *oid_ptr = 1; - oid_ptr++; - *oid_ptr = 3; - oid_ptr++; - } else if (data < 40) { - *oid_ptr = 0; - oid_ptr++; - *oid_ptr = data; - oid_ptr++; - } else if (data < 80) { - *oid_ptr = 1; - oid_ptr++; - *oid_ptr = data - 40; - oid_ptr++; - } else { - *oid_ptr = 2; - oid_ptr++; - *oid_ptr = data - 80; - oid_ptr++; - } - *oid_len = 2; - } else { - /* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */ - return ERR_OK; - } - - while ((len > 0) && (*oid_len < oid_max_len)) { - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - len--; - - if ((data & 0x80) == 0x00) { - /* sub-identifier uses single octet */ - *oid_ptr = data; - } else { - /* sub-identifier uses multiple octets */ - u32_t sub_id = (data & ~0x80); - while ((len > 0) && ((data & 0x80) != 0)) { - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); - len--; - - sub_id = (sub_id << 7) + (data & ~0x80); - } - - if ((data & 0x80) != 0) { - /* "more bytes following" bit still set at end of len */ - return ERR_VAL; - } - *oid_ptr = sub_id; - } - oid_ptr++; - (*oid_len)++; - } - - if (len > 0) { - /* OID to long to fit in our buffer */ - return ERR_MEM; - } - - return ERR_OK; -} - -/** - * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding) - * from incoming message into array. - * - * @param pbuf_stream points to a pbuf stream - * @param len length of the coded raw data (zero is valid, e.g. empty string!) - * @param buf return raw bytes - * @param buf_len returns length of the raw return value - * @param buf_max_len buffer size - * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode - */ -err_t -snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len) -{ - if (len > buf_max_len) { - /* not enough dst space */ - return ERR_MEM; - } - *buf_len = len; - - while (len > 0) { - PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf)); - buf++; - len--; - } - - return ERR_OK; -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/apps/snmp/snmp_asn1.h b/ext/lwip/src/apps/snmp/snmp_asn1.h deleted file mode 100644 index ec50d8c..0000000 --- a/ext/lwip/src/apps/snmp/snmp_asn1.h +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @file - * Abstract Syntax Notation One (ISO 8824, 8825) codec. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * Copyright (c) 2016 Elias Oenal. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons - * Martin Hentschel - * Elias Oenal - */ - -#ifndef LWIP_HDR_APPS_SNMP_ASN1_H -#define LWIP_HDR_APPS_SNMP_ASN1_H - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP - -#include "lwip/err.h" -#include "lwip/apps/snmp_core.h" -#include "snmp_pbuf_stream.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define SNMP_ASN1_TLV_INDEFINITE_LENGTH 0x80 - -#define SNMP_ASN1_CLASS_MASK 0xC0 -#define SNMP_ASN1_CONTENTTYPE_MASK 0x20 -#define SNMP_ASN1_DATATYPE_MASK 0x1F -#define SNMP_ASN1_DATATYPE_EXTENDED 0x1F /* DataType indicating that datatype is encoded in following bytes */ - -/* context specific (SNMP) tags (from SNMP spec. RFC1157) */ -#define SNMP_ASN1_CONTEXT_PDU_GET_REQ 0 -#define SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ 1 -#define SNMP_ASN1_CONTEXT_PDU_GET_RESP 2 -#define SNMP_ASN1_CONTEXT_PDU_SET_REQ 3 -#define SNMP_ASN1_CONTEXT_PDU_TRAP 4 -#define SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ 5 - -#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT 0 -#define SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW 2 - -struct snmp_asn1_tlv -{ - u8_t type; /* only U8 because extended types are not specified by SNMP */ - u8_t type_len; /* encoded length of 'type' field (normally 1) */ - u8_t length_len; /* indicates how many bytes are required to encode the 'value_len' field */ - u16_t value_len; /* encoded length of the value */ -}; -#define SNMP_ASN1_TLV_HDR_LENGTH(tlv) ((tlv).type_len + (tlv).length_len) -#define SNMP_ASN1_TLV_LENGTH(tlv) ((tlv).type_len + (tlv).length_len + (tlv).value_len) -#define SNMP_ASN1_SET_TLV_PARAMS(tlv, type_, length_len_, value_len_) do { (tlv).type = (type_); (tlv).type_len = 0; (tlv).length_len = (length_len_); (tlv).value_len = (value_len_); } while (0); - -err_t snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv); -err_t snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value); -err_t snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value); -err_t snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value); -err_t snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len); -err_t snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len); - -err_t snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv); - -void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed); -void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed); -void snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed); -void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed); -void snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed); -err_t snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len); -err_t snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value); -err_t snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value); -err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value); -err_t snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SNMP */ - -#endif /* LWIP_HDR_APPS_SNMP_ASN1_H */ diff --git a/ext/lwip/src/apps/snmp/snmp_core.c b/ext/lwip/src/apps/snmp/snmp_core.c deleted file mode 100644 index 0887243..0000000 --- a/ext/lwip/src/apps/snmp/snmp_core.c +++ /dev/null @@ -1,1312 +0,0 @@ -/** - * @file - * MIB tree access/construction functions. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons - * Martin Hentschel -*/ - -/** - * @defgroup snmp SNMPv2c agent - * @ingroup apps - * SNMPv2c compatible agent\n - * There is also a MIB compiler and a MIB viewer in lwIP contrib repository - * (lwip-contrib/apps/LwipMibCompiler).\n - * The agent implements the most important MIB2 MIBs including IPv6 support - * (interfaces, UDP, TCP, SNMP, ICMP, SYSTEM). IP MIB is an older version - * whithout IPv6 statistics (TODO).\n - * Work on SNMPv3 has started, but is not finished. - * - * 0 Agent Capabilities - * ==================== - * - * SNMPv1 per RFC1157 and SNMPv2c per RFC 3416 - * ------------------------------------------- - * Note the S in SNMP stands for "Simple". Note that "Simple" is - * relative. SNMP is simple compared to the complex ISO network - * management protocols CMIP (Common Management Information Protocol) - * and CMOT (CMip Over Tcp). - * - * MIB II - * ------ - * The standard lwIP stack management information base. - * This is a required MIB, so this is always enabled. - * The groups EGP, CMOT and transmission are disabled by default. - * - * Most mib-2 objects are not writable except: - * sysName, sysLocation, sysContact, snmpEnableAuthenTraps. - * Writing to or changing the ARP and IP address and route - * tables is not possible. - * - * Note lwIP has a very limited notion of IP routing. It currently - * doen't have a route table and doesn't have a notion of the U,G,H flags. - * Instead lwIP uses the interface list with only one default interface - * acting as a single gateway interface (G) for the default route. - * - * The agent returns a "virtual table" with the default route 0.0.0.0 - * for the default interface and network routes (no H) for each - * network interface in the netif_list. - * All routes are considered to be up (U). - * - * Loading additional MIBs - * ----------------------- - * MIBs can only be added in compile-time, not in run-time. - * - * - * 1 Building the Agent - * ==================== - * First of all you'll need to add the following define - * to your local lwipopts.h: - * \#define LWIP_SNMP 1 - * - * and add the source files your makefile. - * - * Note you'll might need to adapt you network driver to update - * the mib2 variables for your interface. - * - * 2 Running the Agent - * =================== - * The following function calls must be made in your program to - * actually get the SNMP agent running. - * - * Before starting the agent you should supply pointers - * for sysContact, sysLocation, and snmpEnableAuthenTraps. - * You can do this by calling - * - * - snmp_mib2_set_syscontact() - * - snmp_mib2_set_syslocation() - * - snmp_set_auth_traps_enabled() - * - * You can register a callback which is called on successful write access: - * snmp_set_write_callback(). - * - * Additionally you may want to set - * - * - snmp_mib2_set_sysdescr() - * - snmp_set_device_enterprise_oid() - * - snmp_mib2_set_sysname() - * - * Also before starting the agent you need to setup - * one or more trap destinations using these calls: - * - * - snmp_trap_dst_enable() - * - snmp_trap_dst_ip_set() - * - * If you need more than MIB2, set the MIBs you want to use - * by snmp_set_mibs(). - * - * Finally, enable the agent by calling snmp_init() - * - * @defgroup snmp_core Core - * @ingroup snmp - * - * @defgroup snmp_traps Traps - * @ingroup snmp - */ - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "snmp_core_priv.h" -#include "lwip/netif.h" -#include - - -#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0)) - #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h" -#endif -#if (!LWIP_UDP && LWIP_SNMP) - #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif - -struct snmp_statistics snmp_stats; -static const struct snmp_obj_id snmp_device_enterprise_oid_default = {SNMP_DEVICE_ENTERPRISE_OID_LEN, SNMP_DEVICE_ENTERPRISE_OID}; -static const struct snmp_obj_id* snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default; - -const u32_t snmp_zero_dot_zero_values[] = { 0, 0 }; -const struct snmp_obj_id_const_ref snmp_zero_dot_zero = { LWIP_ARRAYSIZE(snmp_zero_dot_zero_values), snmp_zero_dot_zero_values }; - - -#if SNMP_LWIP_MIB2 -#include "lwip/apps/snmp_mib2.h" -static const struct snmp_mib* const default_mibs[] = { &mib2 }; -static u8_t snmp_num_mibs = 1; -#else -static const struct snmp_mib* const default_mibs[] = { NULL }; -static u8_t snmp_num_mibs = 0; -#endif - -/* List of known mibs */ -static struct snmp_mib const * const *snmp_mibs = default_mibs; - -/** - * @ingroup snmp_core - * Sets the MIBs to use. - * Example: call snmp_set_mibs() as follows: - * static const struct snmp_mib *my_snmp_mibs[] = { - * &mib2, - * &private_mib - * }; - * snmp_set_mibs(my_snmp_mibs, LWIP_ARRAYSIZE(my_snmp_mibs)); - */ -void -snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs) -{ - LWIP_ASSERT("mibs pointer must be != NULL", (mibs != NULL)); - LWIP_ASSERT("num_mibs pointer must be != 0", (num_mibs != 0)); - snmp_mibs = mibs; - snmp_num_mibs = num_mibs; -} - -/** - * @ingroup snmp_core - * 'device enterprise oid' is used for 'device OID' field in trap PDU's (for identification of generating device) - * as well as for value returned by MIB-2 'sysObjectID' field (if internal MIB2 implementation is used). - * The 'device enterprise oid' shall point to an OID located under 'private-enterprises' branch (1.3.6.1.4.1.XXX). If a vendor - * wants to provide a custom object there, he has to get its own enterprise oid from IANA (http://www.iana.org). It - * is not allowed to use LWIP enterprise ID! - * In order to identify a specific device it is recommended to create a dedicated OID for each device type under its own - * enterprise oid. - * e.g. - * device a > 1.3.6.1.4.1.XXX(ent-oid).1(devices).1(device a) - * device b > 1.3.6.1.4.1.XXX(ent-oid).1(devices).2(device b) - * for more details see description of 'sysObjectID' field in RFC1213-MIB - */ -void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid) -{ - if (device_enterprise_oid == NULL) { - snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default; - } else { - snmp_device_enterprise_oid = device_enterprise_oid; - } -} - -/** - * @ingroup snmp_core - * Get 'device enterprise oid' - */ -const struct snmp_obj_id* snmp_get_device_enterprise_oid(void) -{ - return snmp_device_enterprise_oid; -} - -#if LWIP_IPV4 -/** - * Conversion from InetAddressIPv4 oid to lwIP ip4_addr - * @param oid points to u32_t ident[4] input - * @param ip points to output struct - */ -u8_t -snmp_oid_to_ip4(const u32_t *oid, ip4_addr_t *ip) -{ - if ((oid[0] > 0xFF) || - (oid[1] > 0xFF) || - (oid[2] > 0xFF) || - (oid[3] > 0xFF)) { - ip4_addr_copy(*ip, *IP4_ADDR_ANY); - return 0; - } - - IP4_ADDR(ip, oid[0], oid[1], oid[2], oid[3]); - return 1; -} - -/** - * Convert ip4_addr to InetAddressIPv4 (no InetAddressType) - * @param ip points to input struct - * @param oid points to u32_t ident[4] output - */ -void -snmp_ip4_to_oid(const ip4_addr_t *ip, u32_t *oid) -{ - oid[0] = ip4_addr1(ip); - oid[1] = ip4_addr2(ip); - oid[2] = ip4_addr3(ip); - oid[3] = ip4_addr4(ip); -} -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -/** - * Conversion from InetAddressIPv6 oid to lwIP ip6_addr - * @param oid points to u32_t oid[16] input - * @param ip points to output struct - */ -u8_t -snmp_oid_to_ip6(const u32_t *oid, ip6_addr_t *ip) -{ - if ((oid[0] > 0xFF) || - (oid[1] > 0xFF) || - (oid[2] > 0xFF) || - (oid[3] > 0xFF) || - (oid[4] > 0xFF) || - (oid[5] > 0xFF) || - (oid[6] > 0xFF) || - (oid[7] > 0xFF) || - (oid[8] > 0xFF) || - (oid[9] > 0xFF) || - (oid[10] > 0xFF) || - (oid[11] > 0xFF) || - (oid[12] > 0xFF) || - (oid[13] > 0xFF) || - (oid[14] > 0xFF) || - (oid[15] > 0xFF)) { - ip6_addr_set_any(ip); - return 0; - } - - ip->addr[0] = (oid[0] << 24) | (oid[1] << 16) | (oid[2] << 8) | (oid[3] << 0); - ip->addr[1] = (oid[4] << 24) | (oid[5] << 16) | (oid[6] << 8) | (oid[7] << 0); - ip->addr[2] = (oid[8] << 24) | (oid[9] << 16) | (oid[10] << 8) | (oid[11] << 0); - ip->addr[3] = (oid[12] << 24) | (oid[13] << 16) | (oid[14] << 8) | (oid[15] << 0); - return 1; -} - -/** - * Convert ip6_addr to InetAddressIPv6 (no InetAddressType) - * @param ip points to input struct - * @param oid points to u32_t ident[16] output - */ -void -snmp_ip6_to_oid(const ip6_addr_t *ip, u32_t *oid) -{ - oid[0] = (ip->addr[0] & 0xFF000000) >> 24; - oid[1] = (ip->addr[0] & 0x00FF0000) >> 16; - oid[2] = (ip->addr[0] & 0x0000FF00) >> 8; - oid[3] = (ip->addr[0] & 0x000000FF) >> 0; - oid[4] = (ip->addr[1] & 0xFF000000) >> 24; - oid[5] = (ip->addr[1] & 0x00FF0000) >> 16; - oid[6] = (ip->addr[1] & 0x0000FF00) >> 8; - oid[7] = (ip->addr[1] & 0x000000FF) >> 0; - oid[8] = (ip->addr[2] & 0xFF000000) >> 24; - oid[9] = (ip->addr[2] & 0x00FF0000) >> 16; - oid[10] = (ip->addr[2] & 0x0000FF00) >> 8; - oid[11] = (ip->addr[2] & 0x000000FF) >> 0; - oid[12] = (ip->addr[3] & 0xFF000000) >> 24; - oid[13] = (ip->addr[3] & 0x00FF0000) >> 16; - oid[14] = (ip->addr[3] & 0x0000FF00) >> 8; - oid[15] = (ip->addr[3] & 0x000000FF) >> 0; -} -#endif /* LWIP_IPV6 */ - -#if LWIP_IPV4 || LWIP_IPV6 -/** - * Convert to InetAddressType+InetAddress+InetPortNumber - * @param ip - * @param port - * @param oid - * @return OID length - */ -u8_t -snmp_ip_port_to_oid(const ip_addr_t *ip, u16_t port, u32_t *oid) -{ - u8_t idx; - - idx = snmp_ip_to_oid(ip, oid); - oid[idx] = port; - idx++; - - return idx; -} - -/** - * Convert to InetAddressType+InetAddress - * @param ip - * @param oid - * @return OID length - */ -u8_t -snmp_ip_to_oid(const ip_addr_t *ip, u32_t *oid) -{ - if (IP_IS_ANY_TYPE_VAL(*ip)) { - oid[0] = 0; /* any */ - oid[1] = 0; /* no IP OIDs follow */ - return 2; - } else if (IP_IS_V6(ip)) { -#if LWIP_IPV6 - oid[0] = 2; /* ipv6 */ - oid[1] = 16; /* 16 InetAddressIPv6 OIDs follow */ - snmp_ip6_to_oid(ip_2_ip6(ip), &oid[2]); - return 18; -#else /* LWIP_IPV6 */ - return 0; -#endif /* LWIP_IPV6 */ - } else { -#if LWIP_IPV4 - oid[0] = 1; /* ipv4 */ - oid[1] = 4; /* 4 InetAddressIPv4 OIDs follow */ - snmp_ip4_to_oid(ip_2_ip4(ip), &oid[2]); - return 6; -#else /* LWIP_IPV4 */ - return 0; -#endif /* LWIP_IPV4 */ - } -} - -/** - * Convert from InetAddressType+InetAddress to ip_addr_t - * @param oid - * @param oid_len - * @param ip - * @return Parsed OID length - */ -u8_t -snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip) -{ - /* InetAddressType */ - if (oid_len < 1) { - return 0; - } - - if (oid[0] == 0) { /* any */ - /* 1x InetAddressType, 1x OID len */ - if (oid_len < 2) { - return 0; - } - if (oid[1] != 0) { - return 0; - } - - memset(ip, 0, sizeof(*ip)); - IP_SET_TYPE(ip, IPADDR_TYPE_ANY); - - return 2; - } else if (oid[0] == 1) { /* ipv4 */ -#if LWIP_IPV4 - /* 1x InetAddressType, 1x OID len, 4x InetAddressIPv4 */ - if (oid_len < 6) { - return 0; - } - - /* 4x ipv4 OID */ - if (oid[1] != 4) { - return 0; - } - - IP_SET_TYPE(ip, IPADDR_TYPE_V4); - if (!snmp_oid_to_ip4(&oid[2], ip_2_ip4(ip))) { - return 0; - } - - return 6; -#else /* LWIP_IPV4 */ - return 0; -#endif /* LWIP_IPV4 */ - } else if (oid[0] == 2) { /* ipv6 */ -#if LWIP_IPV6 - /* 1x InetAddressType, 1x OID len, 16x InetAddressIPv6 */ - if (oid_len < 18) { - return 0; - } - - /* 16x ipv6 OID */ - if (oid[1] != 16) { - return 0; - } - - IP_SET_TYPE(ip, IPADDR_TYPE_V6); - if (!snmp_oid_to_ip6(&oid[2], ip_2_ip6(ip))) { - return 0; - } - - return 18; -#else /* LWIP_IPV6 */ - return 0; -#endif /* LWIP_IPV6 */ - } else { /* unsupported InetAddressType */ - return 0; - } -} - -/** - * Convert from InetAddressType+InetAddress+InetPortNumber to ip_addr_t and u16_t - * @param oid - * @param oid_len - * @param ip - * @param port - * @return Parsed OID length - */ -u8_t -snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port) -{ - u8_t idx = 0; - - /* InetAddressType + InetAddress */ - idx += snmp_oid_to_ip(&oid[idx], oid_len-idx, ip); - if (idx == 0) { - return 0; - } - - /* InetPortNumber */ - if (oid_len < (idx+1)) { - return 0; - } - if (oid[idx] > 0xffff) { - return 0; - } - *port = (u16_t)oid[idx]; - idx++; - - return idx; -} - -#endif /* LWIP_IPV4 || LWIP_IPV6 */ - -/** - * Assign an OID to \struct snmp_obj_id - * @param target - * @param oid - * @param oid_len - */ -void -snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len) -{ - LWIP_ASSERT("oid_len <= LWIP_SNMP_OBJ_ID_LEN", oid_len <= SNMP_MAX_OBJ_ID_LEN); - - target->len = oid_len; - - if (oid_len > 0) { - MEMCPY(target->id, oid, oid_len * sizeof(u32_t)); - } -} - -/** - * Prefix an OID to OID in \struct snmp_obj_id - * @param target - * @param oid - * @param oid_len - */ -void -snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len) -{ - LWIP_ASSERT("target->len + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN); - - if (oid_len > 0) { - /* move existing OID to make room at the beginning for OID to insert */ - int i; - for (i = target->len-1; i>=0; i--) { - target->id[i + oid_len] = target->id[i]; - } - - /* paste oid at the beginning */ - MEMCPY(target->id, oid, oid_len * sizeof(u32_t)); - } -} - -/** - * Combine two OIDs into \struct snmp_obj_id - * @param target - * @param oid1 - * @param oid1_len - * @param oid2 - * @param oid2_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) -{ - snmp_oid_assign(target, oid1, oid1_len); - snmp_oid_append(target, oid2, oid2_len); -} - -/** - * Append OIDs to \struct snmp_obj_id - * @param target - * @param oid - * @param oid_len - */ -void -snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len) -{ - LWIP_ASSERT("offset + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN); - - if (oid_len > 0) { - MEMCPY(&target->id[target->len], oid, oid_len * sizeof(u32_t)); - target->len += oid_len; - } -} - -/** - * Compare two OIDs - * @param oid1 - * @param oid1_len - * @param oid2 - * @param oid2_len - * @return - */ -s8_t -snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) -{ - u8_t level = 0; - LWIP_ASSERT("'oid1' param must not be NULL or 'oid1_len' param be 0!", (oid1 != NULL) || (oid1_len == 0)); - LWIP_ASSERT("'oid2' param must not be NULL or 'oid2_len' param be 0!", (oid2 != NULL) || (oid2_len == 0)); - - while ((level < oid1_len) && (level < oid2_len)) { - if (*oid1 < *oid2) { - return -1; - } - if (*oid1 > *oid2) { - return 1; - } - - level++; - oid1++; - oid2++; - } - - /* common part of both OID's is equal, compare length */ - if (oid1_len < oid2_len) { - return -1; - } - if (oid1_len > oid2_len) { - return 1; - } - - /* they are equal */ - return 0; -} - - -/** - * Check of two OIDs are equal - * @param oid1 - * @param oid1_len - * @param oid2 - * @param oid2_len - * @return - */ -u8_t -snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) -{ - return (snmp_oid_compare(oid1, oid1_len, oid2, oid2_len) == 0)? 1 : 0; -} - -/** - * Convert netif to interface index - * @param netif - * @return index - */ -u8_t -netif_to_num(const struct netif *netif) -{ - u8_t result = 0; - struct netif *netif_iterator = netif_list; - - while (netif_iterator != NULL) { - result++; - - if (netif_iterator == netif) { - return result; - } - - netif_iterator = netif_iterator->next; - } - - LWIP_ASSERT("netif not found in netif_list", 0); - return 0; -} - -static const struct snmp_mib* -snmp_get_mib_from_oid(const u32_t *oid, u8_t oid_len) -{ - const u32_t* list_oid; - const u32_t* searched_oid; - u8_t i, l; - - u8_t max_match_len = 0; - const struct snmp_mib* matched_mib = NULL; - - LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL)); - - if (oid_len == 0) { - return NULL; - } - - for (i = 0; i < snmp_num_mibs; i++) { - LWIP_ASSERT("MIB array not initialized correctly", (snmp_mibs[i] != NULL)); - LWIP_ASSERT("MIB array not initialized correctly - base OID is NULL", (snmp_mibs[i]->base_oid != NULL)); - - if (oid_len >= snmp_mibs[i]->base_oid_len) { - l = snmp_mibs[i]->base_oid_len; - list_oid = snmp_mibs[i]->base_oid; - searched_oid = oid; - - while (l > 0) { - if (*list_oid != *searched_oid) { - break; - } - - l--; - list_oid++; - searched_oid++; - } - - if ((l == 0) && (snmp_mibs[i]->base_oid_len > max_match_len)) { - max_match_len = snmp_mibs[i]->base_oid_len; - matched_mib = snmp_mibs[i]; - } - } - } - - return matched_mib; -} - -static const struct snmp_mib* -snmp_get_next_mib(const u32_t *oid, u8_t oid_len) -{ - u8_t i; - const struct snmp_mib* next_mib = NULL; - - LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL)); - - if (oid_len == 0) { - return NULL; - } - - for (i = 0; i < snmp_num_mibs; i++) { - if (snmp_mibs[i]->base_oid != NULL) { - /* check if mib is located behind starting point */ - if (snmp_oid_compare(snmp_mibs[i]->base_oid, snmp_mibs[i]->base_oid_len, oid, oid_len) > 0) { - if ((next_mib == NULL) || - (snmp_oid_compare(snmp_mibs[i]->base_oid, snmp_mibs[i]->base_oid_len, - next_mib->base_oid, next_mib->base_oid_len) < 0)) { - next_mib = snmp_mibs[i]; - } - } - } - } - - return next_mib; -} - -static const struct snmp_mib* -snmp_get_mib_between(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) -{ - const struct snmp_mib* next_mib = snmp_get_next_mib(oid1, oid1_len); - - LWIP_ASSERT("'oid2' param must not be NULL!", (oid2 != NULL)); - LWIP_ASSERT("'oid2_len' param must be greater than 0!", (oid2_len > 0)); - - if (next_mib != NULL) { - if (snmp_oid_compare(next_mib->base_oid, next_mib->base_oid_len, oid2, oid2_len) < 0) { - return next_mib; - } - } - - return NULL; -} - -u8_t -snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance) -{ - u8_t result = SNMP_ERR_NOSUCHOBJECT; - const struct snmp_mib *mib; - const struct snmp_node *mn = NULL; - - mib = snmp_get_mib_from_oid(oid, oid_len); - if (mib != NULL) { - u8_t oid_instance_len; - - mn = snmp_mib_tree_resolve_exact(mib, oid, oid_len, &oid_instance_len); - if ((mn != NULL) && (mn->node_type != SNMP_NODE_TREE)) { - /* get instance */ - const struct snmp_leaf_node* leaf_node = (const struct snmp_leaf_node*)(const void*)mn; - - node_instance->node = mn; - snmp_oid_assign(&node_instance->instance_oid, oid + (oid_len - oid_instance_len), oid_instance_len); - - result = leaf_node->get_instance( - oid, - oid_len - oid_instance_len, - node_instance); - -#ifdef LWIP_DEBUG - if (result == SNMP_ERR_NOERROR) { - if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != 0) && (node_instance->get_value == NULL)) { - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is readable but no get_value function is specified\n")); - } - if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != 0) && (node_instance->set_value == NULL)) { - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is writable but no set_value and/or set_test function is specified\n")); - } - } -#endif - } - } - - return result; -} - -u8_t -snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void* validate_node_instance_arg, struct snmp_obj_id* node_oid, struct snmp_node_instance* node_instance) -{ - const struct snmp_mib *mib; - const struct snmp_node *mn = NULL; - const u32_t* start_oid = NULL; - u8_t start_oid_len = 0; - - /* resolve target MIB from passed OID */ - mib = snmp_get_mib_from_oid(oid, oid_len); - if (mib == NULL) { - /* passed OID does not reference any known MIB, start at the next closest MIB */ - mib = snmp_get_next_mib(oid, oid_len); - - if (mib != NULL) { - start_oid = mib->base_oid; - start_oid_len = mib->base_oid_len; - } - } else { - start_oid = oid; - start_oid_len = oid_len; - } - - /* resolve target node from MIB, skip to next MIB if no suitable node is found in current MIB */ - while ((mib != NULL) && (mn == NULL)) { - u8_t oid_instance_len; - - /* check if OID directly references a node inside current MIB, in this case we have to ask this node for the next instance */ - mn = snmp_mib_tree_resolve_exact(mib, start_oid, start_oid_len, &oid_instance_len); - if (mn != NULL) { - snmp_oid_assign(node_oid, start_oid, start_oid_len - oid_instance_len); /* set oid to node */ - snmp_oid_assign(&node_instance->instance_oid, start_oid + (start_oid_len - oid_instance_len), oid_instance_len); /* set (relative) instance oid */ - } else { - /* OID does not reference a node, search for the next closest node inside MIB; set instance_oid.len to zero because we want the first instance of this node */ - mn = snmp_mib_tree_resolve_next(mib, start_oid, start_oid_len, node_oid); - node_instance->instance_oid.len = 0; - } - - /* validate the node; if the node has no further instance or the returned instance is invalid, search for the next in MIB and validate again */ - node_instance->node = mn; - while (mn != NULL) { - u8_t result; - - /* clear fields which may have values from previous loops */ - node_instance->asn1_type = 0; - node_instance->access = SNMP_NODE_INSTANCE_NOT_ACCESSIBLE; - node_instance->get_value = NULL; - node_instance->set_test = NULL; - node_instance->set_value = NULL; - node_instance->release_instance = NULL; - node_instance->reference.ptr = NULL; - node_instance->reference_len = 0; - - result = ((const struct snmp_leaf_node*)(const void*)mn)->get_next_instance( - node_oid->id, - node_oid->len, - node_instance); - - if (result == SNMP_ERR_NOERROR) { -#ifdef LWIP_DEBUG - if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != 0) && (node_instance->get_value == NULL)) { - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is readable but no get_value function is specified\n")); - } - if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != 0) && (node_instance->set_value == NULL)) { - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is writable but no set_value function is specified\n")); - } -#endif - - /* validate node because the node may be not accessible for example (but let the caller decide what is valid */ - if ((validate_node_instance_method == NULL) || - (validate_node_instance_method(node_instance, validate_node_instance_arg) == SNMP_ERR_NOERROR)) { - /* node_oid "returns" the full result OID (including the instance part) */ - snmp_oid_append(node_oid, node_instance->instance_oid.id, node_instance->instance_oid.len); - break; - } - - if (node_instance->release_instance != NULL) { - node_instance->release_instance(node_instance); - } - /* - the instance itself is not valid, ask for next instance from same node. - we don't have to change any variables because node_instance->instance_oid is used as input (starting point) - as well as output (resulting next OID), so we have to simply call get_next_instance method again - */ - } else { - if (node_instance->release_instance != NULL) { - node_instance->release_instance(node_instance); - } - - /* the node has no further instance, skip to next node */ - mn = snmp_mib_tree_resolve_next(mib, node_oid->id, node_oid->len, &node_instance->instance_oid); /* misuse node_instance->instance_oid as tmp buffer */ - if (mn != NULL) { - /* prepare for next loop */ - snmp_oid_assign(node_oid, node_instance->instance_oid.id, node_instance->instance_oid.len); - node_instance->instance_oid.len = 0; - node_instance->node = mn; - } - } - } - - if (mn != NULL) { - /* - we found a suitable next node, - now we have to check if a inner MIB is located between the searched OID and the resulting OID. - this is possible because MIB's may be located anywhere in the global tree, that means also in - the subtree of another MIB (e.g. if searched OID is .2 and resulting OID is .4, then another - MIB having .3 as root node may exist) - */ - const struct snmp_mib *intermediate_mib; - intermediate_mib = snmp_get_mib_between(start_oid, start_oid_len, node_oid->id, node_oid->len); - - if (intermediate_mib != NULL) { - /* search for first node inside intermediate mib in next loop */ - if (node_instance->release_instance != NULL) { - node_instance->release_instance(node_instance); - } - - mn = NULL; - mib = intermediate_mib; - start_oid = mib->base_oid; - start_oid_len = mib->base_oid_len; - } - /* else { we found out target node } */ - } else { - /* - there is no further (suitable) node inside this MIB, search for the next MIB with following priority - 1. search for inner MIB's (whose root is located inside tree of current MIB) - 2. search for surrouding MIB's (where the current MIB is the inner MIB) and continue there if any - 3. take the next closest MIB (not being related to the current MIB) - */ - const struct snmp_mib *next_mib; - next_mib = snmp_get_next_mib(start_oid, start_oid_len); /* returns MIB's related to point 1 and 3 */ - - /* is the found MIB an inner MIB? (point 1) */ - if ((next_mib != NULL) && (next_mib->base_oid_len > mib->base_oid_len) && - (snmp_oid_compare(next_mib->base_oid, mib->base_oid_len, mib->base_oid, mib->base_oid_len) == 0)) { - /* yes it is -> continue at inner MIB */ - mib = next_mib; - start_oid = mib->base_oid; - start_oid_len = mib->base_oid_len; - } else { - /* check if there is a surrounding mib where to continue (point 2) (only possible if OID length > 1) */ - if (mib->base_oid_len > 1) { - mib = snmp_get_mib_from_oid(mib->base_oid, mib->base_oid_len - 1); - - if (mib == NULL) { - /* no surrounding mib, use next mib encountered above (point 3) */ - mib = next_mib; - - if (mib != NULL) { - start_oid = mib->base_oid; - start_oid_len = mib->base_oid_len; - } - } - /* else { start_oid stays the same because we want to continue from current offset in surrounding mib (point 2) } */ - } - } - } - } - - if (mib == NULL) { - /* loop is only left when mib == null (error) or mib_node != NULL (success) */ - return SNMP_ERR_ENDOFMIBVIEW; - } - - return SNMP_ERR_NOERROR; -} - -/** - * Searches tree for the supplied object identifier. - * - */ -const struct snmp_node * -snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len) -{ - const struct snmp_node* const* node = &mib->root_node; - u8_t oid_offset = mib->base_oid_len; - - while ((oid_offset < oid_len) && ((*node)->node_type == SNMP_NODE_TREE)) { - /* search for matching sub node */ - u32_t subnode_oid = *(oid + oid_offset); - - u32_t i = (*(const struct snmp_tree_node* const*)node)->subnode_count; - node = (*(const struct snmp_tree_node* const*)node)->subnodes; - while ((i > 0) && ((*node)->oid != subnode_oid)) { - node++; - i--; - } - - if (i == 0) { - /* no matching subnode found */ - return NULL; - } - - oid_offset++; - } - - if ((*node)->node_type != SNMP_NODE_TREE) { - /* we found a leaf node */ - *oid_instance_len = oid_len - oid_offset; - return (*node); - } - - return NULL; -} - -const struct snmp_node* -snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret) -{ - u8_t oid_offset = mib->base_oid_len; - const struct snmp_node* const* node; - const struct snmp_tree_node* node_stack[SNMP_MAX_OBJ_ID_LEN]; - s32_t nsi = 0; /* NodeStackIndex */ - u32_t subnode_oid; - - if (mib->root_node->node_type != SNMP_NODE_TREE) { - /* a next operation on a mib with only a leaf node will always return NULL because there is no other node */ - return NULL; - } - - /* first build node stack related to passed oid (as far as possible), then go backwards to determine the next node */ - node_stack[nsi] = (const struct snmp_tree_node*)(const void*)mib->root_node; - while (oid_offset < oid_len) { - /* search for matching sub node */ - u32_t i = node_stack[nsi]->subnode_count; - node = node_stack[nsi]->subnodes; - - subnode_oid = *(oid + oid_offset); - - while ((i > 0) && ((*node)->oid != subnode_oid)) { - node++; - i--; - } - - if ((i == 0) || ((*node)->node_type != SNMP_NODE_TREE)) { - /* no (matching) tree-subnode found */ - break; - } - nsi++; - node_stack[nsi] = (const struct snmp_tree_node*)(const void*)(*node); - - oid_offset++; - } - - - if (oid_offset >= oid_len) { - /* passed oid references a tree node -> return first useable sub node of it */ - subnode_oid = 0; - } else { - subnode_oid = *(oid + oid_offset) + 1; - } - - while (nsi >= 0) { - const struct snmp_node* subnode = NULL; - - /* find next node on current level */ - s32_t i = node_stack[nsi]->subnode_count; - node = node_stack[nsi]->subnodes; - while (i > 0) { - if ((*node)->oid == subnode_oid) { - subnode = *node; - break; - } else if (((*node)->oid > subnode_oid) && ((subnode == NULL) || ((*node)->oid < subnode->oid))) { - subnode = *node; - } - - node++; - i--; - } - - if (subnode == NULL) { - /* no further node found on this level, go one level up and start searching with index of current node*/ - subnode_oid = node_stack[nsi]->node.oid + 1; - nsi--; - } else { - if (subnode->node_type == SNMP_NODE_TREE) { - /* next is a tree node, go into it and start searching */ - nsi++; - node_stack[nsi] = (const struct snmp_tree_node*)(const void*)subnode; - subnode_oid = 0; - } else { - /* we found a leaf node -> fill oidret and return it */ - snmp_oid_assign(oidret, mib->base_oid, mib->base_oid_len); - i = 1; - while (i <= nsi) { - oidret->id[oidret->len] = node_stack[i]->node.oid; - oidret->len++; - i++; - } - - oidret->id[oidret->len] = subnode->oid; - oidret->len++; - - return subnode; - } - } - } - - return NULL; -} - -/** initialize struct next_oid_state using this function before passing it to next_oid_check */ -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) -{ - state->start_oid = start_oid; - state->start_oid_len = start_oid_len; - state->next_oid = next_oid_buf; - state->next_oid_len = 0; - state->next_oid_max_len = next_oid_max_len; - state->status = SNMP_NEXT_OID_STATUS_NO_MATCH; -} - -/** checks if the passed incomplete OID may be a possible candidate for snmp_next_oid_check(); -this methid is intended if the complete OID is not yet known but it is very expensive to build it up, -so it is possible to test the starting part before building up the complete oid and pass it to snmp_next_oid_check()*/ -u8_t -snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len) -{ - if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL) { - u8_t start_oid_len = (oid_len < state->start_oid_len) ? oid_len : state->start_oid_len; - - /* check passed OID is located behind start offset */ - if (snmp_oid_compare(oid, oid_len, state->start_oid, start_oid_len) >= 0) { - /* check if new oid is located closer to start oid than current closest oid */ - if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) || - (snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0)) { - return 1; - } - } - } - - return 0; -} - -/** checks the passed OID if it is a candidate to be the next one (get_next); returns !=0 if passed oid is currently closest, otherwise 0 */ -u8_t -snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len, void* reference) -{ - /* do not overwrite a fail result */ - if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL) { - /* check passed OID is located behind start offset */ - if (snmp_oid_compare(oid, oid_len, state->start_oid, state->start_oid_len) > 0) { - /* check if new oid is located closer to start oid than current closest oid */ - if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) || - (snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0)) { - if (oid_len <= state->next_oid_max_len) { - MEMCPY(state->next_oid, oid, oid_len * sizeof(u32_t)); - state->next_oid_len = oid_len; - state->status = SNMP_NEXT_OID_STATUS_SUCCESS; - state->reference = reference; - return 1; - } else { - state->status = SNMP_NEXT_OID_STATUS_BUF_TO_SMALL; - } - } - } - } - - return 0; -} - -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) -{ - u8_t i; - - if (oid_len != oid_ranges_len) { - return 0; - } - - for (i = 0; i < oid_ranges_len; i++) { - if ((oid_in[i] < oid_ranges[i].min) || (oid_in[i] > oid_ranges[i].max)) { - return 0; - } - } - - return 1; -} - -snmp_err_t -snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value) -{ - LWIP_UNUSED_ARG(instance); - LWIP_UNUSED_ARG(value_len); - LWIP_UNUSED_ARG(value); - - return SNMP_ERR_NOERROR; -} - -/** - * Decodes BITS pseudotype value from ASN.1 OctetString. - * - * @note Because BITS pseudo type is encoded as OCTET STRING, it cannot directly - * be encoded/decoded by the agent. Instead call this function as required from - * get/test/set methods. - * - * @param buf points to a buffer holding the ASN1 octet string - * @param buf_len length of octet string - * @param bit_value decoded Bit value with Bit0 == LSB - * @return ERR_OK if successful, ERR_ARG if bit value contains more than 32 bit - */ -err_t -snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value) -{ - u8_t b; - u8_t bits_processed = 0; - *bit_value = 0; - - while (buf_len > 0) { - /* any bit set in this byte? */ - if (*buf != 0x00) { - if (bits_processed >= 32) { - /* accept more than 4 bytes, but only when no bits are set */ - return ERR_VAL; - } - - b = *buf; - do { - if (b & 0x80) { - *bit_value |= (1 << bits_processed); - } - bits_processed++; - b <<= 1; - } - while ((bits_processed & 0x07) != 0); /* &0x07 -> % 8 */ - } else { - bits_processed += 8; - } - - buf_len--; - buf++; - } - - return ERR_OK; -} - -err_t -snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value) -{ - /* defined by RFC1443: - TruthValue ::= TEXTUAL-CONVENTION - STATUS current - DESCRIPTION - "Represents a boolean value." - SYNTAX INTEGER { true(1), false(2) } - */ - - if ((asn1_value == NULL) || (bool_value == NULL)) { - return ERR_ARG; - } - - if (*asn1_value == 1) { - *bool_value = 1; - } else if (*asn1_value == 2) { - *bool_value = 0; - } else { - return ERR_VAL; - } - - return ERR_OK; -} - -/** - * Encodes BITS pseudotype value into ASN.1 OctetString. - * - * @note Because BITS pseudo type is encoded as OCTET STRING, it cannot directly - * be encoded/decoded by the agent. Instead call this function as required from - * get/test/set methods. - * - * @param buf points to a buffer where the resulting ASN1 octet string is stored to - * @param buf_len max length of the bufffer - * @param bit_value Bit value to encode with Bit0 == LSB - * @param bit_count Number of possible bits for the bit value (according to rfc we have to send all bits independant from their truth value) - * @return number of bytes used from buffer to store the resulting OctetString - */ -u8_t -snmp_encode_bits(u8_t *buf, u32_t buf_len, u32_t bit_value, u8_t bit_count) -{ - u8_t len = 0; - u8_t min_bytes = (bit_count + 7) >> 3; /* >>3 -> / 8 */ - - while ((buf_len > 0) && (bit_value != 0x00)) { - s8_t i = 7; - *buf = 0x00; - while (i >= 0) { - if (bit_value & 0x01) { - *buf |= 0x01; - } - - if (i > 0) { - *buf <<= 1; - } - - bit_value >>= 1; - i--; - } - - buf++; - buf_len--; - len++; - } - - if (len < min_bytes) { - buf += len; - buf_len -= len; - - while ((len < min_bytes) && (buf_len > 0)) { - *buf = 0x00; - buf++; - buf_len--; - len++; - } - } - - return len; -} - -u8_t -snmp_encode_truthvalue(s32_t *asn1_value, u32_t bool_value) -{ - /* defined by RFC1443: - TruthValue ::= TEXTUAL-CONVENTION - STATUS current - DESCRIPTION - "Represents a boolean value." - SYNTAX INTEGER { true(1), false(2) } - */ - - if (asn1_value == NULL) { - return 0; - } - - if (bool_value) { - *asn1_value = 1; /* defined by RFC1443 */ - } else { - *asn1_value = 2; /* defined by RFC1443 */ - } - - return sizeof(s32_t); -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/apps/snmp/snmp_core_priv.h b/ext/lwip/src/apps/snmp/snmp_core_priv.h deleted file mode 100644 index 5552177..0000000 --- a/ext/lwip/src/apps/snmp/snmp_core_priv.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Martin Hentschel - * - */ - -#ifndef LWIP_HDR_APPS_SNMP_CORE_PRIV_H -#define LWIP_HDR_APPS_SNMP_CORE_PRIV_H - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/apps/snmp_core.h" -#include "snmp_asn1.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* (outdated) SNMPv1 error codes - * shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request - */ -#define SNMP_ERR_NOSUCHNAME 2 -#define SNMP_ERR_BADVALUE 3 -#define SNMP_ERR_READONLY 4 -/* error codes which are internal and shall not be used by MIBS - * shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request - */ -#define SNMP_ERR_TOOBIG 1 -#define SNMP_ERR_AUTHORIZATIONERROR 16 -#define SNMP_ERR_NOSUCHOBJECT SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT -#define SNMP_ERR_ENDOFMIBVIEW SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW - - -const struct snmp_node* snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len); -const struct snmp_node* snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret); - -typedef u8_t (*snmp_validate_node_instance_method)(struct snmp_node_instance*, void*); - -u8_t snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance); -u8_t snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void* validate_node_instance_arg, struct snmp_obj_id* node_oid, struct snmp_node_instance* node_instance); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SNMP */ - -#endif /* LWIP_HDR_APPS_SNMP_CORE_PRIV_H */ diff --git a/ext/lwip/src/apps/snmp/snmp_mib2.c b/ext/lwip/src/apps/snmp/snmp_mib2.c deleted file mode 100644 index 9d8c43c..0000000 --- a/ext/lwip/src/apps/snmp/snmp_mib2.c +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file - * Management Information Base II (RFC1213) objects and functions. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dirk Ziegelmeier - * Christiaan Simons - */ - -/** - * @defgroup snmp_mib2 MIB2 - * @ingroup snmp - */ - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP && SNMP_LWIP_MIB2 /* don't build if not configured for use in lwipopts.h */ - -#if !LWIP_STATS -#error LWIP_SNMP MIB2 needs LWIP_STATS (for MIB2) -#endif -#if !MIB2_STATS -#error LWIP_SNMP MIB2 needs MIB2_STATS (for MIB2) -#endif - -#include "lwip/snmp.h" -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "lwip/apps/snmp_mib2.h" -#include "lwip/apps/snmp_scalar.h" - -#if SNMP_USE_NETCONN -#include "lwip/tcpip.h" -#include "lwip/priv/tcpip_priv.h" -void -snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void* arg) -{ -#if LWIP_TCPIP_CORE_LOCKING - LOCK_TCPIP_CORE(); - fn(arg); - UNLOCK_TCPIP_CORE(); -#else - tcpip_callback(fn, arg); -#endif -} - -struct snmp_threadsync_instance snmp_mib2_lwip_locks; -#endif - -/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */ -/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */ -/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */ - -/* --- mib-2 .1.3.6.1.2.1 ----------------------------------------------------- */ -extern const struct snmp_scalar_array_node snmp_mib2_snmp_root; -extern const struct snmp_tree_node snmp_mib2_udp_root; -extern const struct snmp_tree_node snmp_mib2_tcp_root; -extern const struct snmp_scalar_array_node snmp_mib2_icmp_root; -extern const struct snmp_tree_node snmp_mib2_interface_root; -extern const struct snmp_scalar_array_node snmp_mib2_system_node; -extern const struct snmp_tree_node snmp_mib2_at_root; -extern const struct snmp_tree_node snmp_mib2_ip_root; - -static const struct snmp_node* const mib2_nodes[] = { - &snmp_mib2_system_node.node.node, - &snmp_mib2_interface_root.node, -#if LWIP_ARP && LWIP_IPV4 - &snmp_mib2_at_root.node, -#endif /* LWIP_ARP && LWIP_IPV4 */ -#if LWIP_IPV4 - &snmp_mib2_ip_root.node, -#endif /* LWIP_IPV4 */ -#if LWIP_ICMP - &snmp_mib2_icmp_root.node.node, -#endif /* LWIP_ICMP */ -#if LWIP_TCP - &snmp_mib2_tcp_root.node, -#endif /* LWIP_TCP */ -#if LWIP_UDP - &snmp_mib2_udp_root.node, -#endif /* LWIP_UDP */ - &snmp_mib2_snmp_root.node.node -}; - -static const struct snmp_tree_node mib2_root = SNMP_CREATE_TREE_NODE(1, mib2_nodes); - -static const u32_t mib2_base_oid_arr[] = { 1,3,6,1,2,1 }; -const struct snmp_mib mib2 = SNMP_MIB_CREATE(mib2_base_oid_arr, &mib2_root.node); - -#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */ diff --git a/ext/lwip/src/apps/snmp/snmp_mib2_icmp.c b/ext/lwip/src/apps/snmp/snmp_mib2_icmp.c deleted file mode 100644 index 995bd32..0000000 --- a/ext/lwip/src/apps/snmp/snmp_mib2_icmp.c +++ /dev/null @@ -1,182 +0,0 @@ -/** - * @file - * Management Information Base II (RFC1213) ICMP objects and functions. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dirk Ziegelmeier - * Christiaan Simons - */ - -#include "lwip/snmp.h" -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "lwip/apps/snmp_mib2.h" -#include "lwip/apps/snmp_table.h" -#include "lwip/apps/snmp_scalar.h" -#include "lwip/icmp.h" -#include "lwip/stats.h" - -#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_ICMP - -#if SNMP_USE_NETCONN -#define SYNC_NODE_NAME(node_name) node_name ## _synced -#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ - static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); -#else -#define SYNC_NODE_NAME(node_name) node_name -#define CREATE_LWIP_SYNC_NODE(oid, node_name) -#endif - -/* --- icmp .1.3.6.1.2.1.5 ----------------------------------------------------- */ - -static s16_t -icmp_get_value(const struct snmp_scalar_array_node_def *node, void *value) -{ - u32_t *uint_ptr = (u32_t*)value; - - switch (node->oid) { - case 1: /* icmpInMsgs */ - *uint_ptr = STATS_GET(mib2.icmpinmsgs); - return sizeof(*uint_ptr); - case 2: /* icmpInErrors */ - *uint_ptr = STATS_GET(mib2.icmpinerrors); - return sizeof(*uint_ptr); - case 3: /* icmpInDestUnreachs */ - *uint_ptr = STATS_GET(mib2.icmpindestunreachs); - return sizeof(*uint_ptr); - case 4: /* icmpInTimeExcds */ - *uint_ptr = STATS_GET(mib2.icmpintimeexcds); - return sizeof(*uint_ptr); - case 5: /* icmpInParmProbs */ - *uint_ptr = STATS_GET(mib2.icmpinparmprobs); - return sizeof(*uint_ptr); - case 6: /* icmpInSrcQuenchs */ - *uint_ptr = STATS_GET(mib2.icmpinsrcquenchs); - return sizeof(*uint_ptr); - case 7: /* icmpInRedirects */ - *uint_ptr = STATS_GET(mib2.icmpinredirects); - return sizeof(*uint_ptr); - case 8: /* icmpInEchos */ - *uint_ptr = STATS_GET(mib2.icmpinechos); - return sizeof(*uint_ptr); - case 9: /* icmpInEchoReps */ - *uint_ptr = STATS_GET(mib2.icmpinechoreps); - return sizeof(*uint_ptr); - case 10: /* icmpInTimestamps */ - *uint_ptr = STATS_GET(mib2.icmpintimestamps); - return sizeof(*uint_ptr); - case 11: /* icmpInTimestampReps */ - *uint_ptr = STATS_GET(mib2.icmpintimestampreps); - return sizeof(*uint_ptr); - case 12: /* icmpInAddrMasks */ - *uint_ptr = STATS_GET(mib2.icmpinaddrmasks); - return sizeof(*uint_ptr); - case 13: /* icmpInAddrMaskReps */ - *uint_ptr = STATS_GET(mib2.icmpinaddrmaskreps); - return sizeof(*uint_ptr); - case 14: /* icmpOutMsgs */ - *uint_ptr = STATS_GET(mib2.icmpoutmsgs); - return sizeof(*uint_ptr); - case 15: /* icmpOutErrors */ - *uint_ptr = STATS_GET(mib2.icmpouterrors); - return sizeof(*uint_ptr); - case 16: /* icmpOutDestUnreachs */ - *uint_ptr = STATS_GET(mib2.icmpoutdestunreachs); - return sizeof(*uint_ptr); - case 17: /* icmpOutTimeExcds */ - *uint_ptr = STATS_GET(mib2.icmpouttimeexcds); - return sizeof(*uint_ptr); - case 18: /* icmpOutParmProbs: not supported -> always 0 */ - *uint_ptr = 0; - return sizeof(*uint_ptr); - case 19: /* icmpOutSrcQuenchs: not supported -> always 0 */ - *uint_ptr = 0; - return sizeof(*uint_ptr); - case 20: /* icmpOutRedirects: not supported -> always 0 */ - *uint_ptr = 0; - return sizeof(*uint_ptr); - case 21: /* icmpOutEchos */ - *uint_ptr = STATS_GET(mib2.icmpoutechos); - return sizeof(*uint_ptr); - case 22: /* icmpOutEchoReps */ - *uint_ptr = STATS_GET(mib2.icmpoutechoreps); - return sizeof(*uint_ptr); - case 23: /* icmpOutTimestamps: not supported -> always 0 */ - *uint_ptr = 0; - return sizeof(*uint_ptr); - case 24: /* icmpOutTimestampReps: not supported -> always 0 */ - *uint_ptr = 0; - return sizeof(*uint_ptr); - case 25: /* icmpOutAddrMasks: not supported -> always 0 */ - *uint_ptr = 0; - return sizeof(*uint_ptr); - case 26: /* icmpOutAddrMaskReps: not supported -> always 0 */ - *uint_ptr = 0; - return sizeof(*uint_ptr); - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_value(): unknown id: %"S32_F"\n", node->oid)); - break; - } - - return 0; -} - - -static const struct snmp_scalar_array_node_def icmp_nodes[] = { - { 1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - { 2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - { 3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - { 4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - { 5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - { 6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - { 7, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - { 8, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - { 9, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {21, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {22, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {23, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {24, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {25, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, - {26, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY} -}; - -const struct snmp_scalar_array_node snmp_mib2_icmp_root = SNMP_SCALAR_CREATE_ARRAY_NODE(5, icmp_nodes, icmp_get_value, NULL, NULL); - -#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_ICMP */ diff --git a/ext/lwip/src/apps/snmp/snmp_mib2_interfaces.c b/ext/lwip/src/apps/snmp/snmp_mib2_interfaces.c deleted file mode 100644 index c957a5a..0000000 --- a/ext/lwip/src/apps/snmp/snmp_mib2_interfaces.c +++ /dev/null @@ -1,376 +0,0 @@ -/** - * @file - * Management Information Base II (RFC1213) INTERFACES objects and functions. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dirk Ziegelmeier - * Christiaan Simons - */ - -#include "lwip/snmp.h" -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "lwip/apps/snmp_mib2.h" -#include "lwip/apps/snmp_table.h" -#include "lwip/apps/snmp_scalar.h" -#include "lwip/netif.h" -#include "lwip/stats.h" - -#include - -#if LWIP_SNMP && SNMP_LWIP_MIB2 - -#if SNMP_USE_NETCONN -#define SYNC_NODE_NAME(node_name) node_name ## _synced -#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ - static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); -#else -#define SYNC_NODE_NAME(node_name) node_name -#define CREATE_LWIP_SYNC_NODE(oid, node_name) -#endif - - -/* --- interfaces .1.3.6.1.2.1.2 ----------------------------------------------------- */ - -static s16_t -interfaces_get_value(struct snmp_node_instance* instance, void* value) -{ - if (instance->node->oid == 1) { - s32_t *sint_ptr = (s32_t*)value; - s32_t num_netifs = 0; - - struct netif *netif = netif_list; - while (netif != NULL) { - num_netifs++; - netif = netif->next; - } - - *sint_ptr = num_netifs; - return sizeof(*sint_ptr); - } - - return 0; -} - -/* list of allowed value ranges for incoming OID */ -static const struct snmp_oid_range interfaces_Table_oid_ranges[] = { - { 1, 0xff } /* netif->num is u8_t */ -}; - -static const u8_t iftable_ifOutQLen = 0; - -static const u8_t iftable_ifOperStatus_up = 1; -static const u8_t iftable_ifOperStatus_down = 2; - -static const u8_t iftable_ifAdminStatus_up = 1; -static const u8_t iftable_ifAdminStatus_lowerLayerDown = 7; -static const u8_t iftable_ifAdminStatus_down = 2; - -static snmp_err_t -interfaces_Table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance) -{ - u32_t ifIndex; - struct netif *netif; - - LWIP_UNUSED_ARG(column); - - /* check if incoming OID length and if values are in plausible range */ - if (!snmp_oid_in_range(row_oid, row_oid_len, interfaces_Table_oid_ranges, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges))) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* get netif index from incoming OID */ - ifIndex = row_oid[0]; - - /* find netif with index */ - netif = netif_list; - while (netif != NULL) { - if (netif_to_num(netif) == ifIndex) { - /* store netif pointer for subsequent operations (get/test/set) */ - cell_instance->reference.ptr = netif; - return SNMP_ERR_NOERROR; - } - netif = netif->next; - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -static snmp_err_t -interfaces_Table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance) -{ - struct netif *netif; - struct snmp_next_oid_state state; - u32_t result_temp[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)]; - - LWIP_UNUSED_ARG(column); - - /* init struct to search next oid */ - snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)); - - /* iterate over all possible OIDs to find the next one */ - netif = netif_list; - while (netif != NULL) { - u32_t test_oid[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)]; - test_oid[0] = netif_to_num(netif); - - /* check generated OID: is it a candidate for the next one? */ - snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges), netif); - - netif = netif->next; - } - - /* did we find a next one? */ - if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { - snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); - /* store netif pointer for subsequent operations (get/test/set) */ - cell_instance->reference.ptr = /* (struct netif*) */state.reference; - return SNMP_ERR_NOERROR; - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -static s16_t -interfaces_Table_get_value(struct snmp_node_instance* instance, void* value) -{ - struct netif *netif = (struct netif*)instance->reference.ptr; - u32_t* value_u32 = (u32_t*)value; - s32_t* value_s32 = (s32_t*)value; - u16_t value_len; - - switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id)) - { - case 1: /* ifIndex */ - *value_s32 = netif_to_num(netif); - value_len = sizeof(*value_s32); - break; - case 2: /* ifDescr */ - value_len = sizeof(netif->name); - MEMCPY(value, netif->name, value_len); - break; - case 3: /* ifType */ - *value_s32 = netif->link_type; - value_len = sizeof(*value_s32); - break; - case 4: /* ifMtu */ - *value_s32 = netif->mtu; - value_len = sizeof(*value_s32); - break; - case 5: /* ifSpeed */ - *value_u32 = netif->link_speed; - value_len = sizeof(*value_u32); - break; - case 6: /* ifPhysAddress */ - value_len = sizeof(netif->hwaddr); - MEMCPY(value, &netif->hwaddr, value_len); - break; - case 7: /* ifAdminStatus */ - if (netif_is_up(netif)) { - *value_s32 = iftable_ifOperStatus_up; - } else { - *value_s32 = iftable_ifOperStatus_down; - } - value_len = sizeof(*value_s32); - break; - case 8: /* ifOperStatus */ - if (netif_is_up(netif)) { - if (netif_is_link_up(netif)) { - *value_s32 = iftable_ifAdminStatus_up; - } else { - *value_s32 = iftable_ifAdminStatus_lowerLayerDown; - } - } else { - *value_s32 = iftable_ifAdminStatus_down; - } - value_len = sizeof(*value_s32); - break; - case 9: /* ifLastChange */ - *value_u32 = netif->ts; - value_len = sizeof(*value_u32); - break; - case 10: /* ifInOctets */ - *value_u32 = netif->mib2_counters.ifinoctets; - value_len = sizeof(*value_u32); - break; - case 11: /* ifInUcastPkts */ - *value_u32 = netif->mib2_counters.ifinucastpkts; - value_len = sizeof(*value_u32); - break; - case 12: /* ifInNUcastPkts */ - *value_u32 = netif->mib2_counters.ifinnucastpkts; - value_len = sizeof(*value_u32); - break; - case 13: /* ifInDiscards */ - *value_u32 = netif->mib2_counters.ifindiscards; - value_len = sizeof(*value_u32); - break; - case 14: /* ifInErrors */ - *value_u32 = netif->mib2_counters.ifinerrors; - value_len = sizeof(*value_u32); - break; - case 15: /* ifInUnkownProtos */ - *value_u32 = netif->mib2_counters.ifinunknownprotos; - value_len = sizeof(*value_u32); - break; - case 16: /* ifOutOctets */ - *value_u32 = netif->mib2_counters.ifoutoctets; - value_len = sizeof(*value_u32); - break; - case 17: /* ifOutUcastPkts */ - *value_u32 = netif->mib2_counters.ifoutucastpkts; - value_len = sizeof(*value_u32); - break; - case 18: /* ifOutNUcastPkts */ - *value_u32 = netif->mib2_counters.ifoutnucastpkts; - value_len = sizeof(*value_u32); - break; - case 19: /* ifOutDiscarts */ - *value_u32 = netif->mib2_counters.ifoutdiscards; - value_len = sizeof(*value_u32); - break; - case 20: /* ifOutErrors */ - *value_u32 = netif->mib2_counters.ifouterrors; - value_len = sizeof(*value_u32); - break; - case 21: /* ifOutQLen */ - *value_u32 = iftable_ifOutQLen; - value_len = sizeof(*value_u32); - break; - /** @note returning zeroDotZero (0.0) no media specific MIB support */ - case 22: /* ifSpecific */ - value_len = snmp_zero_dot_zero.len * sizeof(u32_t); - MEMCPY(value, snmp_zero_dot_zero.id, value_len); - break; - default: - return 0; - } - - return value_len; -} - -#if !SNMP_SAFE_REQUESTS - -static snmp_err_t -interfaces_Table_set_test(struct snmp_node_instance* instance, u16_t len, void *value) -{ - s32_t *sint_ptr = (s32_t*)value; - - /* stack should never call this method for another column, - because all other columns are set to readonly */ - LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7)); - LWIP_UNUSED_ARG(len); - - if (*sint_ptr == 1 || *sint_ptr == 2) - { - return SNMP_ERR_NOERROR; - } - - return SNMP_ERR_WRONGVALUE; -} - -static snmp_err_t -interfaces_Table_set_value(struct snmp_node_instance* instance, u16_t len, void *value) -{ - struct netif *netif = (struct netif*)instance->reference.ptr; - s32_t *sint_ptr = (s32_t*)value; - - /* stack should never call this method for another column, - because all other columns are set to readonly */ - LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7)); - LWIP_UNUSED_ARG(len); - - if (*sint_ptr == 1) { - netif_set_up(netif); - } else if (*sint_ptr == 2) { - netif_set_down(netif); - } - - return SNMP_ERR_NOERROR; -} - -#endif /* SNMP_SAFE_REQUESTS */ - -static const struct snmp_scalar_node interfaces_Number = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, interfaces_get_value); - -static const struct snmp_table_col_def interfaces_Table_columns[] = { - { 1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifIndex */ - { 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifDescr */ - { 3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifType */ - { 4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifMtu */ - { 5, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifSpeed */ - { 6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifPhysAddress */ -#if !SNMP_SAFE_REQUESTS - { 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE }, /* ifAdminStatus */ -#else - { 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifAdminStatus */ -#endif - { 8, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOperStatus */ - { 9, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifLastChange */ - { 10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInOctets */ - { 11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUcastPkts */ - { 12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInNUcastPkts */ - { 13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInDiscarts */ - { 14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInErrors */ - { 15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUnkownProtos */ - { 16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutOctets */ - { 17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutUcastPkts */ - { 18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutNUcastPkts */ - { 19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutDiscarts */ - { 20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutErrors */ - { 21, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutQLen */ - { 22, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY } /* ifSpecific */ -}; - -#if !SNMP_SAFE_REQUESTS -static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE( - 2, interfaces_Table_columns, - interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance, - interfaces_Table_get_value, interfaces_Table_set_test, interfaces_Table_set_value); -#else -static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE( - 2, interfaces_Table_columns, - interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance, - interfaces_Table_get_value, NULL, NULL); -#endif - -/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */ -CREATE_LWIP_SYNC_NODE(1, interfaces_Number) -CREATE_LWIP_SYNC_NODE(2, interfaces_Table) - -static const struct snmp_node* const interface_nodes[] = { - &SYNC_NODE_NAME(interfaces_Number).node.node, - &SYNC_NODE_NAME(interfaces_Table).node.node -}; - -const struct snmp_tree_node snmp_mib2_interface_root = SNMP_CREATE_TREE_NODE(2, interface_nodes); - -#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */ diff --git a/ext/lwip/src/apps/snmp/snmp_mib2_ip.c b/ext/lwip/src/apps/snmp/snmp_mib2_ip.c deleted file mode 100644 index da0e6f5..0000000 --- a/ext/lwip/src/apps/snmp/snmp_mib2_ip.c +++ /dev/null @@ -1,743 +0,0 @@ -/** - * @file - * Management Information Base II (RFC1213) IP objects and functions. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dirk Ziegelmeier - * Christiaan Simons - */ - -#include "lwip/snmp.h" -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "lwip/apps/snmp_mib2.h" -#include "lwip/apps/snmp_table.h" -#include "lwip/apps/snmp_scalar.h" -#include "lwip/stats.h" -#include "lwip/netif.h" -#include "lwip/ip.h" -#include "lwip/etharp.h" - -#if LWIP_SNMP && SNMP_LWIP_MIB2 - -#if SNMP_USE_NETCONN -#define SYNC_NODE_NAME(node_name) node_name ## _synced -#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ - static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); -#else -#define SYNC_NODE_NAME(node_name) node_name -#define CREATE_LWIP_SYNC_NODE(oid, node_name) -#endif - -#if LWIP_IPV4 -/* --- ip .1.3.6.1.2.1.4 ----------------------------------------------------- */ - -static s16_t -ip_get_value(struct snmp_node_instance* instance, void* value) -{ - s32_t* sint_ptr = (s32_t*)value; - u32_t* uint_ptr = (u32_t*)value; - - switch (instance->node->oid) { - case 1: /* ipForwarding */ -#if IP_FORWARD - /* forwarding */ - *sint_ptr = 1; -#else - /* not-forwarding */ - *sint_ptr = 2; -#endif - return sizeof(*sint_ptr); - case 2: /* ipDefaultTTL */ - *sint_ptr = IP_DEFAULT_TTL; - return sizeof(*sint_ptr); - case 3: /* ipInReceives */ - *uint_ptr = STATS_GET(mib2.ipinreceives); - return sizeof(*uint_ptr); - case 4: /* ipInHdrErrors */ - *uint_ptr = STATS_GET(mib2.ipinhdrerrors); - return sizeof(*uint_ptr); - case 5: /* ipInAddrErrors */ - *uint_ptr = STATS_GET(mib2.ipinaddrerrors); - return sizeof(*uint_ptr); - case 6: /* ipForwDatagrams */ - *uint_ptr = STATS_GET(mib2.ipforwdatagrams); - return sizeof(*uint_ptr); - case 7: /* ipInUnknownProtos */ - *uint_ptr = STATS_GET(mib2.ipinunknownprotos); - return sizeof(*uint_ptr); - case 8: /* ipInDiscards */ - *uint_ptr = STATS_GET(mib2.ipindiscards); - return sizeof(*uint_ptr); - case 9: /* ipInDelivers */ - *uint_ptr = STATS_GET(mib2.ipindelivers); - return sizeof(*uint_ptr); - case 10: /* ipOutRequests */ - *uint_ptr = STATS_GET(mib2.ipoutrequests); - return sizeof(*uint_ptr); - case 11: /* ipOutDiscards */ - *uint_ptr = STATS_GET(mib2.ipoutdiscards); - return sizeof(*uint_ptr); - case 12: /* ipOutNoRoutes */ - *uint_ptr = STATS_GET(mib2.ipoutnoroutes); - return sizeof(*uint_ptr); - case 13: /* ipReasmTimeout */ -#if IP_REASSEMBLY - *sint_ptr = IP_REASS_MAXAGE; -#else - *sint_ptr = 0; -#endif - return sizeof(*sint_ptr); - case 14: /* ipReasmReqds */ - *uint_ptr = STATS_GET(mib2.ipreasmreqds); - return sizeof(*uint_ptr); - case 15: /* ipReasmOKs */ - *uint_ptr = STATS_GET(mib2.ipreasmoks); - return sizeof(*uint_ptr); - case 16: /* ipReasmFails */ - *uint_ptr = STATS_GET(mib2.ipreasmfails); - return sizeof(*uint_ptr); - case 17: /* ipFragOKs */ - *uint_ptr = STATS_GET(mib2.ipfragoks); - return sizeof(*uint_ptr); - case 18: /* ipFragFails */ - *uint_ptr = STATS_GET(mib2.ipfragfails); - return sizeof(*uint_ptr); - case 19: /* ipFragCreates */ - *uint_ptr = STATS_GET(mib2.ipfragcreates); - return sizeof(*uint_ptr); - case 23: /* ipRoutingDiscards: not supported -> always 0 */ - *uint_ptr = 0; - return sizeof(*uint_ptr); - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_value(): unknown id: %"S32_F"\n", instance->node->oid)); - break; - } - - return 0; -} - -/** - * Test ip object value before setting. - * - * @param od is the object definition - * @param len return value space (in bytes) - * @param value points to (varbind) space to copy value from. - * - * @note we allow set if the value matches the hardwired value, - * otherwise return badvalue. - */ -static snmp_err_t -ip_set_test(struct snmp_node_instance* instance, u16_t len, void *value) -{ - snmp_err_t ret = SNMP_ERR_WRONGVALUE; - s32_t *sint_ptr = (s32_t*)value; - - LWIP_UNUSED_ARG(len); - switch (instance->node->oid) { - case 1: /* ipForwarding */ -#if IP_FORWARD - /* forwarding */ - if (*sint_ptr == 1) -#else - /* not-forwarding */ - if (*sint_ptr == 2) -#endif - { - ret = SNMP_ERR_NOERROR; - } - break; - case 2: /* ipDefaultTTL */ - if (*sint_ptr == IP_DEFAULT_TTL) { - ret = SNMP_ERR_NOERROR; - } - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_set_test(): unknown id: %"S32_F"\n", instance->node->oid)); - break; - } - - return ret; -} - -static snmp_err_t -ip_set_value(struct snmp_node_instance* instance, u16_t len, void *value) -{ - LWIP_UNUSED_ARG(instance); - LWIP_UNUSED_ARG(len); - LWIP_UNUSED_ARG(value); - /* nothing to do here because in set_test we only accept values being the same as our own stored value -> no need to store anything */ - return SNMP_ERR_NOERROR; -} - -/* --- ipAddrTable --- */ - -/* list of allowed value ranges for incoming OID */ -static const struct snmp_oid_range ip_AddrTable_oid_ranges[] = { - { 0, 0xff }, /* IP A */ - { 0, 0xff }, /* IP B */ - { 0, 0xff }, /* IP C */ - { 0, 0xff } /* IP D */ -}; - -static snmp_err_t -ip_AddrTable_get_cell_value_core(struct netif *netif, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) -{ - LWIP_UNUSED_ARG(value_len); - - switch (*column) { - case 1: /* ipAdEntAddr */ - value->u32 = netif_ip4_addr(netif)->addr; - break; - case 2: /* ipAdEntIfIndex */ - value->u32 = netif_to_num(netif); - break; - case 3: /* ipAdEntNetMask */ - value->u32 = netif_ip4_netmask(netif)->addr; - break; - case 4: /* ipAdEntBcastAddr */ - /* lwIP oddity, there's no broadcast - address in the netif we can rely on */ - value->u32 = IPADDR_BROADCAST & 1; - break; - case 5: /* ipAdEntReasmMaxSize */ -#if IP_REASSEMBLY - /* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs, - * but only if receiving one fragmented packet at a time. - * The current solution is to calculate for 2 simultaneous packets... - */ - value->u32 = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) * - (PBUF_POOL_BUFSIZE - PBUF_LINK_ENCAPSULATION_HLEN - PBUF_LINK_HLEN - IP_HLEN))); -#else - /** @todo returning MTU would be a bad thing and - returning a wild guess like '576' isn't good either */ - value->u32 = 0; -#endif - break; - default: - return SNMP_ERR_NOSUCHINSTANCE; - } - - return SNMP_ERR_NOERROR; -} - -static snmp_err_t -ip_AddrTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) -{ - ip4_addr_t ip; - struct netif *netif; - - /* check if incoming OID length and if values are in plausible range */ - if (!snmp_oid_in_range(row_oid, row_oid_len, ip_AddrTable_oid_ranges, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges))) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* get IP from incoming OID */ - snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */ - - /* find netif with requested ip */ - netif = netif_list; - while (netif != NULL) { - if (ip4_addr_cmp(&ip, netif_ip4_addr(netif))) { - /* fill in object properties */ - return ip_AddrTable_get_cell_value_core(netif, column, value, value_len); - } - - netif = netif->next; - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -static snmp_err_t -ip_AddrTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) -{ - struct netif *netif; - struct snmp_next_oid_state state; - u32_t result_temp[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)]; - - /* init struct to search next oid */ - snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)); - - /* iterate over all possible OIDs to find the next one */ - netif = netif_list; - while (netif != NULL) { - u32_t test_oid[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)]; - snmp_ip4_to_oid(netif_ip4_addr(netif), &test_oid[0]); - - /* check generated OID: is it a candidate for the next one? */ - snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges), netif); - - netif = netif->next; - } - - /* did we find a next one? */ - if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { - snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); - /* fill in object properties */ - return ip_AddrTable_get_cell_value_core((struct netif*)state.reference, column, value, value_len); - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -/* --- ipRouteTable --- */ - -/* list of allowed value ranges for incoming OID */ -static const struct snmp_oid_range ip_RouteTable_oid_ranges[] = { - { 0, 0xff }, /* IP A */ - { 0, 0xff }, /* IP B */ - { 0, 0xff }, /* IP C */ - { 0, 0xff }, /* IP D */ -}; - -static snmp_err_t -ip_RouteTable_get_cell_value_core(struct netif *netif, u8_t default_route, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) -{ - switch (*column) { - case 1: /* ipRouteDest */ - if (default_route) { - /* default rte has 0.0.0.0 dest */ - value->u32 = IP4_ADDR_ANY->addr; - } else { - /* netifs have netaddress dest */ - ip4_addr_t tmp; - ip4_addr_get_network(&tmp, netif_ip4_addr(netif), netif_ip4_netmask(netif)); - value->u32 = tmp.addr; - } - break; - case 2: /* ipRouteIfIndex */ - value->u32 = netif_to_num(netif); - break; - case 3: /* ipRouteMetric1 */ - if (default_route) { - value->s32 = 1; /* default */ - } else { - value->s32 = 0; /* normal */ - } - break; - case 4: /* ipRouteMetric2 */ - case 5: /* ipRouteMetric3 */ - case 6: /* ipRouteMetric4 */ - value->s32 = -1; /* none */ - break; - case 7: /* ipRouteNextHop */ - if (default_route) { - /* default rte: gateway */ - value->u32 = netif_ip4_gw(netif)->addr; - } else { - /* other rtes: netif ip_addr */ - value->u32 = netif_ip4_addr(netif)->addr; - } - break; - case 8: /* ipRouteType */ - if (default_route) { - /* default rte is indirect */ - value->u32 = 4; /* indirect */ - } else { - /* other rtes are direct */ - value->u32 = 3; /* direct */ - } - break; - case 9: /* ipRouteProto */ - /* locally defined routes */ - value->u32 = 2; /* local */ - break; - case 10: /* ipRouteAge */ - /* @todo (sysuptime - timestamp last change) / 100 */ - value->u32 = 0; - break; - case 11: /* ipRouteMask */ - if (default_route) { - /* default rte use 0.0.0.0 mask */ - value->u32 = IP4_ADDR_ANY->addr; - } else { - /* other rtes use netmask */ - value->u32 = netif_ip4_netmask(netif)->addr; - } - break; - case 12: /* ipRouteMetric5 */ - value->s32 = -1; /* none */ - break; - case 13: /* ipRouteInfo */ - value->const_ptr = snmp_zero_dot_zero.id; - *value_len = snmp_zero_dot_zero.len * sizeof(u32_t); - break; - default: - return SNMP_ERR_NOSUCHINSTANCE; - } - - return SNMP_ERR_NOERROR; -} - -static snmp_err_t -ip_RouteTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) -{ - ip4_addr_t test_ip; - struct netif *netif; - - /* check if incoming OID length and if values are in plausible range */ - if (!snmp_oid_in_range(row_oid, row_oid_len, ip_RouteTable_oid_ranges, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges))) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* get IP and port from incoming OID */ - snmp_oid_to_ip4(&row_oid[0], &test_ip); /* we know it succeeds because of oid_in_range check above */ - - /* default route is on default netif */ - if (ip4_addr_isany_val(test_ip) && (netif_default != NULL)) { - /* fill in object properties */ - return ip_RouteTable_get_cell_value_core(netif_default, 1, column, value, value_len); - } - - /* find netif with requested route */ - netif = netif_list; - while (netif != NULL) { - ip4_addr_t dst; - ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif)); - - if (ip4_addr_cmp(&dst, &test_ip)) { - /* fill in object properties */ - return ip_RouteTable_get_cell_value_core(netif, 0, column, value, value_len); - } - - netif = netif->next; - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -static snmp_err_t -ip_RouteTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) -{ - struct netif *netif; - struct snmp_next_oid_state state; - u32_t result_temp[LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)]; - u32_t test_oid[LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)]; - - /* init struct to search next oid */ - snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)); - - /* check default route */ - if (netif_default != NULL) { - snmp_ip4_to_oid(IP4_ADDR_ANY, &test_oid[0]); - snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif_default); - } - - /* iterate over all possible OIDs to find the next one */ - netif = netif_list; - while (netif != NULL) { - ip4_addr_t dst; - ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif)); - - /* check generated OID: is it a candidate for the next one? */ - if (!ip4_addr_isany_val(dst)) { - snmp_ip4_to_oid(&dst, &test_oid[0]); - snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif); - } - - netif = netif->next; - } - - /* did we find a next one? */ - if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { - ip4_addr_t dst; - snmp_oid_to_ip4(&result_temp[0], &dst); - snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); - /* fill in object properties */ - return ip_RouteTable_get_cell_value_core((struct netif*)state.reference, ip4_addr_isany_val(dst), column, value, value_len); - } else { - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; - } -} - -#if LWIP_ARP && LWIP_IPV4 -/* --- ipNetToMediaTable --- */ - -/* list of allowed value ranges for incoming OID */ -static const struct snmp_oid_range ip_NetToMediaTable_oid_ranges[] = { - { 1, 0xff }, /* IfIndex */ - { 0, 0xff }, /* IP A */ - { 0, 0xff }, /* IP B */ - { 0, 0xff }, /* IP C */ - { 0, 0xff } /* IP D */ -}; - -static snmp_err_t -ip_NetToMediaTable_get_cell_value_core(u8_t arp_table_index, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) -{ - ip4_addr_t *ip; - struct netif *netif; - struct eth_addr *ethaddr; - - etharp_get_entry(arp_table_index, &ip, &netif, ðaddr); - - /* value */ - switch (*column) { - case 1: /* atIfIndex / ipNetToMediaIfIndex */ - value->u32 = netif_to_num(netif); - break; - case 2: /* atPhysAddress / ipNetToMediaPhysAddress */ - value->ptr = ethaddr; - *value_len = sizeof(*ethaddr); - break; - case 3: /* atNetAddress / ipNetToMediaNetAddress */ - value->u32 = ip->addr; - break; - case 4: /* ipNetToMediaType */ - value->u32 = 3; /* dynamic*/ - break; - default: - return SNMP_ERR_NOSUCHINSTANCE; - } - - return SNMP_ERR_NOERROR; -} - -static snmp_err_t -ip_NetToMediaTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) -{ - ip4_addr_t ip_in; - u8_t netif_index; - u8_t i; - - /* check if incoming OID length and if values are in plausible range */ - if (!snmp_oid_in_range(row_oid, row_oid_len, ip_NetToMediaTable_oid_ranges, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges))) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* get IP from incoming OID */ - netif_index = (u8_t)row_oid[0]; - snmp_oid_to_ip4(&row_oid[1], &ip_in); /* we know it succeeds because of oid_in_range check above */ - - /* find requested entry */ - for (i=0; iid, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)); - - /* iterate over all possible OIDs to find the next one */ - for (i=0; i - * Christiaan Simons - */ - -#include "lwip/snmp.h" -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "lwip/apps/snmp_mib2.h" -#include "lwip/apps/snmp_scalar.h" - -#if LWIP_SNMP && SNMP_LWIP_MIB2 - -#define MIB2_AUTH_TRAPS_ENABLED 1 -#define MIB2_AUTH_TRAPS_DISABLED 2 - -/* --- snmp .1.3.6.1.2.1.11 ----------------------------------------------------- */ -static s16_t -snmp_get_value(const struct snmp_scalar_array_node_def *node, void *value) -{ - u32_t *uint_ptr = (u32_t*)value; - switch (node->oid) { - case 1: /* snmpInPkts */ - *uint_ptr = snmp_stats.inpkts; - break; - case 2: /* snmpOutPkts */ - *uint_ptr = snmp_stats.outpkts; - break; - case 3: /* snmpInBadVersions */ - *uint_ptr = snmp_stats.inbadversions; - break; - case 4: /* snmpInBadCommunityNames */ - *uint_ptr = snmp_stats.inbadcommunitynames; - break; - case 5: /* snmpInBadCommunityUses */ - *uint_ptr = snmp_stats.inbadcommunityuses; - break; - case 6: /* snmpInASNParseErrs */ - *uint_ptr = snmp_stats.inasnparseerrs; - break; - case 8: /* snmpInTooBigs */ - *uint_ptr = snmp_stats.intoobigs; - break; - case 9: /* snmpInNoSuchNames */ - *uint_ptr = snmp_stats.innosuchnames; - break; - case 10: /* snmpInBadValues */ - *uint_ptr = snmp_stats.inbadvalues; - break; - case 11: /* snmpInReadOnlys */ - *uint_ptr = snmp_stats.inreadonlys; - break; - case 12: /* snmpInGenErrs */ - *uint_ptr = snmp_stats.ingenerrs; - break; - case 13: /* snmpInTotalReqVars */ - *uint_ptr = snmp_stats.intotalreqvars; - break; - case 14: /* snmpInTotalSetVars */ - *uint_ptr = snmp_stats.intotalsetvars; - break; - case 15: /* snmpInGetRequests */ - *uint_ptr = snmp_stats.ingetrequests; - break; - case 16: /* snmpInGetNexts */ - *uint_ptr = snmp_stats.ingetnexts; - break; - case 17: /* snmpInSetRequests */ - *uint_ptr = snmp_stats.insetrequests; - break; - case 18: /* snmpInGetResponses */ - *uint_ptr = snmp_stats.ingetresponses; - break; - case 19: /* snmpInTraps */ - *uint_ptr = snmp_stats.intraps; - break; - case 20: /* snmpOutTooBigs */ - *uint_ptr = snmp_stats.outtoobigs; - break; - case 21: /* snmpOutNoSuchNames */ - *uint_ptr = snmp_stats.outnosuchnames; - break; - case 22: /* snmpOutBadValues */ - *uint_ptr = snmp_stats.outbadvalues; - break; - case 24: /* snmpOutGenErrs */ - *uint_ptr = snmp_stats.outgenerrs; - break; - case 25: /* snmpOutGetRequests */ - *uint_ptr = snmp_stats.outgetrequests; - break; - case 26: /* snmpOutGetNexts */ - *uint_ptr = snmp_stats.outgetnexts; - break; - case 27: /* snmpOutSetRequests */ - *uint_ptr = snmp_stats.outsetrequests; - break; - case 28: /* snmpOutGetResponses */ - *uint_ptr = snmp_stats.outgetresponses; - break; - case 29: /* snmpOutTraps */ - *uint_ptr = snmp_stats.outtraps; - break; - case 30: /* snmpEnableAuthenTraps */ - if (snmp_get_auth_traps_enabled() == SNMP_AUTH_TRAPS_DISABLED) { - *uint_ptr = MIB2_AUTH_TRAPS_DISABLED; - } else { - *uint_ptr = MIB2_AUTH_TRAPS_ENABLED; - } - break; - case 31: /* snmpSilentDrops */ - *uint_ptr = 0; /* not supported */ - break; - case 32: /* snmpProxyDrops */ - *uint_ptr = 0; /* not supported */ - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_value(): unknown id: %"S32_F"\n", node->oid)); - return 0; - } - - return sizeof(*uint_ptr); -} - -static snmp_err_t -snmp_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value) -{ - snmp_err_t ret = SNMP_ERR_WRONGVALUE; - LWIP_UNUSED_ARG(len); - - if (node->oid == 30) { - /* snmpEnableAuthenTraps */ - s32_t *sint_ptr = (s32_t*)value; - - /* we should have writable non-volatile mem here */ - if ((*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) || (*sint_ptr == MIB2_AUTH_TRAPS_ENABLED)) { - ret = SNMP_ERR_NOERROR; - } - } - return ret; -} - -static snmp_err_t -snmp_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value) -{ - LWIP_UNUSED_ARG(len); - - if (node->oid == 30) { - /* snmpEnableAuthenTraps */ - s32_t *sint_ptr = (s32_t*)value; - if (*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) { - snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_DISABLED); - } else { - snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_ENABLED); - } - } - - return SNMP_ERR_NOERROR; -} - -/* the following nodes access variables in SNMP stack (snmp_stats) from SNMP worker thread -> OK, no sync needed */ -static const struct snmp_scalar_array_node_def snmp_nodes[] = { - { 1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInPkts */ - { 2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutPkts */ - { 3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadVersions */ - { 4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadCommunityNames */ - { 5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadCommunityUses */ - { 6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInASNParseErrs */ - { 8, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTooBigs */ - { 9, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInNoSuchNames */ - {10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadValues */ - {11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInReadOnlys */ - {12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGenErrs */ - {13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTotalReqVars */ - {14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTotalSetVars */ - {15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetRequests */ - {16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetNexts */ - {17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInSetRequests */ - {18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetResponses */ - {19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTraps */ - {20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutTooBigs */ - {21, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutNoSuchNames */ - {22, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutBadValues */ - {24, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGenErrs */ - {25, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetRequests */ - {26, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetNexts */ - {27, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutSetRequests */ - {28, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetResponses */ - {29, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutTraps */ - {30, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* snmpEnableAuthenTraps */ - {31, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpSilentDrops */ - {32, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY} /* snmpProxyDrops */ -}; - -const struct snmp_scalar_array_node snmp_mib2_snmp_root = SNMP_SCALAR_CREATE_ARRAY_NODE(11, snmp_nodes, snmp_get_value, snmp_set_test, snmp_set_value); - -#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */ diff --git a/ext/lwip/src/apps/snmp/snmp_mib2_system.c b/ext/lwip/src/apps/snmp/snmp_mib2_system.c deleted file mode 100644 index 2cf8848..0000000 --- a/ext/lwip/src/apps/snmp/snmp_mib2_system.c +++ /dev/null @@ -1,377 +0,0 @@ -/** - * @file - * Management Information Base II (RFC1213) SYSTEM objects and functions. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dirk Ziegelmeier - * Christiaan Simons - */ - -#include "lwip/snmp.h" -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "lwip/apps/snmp_mib2.h" -#include "lwip/apps/snmp_table.h" -#include "lwip/apps/snmp_scalar.h" -#include "lwip/sys.h" - -#include - -#if LWIP_SNMP && SNMP_LWIP_MIB2 - -#if SNMP_USE_NETCONN -#define SYNC_NODE_NAME(node_name) node_name ## _synced -#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ - static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); -#else -#define SYNC_NODE_NAME(node_name) node_name -#define CREATE_LWIP_SYNC_NODE(oid, node_name) -#endif - -/* --- system .1.3.6.1.2.1.1 ----------------------------------------------------- */ - -/** mib-2.system.sysDescr */ -static const u8_t sysdescr_default[] = SNMP_LWIP_MIB2_SYSDESC; -static const u8_t* sysdescr = sysdescr_default; -static const u16_t* sysdescr_len = NULL; /* use strlen for determining len */ - -/** mib-2.system.sysContact */ -static const u8_t syscontact_default[] = SNMP_LWIP_MIB2_SYSCONTACT; -static const u8_t* syscontact = syscontact_default; -static const u16_t* syscontact_len = NULL; /* use strlen for determining len */ -static u8_t* syscontact_wr = NULL; /* if writable, points to the same buffer as syscontact (required for correct constness) */ -static u16_t* syscontact_wr_len = NULL; /* if writable, points to the same buffer as syscontact_len (required for correct constness) */ -static u16_t syscontact_bufsize = 0; /* 0=not writable */ - -/** mib-2.system.sysName */ -static const u8_t sysname_default[] = SNMP_LWIP_MIB2_SYSNAME; -static const u8_t* sysname = sysname_default; -static const u16_t* sysname_len = NULL; /* use strlen for determining len */ -static u8_t* sysname_wr = NULL; /* if writable, points to the same buffer as sysname (required for correct constness) */ -static u16_t* sysname_wr_len = NULL; /* if writable, points to the same buffer as sysname_len (required for correct constness) */ -static u16_t sysname_bufsize = 0; /* 0=not writable */ - -/** mib-2.system.sysLocation */ -static const u8_t syslocation_default[] = SNMP_LWIP_MIB2_SYSLOCATION; -static const u8_t* syslocation = syslocation_default; -static const u16_t* syslocation_len = NULL; /* use strlen for determining len */ -static u8_t* syslocation_wr = NULL; /* if writable, points to the same buffer as syslocation (required for correct constness) */ -static u16_t* syslocation_wr_len = NULL; /* if writable, points to the same buffer as syslocation_len (required for correct constness) */ -static u16_t syslocation_bufsize = 0; /* 0=not writable */ - -/** - * @ingroup snmp_mib2 - * Initializes sysDescr pointers. - * - * @param str if non-NULL then copy str pointer - * @param len points to string length, excluding zero terminator - */ -void -snmp_mib2_set_sysdescr(const u8_t *str, const u16_t *len) -{ - if (str != NULL) { - sysdescr = str; - sysdescr_len = len; - } -} - -/** - * @ingroup snmp_mib2 - * Initializes sysContact pointers - * - * @param ocstr if non-NULL then copy str pointer - * @param ocstrlen points to string length, excluding zero terminator. - * if set to NULL it is assumed that ocstr is NULL-terminated. - * @param bufsize size of the buffer in bytes. - * (this is required because the buffer can be overwritten by snmp-set) - * if ocstrlen is NULL buffer needs space for terminating 0 byte. - * otherwise complete buffer is used for string. - * if bufsize is set to 0, the value is regarded as read-only. - */ -void -snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize) -{ - if (ocstr != NULL) { - syscontact = ocstr; - syscontact_wr = ocstr; - syscontact_len = ocstrlen; - syscontact_wr_len = ocstrlen; - syscontact_bufsize = bufsize; - } -} - -/** - * @ingroup snmp_mib2 - * see \ref snmp_mib2_set_syscontact but set pointer to readonly memory - */ -void -snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen) -{ - if (ocstr != NULL) { - syscontact = ocstr; - syscontact_len = ocstrlen; - syscontact_wr = NULL; - syscontact_wr_len = NULL; - syscontact_bufsize = 0; - } -} - - -/** - * @ingroup snmp_mib2 - * Initializes sysName pointers - * - * @param ocstr if non-NULL then copy str pointer - * @param ocstrlen points to string length, excluding zero terminator. - * if set to NULL it is assumed that ocstr is NULL-terminated. - * @param bufsize size of the buffer in bytes. - * (this is required because the buffer can be overwritten by snmp-set) - * if ocstrlen is NULL buffer needs space for terminating 0 byte. - * otherwise complete buffer is used for string. - * if bufsize is set to 0, the value is regarded as read-only. - */ -void -snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize) -{ - if (ocstr != NULL) { - sysname = ocstr; - sysname_wr = ocstr; - sysname_len = ocstrlen; - sysname_wr_len = ocstrlen; - sysname_bufsize = bufsize; - } -} - -/** - * @ingroup snmp_mib2 - * see \ref snmp_mib2_set_sysname but set pointer to readonly memory - */ -void -snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen) -{ - if (ocstr != NULL) { - sysname = ocstr; - sysname_len = ocstrlen; - sysname_wr = NULL; - sysname_wr_len = NULL; - sysname_bufsize = 0; - } -} - -/** - * @ingroup snmp_mib2 - * Initializes sysLocation pointers - * - * @param ocstr if non-NULL then copy str pointer - * @param ocstrlen points to string length, excluding zero terminator. - * if set to NULL it is assumed that ocstr is NULL-terminated. - * @param bufsize size of the buffer in bytes. - * (this is required because the buffer can be overwritten by snmp-set) - * if ocstrlen is NULL buffer needs space for terminating 0 byte. - * otherwise complete buffer is used for string. - * if bufsize is set to 0, the value is regarded as read-only. - */ -void -snmp_mib2_set_syslocation(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize) -{ - if (ocstr != NULL) { - syslocation = ocstr; - syslocation_wr = ocstr; - syslocation_len = ocstrlen; - syslocation_wr_len = ocstrlen; - syslocation_bufsize = bufsize; - } -} - -/** - * @ingroup snmp_mib2 - * see \ref snmp_mib2_set_syslocation but set pointer to readonly memory - */ -void -snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen) -{ - if (ocstr != NULL) { - syslocation = ocstr; - syslocation_len = ocstrlen; - syslocation_wr = NULL; - syslocation_wr_len = NULL; - syslocation_bufsize = 0; - } -} - - -static s16_t -system_get_value(const struct snmp_scalar_array_node_def *node, void *value) -{ - const u8_t* var = NULL; - const s16_t* var_len; - u16_t result; - - switch (node->oid) { - case 1: /* sysDescr */ - var = sysdescr; - var_len = (const s16_t*)sysdescr_len; - break; - case 2: /* sysObjectID */ - { - const struct snmp_obj_id* dev_enterprise_oid = snmp_get_device_enterprise_oid(); - MEMCPY(value, dev_enterprise_oid->id, dev_enterprise_oid->len * sizeof(u32_t)); - return dev_enterprise_oid->len * sizeof(u32_t); - } - case 3: /* sysUpTime */ - MIB2_COPY_SYSUPTIME_TO((u32_t*)value); - return sizeof(u32_t); - case 4: /* sysContact */ - var = syscontact; - var_len = (const s16_t*)syscontact_len; - break; - case 5: /* sysName */ - var = sysname; - var_len = (const s16_t*)sysname_len; - break; - case 6: /* sysLocation */ - var = syslocation; - var_len = (const s16_t*)syslocation_len; - break; - case 7: /* sysServices */ - *(s32_t*)value = SNMP_SYSSERVICES; - return sizeof(s32_t); - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_value(): unknown id: %"S32_F"\n", node->oid)); - return 0; - } - - /* handle string values (OID 1,4,5 and 6) */ - LWIP_ASSERT("", (value != NULL)); - if (var_len == NULL) { - result = (s16_t)strlen((const char*)var); - } else { - result = *var_len; - } - MEMCPY(value, var, result); - return result; -} - -static snmp_err_t -system_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value) -{ - snmp_err_t ret = SNMP_ERR_WRONGVALUE; - const u16_t* var_bufsize = NULL; - const u16_t* var_wr_len; - - LWIP_UNUSED_ARG(value); - - switch (node->oid) { - case 4: /* sysContact */ - var_bufsize = &syscontact_bufsize; - var_wr_len = syscontact_wr_len; - break; - case 5: /* sysName */ - var_bufsize = &sysname_bufsize; - var_wr_len = sysname_wr_len; - break; - case 6: /* sysLocation */ - var_bufsize = &syslocation_bufsize; - var_wr_len = syslocation_wr_len; - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_test(): unknown id: %"S32_F"\n", node->oid)); - return ret; - } - - /* check if value is writable at all */ - if (*var_bufsize > 0) { - if (var_wr_len == NULL) { - /* we have to take the terminating 0 into account */ - if (len < *var_bufsize) { - ret = SNMP_ERR_NOERROR; - } - } else { - if (len <= *var_bufsize) { - ret = SNMP_ERR_NOERROR; - } - } - } else { - ret = SNMP_ERR_NOTWRITABLE; - } - - return ret; -} - -static snmp_err_t -system_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value) -{ - u8_t* var_wr = NULL; - u16_t* var_wr_len; - - switch (node->oid) { - case 4: /* sysContact */ - var_wr = syscontact_wr; - var_wr_len = syscontact_wr_len; - break; - case 5: /* sysName */ - var_wr = sysname_wr; - var_wr_len = sysname_wr_len; - break; - case 6: /* sysLocation */ - var_wr = syslocation_wr; - var_wr_len = syslocation_wr_len; - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_value(): unknown id: %"S32_F"\n", node->oid)); - return SNMP_ERR_GENERROR; - } - - /* no need to check size of target buffer, this was already done in set_test method */ - LWIP_ASSERT("", var_wr != NULL); - MEMCPY(var_wr, value, len); - - if (var_wr_len == NULL) { - /* add terminating 0 */ - var_wr[len] = 0; - } else { - *var_wr_len = len; - } - - return SNMP_ERR_NOERROR; -} - -static const struct snmp_scalar_array_node_def system_nodes[] = { - {1, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysDescr */ - {2, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysObjectID */ - {3, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysUpTime */ - {4, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysContact */ - {5, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysName */ - {6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysLocation */ - {7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY} /* sysServices */ -}; - -const struct snmp_scalar_array_node snmp_mib2_system_node = SNMP_SCALAR_CREATE_ARRAY_NODE(1, system_nodes, system_get_value, system_set_test, system_set_value); - -#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */ diff --git a/ext/lwip/src/apps/snmp/snmp_mib2_tcp.c b/ext/lwip/src/apps/snmp/snmp_mib2_tcp.c deleted file mode 100644 index db3f74c..0000000 --- a/ext/lwip/src/apps/snmp/snmp_mib2_tcp.c +++ /dev/null @@ -1,594 +0,0 @@ -/** - * @file - * Management Information Base II (RFC1213) TCP objects and functions. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dirk Ziegelmeier - * Christiaan Simons - */ - -#include "lwip/snmp.h" -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "lwip/apps/snmp_mib2.h" -#include "lwip/apps/snmp_table.h" -#include "lwip/apps/snmp_scalar.h" -#include "lwip/tcp.h" -#include "lwip/priv/tcp_priv.h" -#include "lwip/stats.h" - -#include - -#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_TCP - -#if SNMP_USE_NETCONN -#define SYNC_NODE_NAME(node_name) node_name ## _synced -#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ - static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); -#else -#define SYNC_NODE_NAME(node_name) node_name -#define CREATE_LWIP_SYNC_NODE(oid, node_name) -#endif - -/* --- tcp .1.3.6.1.2.1.6 ----------------------------------------------------- */ - -static s16_t -tcp_get_value(struct snmp_node_instance* instance, void* value) -{ - u32_t *uint_ptr = (u32_t*)value; - s32_t *sint_ptr = (s32_t*)value; - - switch (instance->node->oid) { - case 1: /* tcpRtoAlgorithm, vanj(4) */ - *sint_ptr = 4; - return sizeof(*sint_ptr); - case 2: /* tcpRtoMin */ - /* @todo not the actual value, a guess, - needs to be calculated */ - *sint_ptr = 1000; - return sizeof(*sint_ptr); - case 3: /* tcpRtoMax */ - /* @todo not the actual value, a guess, - needs to be calculated */ - *sint_ptr = 60000; - return sizeof(*sint_ptr); - case 4: /* tcpMaxConn */ - *sint_ptr = MEMP_NUM_TCP_PCB; - return sizeof(*sint_ptr); - case 5: /* tcpActiveOpens */ - *uint_ptr = STATS_GET(mib2.tcpactiveopens); - return sizeof(*uint_ptr); - case 6: /* tcpPassiveOpens */ - *uint_ptr = STATS_GET(mib2.tcppassiveopens); - return sizeof(*uint_ptr); - case 7: /* tcpAttemptFails */ - *uint_ptr = STATS_GET(mib2.tcpattemptfails); - return sizeof(*uint_ptr); - case 8: /* tcpEstabResets */ - *uint_ptr = STATS_GET(mib2.tcpestabresets); - return sizeof(*uint_ptr); - case 9: /* tcpCurrEstab */ - { - u16_t tcpcurrestab = 0; - struct tcp_pcb *pcb = tcp_active_pcbs; - while (pcb != NULL) { - if ((pcb->state == ESTABLISHED) || - (pcb->state == CLOSE_WAIT)) { - tcpcurrestab++; - } - pcb = pcb->next; - } - *uint_ptr = tcpcurrestab; - } - return sizeof(*uint_ptr); - case 10: /* tcpInSegs */ - *uint_ptr = STATS_GET(mib2.tcpinsegs); - return sizeof(*uint_ptr); - case 11: /* tcpOutSegs */ - *uint_ptr = STATS_GET(mib2.tcpoutsegs); - return sizeof(*uint_ptr); - case 12: /* tcpRetransSegs */ - *uint_ptr = STATS_GET(mib2.tcpretranssegs); - return sizeof(*uint_ptr); - case 14: /* tcpInErrs */ - *uint_ptr = STATS_GET(mib2.tcpinerrs); - return sizeof(*uint_ptr); - case 15: /* tcpOutRsts */ - *uint_ptr = STATS_GET(mib2.tcpoutrsts); - return sizeof(*uint_ptr); - case 17: /* tcpHCInSegs */ - memset(value, 0, 2*sizeof(u32_t)); /* not supported */ - return 2*sizeof(u32_t); - case 18: /* tcpHCOutSegs */ - memset(value, 0, 2*sizeof(u32_t)); /* not supported */ - return 2*sizeof(u32_t); - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_value(): unknown id: %"S32_F"\n", instance->node->oid)); - break; - } - - return 0; -} - -/* --- tcpConnTable --- */ - -#if LWIP_IPV4 - -/* list of allowed value ranges for incoming OID */ -static const struct snmp_oid_range tcp_ConnTable_oid_ranges[] = { - { 0, 0xff }, /* IP A */ - { 0, 0xff }, /* IP B */ - { 0, 0xff }, /* IP C */ - { 0, 0xff }, /* IP D */ - { 0, 0xffff }, /* Port */ - { 0, 0xff }, /* IP A */ - { 0, 0xff }, /* IP B */ - { 0, 0xff }, /* IP C */ - { 0, 0xff }, /* IP D */ - { 0, 0xffff } /* Port */ -}; - -static snmp_err_t -tcp_ConnTable_get_cell_value_core(struct tcp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) -{ - LWIP_UNUSED_ARG(value_len); - - /* value */ - switch (*column) { - case 1: /* tcpConnState */ - value->u32 = pcb->state + 1; - break; - case 2: /* tcpConnLocalAddress */ - value->u32 = ip_2_ip4(&pcb->local_ip)->addr; - break; - case 3: /* tcpConnLocalPort */ - value->u32 = pcb->local_port; - break; - case 4: /* tcpConnRemAddress */ - if (pcb->state == LISTEN) { - value->u32 = IP4_ADDR_ANY->addr; - } else { - value->u32 = ip_2_ip4(&pcb->remote_ip)->addr; - } - break; - case 5: /* tcpConnRemPort */ - if (pcb->state == LISTEN) { - value->u32 = 0; - } else { - value->u32 = pcb->remote_port; - } - break; - default: - LWIP_ASSERT("invalid id", 0); - return SNMP_ERR_NOSUCHINSTANCE; - } - - return SNMP_ERR_NOERROR; -} - -static snmp_err_t -tcp_ConnTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) -{ - u8_t i; - ip4_addr_t local_ip; - ip4_addr_t remote_ip; - u16_t local_port; - u16_t remote_port; - struct tcp_pcb *pcb; - - /* check if incoming OID length and if values are in plausible range */ - if (!snmp_oid_in_range(row_oid, row_oid_len, tcp_ConnTable_oid_ranges, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges))) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* get IPs and ports from incoming OID */ - snmp_oid_to_ip4(&row_oid[0], &local_ip); /* we know it succeeds because of oid_in_range check above */ - local_port = (u16_t)row_oid[4]; - snmp_oid_to_ip4(&row_oid[5], &remote_ip); /* we know it succeeds because of oid_in_range check above */ - remote_port = (u16_t)row_oid[9]; - - /* find tcp_pcb with requested ips and ports */ - for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) { - pcb = *tcp_pcb_lists[i]; - - while (pcb != NULL) { - /* do local IP and local port match? */ - if (IP_IS_V4_VAL(pcb->local_ip) && - ip4_addr_cmp(&local_ip, ip_2_ip4(&pcb->local_ip)) && (local_port == pcb->local_port)) { - - /* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */ - if (pcb->state == LISTEN) { - if (ip4_addr_cmp(&remote_ip, IP4_ADDR_ANY) && (remote_port == 0)) { - /* fill in object properties */ - return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len); - } - } else { - if (IP_IS_V4_VAL(pcb->remote_ip) && - ip4_addr_cmp(&remote_ip, ip_2_ip4(&pcb->remote_ip)) && (remote_port == pcb->remote_port)) { - /* fill in object properties */ - return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len); - } - } - } - - pcb = pcb->next; - } - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -static snmp_err_t -tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) -{ - u8_t i; - struct tcp_pcb *pcb; - struct snmp_next_oid_state state; - u32_t result_temp[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)]; - - /* init struct to search next oid */ - snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)); - - /* iterate over all possible OIDs to find the next one */ - for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) { - pcb = *tcp_pcb_lists[i]; - while (pcb != NULL) { - u32_t test_oid[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)]; - - if (IP_IS_V4_VAL(pcb->local_ip)) { - snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]); - test_oid[4] = pcb->local_port; - - /* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */ - if (pcb->state == LISTEN) { - snmp_ip4_to_oid(IP4_ADDR_ANY, &test_oid[5]); - test_oid[9] = 0; - } else { - if (IP_IS_V6_VAL(pcb->remote_ip)) { /* should never happen */ - continue; - } - snmp_ip4_to_oid(ip_2_ip4(&pcb->remote_ip), &test_oid[5]); - test_oid[9] = pcb->remote_port; - } - - /* check generated OID: is it a candidate for the next one? */ - snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges), pcb); - } - - pcb = pcb->next; - } - } - - /* did we find a next one? */ - if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { - snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); - /* fill in object properties */ - return tcp_ConnTable_get_cell_value_core((struct tcp_pcb*)state.reference, column, value, value_len); - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -#endif /* LWIP_IPV4 */ - -/* --- tcpConnectionTable --- */ - -static snmp_err_t -tcp_ConnectionTable_get_cell_value_core(const u32_t* column, struct tcp_pcb *pcb, union snmp_variant_value* value) -{ - /* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */ - switch (*column) { - case 7: /* tcpConnectionState */ - value->u32 = pcb->state + 1; - break; - case 8: /* tcpConnectionProcess */ - value->u32 = 0; /* not supported */ - break; - default: - return SNMP_ERR_NOSUCHINSTANCE; - } - - return SNMP_ERR_NOERROR; -} - -static snmp_err_t -tcp_ConnectionTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) -{ - ip_addr_t local_ip, remote_ip; - u16_t local_port, remote_port; - struct tcp_pcb *pcb; - u8_t idx = 0; - u8_t i; - struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs}; - - LWIP_UNUSED_ARG(value_len); - - /* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */ - idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port); - if (idx == 0) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */ - idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port); - if (idx == 0) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* find tcp_pcb with requested ip and port*/ - for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) { - pcb = *tcp_pcb_nonlisten_lists[i]; - - while (pcb != NULL) { - if (ip_addr_cmp(&local_ip, &pcb->local_ip) && - (local_port == pcb->local_port) && - ip_addr_cmp(&remote_ip, &pcb->remote_ip) && - (remote_port == pcb->remote_port)) { - /* fill in object properties */ - return tcp_ConnectionTable_get_cell_value_core(column, pcb, value); - } - pcb = pcb->next; - } - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -static snmp_err_t -tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) -{ - struct tcp_pcb *pcb; - struct snmp_next_oid_state state; - /* 1x tcpConnectionLocalAddressType + 1x OID len + 16x tcpConnectionLocalAddress + 1x tcpConnectionLocalPort - * 1x tcpConnectionRemAddressType + 1x OID len + 16x tcpConnectionRemAddress + 1x tcpConnectionRemPort */ - u32_t result_temp[38]; - u8_t i; - struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs}; - - LWIP_UNUSED_ARG(value_len); - - /* init struct to search next oid */ - snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp)); - - /* iterate over all possible OIDs to find the next one */ - for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) { - pcb = *tcp_pcb_nonlisten_lists[i]; - - while (pcb != NULL) { - u8_t idx = 0; - u32_t test_oid[LWIP_ARRAYSIZE(result_temp)]; - - /* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */ - idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]); - - /* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */ - idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]); - - /* check generated OID: is it a candidate for the next one? */ - snmp_next_oid_check(&state, test_oid, idx, pcb); - - pcb = pcb->next; - } - } - - /* did we find a next one? */ - if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { - snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); - /* fill in object properties */ - return tcp_ConnectionTable_get_cell_value_core(column, (struct tcp_pcb*)state.reference, value); - } else { - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; - } -} - -/* --- tcpListenerTable --- */ - -static snmp_err_t -tcp_ListenerTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value) -{ - /* all items except tcpListenerProcess are declared as not-accessible */ - switch (*column) { - case 4: /* tcpListenerProcess */ - value->u32 = 0; /* not supported */ - break; - default: - return SNMP_ERR_NOSUCHINSTANCE; - } - - return SNMP_ERR_NOERROR; -} - -static snmp_err_t -tcp_ListenerTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) -{ - ip_addr_t local_ip; - u16_t local_port; - struct tcp_pcb_listen *pcb; - u8_t idx = 0; - - LWIP_UNUSED_ARG(value_len); - - /* tcpListenerLocalAddressType + tcpListenerLocalAddress + tcpListenerLocalPort */ - idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port); - if (idx == 0) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* find tcp_pcb with requested ip and port*/ - pcb = tcp_listen_pcbs.listen_pcbs; - while (pcb != NULL) { - if (ip_addr_cmp(&local_ip, &pcb->local_ip) && - (local_port == pcb->local_port)) { - /* fill in object properties */ - return tcp_ListenerTable_get_cell_value_core(column, value); - } - pcb = pcb->next; - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -static snmp_err_t -tcp_ListenerTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) -{ - struct tcp_pcb_listen *pcb; - struct snmp_next_oid_state state; - /* 1x tcpListenerLocalAddressType + 1x OID len + 16x tcpListenerLocalAddress + 1x tcpListenerLocalPort */ - u32_t result_temp[19]; - - LWIP_UNUSED_ARG(value_len); - - /* init struct to search next oid */ - snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp)); - - /* iterate over all possible OIDs to find the next one */ - pcb = tcp_listen_pcbs.listen_pcbs; - while (pcb != NULL) { - u8_t idx = 0; - u32_t test_oid[LWIP_ARRAYSIZE(result_temp)]; - - /* tcpListenerLocalAddressType + tcpListenerLocalAddress + tcpListenerLocalPort */ - idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]); - - /* check generated OID: is it a candidate for the next one? */ - snmp_next_oid_check(&state, test_oid, idx, NULL); - - pcb = pcb->next; - } - - /* did we find a next one? */ - if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { - snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); - /* fill in object properties */ - return tcp_ListenerTable_get_cell_value_core(column, value); - } else { - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; - } -} - -static const struct snmp_scalar_node tcp_RtoAlgorithm = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, tcp_get_value); -static const struct snmp_scalar_node tcp_RtoMin = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_INTEGER, tcp_get_value); -static const struct snmp_scalar_node tcp_RtoMax = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_INTEGER, tcp_get_value); -static const struct snmp_scalar_node tcp_MaxConn = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_INTEGER, tcp_get_value); -static const struct snmp_scalar_node tcp_ActiveOpens = SNMP_SCALAR_CREATE_NODE_READONLY(5, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); -static const struct snmp_scalar_node tcp_PassiveOpens = SNMP_SCALAR_CREATE_NODE_READONLY(6, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); -static const struct snmp_scalar_node tcp_AttemptFails = SNMP_SCALAR_CREATE_NODE_READONLY(7, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); -static const struct snmp_scalar_node tcp_EstabResets = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); -static const struct snmp_scalar_node tcp_CurrEstab = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_GAUGE, tcp_get_value); -static const struct snmp_scalar_node tcp_InSegs = SNMP_SCALAR_CREATE_NODE_READONLY(10, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); -static const struct snmp_scalar_node tcp_OutSegs = SNMP_SCALAR_CREATE_NODE_READONLY(11, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); -static const struct snmp_scalar_node tcp_RetransSegs = SNMP_SCALAR_CREATE_NODE_READONLY(12, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); -static const struct snmp_scalar_node tcp_InErrs = SNMP_SCALAR_CREATE_NODE_READONLY(14, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); -static const struct snmp_scalar_node tcp_OutRsts = SNMP_SCALAR_CREATE_NODE_READONLY(15, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); -static const struct snmp_scalar_node tcp_HCInSegs = SNMP_SCALAR_CREATE_NODE_READONLY(17, SNMP_ASN1_TYPE_COUNTER64, tcp_get_value); -static const struct snmp_scalar_node tcp_HCOutSegs = SNMP_SCALAR_CREATE_NODE_READONLY(18, SNMP_ASN1_TYPE_COUNTER64, tcp_get_value); - -#if LWIP_IPV4 -static const struct snmp_table_simple_col_def tcp_ConnTable_columns[] = { - { 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnState */ - { 2, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnLocalAddress */ - { 3, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnLocalPort */ - { 4, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnRemAddress */ - { 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnRemPort */ -}; - -static const struct snmp_table_simple_node tcp_ConnTable = SNMP_TABLE_CREATE_SIMPLE(13, tcp_ConnTable_columns, tcp_ConnTable_get_cell_value, tcp_ConnTable_get_next_cell_instance_and_value); -#endif /* LWIP_IPV4 */ - -static const struct snmp_table_simple_col_def tcp_ConnectionTable_columns[] = { - /* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */ - { 7, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnectionState */ - { 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnectionProcess */ -}; - -static const struct snmp_table_simple_node tcp_ConnectionTable = SNMP_TABLE_CREATE_SIMPLE(19, tcp_ConnectionTable_columns, tcp_ConnectionTable_get_cell_value, tcp_ConnectionTable_get_next_cell_instance_and_value); - - -static const struct snmp_table_simple_col_def tcp_ListenerTable_columns[] = { - /* all items except tcpListenerProcess are declared as not-accessible */ - { 4, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpListenerProcess */ -}; - -static const struct snmp_table_simple_node tcp_ListenerTable = SNMP_TABLE_CREATE_SIMPLE(20, tcp_ListenerTable_columns, tcp_ListenerTable_get_cell_value, tcp_ListenerTable_get_next_cell_instance_and_value); - -/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */ -CREATE_LWIP_SYNC_NODE( 1, tcp_RtoAlgorithm) -CREATE_LWIP_SYNC_NODE( 2, tcp_RtoMin) -CREATE_LWIP_SYNC_NODE( 3, tcp_RtoMax) -CREATE_LWIP_SYNC_NODE( 4, tcp_MaxConn) -CREATE_LWIP_SYNC_NODE( 5, tcp_ActiveOpens) -CREATE_LWIP_SYNC_NODE( 6, tcp_PassiveOpens) -CREATE_LWIP_SYNC_NODE( 7, tcp_AttemptFails) -CREATE_LWIP_SYNC_NODE( 8, tcp_EstabResets) -CREATE_LWIP_SYNC_NODE( 9, tcp_CurrEstab) -CREATE_LWIP_SYNC_NODE(10, tcp_InSegs) -CREATE_LWIP_SYNC_NODE(11, tcp_OutSegs) -CREATE_LWIP_SYNC_NODE(12, tcp_RetransSegs) -#if LWIP_IPV4 -CREATE_LWIP_SYNC_NODE(13, tcp_ConnTable) -#endif /* LWIP_IPV4 */ -CREATE_LWIP_SYNC_NODE(14, tcp_InErrs) -CREATE_LWIP_SYNC_NODE(15, tcp_OutRsts) -CREATE_LWIP_SYNC_NODE(17, tcp_HCInSegs) -CREATE_LWIP_SYNC_NODE(18, tcp_HCOutSegs) -CREATE_LWIP_SYNC_NODE(19, tcp_ConnectionTable) -CREATE_LWIP_SYNC_NODE(20, tcp_ListenerTable) - -static const struct snmp_node* const tcp_nodes[] = { - &SYNC_NODE_NAME(tcp_RtoAlgorithm).node.node, - &SYNC_NODE_NAME(tcp_RtoMin).node.node, - &SYNC_NODE_NAME(tcp_RtoMax).node.node, - &SYNC_NODE_NAME(tcp_MaxConn).node.node, - &SYNC_NODE_NAME(tcp_ActiveOpens).node.node, - &SYNC_NODE_NAME(tcp_PassiveOpens).node.node, - &SYNC_NODE_NAME(tcp_AttemptFails).node.node, - &SYNC_NODE_NAME(tcp_EstabResets).node.node, - &SYNC_NODE_NAME(tcp_CurrEstab).node.node, - &SYNC_NODE_NAME(tcp_InSegs).node.node, - &SYNC_NODE_NAME(tcp_OutSegs).node.node, - &SYNC_NODE_NAME(tcp_RetransSegs).node.node, -#if LWIP_IPV4 - &SYNC_NODE_NAME(tcp_ConnTable).node.node, -#endif /* LWIP_IPV4 */ - &SYNC_NODE_NAME(tcp_InErrs).node.node, - &SYNC_NODE_NAME(tcp_OutRsts).node.node, - &SYNC_NODE_NAME(tcp_HCInSegs).node.node, - &SYNC_NODE_NAME(tcp_HCOutSegs).node.node, - &SYNC_NODE_NAME(tcp_ConnectionTable).node.node, - &SYNC_NODE_NAME(tcp_ListenerTable).node.node -}; - -const struct snmp_tree_node snmp_mib2_tcp_root = SNMP_CREATE_TREE_NODE(6, tcp_nodes); -#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_TCP */ diff --git a/ext/lwip/src/apps/snmp/snmp_mib2_udp.c b/ext/lwip/src/apps/snmp/snmp_mib2_udp.c deleted file mode 100644 index de1c858..0000000 --- a/ext/lwip/src/apps/snmp/snmp_mib2_udp.c +++ /dev/null @@ -1,357 +0,0 @@ -/** - * @file - * Management Information Base II (RFC1213) UDP objects and functions. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dirk Ziegelmeier - * Christiaan Simons - */ - -#include "lwip/snmp.h" -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "lwip/apps/snmp_mib2.h" -#include "lwip/apps/snmp_table.h" -#include "lwip/apps/snmp_scalar.h" -#include "lwip/udp.h" -#include "lwip/stats.h" - -#include - -#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP - -#if SNMP_USE_NETCONN -#define SYNC_NODE_NAME(node_name) node_name ## _synced -#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ - static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); -#else -#define SYNC_NODE_NAME(node_name) node_name -#define CREATE_LWIP_SYNC_NODE(oid, node_name) -#endif - -/* --- udp .1.3.6.1.2.1.7 ----------------------------------------------------- */ - -static s16_t -udp_get_value(struct snmp_node_instance* instance, void* value) -{ - u32_t *uint_ptr = (u32_t*)value; - - switch (instance->node->oid) { - case 1: /* udpInDatagrams */ - *uint_ptr = STATS_GET(mib2.udpindatagrams); - return sizeof(*uint_ptr); - case 2: /* udpNoPorts */ - *uint_ptr = STATS_GET(mib2.udpnoports); - return sizeof(*uint_ptr); - case 3: /* udpInErrors */ - *uint_ptr = STATS_GET(mib2.udpinerrors); - return sizeof(*uint_ptr); - case 4: /* udpOutDatagrams */ - *uint_ptr = STATS_GET(mib2.udpoutdatagrams); - return sizeof(*uint_ptr); - case 8: /* udpHCInDatagrams */ - memset(value, 0, 2*sizeof(u32_t)); /* not supported */ - return 2*sizeof(u32_t); - case 9: /* udpHCOutDatagrams */ - memset(value, 0, 2*sizeof(u32_t)); /* not supported */ - return 2*sizeof(u32_t); - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_value(): unknown id: %"S32_F"\n", instance->node->oid)); - break; - } - - return 0; -} - -/* --- udpEndpointTable --- */ - -static snmp_err_t -udp_endpointTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value) -{ - /* all items except udpEndpointProcess are declared as not-accessible */ - switch (*column) { - case 8: /* udpEndpointProcess */ - value->u32 = 0; /* not supported */ - break; - default: - return SNMP_ERR_NOSUCHINSTANCE; - } - - return SNMP_ERR_NOERROR; -} - -static snmp_err_t -udp_endpointTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) -{ - ip_addr_t local_ip, remote_ip; - u16_t local_port, remote_port; - struct udp_pcb *pcb; - u8_t idx = 0; - - LWIP_UNUSED_ARG(value_len); - - /* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */ - idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port); - if (idx == 0) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */ - idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port); - if (idx == 0) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* udpEndpointInstance */ - if (row_oid_len < (idx+1)) { - return SNMP_ERR_NOSUCHINSTANCE; - } - if (row_oid[idx] != 0) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* find udp_pcb with requested ip and port*/ - pcb = udp_pcbs; - while (pcb != NULL) { - if (ip_addr_cmp(&local_ip, &pcb->local_ip) && - (local_port == pcb->local_port) && - ip_addr_cmp(&remote_ip, &pcb->remote_ip) && - (remote_port == pcb->remote_port)) { - /* fill in object properties */ - return udp_endpointTable_get_cell_value_core(column, value); - } - pcb = pcb->next; - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -static snmp_err_t -udp_endpointTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) -{ - struct udp_pcb *pcb; - struct snmp_next_oid_state state; - /* 1x udpEndpointLocalAddressType + 1x OID len + 16x udpEndpointLocalAddress + 1x udpEndpointLocalPort + - * 1x udpEndpointRemoteAddressType + 1x OID len + 16x udpEndpointRemoteAddress + 1x udpEndpointRemotePort + - * 1x udpEndpointInstance = 39 - */ - u32_t result_temp[39]; - - LWIP_UNUSED_ARG(value_len); - - /* init struct to search next oid */ - snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp)); - - /* iterate over all possible OIDs to find the next one */ - pcb = udp_pcbs; - while (pcb != NULL) { - u32_t test_oid[LWIP_ARRAYSIZE(result_temp)]; - u8_t idx = 0; - - /* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */ - idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]); - - /* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */ - idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]); - - test_oid[idx] = 0; /* udpEndpointInstance */ - idx++; - - /* check generated OID: is it a candidate for the next one? */ - snmp_next_oid_check(&state, test_oid, idx, NULL); - - pcb = pcb->next; - } - - /* did we find a next one? */ - if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { - snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); - /* fill in object properties */ - return udp_endpointTable_get_cell_value_core(column, value); - } else { - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; - } -} - -/* --- udpTable --- */ - -#if LWIP_IPV4 - -/* list of allowed value ranges for incoming OID */ -static const struct snmp_oid_range udp_Table_oid_ranges[] = { - { 0, 0xff }, /* IP A */ - { 0, 0xff }, /* IP B */ - { 0, 0xff }, /* IP C */ - { 0, 0xff }, /* IP D */ - { 1, 0xffff } /* Port */ -}; - -static snmp_err_t -udp_Table_get_cell_value_core(struct udp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) -{ - LWIP_UNUSED_ARG(value_len); - - switch (*column) { - case 1: /* udpLocalAddress */ - /* set reference to PCB local IP and return a generic node that copies IP4 addresses */ - value->u32 = ip_2_ip4(&pcb->local_ip)->addr; - break; - case 2: /* udpLocalPort */ - /* set reference to PCB local port and return a generic node that copies u16_t values */ - value->u32 = pcb->local_port; - break; - default: - return SNMP_ERR_NOSUCHINSTANCE; - } - - return SNMP_ERR_NOERROR; -} - -static snmp_err_t -udp_Table_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) -{ - ip4_addr_t ip; - u16_t port; - struct udp_pcb *pcb; - - /* check if incoming OID length and if values are in plausible range */ - if (!snmp_oid_in_range(row_oid, row_oid_len, udp_Table_oid_ranges, LWIP_ARRAYSIZE(udp_Table_oid_ranges))) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - /* get IP and port from incoming OID */ - snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */ - port = (u16_t)row_oid[4]; - - /* find udp_pcb with requested ip and port*/ - pcb = udp_pcbs; - while (pcb != NULL) { - if (IP_IS_V4_VAL(pcb->local_ip)) { - if (ip4_addr_cmp(&ip, ip_2_ip4(&pcb->local_ip)) && (port == pcb->local_port)) { - /* fill in object properties */ - return udp_Table_get_cell_value_core(pcb, column, value, value_len); - } - } - pcb = pcb->next; - } - - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; -} - -static snmp_err_t -udp_Table_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) -{ - struct udp_pcb *pcb; - struct snmp_next_oid_state state; - u32_t result_temp[LWIP_ARRAYSIZE(udp_Table_oid_ranges)]; - - /* init struct to search next oid */ - snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(udp_Table_oid_ranges)); - - /* iterate over all possible OIDs to find the next one */ - pcb = udp_pcbs; - while (pcb != NULL) { - u32_t test_oid[LWIP_ARRAYSIZE(udp_Table_oid_ranges)]; - - if (IP_IS_V4_VAL(pcb->local_ip)) { - snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]); - test_oid[4] = pcb->local_port; - - /* check generated OID: is it a candidate for the next one? */ - snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(udp_Table_oid_ranges), pcb); - } - - pcb = pcb->next; - } - - /* did we find a next one? */ - if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { - snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); - /* fill in object properties */ - return udp_Table_get_cell_value_core((struct udp_pcb*)state.reference, column, value, value_len); - } else { - /* not found */ - return SNMP_ERR_NOSUCHINSTANCE; - } -} - -#endif /* LWIP_IPV4 */ - -static const struct snmp_scalar_node udp_inDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_COUNTER, udp_get_value); -static const struct snmp_scalar_node udp_noPorts = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_COUNTER, udp_get_value); -static const struct snmp_scalar_node udp_inErrors = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_COUNTER, udp_get_value); -static const struct snmp_scalar_node udp_outDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_COUNTER, udp_get_value); -static const struct snmp_scalar_node udp_HCInDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER64, udp_get_value); -static const struct snmp_scalar_node udp_HCOutDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_COUNTER64, udp_get_value); - -#if LWIP_IPV4 -static const struct snmp_table_simple_col_def udp_Table_columns[] = { - { 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* udpLocalAddress */ - { 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpLocalPort */ -}; -static const struct snmp_table_simple_node udp_Table = SNMP_TABLE_CREATE_SIMPLE(5, udp_Table_columns, udp_Table_get_cell_value, udp_Table_get_next_cell_instance_and_value); -#endif /* LWIP_IPV4 */ - -static const struct snmp_table_simple_col_def udp_endpointTable_columns[] = { - /* all items except udpEndpointProcess are declared as not-accessible */ - { 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpEndpointProcess */ -}; - -static const struct snmp_table_simple_node udp_endpointTable = SNMP_TABLE_CREATE_SIMPLE(7, udp_endpointTable_columns, udp_endpointTable_get_cell_value, udp_endpointTable_get_next_cell_instance_and_value); - -/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */ -CREATE_LWIP_SYNC_NODE(1, udp_inDatagrams) -CREATE_LWIP_SYNC_NODE(2, udp_noPorts) -CREATE_LWIP_SYNC_NODE(3, udp_inErrors) -CREATE_LWIP_SYNC_NODE(4, udp_outDatagrams) -#if LWIP_IPV4 -CREATE_LWIP_SYNC_NODE(5, udp_Table) -#endif /* LWIP_IPV4 */ -CREATE_LWIP_SYNC_NODE(7, udp_endpointTable) -CREATE_LWIP_SYNC_NODE(8, udp_HCInDatagrams) -CREATE_LWIP_SYNC_NODE(9, udp_HCOutDatagrams) - -static const struct snmp_node* const udp_nodes[] = { - &SYNC_NODE_NAME(udp_inDatagrams).node.node, - &SYNC_NODE_NAME(udp_noPorts).node.node, - &SYNC_NODE_NAME(udp_inErrors).node.node, - &SYNC_NODE_NAME(udp_outDatagrams).node.node, -#if LWIP_IPV4 - &SYNC_NODE_NAME(udp_Table).node.node, -#endif /* LWIP_IPV4 */ - &SYNC_NODE_NAME(udp_endpointTable).node.node, - &SYNC_NODE_NAME(udp_HCInDatagrams).node.node, - &SYNC_NODE_NAME(udp_HCOutDatagrams).node.node -}; - -const struct snmp_tree_node snmp_mib2_udp_root = SNMP_CREATE_TREE_NODE(7, udp_nodes); -#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP */ diff --git a/ext/lwip/src/apps/snmp/snmp_msg.c b/ext/lwip/src/apps/snmp/snmp_msg.c deleted file mode 100644 index 48c08d5..0000000 --- a/ext/lwip/src/apps/snmp/snmp_msg.c +++ /dev/null @@ -1,1657 +0,0 @@ -/** - * @file - * SNMP message processing (RFC1157). - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * Copyright (c) 2016 Elias Oenal. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons - * Martin Hentschel - * Elias Oenal - */ - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "snmp_msg.h" -#include "snmp_asn1.h" -#include "snmp_core_priv.h" -#include "lwip/ip_addr.h" -#include "lwip/stats.h" - -#if LWIP_SNMP_V3 -#include "lwip/apps/snmpv3.h" -#include "snmpv3_priv.h" -#ifdef LWIP_SNMPV3_INCLUDE_ENGINE -#include LWIP_SNMPV3_INCLUDE_ENGINE -#endif -#endif - -#include - -/* public (non-static) constants */ -/** SNMP community string */ -const char *snmp_community = SNMP_COMMUNITY; -/** SNMP community string for write access */ -const char *snmp_community_write = SNMP_COMMUNITY_WRITE; -/** SNMP community string for sending traps */ -const char *snmp_community_trap = SNMP_COMMUNITY_TRAP; - -snmp_write_callback_fct snmp_write_callback = NULL; -void* snmp_write_callback_arg = NULL; - -/** - * @ingroup snmp_core - * Returns current SNMP community string. - * @return current SNMP community string - */ -const char * -snmp_get_community(void) -{ - return snmp_community; -} - -/** - * @ingroup snmp_core - * Sets SNMP community string. - * The string itself (its storage) must be valid throughout the whole life of - * program (or until it is changed to sth else). - * - * @param community is a pointer to new community string - */ -void -snmp_set_community(const char * const community) -{ - LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); - snmp_community = community; -} - -/** - * @ingroup snmp_core - * Returns current SNMP write-access community string. - * @return current SNMP write-access community string - */ -const char * -snmp_get_community_write(void) -{ - return snmp_community_write; -} - -/** - * @ingroup snmp_traps - * Returns current SNMP community string used for sending traps. - * @return current SNMP community string used for sending traps - */ -const char * -snmp_get_community_trap(void) -{ - return snmp_community_trap; -} - -/** - * @ingroup snmp_core - * Sets SNMP community string for write-access. - * The string itself (its storage) must be valid throughout the whole life of - * program (or until it is changed to sth else). - * - * @param community is a pointer to new write-access community string - */ -void -snmp_set_community_write(const char * const community) -{ - LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); - snmp_community_write = community; -} - -/** - * @ingroup snmp_traps - * Sets SNMP community string used for sending traps. - * The string itself (its storage) must be valid throughout the whole life of - * program (or until it is changed to sth else). - * - * @param community is a pointer to new trap community string - */ -void -snmp_set_community_trap(const char * const community) -{ - LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); - snmp_community_trap = community; -} - -/** - * @ingroup snmp_core - * Callback fired on every successful write access - */ -void -snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg) -{ - snmp_write_callback = write_callback; - snmp_write_callback_arg = callback_arg; -} - -/* ----------------------------------------------------------------------- */ -/* forward declarations */ -/* ----------------------------------------------------------------------- */ - -static err_t snmp_process_get_request(struct snmp_request *request); -static err_t snmp_process_getnext_request(struct snmp_request *request); -static err_t snmp_process_getbulk_request(struct snmp_request *request); -static err_t snmp_process_set_request(struct snmp_request *request); - -static err_t snmp_parse_inbound_frame(struct snmp_request *request); -static err_t snmp_prepare_outbound_frame(struct snmp_request *request); -static err_t snmp_complete_outbound_frame(struct snmp_request *request); -static void snmp_execute_write_callbacks(struct snmp_request *request); - - -/* ----------------------------------------------------------------------- */ -/* implementation */ -/* ----------------------------------------------------------------------- */ - -void -snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port) -{ - err_t err; - struct snmp_request request; - - memset(&request, 0, sizeof(request)); - request.handle = handle; - request.source_ip = source_ip; - request.source_port = port; - request.inbound_pbuf = p; - - snmp_stats.inpkts++; - - err = snmp_parse_inbound_frame(&request); - if (err == ERR_OK) { - err = snmp_prepare_outbound_frame(&request); - if (err == ERR_OK) { - - if (request.error_status == SNMP_ERR_NOERROR) { - /* only process frame if we do not already have an error to return (e.g. all readonly) */ - if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) { - err = snmp_process_get_request(&request); - } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) { - err = snmp_process_getnext_request(&request); - } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { - err = snmp_process_getbulk_request(&request); - } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { - err = snmp_process_set_request(&request); - } - } - - if (err == ERR_OK) { - err = snmp_complete_outbound_frame(&request); - - if (err == ERR_OK) { - err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port); - - if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) - && (request.error_status == SNMP_ERR_NOERROR) - && (snmp_write_callback != NULL)) { - /* raise write notification for all written objects */ - snmp_execute_write_callbacks(&request); - } - } - } - } - - if (request.outbound_pbuf != NULL) { - pbuf_free(request.outbound_pbuf); - } - } -} - -static u8_t -snmp_msg_getnext_validate_node_inst(struct snmp_node_instance* node_instance, void* validate_arg) -{ - if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request*)validate_arg)->version == SNMP_VERSION_1)) { - /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */ - return SNMP_ERR_NOSUCHINSTANCE; - } - - return SNMP_ERR_NOERROR; -} - -static void -snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next) -{ - err_t err; - struct snmp_node_instance node_instance; - memset(&node_instance, 0, sizeof(node_instance)); - - if (get_next) { - struct snmp_obj_id result_oid; - request->error_status = snmp_get_next_node_instance_from_oid(vb->oid.id, vb->oid.len, snmp_msg_getnext_validate_node_inst, request, &result_oid, &node_instance); - - if (request->error_status == SNMP_ERR_NOERROR) { - snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len); - } - } else { - request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance); - - if (request->error_status == SNMP_ERR_NOERROR) { - /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */ - request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request); - - if (request->error_status != SNMP_ERR_NOERROR) { - if (node_instance.release_instance != NULL) { - node_instance.release_instance(&node_instance); - } - } - } - } - - if (request->error_status != SNMP_ERR_NOERROR) - { - if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) { - if ((request->version == SNMP_VERSION_2c) || request->version == SNMP_VERSION_3) { - /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */ - vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK)); - vb->value_len = 0; - - err = snmp_append_outbound_varbind(&(request->outbound_pbuf_stream), vb); - if (err == ERR_OK) { - /* we stored the exception in varbind -> go on */ - request->error_status = SNMP_ERR_NOERROR; - } else if (err == ERR_BUF) { - request->error_status = SNMP_ERR_TOOBIG; - } else { - request->error_status = SNMP_ERR_GENERROR; - } - } - } else { - /* according to RFC 1157/1905, all other errors only return genError */ - request->error_status = SNMP_ERR_GENERROR; - } - } else { - s16_t len = node_instance.get_value(&node_instance, vb->value); - vb->type = node_instance.asn1_type; - - if(len >= 0) { - vb->value_len = (u16_t)len; /* cast is OK because we checked >= 0 above */ - - LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE); - err = snmp_append_outbound_varbind(&request->outbound_pbuf_stream, vb); - - if (err == ERR_BUF) { - request->error_status = SNMP_ERR_TOOBIG; - } else if (err != ERR_OK) { - request->error_status = SNMP_ERR_GENERROR; - } - } else { - request->error_status = SNMP_ERR_GENERROR; - } - - if (node_instance.release_instance != NULL) { - node_instance.release_instance(&node_instance); - } - } -} - - -/** - * Service an internal or external event for SNMP GET. - * - * @param msg_ps points to the associated message process state - */ -static err_t -snmp_process_get_request(struct snmp_request *request) -{ - snmp_vb_enumerator_err_t err; - struct snmp_varbind vb; - vb.value = request->value_buffer; - - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get request\n")); - - while (request->error_status == SNMP_ERR_NOERROR) { - err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); - if (err == SNMP_VB_ENUMERATOR_ERR_OK) { - if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) { - snmp_process_varbind(request, &vb, 0); - } else { - request->error_status = SNMP_ERR_GENERROR; - } - } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { - /* no more varbinds in request */ - break; - } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { - /* malformed ASN.1, don't answer */ - return ERR_ARG; - } else { - request->error_status = SNMP_ERR_GENERROR; - } - } - - return ERR_OK; -} - -/** - * Service an internal or external event for SNMP GET. - * - * @param msg_ps points to the associated message process state - */ -static err_t -snmp_process_getnext_request(struct snmp_request *request) -{ - snmp_vb_enumerator_err_t err; - struct snmp_varbind vb; - vb.value = request->value_buffer; - - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-next request\n")); - - while (request->error_status == SNMP_ERR_NOERROR) { - err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); - if (err == SNMP_VB_ENUMERATOR_ERR_OK) { - if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) { - snmp_process_varbind(request, &vb, 1); - } else { - request->error_status = SNMP_ERR_GENERROR; - } - } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { - /* no more varbinds in request */ - break; - } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { - /* malformed ASN.1, don't answer */ - return ERR_ARG; - } else { - request->error_status = SNMP_ERR_GENERROR; - } - } - - return ERR_OK; -} - -/** - * Service an internal or external event for SNMP GETBULKT. - * - * @param msg_ps points to the associated message process state - */ -static err_t -snmp_process_getbulk_request(struct snmp_request *request) -{ - snmp_vb_enumerator_err_t err; - s32_t non_repeaters = request->non_repeaters; - s32_t repetitions; - u16_t repetition_offset = 0; - struct snmp_varbind_enumerator repetition_varbind_enumerator; - struct snmp_varbind vb; - vb.value = request->value_buffer; - - if (SNMP_LWIP_GETBULK_MAX_REPETITIONS > 0) { - repetitions = LWIP_MIN(request->max_repetitions, SNMP_LWIP_GETBULK_MAX_REPETITIONS); - } else { - repetitions = request->max_repetitions; - } - - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-bulk request\n")); - - /* process non repeaters and first repetition */ - while (request->error_status == SNMP_ERR_NOERROR) { - if (non_repeaters == 0) { - repetition_offset = request->outbound_pbuf_stream.offset; - - if (repetitions == 0) { - /* do not resolve repeaters when repetitions is set to 0 */ - break; - } - repetitions--; - } - - err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); - if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { - /* no more varbinds in request */ - break; - } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { - /* malformed ASN.1, don't answer */ - return ERR_ARG; - } else if ((err != SNMP_VB_ENUMERATOR_ERR_OK) || (vb.type != SNMP_ASN1_TYPE_NULL) || (vb.value_len != 0)) { - request->error_status = SNMP_ERR_GENERROR; - } else { - snmp_process_varbind(request, &vb, 1); - non_repeaters--; - } - } - - /* process repetitions > 1 */ - while ((request->error_status == SNMP_ERR_NOERROR) && (repetitions > 0) && (request->outbound_pbuf_stream.offset != repetition_offset)) { - - u8_t all_endofmibview = 1; - - snmp_vb_enumerator_init(&repetition_varbind_enumerator, request->outbound_pbuf, repetition_offset, request->outbound_pbuf_stream.offset - repetition_offset); - repetition_offset = request->outbound_pbuf_stream.offset; /* for next loop */ - - while (request->error_status == SNMP_ERR_NOERROR) { - vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned) */ - err = snmp_vb_enumerator_get_next(&repetition_varbind_enumerator, &vb); - if (err == SNMP_VB_ENUMERATOR_ERR_OK) { - vb.value = request->value_buffer; - snmp_process_varbind(request, &vb, 1); - - if (request->error_status != SNMP_ERR_NOERROR) { - /* already set correct error-index (here it cannot be taken from inbound varbind enumerator) */ - request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count; - } else if (vb.type != (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW)) { - all_endofmibview = 0; - } - } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { - /* no more varbinds in request */ - break; - } else { - LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!")); - request->error_status = SNMP_ERR_GENERROR; - request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count; - } - } - - if ((request->error_status == SNMP_ERR_NOERROR) && all_endofmibview) { - /* stop when all varbinds in a loop return EndOfMibView */ - break; - } - - repetitions--; - } - - if (request->error_status == SNMP_ERR_TOOBIG) { - /* for GetBulk it is ok, if not all requested variables fit into the response -> just return the varbinds added so far */ - request->error_status = SNMP_ERR_NOERROR; - } - - return ERR_OK; -} - -/** - * Service an internal or external event for SNMP SET. - * - * @param msg_ps points to the associated message process state - */ -static err_t -snmp_process_set_request(struct snmp_request *request) -{ - snmp_vb_enumerator_err_t err; - struct snmp_varbind vb; - vb.value = request->value_buffer; - - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP set request\n")); - - /* perform set test on all objects */ - while (request->error_status == SNMP_ERR_NOERROR) { - err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); - if (err == SNMP_VB_ENUMERATOR_ERR_OK) { - struct snmp_node_instance node_instance; - memset(&node_instance, 0, sizeof(node_instance)); - - request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance); - if (request->error_status == SNMP_ERR_NOERROR) - { - if (node_instance.asn1_type != vb.type) { - request->error_status = SNMP_ERR_WRONGTYPE; - } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) { - request->error_status = SNMP_ERR_NOTWRITABLE; - } else { - if (node_instance.set_test != NULL) { - request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value); - } - } - - if (node_instance.release_instance != NULL) { - node_instance.release_instance(&node_instance); - } - } - } - else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { - /* no more varbinds in request */ - break; - } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) { - request->error_status = SNMP_ERR_WRONGLENGTH; - } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { - /* malformed ASN.1, don't answer */ - return ERR_ARG; - } else { - request->error_status = SNMP_ERR_GENERROR; - } - } - - /* perform real set operation on all objects */ - if (request->error_status == SNMP_ERR_NOERROR) { - snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); - while (request->error_status == SNMP_ERR_NOERROR) { - err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); - if (err == SNMP_VB_ENUMERATOR_ERR_OK) { - struct snmp_node_instance node_instance; - memset(&node_instance, 0, sizeof(node_instance)); - request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance); - if (request->error_status == SNMP_ERR_NOERROR) - { - if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR) - { - if (request->inbound_varbind_enumerator.varbind_count == 1) { - request->error_status = SNMP_ERR_COMMITFAILED; - } else { - /* we cannot undo the set operations done so far */ - request->error_status = SNMP_ERR_UNDOFAILED; - } - } - - if (node_instance.release_instance != NULL) { - node_instance.release_instance(&node_instance); - } - } - } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { - /* no more varbinds in request */ - break; - } else { - /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */ - request->error_status = SNMP_ERR_GENERROR; - } - } - } - - return ERR_OK; -} - -#define PARSE_EXEC(code, retValue) \ - if ((code) != ERR_OK) { \ - LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \ - snmp_stats.inasnparseerrs++; \ - return retValue; \ - } - -#define PARSE_ASSERT(cond, retValue) \ - if (!(cond)) { \ - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \ - snmp_stats.inasnparseerrs++; \ - return retValue; \ - } - -#define BUILD_EXEC(code, retValue) \ - if ((code) != ERR_OK) { \ - LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \ - return retValue; \ - } - -#define IF_PARSE_EXEC(code) PARSE_EXEC(code, ERR_ARG) -#define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ARG) - -/** - * Checks and decodes incoming SNMP message header, logs header errors. - * - * @param request points to the current message request state return - * @return - * - ERR_OK SNMP header is sane and accepted - * - ERR_VAL SNMP header is either malformed or rejected - */ -static err_t -snmp_parse_inbound_frame(struct snmp_request *request) -{ - struct snmp_pbuf_stream pbuf_stream; - struct snmp_asn1_tlv tlv; - s32_t parent_tlv_value_len; - s32_t s32_value; - err_t err; - - IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); - - /* decode main container consisting of version, community and PDU */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length)); - parent_tlv_value_len = tlv.value_len; - - /* decode version */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); - if ((s32_value != SNMP_VERSION_1) && - (s32_value != SNMP_VERSION_2c) -#if LWIP_SNMP_V3 - && (s32_value != SNMP_VERSION_3) -#endif - ) - { - /* unsupported SNMP version */ - snmp_stats.inbadversions++; - return ERR_ARG; - } - request->version = (u8_t)s32_value; - -#if LWIP_SNMP_V3 - if (request->version == SNMP_VERSION_3) { - u16_t u16_value; - - /* SNMPv3 doesn't use communities */ - /* @todo: Differentiate read/write access */ - strcpy((char*)request->community, snmp_community); - request->community_strlen = strlen(snmp_community); - - /* RFC3414 globalData */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); - parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - /* decode msgID */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); - request->msg_id = s32_value; - - /* decode msgMaxSize */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); - request->msg_max_size = s32_value; - - /* decode msgFlags */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); - request->msg_flags = s32_value; - - /* decode msgSecurityModel */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); - request->msg_security_model = s32_value; - - /* RFC3414 msgSecurityParameters - * The User-based Security Model defines the contents of the OCTET - * STRING as a SEQUENCE. - * - * We skip the protective dummy OCTET STRING header - * to access the SEQUENCE header. - */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); - parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - /* msgSecurityParameters SEQUENCE header */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); - parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - /* decode msgAuthoritativeEngineID */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id, - &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); - request->msg_authoritative_engine_id_len = u16_value; - - /* msgAuthoritativeEngineBoots */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_boots)); - - /* msgAuthoritativeEngineTime */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_time)); - /* @todo: Implement time window checking */ - - /* msgUserName */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name, - &u16_value, SNMP_V3_MAX_USER_LENGTH)); - request->msg_user_name_len = u16_value; - /* @todo: Implement unknown user error response */ - IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, NULL, NULL)); - - /* msgAuthenticationParameters */ - memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - /* Remember position */ - u16_t inbound_msgAuthenticationParameters_offset = pbuf_stream.offset; - LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset); - /* Read auth parameters */ - IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH); - IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters, - &u16_value, tlv.value_len)); - -#if LWIP_SNMP_V3_CRYPTO - if (request->msg_flags & SNMP_V3_AUTH_FLAG) { - /* Rewind stream */ - IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); - IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&pbuf_stream, inbound_msgAuthenticationParameters_offset)); - /* Set auth parameters to zero for verification */ - const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 }; - IF_PARSE_EXEC(snmp_asn1_enc_raw(&pbuf_stream, zero_arr, tlv.value_len)); - - /* Verify authentication */ - u8_t key[20]; - u8_t algo; - u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)]; - struct snmp_pbuf_stream auth_stream; - IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); - - IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL)); - IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, algo, hmac)); - /* @todo: Implement error response */ - IF_PARSE_EXEC(memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); - } -#else - /* Ungraceful exit if we encounter cryptography and don't support it. - * @todo: Implement error response - */ - IF_PARSE_ASSERT(!(request->msg_flags & (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG))); -#endif - - /* msgPrivacyParameters */ - memset(request->msg_privacy_parameters, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH); - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters, - &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); - -#if LWIP_SNMP_V3_CRYPTO - /* Decrypt message */ - if (request->msg_flags & SNMP_V3_PRIV_FLAG) { - u8_t key[20]; - u8_t algo; - - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); - parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &algo, key)); - IF_PARSE_EXEC(snmpv3_crypt(&pbuf_stream, tlv.value_len, key, - request->msg_privacy_parameters, request->msg_authoritative_engine_boots, - request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_DECRYPT)); - } -#endif - - /* Scoped PDU - * Encryption context - */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); - parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - /* contextEngineID */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id, - &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); - request->context_engine_id_len = u16_value; - - /* contextName */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_name, - &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); - request->context_name_len = u16_value; - } else -#endif - { - /* decode community */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN); - if (err == ERR_MEM) { - /* community string does not fit in our buffer -> its too long -> its invalid */ - request->community_strlen = 0; - snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len); - } else { - IF_PARSE_ASSERT(err == ERR_OK); - } - /* add zero terminator */ - request->community[request->community_strlen] = 0; - } - - /* decode PDU type (next container level) */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.value_len <= pbuf_stream.length); - request->inbound_padding_len = pbuf_stream.length - tlv.value_len; - parent_tlv_value_len = tlv.value_len; - - /* validate PDU type */ - switch(tlv.type) { - case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ): - /* GetRequest PDU */ - snmp_stats.ingetrequests++; - break; - case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ): - /* GetNextRequest PDU */ - snmp_stats.ingetnexts++; - break; - case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ): - /* GetBulkRequest PDU */ - if (request->version < SNMP_VERSION_2c) { - /* RFC2089: invalid, drop packet */ - return ERR_ARG; - } - break; - case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ): - /* SetRequest PDU */ - snmp_stats.insetrequests++; - break; - default: - /* unsupported input PDU for this agent (no parse error) */ - LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \ - return ERR_ARG; - break; - } - request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK; - - /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */ - if (request->community_strlen == 0) { - /* community string was too long or really empty*/ - snmp_stats.inbadcommunitynames++; - snmp_authfail_trap(); - return ERR_ARG; - } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { - if (strnlen(snmp_community_write, SNMP_MAX_COMMUNITY_STR_LEN) == 0) { - /* our write community is empty, that means all our objects are readonly */ - request->error_status = SNMP_ERR_NOTWRITABLE; - request->error_index = 1; - } else if (strncmp(snmp_community_write, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) { - /* community name does not match */ - snmp_stats.inbadcommunitynames++; - snmp_authfail_trap(); - return ERR_ARG; - } - } else { - if (strncmp(snmp_community, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) { - /* community name does not match */ - snmp_stats.inbadcommunitynames++; - snmp_authfail_trap(); - return ERR_ARG; - } - } - - /* decode request ID */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id)); - - /* decode error status / non-repeaters */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters)); - if (request->non_repeaters < 0) { - /* RFC 1905, 4.2.3 */ - request->non_repeaters = 0; - } - } else { - /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */ - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); - IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR); - } - - /* decode error index / max-repetitions */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); - parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); - IF_PARSE_ASSERT(parent_tlv_value_len > 0); - - if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions)); - if (request->max_repetitions < 0) { - /* RFC 1905, 4.2.3 */ - request->max_repetitions = 0; - } - } else { - IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index)); - IF_PARSE_ASSERT(s32_value == 0); - } - - /* decode varbind-list type (next container level) */ - IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); - IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= pbuf_stream.length)); - - request->inbound_varbind_offset = pbuf_stream.offset; - request->inbound_varbind_len = pbuf_stream.length - request->inbound_padding_len; - snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); - - return ERR_OK; -} - -#define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG) - -static err_t -snmp_prepare_outbound_frame(struct snmp_request *request) -{ - struct snmp_asn1_tlv tlv; - struct snmp_pbuf_stream* pbuf_stream = &(request->outbound_pbuf_stream); - - /* try allocating pbuf(s) for maximum response size */ - request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM); - if (request->outbound_pbuf == NULL) { - return ERR_MEM; - } - - snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len); - - /* 'Message' sequence */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); - OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - - /* version */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); - snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len); - OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) ); - -#if LWIP_SNMP_V3 - if (request->version < SNMP_VERSION_3) { -#endif - /* community */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen); - OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) ); -#if LWIP_SNMP_V3 - } else { - const char* id; - - /* globalData */ - request->outbound_msg_global_data_offset = pbuf_stream->offset; - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - - /* msgID */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); - snmp_asn1_enc_s32t_cnt(request->msg_id, &tlv.value_len); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_id)); - - /* msgMaxSize */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); - snmp_asn1_enc_s32t_cnt(request->msg_max_size, &tlv.value_len); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_max_size)); - - /* msgFlags */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 1); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, &request->msg_flags, 1)); - - /* msgSecurityModel */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); - snmp_asn1_enc_s32t_cnt(request->msg_security_model, &tlv.value_len); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_security_model)); - - /* end of msgGlobalData */ - request->outbound_msg_global_data_end = pbuf_stream->offset; - - /* msgSecurityParameters */ - request->outbound_msg_security_parameters_str_offset = pbuf_stream->offset; - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, 0); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - - request->outbound_msg_security_parameters_seq_offset = pbuf_stream->offset; - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - - /* msgAuthoritativeEngineID */ - snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len); - memcpy(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len); - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len)); - - request->msg_authoritative_engine_time = snmpv3_get_engine_time(); - request->msg_authoritative_engine_boots = snmpv3_get_engine_boots(); - - /* msgAuthoritativeEngineBoots */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); - snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_boots, &tlv.value_len); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_boots)); - - /* msgAuthoritativeEngineTime */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); - snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_time, &tlv.value_len); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_time)); - - /* msgUserName */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_user_name_len); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len)); - -#if LWIP_SNMP_V3_CRYPTO - /* msgAuthenticationParameters */ - if (request->msg_flags & SNMP_V3_AUTH_FLAG) { - memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); - request->outbound_msg_authentication_parameters_offset = pbuf_stream->offset; - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); - } else -#endif - { - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - } - -#if LWIP_SNMP_V3_CRYPTO - /* msgPrivacyParameters */ - if (request->msg_flags & SNMP_V3_PRIV_FLAG) { - snmpv3_build_priv_param(request->msg_privacy_parameters); - - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_privacy_parameters, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); - } else -#endif - { - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - } - - /* End of msgSecurityParameters, so we can calculate the length of this sequence later */ - request->outbound_msg_security_parameters_end = pbuf_stream->offset; - -#if LWIP_SNMP_V3_CRYPTO - /* For encryption we have to encapsulate the payload in an octet string */ - if (request->msg_flags & SNMP_V3_PRIV_FLAG) { - request->outbound_scoped_pdu_string_offset = pbuf_stream->offset; - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, 0); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - } -#endif - /* Scoped PDU - * Encryption context - */ - request->outbound_scoped_pdu_seq_offset = pbuf_stream->offset; - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - - /* contextEngineID */ - snmpv3_get_engine_id(&id, &request->context_engine_id_len); - memcpy(request->context_engine_id, id, request->context_engine_id_len); - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len)); - - /* contextName */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_name_len); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_name, request->context_name_len)); - } -#endif - - /* 'PDU' sequence */ - request->outbound_pdu_offset = pbuf_stream->offset; - SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, 0); - OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - - /* request ID */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); - snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len); - OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) ); - - /* error status */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); - OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - request->outbound_error_status_offset = pbuf_stream->offset; - OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) ); - - /* error index */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); - OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - request->outbound_error_index_offset = pbuf_stream->offset; - OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) ); - - /* 'VarBindList' sequence */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); - OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); - - request->outbound_varbind_offset = pbuf_stream->offset; - - return ERR_OK; -} - -/** Calculate the length of a varbind list */ -err_t -snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len) -{ - /* calculate required lengths */ - snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &len->oid_value_len); - snmp_asn1_enc_length_cnt(len->oid_value_len, &len->oid_len_len); - - if (varbind->value_len == 0) { - len->value_value_len = 0; - } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { - len->value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA); - } else { - switch (varbind->type) { - case SNMP_ASN1_TYPE_INTEGER: - if (varbind->value_len != sizeof (s32_t)) { - return ERR_VAL; - } - snmp_asn1_enc_s32t_cnt(*((s32_t*) varbind->value), &len->value_value_len); - break; - case SNMP_ASN1_TYPE_COUNTER: - case SNMP_ASN1_TYPE_GAUGE: - case SNMP_ASN1_TYPE_TIMETICKS: - if (varbind->value_len != sizeof (u32_t)) { - return ERR_VAL; - } - snmp_asn1_enc_u32t_cnt(*((u32_t*) varbind->value), &len->value_value_len); - break; - case SNMP_ASN1_TYPE_OCTET_STRING: - case SNMP_ASN1_TYPE_IPADDR: - case SNMP_ASN1_TYPE_OPAQUE: - len->value_value_len = varbind->value_len; - break; - case SNMP_ASN1_TYPE_NULL: - if (varbind->value_len != 0) { - return ERR_VAL; - } - len->value_value_len = 0; - break; - case SNMP_ASN1_TYPE_OBJECT_ID: - if ((varbind->value_len & 0x03) != 0) { - return ERR_VAL; - } - snmp_asn1_enc_oid_cnt((u32_t*) varbind->value, varbind->value_len >> 2, &len->value_value_len); - break; - case SNMP_ASN1_TYPE_COUNTER64: - if (varbind->value_len != (2 * sizeof (u32_t))) { - return ERR_VAL; - } - snmp_asn1_enc_u64t_cnt((u32_t*) varbind->value, &len->value_value_len); - break; - default: - /* unsupported type */ - return ERR_VAL; - } - } - snmp_asn1_enc_length_cnt(len->value_value_len, &len->value_len_len); - - len->vb_value_len = 1 + len->oid_len_len + len->oid_value_len + 1 + len->value_len_len + len->value_value_len; - snmp_asn1_enc_length_cnt(len->vb_value_len, &len->vb_len_len); - - return ERR_OK; -} - -#define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG) - -err_t -snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind) -{ - struct snmp_asn1_tlv tlv; - struct snmp_varbind_len len; - err_t err; - - err = snmp_varbind_length(varbind, &len); - - if (err != ERR_OK) { - return err; - } - - /* check length already before adding first data because in case of GetBulk, - * data added so far is returned and therefore no partial data shall be added - */ - if ((1 + len.vb_len_len + len.vb_value_len) > pbuf_stream->length) { - return ERR_BUF; - } - - /* 'VarBind' sequence */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, len.vb_len_len, len.vb_value_len); - OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - - /* VarBind OID */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, len.oid_len_len, len.oid_value_len); - OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, varbind->oid.id, varbind->oid.len)); - - /* VarBind value */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, len.value_len_len, len.value_value_len); - OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); - - if (len.value_value_len > 0) { - if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { - OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len)); - } else { - switch (varbind->type) { - case SNMP_ASN1_TYPE_INTEGER: - OVB_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, len.value_value_len, *((s32_t*) varbind->value))); - break; - case SNMP_ASN1_TYPE_COUNTER: - case SNMP_ASN1_TYPE_GAUGE: - case SNMP_ASN1_TYPE_TIMETICKS: - OVB_BUILD_EXEC(snmp_asn1_enc_u32t(pbuf_stream, len.value_value_len, *((u32_t*) varbind->value))); - break; - case SNMP_ASN1_TYPE_OCTET_STRING: - case SNMP_ASN1_TYPE_IPADDR: - case SNMP_ASN1_TYPE_OPAQUE: - OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len)); - len.value_value_len = varbind->value_len; - break; - case SNMP_ASN1_TYPE_OBJECT_ID: - OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, (u32_t*) varbind->value, varbind->value_len / sizeof (u32_t))); - break; - case SNMP_ASN1_TYPE_COUNTER64: - OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, (u32_t*) varbind->value)); - break; - default: - LWIP_ASSERT("Unknown variable type", 0); - break; - } - } - } - - return ERR_OK; -} - -static err_t -snmp_complete_outbound_frame(struct snmp_request *request) -{ - struct snmp_asn1_tlv tlv; - u16_t frame_size; - u8_t outbound_padding = 0; - - if (request->version == SNMP_VERSION_1) { - if (request->error_status != SNMP_ERR_NOERROR) { - /* map v2c error codes to v1 compliant error code (according to RFC 2089) */ - switch (request->error_status) { - /* mapping of implementation specific "virtual" error codes - * (during processing of frame we already stored them in error_status field, - * so no need to check all varbinds here for those exceptions as suggested by RFC) */ - case SNMP_ERR_NOSUCHINSTANCE: - case SNMP_ERR_NOSUCHOBJECT: - case SNMP_ERR_ENDOFMIBVIEW: - request->error_status = SNMP_ERR_NOSUCHNAME; - break; - /* mapping according to RFC */ - case SNMP_ERR_WRONGVALUE: - case SNMP_ERR_WRONGENCODING: - case SNMP_ERR_WRONGTYPE: - case SNMP_ERR_WRONGLENGTH: - case SNMP_ERR_INCONSISTENTVALUE: - request->error_status = SNMP_ERR_BADVALUE; - break; - case SNMP_ERR_NOACCESS: - case SNMP_ERR_NOTWRITABLE: - case SNMP_ERR_NOCREATION: - case SNMP_ERR_INCONSISTENTNAME: - case SNMP_ERR_AUTHORIZATIONERROR: - request->error_status = SNMP_ERR_NOSUCHNAME; - break; - case SNMP_ERR_RESOURCEUNAVAILABLE: - case SNMP_ERR_COMMITFAILED: - case SNMP_ERR_UNDOFAILED: - default: - request->error_status = SNMP_ERR_GENERROR; - break; - } - } - } else { - if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) { - /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */ - LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n")); - return ERR_ARG; - } - } - - if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) { - /* all inbound vars are returned in response without any modification for error responses and successful set requests*/ - struct snmp_pbuf_stream inbound_stream; - OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) ); - OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, request->outbound_varbind_offset, request->outbound_pbuf->tot_len - request->outbound_varbind_offset) ); - snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0); - } - - frame_size = request->outbound_pbuf_stream.offset; - -#if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO - /* Calculate padding for encryption */ - if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { - u8_t i; - outbound_padding = (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x03); - for (i = 0; i < outbound_padding; i++) { - snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0); - } - } -#endif - - /* complete missing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size + outbound_padding - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ - OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) ); - OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); - -#if LWIP_SNMP_V3 - if (request->version == SNMP_VERSION_3) { - /* complete missing length in 'globalData' sequence */ - /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_global_data_end - - request->outbound_msg_global_data_offset - 1 - 1); - OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_global_data_offset)); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); - - /* complete missing length in 'msgSecurityParameters' sequence */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, request->outbound_msg_security_parameters_end - - request->outbound_msg_security_parameters_str_offset - 1 - 1); - OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_str_offset)); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); - - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_security_parameters_end - - request->outbound_msg_security_parameters_seq_offset - 1 - 1); - OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_seq_offset)); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); - - /* complete missing length in scoped PDU sequence */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_scoped_pdu_seq_offset - 1 - 3); - OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_seq_offset)); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); - } -#endif - - /* complete missing length in 'PDU' sequence */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, - frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ - OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) ); - OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); - - /* process and encode final error status */ - if (request->error_status != 0) { - u16_t len; - snmp_asn1_enc_s32t_cnt(request->error_status, &len); - if (len != 1) { - /* error, we only reserved one byte for it */ - return ERR_ARG; - } - OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) ); - OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) ); - - /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */ - switch (request->error_status) { - case SNMP_ERR_TOOBIG: - snmp_stats.outtoobigs++; - break; - case SNMP_ERR_NOSUCHNAME: - snmp_stats.outnosuchnames++; - break; - case SNMP_ERR_BADVALUE: - snmp_stats.outbadvalues++; - break; - case SNMP_ERR_GENERROR: - default: - snmp_stats.outgenerrs++; - break; - } - - if (request->error_status == SNMP_ERR_TOOBIG) { - request->error_index = 0; /* defined by RFC 1157 */ - } else if (request->error_index == 0) { - /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */ - request->error_index = request->inbound_varbind_enumerator.varbind_count; - } - } else { - if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { - snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count; - } else { - snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count; - } - } - - /* encode final error index*/ - if (request->error_index != 0) { - u16_t len; - snmp_asn1_enc_s32t_cnt(request->error_index, &len); - if (len != 1) { - /* error, we only reserved one byte for it */ - return ERR_VAL; - } - OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) ); - OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) ); - } - - /* complete missing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset); - OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_varbind_offset - 1 - 3) ); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ - OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); - - /* Authenticate response */ -#if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO - /* Encrypt response */ - if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { - u8_t key[20]; - u8_t algo; - - /* complete missing length in PDU sequence */ - OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); - OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_string_offset)); - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, frame_size + outbound_padding - - request->outbound_scoped_pdu_string_offset - 1 - 3); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); - - OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &algo, key)); - - OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key, - request->msg_privacy_parameters, request->msg_authoritative_engine_boots, - request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_ENCRYPT)); - } - - if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) { - u8_t key[20]; - u8_t algo; - u8_t hmac[20]; - - OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL)); - OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), - request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); - OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac)); - - memcpy(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH); - OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, - request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); - OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream, - request->outbound_msg_authentication_parameters_offset)); - - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH); - OF_BUILD_EXEC(snmp_ans1_enc_tlv(&request->outbound_pbuf_stream, &tlv)); - OF_BUILD_EXEC(snmp_asn1_enc_raw(&request->outbound_pbuf_stream, - request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); - } -#endif - - pbuf_realloc(request->outbound_pbuf, frame_size + outbound_padding); - - snmp_stats.outgetresponses++; - snmp_stats.outpkts++; - - return ERR_OK; -} - -static void -snmp_execute_write_callbacks(struct snmp_request *request) -{ - struct snmp_varbind_enumerator inbound_varbind_enumerator; - struct snmp_varbind vb; - - snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); - vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */ - - while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == ERR_OK) { - snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg); - } -} - - -/* ----------------------------------------------------------------------- */ -/* VarBind enumerator methods */ -/* ----------------------------------------------------------------------- */ - -void -snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length) -{ - snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length); - enumerator->varbind_count = 0; -} - -#define VB_PARSE_EXEC(code) PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) -#define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) - -snmp_vb_enumerator_err_t -snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind) -{ - struct snmp_asn1_tlv tlv; - u16_t varbind_len; - err_t err; - - if (enumerator->pbuf_stream.length == 0) - { - return SNMP_VB_ENUMERATOR_ERR_EOVB; - } - enumerator->varbind_count++; - - /* decode varbind itself (parent container of a varbind) */ - VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); - VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length)); - varbind_len = tlv.value_len; - - /* decode varbind name (object id) */ - VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); - VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length)); - - VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN)); - varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv); - - /* decode varbind value (object id) */ - VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); - VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length)); - varbind->type = tlv.type; - - /* shall the value be decoded ? */ - if (varbind->value != NULL) { - switch (varbind->type) { - case SNMP_ASN1_TYPE_INTEGER: - VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t*)varbind->value)); - varbind->value_len = sizeof(s32_t*); - break; - case SNMP_ASN1_TYPE_COUNTER: - case SNMP_ASN1_TYPE_GAUGE: - case SNMP_ASN1_TYPE_TIMETICKS: - VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value)); - varbind->value_len = sizeof(u32_t*); - break; - case SNMP_ASN1_TYPE_OCTET_STRING: - case SNMP_ASN1_TYPE_OPAQUE: - err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE); - if (err == ERR_MEM) { - return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH; - } - VB_PARSE_ASSERT(err == ERR_OK); - break; - case SNMP_ASN1_TYPE_NULL: - varbind->value_len = 0; - break; - case SNMP_ASN1_TYPE_OBJECT_ID: - /* misuse tlv.length_len as OID_length transporter */ - err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN); - if (err == ERR_MEM) { - return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH; - } - VB_PARSE_ASSERT(err == ERR_OK); - varbind->value_len = tlv.length_len * sizeof(u32_t); - break; - case SNMP_ASN1_TYPE_IPADDR: - if (tlv.value_len == 4) { - /* must be exactly 4 octets! */ - VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE)); - } else { - VB_PARSE_ASSERT(0); - } - break; - case SNMP_ASN1_TYPE_COUNTER64: - VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value)); - varbind->value_len = 2 * sizeof(u32_t*); - break; - default: - VB_PARSE_ASSERT(0); - break; - } - } else { - snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len); - varbind->value_len = tlv.value_len; - } - - return SNMP_VB_ENUMERATOR_ERR_OK; -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/apps/snmp/snmp_msg.h b/ext/lwip/src/apps/snmp/snmp_msg.h deleted file mode 100644 index a14b05a..0000000 --- a/ext/lwip/src/apps/snmp/snmp_msg.h +++ /dev/null @@ -1,193 +0,0 @@ -/** - * @file - * SNMP Agent message handling structures (internal API, do not use in client code). - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * Copyright (c) 2016 Elias Oenal. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons - * Martin Hentschel - * Elias Oenal - */ - -#ifndef LWIP_HDR_APPS_SNMP_MSG_H -#define LWIP_HDR_APPS_SNMP_MSG_H - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP - -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "snmp_pbuf_stream.h" -#include "lwip/ip_addr.h" -#include "lwip/err.h" - -#if LWIP_SNMP_V3 -#include "snmpv3_priv.h" -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - -/* The listen port of the SNMP agent. Clients have to make their requests to - this port. Most standard clients won't work if you change this! */ -#ifndef SNMP_IN_PORT -#define SNMP_IN_PORT 161 -#endif -/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't - work if you change this! */ -#ifndef SNMP_TRAP_PORT -#define SNMP_TRAP_PORT 162 -#endif - -/* version defines used in PDU */ -#define SNMP_VERSION_1 0 -#define SNMP_VERSION_2c 1 -#define SNMP_VERSION_3 3 - -struct snmp_varbind_enumerator -{ - struct snmp_pbuf_stream pbuf_stream; - u16_t varbind_count; -}; - -typedef u8_t snmp_vb_enumerator_err_t; -#define SNMP_VB_ENUMERATOR_ERR_OK 0 -#define SNMP_VB_ENUMERATOR_ERR_EOVB 1 -#define SNMP_VB_ENUMERATOR_ERR_ASN1ERROR 2 -#define SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH 3 - -void snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length); -snmp_vb_enumerator_err_t snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind); - -struct snmp_request -{ - /* Communication handle */ - void *handle; - /* source IP address */ - const ip_addr_t *source_ip; - /* source UDP port */ - u16_t source_port; - /* incoming snmp version */ - u8_t version; - /* community name (zero terminated) */ - u8_t community[SNMP_MAX_COMMUNITY_STR_LEN + 1]; - /* community string length (exclusive zero term) */ - u16_t community_strlen; - /* request type */ - u8_t request_type; - /* request ID */ - s32_t request_id; - /* error status */ - s32_t error_status; - /* error index */ - s32_t error_index; - /* non-repeaters (getBulkRequest (SNMPv2c)) */ - s32_t non_repeaters; - /* max-repetitions (getBulkRequest (SNMPv2c)) */ - s32_t max_repetitions; - -#if LWIP_SNMP_V3 - s32_t msg_id; - s32_t msg_max_size; - u8_t msg_flags; - s32_t msg_security_model; - u8_t msg_authoritative_engine_id[SNMP_V3_MAX_ENGINE_ID_LENGTH]; - u8_t msg_authoritative_engine_id_len; - s32_t msg_authoritative_engine_boots; - s32_t msg_authoritative_engine_time; - u8_t msg_user_name[SNMP_V3_MAX_USER_LENGTH]; - u8_t msg_user_name_len; - u8_t msg_authentication_parameters[SNMP_V3_MAX_AUTH_PARAM_LENGTH]; - u8_t msg_privacy_parameters[SNMP_V3_MAX_PRIV_PARAM_LENGTH]; - u8_t context_engine_id[SNMP_V3_MAX_ENGINE_ID_LENGTH]; - u8_t context_engine_id_len; - u8_t context_name[SNMP_V3_MAX_ENGINE_ID_LENGTH]; - u8_t context_name_len; -#endif - - struct pbuf *inbound_pbuf; - struct snmp_varbind_enumerator inbound_varbind_enumerator; - u16_t inbound_varbind_offset; - u16_t inbound_varbind_len; - u16_t inbound_padding_len; - - struct pbuf *outbound_pbuf; - struct snmp_pbuf_stream outbound_pbuf_stream; - u16_t outbound_pdu_offset; - u16_t outbound_error_status_offset; - u16_t outbound_error_index_offset; - u16_t outbound_varbind_offset; -#if LWIP_SNMP_V3 - u16_t outbound_msg_global_data_offset; - u16_t outbound_msg_global_data_end; - u16_t outbound_msg_security_parameters_str_offset; - u16_t outbound_msg_security_parameters_seq_offset; - u16_t outbound_msg_security_parameters_end; - u16_t outbound_msg_authentication_parameters_offset; - u16_t outbound_scoped_pdu_seq_offset; - u16_t outbound_scoped_pdu_string_offset; -#endif - - u8_t value_buffer[SNMP_MAX_VALUE_SIZE]; -}; - -/** A helper struct keeping length information about varbinds */ -struct snmp_varbind_len -{ - u8_t vb_len_len; - u16_t vb_value_len; - u8_t oid_len_len; - u16_t oid_value_len; - u8_t value_len_len; - u16_t value_value_len; -}; - -/** Agent community string */ -extern const char *snmp_community; -/** Agent community string for write access */ -extern const char *snmp_community_write; -/** handle for sending traps */ -extern void* snmp_traps_handle; - -void snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port); -err_t snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port); -u8_t snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result); -err_t snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len); -err_t snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SNMP */ - -#endif /* LWIP_HDR_APPS_SNMP_MSG_H */ diff --git a/ext/lwip/src/apps/snmp/snmp_netconn.c b/ext/lwip/src/apps/snmp/snmp_netconn.c deleted file mode 100644 index 7eead2e..0000000 --- a/ext/lwip/src/apps/snmp/snmp_netconn.c +++ /dev/null @@ -1,120 +0,0 @@ -/** - * @file - * SNMP netconn frontend. - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dirk Ziegelmeier - */ - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP && SNMP_USE_NETCONN - -#include "lwip/api.h" -#include "lwip/ip.h" -#include "lwip/udp.h" -#include "snmp_msg.h" -#include "lwip/sys.h" - -/** SNMP netconn API worker thread */ -static void -snmp_netconn_thread(void *arg) -{ - struct netconn *conn; - struct netbuf *buf; - err_t err; - LWIP_UNUSED_ARG(arg); - - /* Bind to SNMP port with default IP address */ - #if LWIP_IPV6 - conn = netconn_new(NETCONN_UDP_IPV6); - netconn_bind(conn, IP6_ADDR_ANY, SNMP_IN_PORT); -#else /* LWIP_IPV6 */ - conn = netconn_new(NETCONN_UDP); - netconn_bind(conn, IP_ADDR_ANY, SNMP_IN_PORT); -#endif /* LWIP_IPV6 */ - LWIP_ERROR("snmp_netconn: invalid conn", (conn != NULL), return;); - - snmp_traps_handle = conn; - - do { - err = netconn_recv(conn, &buf); - - if (err == ERR_OK) { - snmp_receive(conn, buf->p, &buf->addr, buf->port); - } - - if (buf != NULL) { - netbuf_delete(buf); - } - } while(1); -} - -err_t -snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port) -{ - err_t result; - struct netbuf buf; - - memset(&buf, 0, sizeof(buf)); - buf.p = p; - result = netconn_sendto((struct netconn*)handle, &buf, dst, port); - - return result; -} - -u8_t -snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result) -{ - struct netconn* conn = (struct netconn*)handle; - struct netif *dst_if; - const ip_addr_t* dst_ip; - - LWIP_UNUSED_ARG(conn); /* unused in case of IPV4 only configuration */ - - ip_route_get_local_ip(&conn->pcb.udp->local_ip, dst, dst_if, dst_ip); - - if ((dst_if != NULL) && (dst_ip != NULL)) { - ip_addr_copy(*result, *dst_ip); - return 1; - } else { - return 0; - } -} - -/** - * Starts SNMP Agent. - */ -void -snmp_init(void) -{ - sys_thread_new("snmp_netconn", snmp_netconn_thread, NULL, SNMP_STACK_SIZE, SNMP_THREAD_PRIO); -} - -#endif /* LWIP_SNMP && SNMP_USE_NETCONN */ diff --git a/ext/lwip/src/apps/snmp/snmp_pbuf_stream.c b/ext/lwip/src/apps/snmp/snmp_pbuf_stream.c deleted file mode 100644 index 3c1217d..0000000 --- a/ext/lwip/src/apps/snmp/snmp_pbuf_stream.c +++ /dev/null @@ -1,156 +0,0 @@ -/** - * @file - * SNMP pbuf stream wrapper implementation (internal API, do not use in client code). - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Martin Hentschel - * - */ - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "snmp_pbuf_stream.h" -#include "lwip/def.h" -#include - -err_t -snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length) -{ - pbuf_stream->offset = offset; - pbuf_stream->length = length; - pbuf_stream->pbuf = p; - - return ERR_OK; -} - -err_t -snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data) -{ - if (pbuf_stream->length == 0) { - return ERR_BUF; - } - - if (pbuf_copy_partial(pbuf_stream->pbuf, data, 1, pbuf_stream->offset) == 0) { - return ERR_BUF; - } - - pbuf_stream->offset++; - pbuf_stream->length--; - - return ERR_OK; -} - -err_t -snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data) -{ - return snmp_pbuf_stream_writebuf(pbuf_stream, &data, 1); -} - -err_t -snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len) -{ - if (pbuf_stream->length < buf_len) { - return ERR_BUF; - } - - if (pbuf_take_at(pbuf_stream->pbuf, buf, buf_len, pbuf_stream->offset) != ERR_OK) { - return ERR_BUF; - } - - pbuf_stream->offset += buf_len; - pbuf_stream->length -= buf_len; - - return ERR_OK; -} - -err_t -snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len) -{ - - if ((pbuf_stream == NULL) || (target_pbuf_stream == NULL)) { - return ERR_ARG; - } - if ((len > pbuf_stream->length) || (len > target_pbuf_stream->length)) { - return ERR_ARG; - } - - if (len == 0) { - len = LWIP_MIN(pbuf_stream->length, target_pbuf_stream->length); - } - - while (len > 0) { - u16_t chunk_len; - err_t err; - u16_t target_offset; - struct pbuf* pbuf = pbuf_skip(pbuf_stream->pbuf, pbuf_stream->offset, &target_offset); - - if ((pbuf == NULL) || (pbuf->len == 0)) { - return ERR_BUF; - } - - chunk_len = LWIP_MIN(len, pbuf->len); - err = snmp_pbuf_stream_writebuf(target_pbuf_stream, &((u8_t*)pbuf->payload)[target_offset], chunk_len); - if (err != ERR_OK) { - return err; - } - - pbuf_stream->offset += chunk_len; - pbuf_stream->length -= chunk_len; - len -= chunk_len; - } - - return ERR_OK; -} - -err_t -snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset) -{ - if ((offset < 0) || (offset > pbuf_stream->length)) { - /* we cannot seek backwards or forward behind stream end */ - return ERR_ARG; - } - - pbuf_stream->offset += (u16_t)offset; - pbuf_stream->length -= (u16_t)offset; - - return ERR_OK; -} - -err_t -snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset) -{ - s32_t rel_offset = offset - pbuf_stream->offset; - return snmp_pbuf_stream_seek(pbuf_stream, rel_offset); -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/apps/snmp/snmp_pbuf_stream.h b/ext/lwip/src/apps/snmp/snmp_pbuf_stream.h deleted file mode 100644 index 9778de7..0000000 --- a/ext/lwip/src/apps/snmp/snmp_pbuf_stream.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file - * SNMP pbuf stream wrapper (internal API, do not use in client code). - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Martin Hentschel - * - */ - -#ifndef LWIP_HDR_APPS_SNMP_PBUF_STREAM_H -#define LWIP_HDR_APPS_SNMP_PBUF_STREAM_H - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP - -#include "lwip/err.h" -#include "lwip/pbuf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct snmp_pbuf_stream -{ - struct pbuf* pbuf; - u16_t offset; - u16_t length; -}; - -err_t snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length); -err_t snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data); -err_t snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data); -err_t snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len); -err_t snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len); -err_t snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset); -err_t snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SNMP */ - -#endif /* LWIP_HDR_APPS_SNMP_PBUF_STREAM_H */ diff --git a/ext/lwip/src/apps/snmp/snmp_raw.c b/ext/lwip/src/apps/snmp/snmp_raw.c deleted file mode 100644 index 8cfe77a..0000000 --- a/ext/lwip/src/apps/snmp/snmp_raw.c +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file - * SNMP RAW API frontend. - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dirk Ziegelmeier - */ - -#include "lwip/apps/snmp_opts.h" -#include "lwip/ip_addr.h" - -#if LWIP_SNMP && SNMP_USE_RAW - -#include "lwip/udp.h" -#include "lwip/ip.h" -#include "snmp_msg.h" - -/* lwIP UDP receive callback function */ -static void -snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) -{ - LWIP_UNUSED_ARG(arg); - - snmp_receive(pcb, p, addr, port); - - pbuf_free(p); -} - -err_t -snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port) -{ - return udp_sendto((struct udp_pcb*)handle, p, dst, port); -} - -u8_t -snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result) -{ - struct udp_pcb* udp_pcb = (struct udp_pcb*)handle; - struct netif *dst_if; - const ip_addr_t* dst_ip; - - LWIP_UNUSED_ARG(udp_pcb); /* unused in case of IPV4 only configuration */ - - ip_route_get_local_ip(&udp_pcb->local_ip, dst, dst_if, dst_ip); - - if ((dst_if != NULL) && (dst_ip != NULL)) { - ip_addr_copy(*result, *dst_ip); - return 1; - } else { - return 0; - } -} - -/** - * @ingroup snmp_core - * Starts SNMP Agent. - * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161. - */ -void -snmp_init(void) -{ - err_t err; - - struct udp_pcb *snmp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); - LWIP_ERROR("snmp_raw: no PCB", (snmp_pcb != NULL), return;); - - snmp_traps_handle = snmp_pcb; - - udp_recv(snmp_pcb, snmp_recv, (void *)SNMP_IN_PORT); - err = udp_bind(snmp_pcb, IP_ANY_TYPE, SNMP_IN_PORT); - LWIP_ERROR("snmp_raw: Unable to bind PCB", (err == ERR_OK), return;); -} - -#endif /* LWIP_SNMP && SNMP_USE_RAW */ diff --git a/ext/lwip/src/apps/snmp/snmp_scalar.c b/ext/lwip/src/apps/snmp/snmp_scalar.c deleted file mode 100644 index 136c9ec..0000000 --- a/ext/lwip/src/apps/snmp/snmp_scalar.c +++ /dev/null @@ -1,220 +0,0 @@ -/** - * @file - * SNMP scalar node support implementation. - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Martin Hentschel - * - */ - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/apps/snmp_scalar.h" -#include "lwip/apps/snmp_core.h" - -static s16_t snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value); -static snmp_err_t snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value); -static snmp_err_t snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value); - -snmp_err_t -snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) -{ - const struct snmp_scalar_node* scalar_node = (const struct snmp_scalar_node*)(const void*)instance->node; - - LWIP_UNUSED_ARG(root_oid); - LWIP_UNUSED_ARG(root_oid_len); - - /* scalar only has one dedicated instance: .0 */ - if ((instance->instance_oid.len != 1) || (instance->instance_oid.id[0] != 0)) { - return SNMP_ERR_NOSUCHINSTANCE; - } - - instance->access = scalar_node->access; - instance->asn1_type = scalar_node->asn1_type; - instance->get_value = scalar_node->get_value; - instance->set_test = scalar_node->set_test; - instance->set_value = scalar_node->set_value; - return SNMP_ERR_NOERROR; -} - -snmp_err_t -snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) -{ - /* because our only instance is .0 we can only return a next instance if no instance oid is passed */ - if (instance->instance_oid.len == 0) { - instance->instance_oid.len = 1; - instance->instance_oid.id[0] = 0; - - return snmp_scalar_get_instance(root_oid, root_oid_len, instance); - } - - return SNMP_ERR_NOSUCHINSTANCE; -} - - -snmp_err_t -snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) -{ - LWIP_UNUSED_ARG(root_oid); - LWIP_UNUSED_ARG(root_oid_len); - - if ((instance->instance_oid.len == 2) && (instance->instance_oid.id[1] == 0)) { - const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node; - const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes; - u32_t i = 0; - - while (i < array_node->array_node_count) { - if (array_node_def->oid == instance->instance_oid.id[0]) { - break; - } - - array_node_def++; - i++; - } - - if (i < array_node->array_node_count) { - instance->access = array_node_def->access; - instance->asn1_type = array_node_def->asn1_type; - instance->get_value = snmp_scalar_array_get_value; - instance->set_test = snmp_scalar_array_set_test; - instance->set_value = snmp_scalar_array_set_value; - instance->reference.const_ptr = array_node_def; - - return SNMP_ERR_NOERROR; - } - } - - return SNMP_ERR_NOSUCHINSTANCE; -} - -snmp_err_t -snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) -{ - const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node; - const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes; - const struct snmp_scalar_array_node_def* result = NULL; - - LWIP_UNUSED_ARG(root_oid); - LWIP_UNUSED_ARG(root_oid_len); - - if ((instance->instance_oid.len == 0) && (array_node->array_node_count > 0)) { - /* return node with lowest OID */ - u16_t i = 0; - - result = array_node_def; - array_node_def++; - - for (i = 1; i < array_node->array_node_count; i++) { - if (array_node_def->oid < result->oid) { - result = array_node_def; - } - array_node_def++; - } - } else if (instance->instance_oid.len >= 1) { - if (instance->instance_oid.len == 1) { - /* if we have the requested OID we return its instance, otherwise we search for the next available */ - u16_t i = 0; - while (i < array_node->array_node_count) { - if (array_node_def->oid == instance->instance_oid.id[0]) { - result = array_node_def; - break; - } - - array_node_def++; - i++; - } - } - if (result == NULL) { - u32_t oid_dist = 0xFFFFFFFFUL; - u16_t i = 0; - array_node_def = array_node->array_nodes; /* may be already at the end when if case before was executed without result -> reinitialize to start */ - while (i < array_node->array_node_count) { - if ((array_node_def->oid > instance->instance_oid.id[0]) && - ((u32_t)(array_node_def->oid - instance->instance_oid.id[0]) < oid_dist)) { - result = array_node_def; - oid_dist = array_node_def->oid - instance->instance_oid.id[0]; - } - - array_node_def++; - i++; - } - } - } - - if (result == NULL) { - /* nothing to return */ - return SNMP_ERR_NOSUCHINSTANCE; - } - - instance->instance_oid.len = 2; - instance->instance_oid.id[0] = result->oid; - instance->instance_oid.id[1] = 0; - - instance->access = result->access; - instance->asn1_type = result->asn1_type; - instance->get_value = snmp_scalar_array_get_value; - instance->set_test = snmp_scalar_array_set_test; - instance->set_value = snmp_scalar_array_set_value; - instance->reference.const_ptr = result; - - return SNMP_ERR_NOERROR; -} - -static s16_t -snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value) -{ - const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node; - const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr; - - return array_node->get_value(array_node_def, value); -} - -static snmp_err_t -snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value) -{ - const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node; - const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr; - - return array_node->set_test(array_node_def, value_len, value); -} - -static snmp_err_t -snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value) -{ - const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node; - const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr; - - return array_node->set_value(array_node_def, value_len, value); -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/apps/snmp/snmp_table.c b/ext/lwip/src/apps/snmp/snmp_table.c deleted file mode 100644 index 63ca595..0000000 --- a/ext/lwip/src/apps/snmp/snmp_table.c +++ /dev/null @@ -1,343 +0,0 @@ -/** - * @file - * SNMP table support implementation. - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Martin Hentschel - * - */ - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/apps/snmp_core.h" -#include "lwip/apps/snmp_table.h" -#include - -snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) -{ - snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE; - const struct snmp_table_node* table_node = (const struct snmp_table_node*)(const void*)instance->node; - - LWIP_UNUSED_ARG(root_oid); - LWIP_UNUSED_ARG(root_oid_len); - - /* check min. length (fixed row entry definition, column, row instance oid with at least one entry */ - /* fixed row entry always has oid 1 */ - if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) { - /* search column */ - const struct snmp_table_col_def* col_def = table_node->columns; - u16_t i = table_node->column_count; - while (i > 0) { - if (col_def->index == instance->instance_oid.id[1]) { - break; - } - - col_def++; - i--; - } - - if (i > 0) { - /* everything may be overwritten by get_cell_instance_method() in order to implement special handling for single columns/cells */ - instance->asn1_type = col_def->asn1_type; - instance->access = col_def->access; - instance->get_value = table_node->get_value; - instance->set_test = table_node->set_test; - instance->set_value = table_node->set_value; - - ret = table_node->get_cell_instance( - &(instance->instance_oid.id[1]), - &(instance->instance_oid.id[2]), - instance->instance_oid.len-2, - instance); - } - } - - return ret; -} - -snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) -{ - const struct snmp_table_node* table_node = (const struct snmp_table_node*)(const void*)instance->node; - const struct snmp_table_col_def* col_def; - struct snmp_obj_id row_oid; - u32_t column = 0; - snmp_err_t result; - - LWIP_UNUSED_ARG(root_oid); - LWIP_UNUSED_ARG(root_oid_len); - - /* check that first part of id is 0 or 1, referencing fixed row entry */ - if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) { - return SNMP_ERR_NOSUCHINSTANCE; - } - if (instance->instance_oid.len > 1) { - column = instance->instance_oid.id[1]; - } - if (instance->instance_oid.len > 2) { - snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2); - } else { - row_oid.len = 0; - } - - instance->get_value = table_node->get_value; - instance->set_test = table_node->set_test; - instance->set_value = table_node->set_value; - - /* resolve column and value */ - do { - u16_t i; - const struct snmp_table_col_def* next_col_def = NULL; - col_def = table_node->columns; - - for (i = 0; i < table_node->column_count; i++) { - if (col_def->index == column) { - next_col_def = col_def; - break; - } else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index))) { - next_col_def = col_def; - } - col_def++; - } - - if (next_col_def == NULL) { - /* no further column found */ - return SNMP_ERR_NOSUCHINSTANCE; - } - - instance->asn1_type = next_col_def->asn1_type; - instance->access = next_col_def->access; - - result = table_node->get_next_cell_instance( - &next_col_def->index, - &row_oid, - instance); - - if (result == SNMP_ERR_NOERROR) { - col_def = next_col_def; - break; - } - - row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */ - column = next_col_def->index + 1; - } while (1); - - /* build resulting oid */ - instance->instance_oid.len = 2; - instance->instance_oid.id[0] = 1; - instance->instance_oid.id[1] = col_def->index; - snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len); - - return SNMP_ERR_NOERROR; -} - - -snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) -{ - snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE; - const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)(const void*)instance->node; - - LWIP_UNUSED_ARG(root_oid); - LWIP_UNUSED_ARG(root_oid_len); - - /* check min. length (fixed row entry definition, column, row instance oid with at least one entry */ - /* fixed row entry always has oid 1 */ - if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) { - ret = table_node->get_cell_value( - &(instance->instance_oid.id[1]), - &(instance->instance_oid.id[2]), - instance->instance_oid.len-2, - &instance->reference, - &instance->reference_len); - - if (ret == SNMP_ERR_NOERROR) { - /* search column */ - const struct snmp_table_simple_col_def* col_def = table_node->columns; - u32_t i = table_node->column_count; - while (i > 0) { - if (col_def->index == instance->instance_oid.id[1]) { - break; - } - - col_def++; - i--; - } - - if (i > 0) { - instance->asn1_type = col_def->asn1_type; - instance->access = SNMP_NODE_INSTANCE_READ_ONLY; - instance->set_test = NULL; - instance->set_value = NULL; - - switch (col_def->data_type) { - case SNMP_VARIANT_VALUE_TYPE_U32: - instance->get_value = snmp_table_extract_value_from_u32ref; - break; - case SNMP_VARIANT_VALUE_TYPE_S32: - instance->get_value = snmp_table_extract_value_from_s32ref; - break; - case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */ - case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: - instance->get_value = snmp_table_extract_value_from_refconstptr; - break; - default: - LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type)); - return SNMP_ERR_GENERROR; - } - - ret = SNMP_ERR_NOERROR; - } else { - ret = SNMP_ERR_NOSUCHINSTANCE; - } - } - } - - return ret; -} - -snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) -{ - const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)(const void*)instance->node; - const struct snmp_table_simple_col_def* col_def; - struct snmp_obj_id row_oid; - u32_t column = 0; - snmp_err_t result; - - LWIP_UNUSED_ARG(root_oid); - LWIP_UNUSED_ARG(root_oid_len); - - /* check that first part of id is 0 or 1, referencing fixed row entry */ - if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) { - return SNMP_ERR_NOSUCHINSTANCE; - } - if (instance->instance_oid.len > 1) { - column = instance->instance_oid.id[1]; - } - if (instance->instance_oid.len > 2) { - snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2); - } else { - row_oid.len = 0; - } - - /* resolve column and value */ - do { - u32_t i; - const struct snmp_table_simple_col_def* next_col_def = NULL; - col_def = table_node->columns; - - for (i = 0; i < table_node->column_count; i++) { - if (col_def->index == column) { - next_col_def = col_def; - break; - } else if ((col_def->index > column) && ((next_col_def == NULL) || - (col_def->index < next_col_def->index))) { - next_col_def = col_def; - } - col_def++; - } - - if (next_col_def == NULL) { - /* no further column found */ - return SNMP_ERR_NOSUCHINSTANCE; - } - - result = table_node->get_next_cell_instance_and_value( - &next_col_def->index, - &row_oid, - &instance->reference, - &instance->reference_len); - - if (result == SNMP_ERR_NOERROR) { - col_def = next_col_def; - break; - } - - row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */ - column = next_col_def->index + 1; - } - while (1); - - instance->asn1_type = col_def->asn1_type; - instance->access = SNMP_NODE_INSTANCE_READ_ONLY; - instance->set_test = NULL; - instance->set_value = NULL; - - switch (col_def->data_type) { - case SNMP_VARIANT_VALUE_TYPE_U32: - instance->get_value = snmp_table_extract_value_from_u32ref; - break; - case SNMP_VARIANT_VALUE_TYPE_S32: - instance->get_value = snmp_table_extract_value_from_s32ref; - break; - case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */ - case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: - instance->get_value = snmp_table_extract_value_from_refconstptr; - break; - default: - LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type)); - return SNMP_ERR_GENERROR; - } - - /* build resulting oid */ - instance->instance_oid.len = 2; - instance->instance_oid.id[0] = 1; - instance->instance_oid.id[1] = col_def->index; - snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len); - - return SNMP_ERR_NOERROR; -} - - -s16_t -snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value) -{ - s32_t *dst = (s32_t*)value; - *dst = instance->reference.s32; - return sizeof(*dst); -} - -s16_t -snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value) -{ - u32_t *dst = (u32_t*)value; - *dst = instance->reference.u32; - return sizeof(*dst); -} - -s16_t -snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value) -{ - MEMCPY(value, instance->reference.const_ptr, instance->reference_len); - return (u16_t)instance->reference_len; -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/apps/snmp/snmp_threadsync.c b/ext/lwip/src/apps/snmp/snmp_threadsync.c deleted file mode 100644 index 858c40e..0000000 --- a/ext/lwip/src/apps/snmp/snmp_threadsync.c +++ /dev/null @@ -1,218 +0,0 @@ -/** - * @file - * SNMP thread synchronization implementation. - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dirk Ziegelmeier - */ - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP && (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/apps/snmp_threadsync.h" -#include "lwip/apps/snmp_core.h" -#include "lwip/sys.h" -#include - -static void -call_synced_function(struct threadsync_data *call_data, snmp_threadsync_called_fn fn) -{ - sys_mutex_lock(&call_data->threadsync_node->instance->sem_usage_mutex); - call_data->threadsync_node->instance->sync_fn(fn, call_data); - sys_sem_wait(&call_data->threadsync_node->instance->sem); - sys_mutex_unlock(&call_data->threadsync_node->instance->sem_usage_mutex); -} - -static void -threadsync_get_value_synced(void *ctx) -{ - struct threadsync_data *call_data = (struct threadsync_data*)ctx; - - call_data->retval.s16 = call_data->proxy_instance.get_value(&call_data->proxy_instance, call_data->arg1.value); - - sys_sem_signal(&call_data->threadsync_node->instance->sem); -} - -static s16_t -threadsync_get_value(struct snmp_node_instance* instance, void* value) -{ - struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr; - - call_data->arg1.value = value; - call_synced_function(call_data, threadsync_get_value_synced); - - return call_data->retval.s16; -} - -static void -threadsync_set_test_synced(void *ctx) -{ - struct threadsync_data *call_data = (struct threadsync_data*)ctx; - - call_data->retval.err = call_data->proxy_instance.set_test(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value); - - sys_sem_signal(&call_data->threadsync_node->instance->sem); -} - -static snmp_err_t -threadsync_set_test(struct snmp_node_instance* instance, u16_t len, void *value) -{ - struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr; - - call_data->arg1.value = value; - call_data->arg2.len = len; - call_synced_function(call_data, threadsync_set_test_synced); - - return call_data->retval.err; -} - -static void -threadsync_set_value_synced(void *ctx) -{ - struct threadsync_data *call_data = (struct threadsync_data*)ctx; - - call_data->retval.err = call_data->proxy_instance.set_value(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value); - - sys_sem_signal(&call_data->threadsync_node->instance->sem); -} - -static snmp_err_t -threadsync_set_value(struct snmp_node_instance* instance, u16_t len, void *value) -{ - struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr; - - call_data->arg1.value = value; - call_data->arg2.len = len; - call_synced_function(call_data, threadsync_set_value_synced); - - return call_data->retval.err; -} - -static void -threadsync_release_instance_synced(void* ctx) -{ - struct threadsync_data *call_data = (struct threadsync_data*)ctx; - - call_data->proxy_instance.release_instance(&call_data->proxy_instance); - - sys_sem_signal(&call_data->threadsync_node->instance->sem); -} - -static void -threadsync_release_instance(struct snmp_node_instance *instance) -{ - struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr; - - if (call_data->proxy_instance.release_instance != NULL) { - call_synced_function(call_data, threadsync_release_instance_synced); - } -} - -static void -get_instance_synced(void* ctx) -{ - struct threadsync_data *call_data = (struct threadsync_data*)ctx; - const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)(const void*)call_data->proxy_instance.node; - - call_data->retval.err = leaf->get_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance); - - sys_sem_signal(&call_data->threadsync_node->instance->sem); -} - -static void -get_next_instance_synced(void* ctx) -{ - struct threadsync_data *call_data = (struct threadsync_data*)ctx; - const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)(const void*)call_data->proxy_instance.node; - - call_data->retval.err = leaf->get_next_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance); - - sys_sem_signal(&call_data->threadsync_node->instance->sem); -} - -static snmp_err_t -do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance, snmp_threadsync_called_fn fn) -{ - const struct snmp_threadsync_node *threadsync_node = (const struct snmp_threadsync_node*)(const void*)instance->node; - struct threadsync_data *call_data = &threadsync_node->instance->data; - - if (threadsync_node->node.node.oid != threadsync_node->target->node.oid) { - LWIP_DEBUGF(SNMP_DEBUG, ("Sync node OID does not match target node OID")); - return SNMP_ERR_NOSUCHINSTANCE; - } - - memset(&call_data->proxy_instance, 0, sizeof(call_data->proxy_instance)); - - instance->reference.ptr = call_data; - snmp_oid_assign(&call_data->proxy_instance.instance_oid, instance->instance_oid.id, instance->instance_oid.len); - - call_data->proxy_instance.node = &threadsync_node->target->node; - call_data->threadsync_node = threadsync_node; - - call_data->arg1.root_oid = root_oid; - call_data->arg2.root_oid_len = root_oid_len; - call_synced_function(call_data, fn); - - if (call_data->retval.err == SNMP_ERR_NOERROR) { - instance->access = call_data->proxy_instance.access; - instance->asn1_type = call_data->proxy_instance.asn1_type; - instance->release_instance = threadsync_release_instance; - instance->get_value = (call_data->proxy_instance.get_value != NULL)? threadsync_get_value : NULL; - instance->set_value = (call_data->proxy_instance.set_value != NULL)? threadsync_set_value : NULL; - instance->set_test = (call_data->proxy_instance.set_test != NULL)? threadsync_set_test : NULL; - snmp_oid_assign(&instance->instance_oid, call_data->proxy_instance.instance_oid.id, call_data->proxy_instance.instance_oid.len); - } - - return call_data->retval.err; -} - -snmp_err_t -snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) -{ - return do_sync(root_oid, root_oid_len, instance, get_instance_synced); -} - -snmp_err_t -snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) -{ - return do_sync(root_oid, root_oid_len, instance, get_next_instance_synced); -} - -/** Initializes thread synchronization instance */ -void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_threadsync_synchronizer_fn sync_fn) -{ - err_t err = sys_mutex_new(&instance->sem_usage_mutex); - LWIP_ASSERT("Failed to set up mutex", err == ERR_OK); - err = sys_sem_new(&instance->sem, 0); - LWIP_ASSERT("Failed to set up semaphore", err == ERR_OK); - instance->sync_fn = sync_fn; -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/apps/snmp/snmp_traps.c b/ext/lwip/src/apps/snmp/snmp_traps.c deleted file mode 100644 index 8061766..0000000 --- a/ext/lwip/src/apps/snmp/snmp_traps.c +++ /dev/null @@ -1,443 +0,0 @@ -/** - * @file - * SNMPv1 traps implementation. - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Martin Hentschel - * Christiaan Simons - * - */ - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include - -#include "lwip/snmp.h" -#include "lwip/sys.h" -#include "lwip/apps/snmp.h" -#include "lwip/apps/snmp_core.h" -#include "snmp_msg.h" -#include "snmp_asn1.h" -#include "snmp_core_priv.h" - -struct snmp_msg_trap -{ - /* source enterprise ID (sysObjectID) */ - const struct snmp_obj_id *enterprise; - /* source IP address, raw network order format */ - ip_addr_t sip; - /* generic trap code */ - u32_t gen_trap; - /* specific trap code */ - u32_t spc_trap; - /* timestamp */ - u32_t ts; - /* snmp_version */ - u32_t snmp_version; - - /* output trap lengths used in ASN encoding */ - /* encoding pdu length */ - u16_t pdulen; - /* encoding community length */ - u16_t comlen; - /* encoding sequence length */ - u16_t seqlen; - /* encoding varbinds sequence length */ - u16_t vbseqlen; -}; - -static u16_t snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds); -static u16_t snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len); -static void snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream); -static void snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds); - -/** Agent community string for sending traps */ -extern const char *snmp_community_trap; - -void* snmp_traps_handle; - -struct snmp_trap_dst -{ - /* destination IP address in network order */ - ip_addr_t dip; - /* set to 0 when disabled, >0 when enabled */ - u8_t enable; -}; -static struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS]; - -static u8_t snmp_auth_traps_enabled = 0; - -/** - * @ingroup snmp_traps - * Sets enable switch for this trap destination. - * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 - * @param enable switch if 0 destination is disabled >0 enabled. - */ -void -snmp_trap_dst_enable(u8_t dst_idx, u8_t enable) -{ - if (dst_idx < SNMP_TRAP_DESTINATIONS) { - trap_dst[dst_idx].enable = enable; - } -} - -/** - * @ingroup snmp_traps - * Sets IPv4 address for this trap destination. - * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 - * @param dst IPv4 address in host order. - */ -void -snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst) -{ - if (dst_idx < SNMP_TRAP_DESTINATIONS) { - ip_addr_set(&trap_dst[dst_idx].dip, dst); - } -} - -/** - * @ingroup snmp_traps - * Enable/disable authentication traps - */ -void -snmp_set_auth_traps_enabled(u8_t enable) -{ - snmp_auth_traps_enabled = enable; -} - -/** - * @ingroup snmp_traps - * Get authentication traps enabled state - */ -u8_t -snmp_get_auth_traps_enabled(void) -{ - return snmp_auth_traps_enabled; -} - - -/** - * Sends an generic or enterprise specific trap message. - * - * @param generic_trap is the trap code - * @param eoid points to enterprise object identifier - * @param specific_trap used for enterprise traps when generic_trap == 6 - * @return ERR_OK when success, ERR_MEM if we're out of memory - * - * @note the use of the enterprise identifier field - * is per RFC1215. - * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps - * and .iso.org.dod.internet.private.enterprises.yourenterprise - * (sysObjectID) for specific traps. - */ -static err_t -snmp_send_trap(const struct snmp_obj_id *device_enterprise_oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds) -{ - struct snmp_msg_trap trap_msg; - struct snmp_trap_dst *td; - struct pbuf *p; - u16_t i, tot_len; - err_t err = ERR_OK; - - trap_msg.snmp_version = 0; - - for (i = 0, td = &trap_dst[0]; i < SNMP_TRAP_DESTINATIONS; i++, td++) { - if ((td->enable != 0) && !ip_addr_isany(&td->dip)) { - /* lookup current source address for this dst */ - if (snmp_get_local_ip_for_dst(snmp_traps_handle, &td->dip, &trap_msg.sip)) { - if (device_enterprise_oid == NULL) { - trap_msg.enterprise = snmp_get_device_enterprise_oid(); - } else { - trap_msg.enterprise = device_enterprise_oid; - } - - trap_msg.gen_trap = generic_trap; - if (generic_trap == SNMP_GENTRAP_ENTERPRISE_SPECIFIC) { - trap_msg.spc_trap = specific_trap; - } else { - trap_msg.spc_trap = 0; - } - - MIB2_COPY_SYSUPTIME_TO(&trap_msg.ts); - - /* pass 0, calculate length fields */ - tot_len = snmp_trap_varbind_sum(&trap_msg, varbinds); - tot_len = snmp_trap_header_sum(&trap_msg, tot_len); - - /* allocate pbuf(s) */ - p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM); - if (p != NULL) { - struct snmp_pbuf_stream pbuf_stream; - snmp_pbuf_stream_init(&pbuf_stream, p, 0, tot_len); - - /* pass 1, encode packet ino the pbuf(s) */ - snmp_trap_header_enc(&trap_msg, &pbuf_stream); - snmp_trap_varbind_enc(&trap_msg, &pbuf_stream, varbinds); - - snmp_stats.outtraps++; - snmp_stats.outpkts++; - - /** send to the TRAP destination */ - snmp_sendto(snmp_traps_handle, p, &td->dip, SNMP_TRAP_PORT); - pbuf_free(p); - } else { - err = ERR_MEM; - } - } else { - /* routing error */ - err = ERR_RTE; - } - } - } - return err; -} - -/** - * @ingroup snmp_traps - * Send generic SNMP trap - */ -err_t -snmp_send_trap_generic(s32_t generic_trap) -{ - static const struct snmp_obj_id oid = { 7, { 1, 3, 6, 1, 2, 1, 11 } }; - return snmp_send_trap(&oid, generic_trap, 0, NULL); -} - -/** - *@ingroup snmp_traps - * Send specific SNMP trap with variable bindings - */ -err_t -snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds) -{ - return snmp_send_trap(NULL, SNMP_GENTRAP_ENTERPRISE_SPECIFIC, specific_trap, varbinds); -} - -/** - * @ingroup snmp_traps - * Send coldstart trap - */ -void -snmp_coldstart_trap(void) -{ - snmp_send_trap_generic(SNMP_GENTRAP_COLDSTART); -} - -/** - * @ingroup snmp_traps - * Send authentication failure trap (used internally by agent) - */ -void -snmp_authfail_trap(void) -{ - if (snmp_auth_traps_enabled != 0) { - snmp_send_trap_generic(SNMP_GENTRAP_AUTH_FAILURE); - } -} - -static u16_t -snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds) -{ - struct snmp_varbind *varbind; - u16_t tot_len; - u8_t tot_len_len; - - tot_len = 0; - varbind = varbinds; - while (varbind != NULL) { - struct snmp_varbind_len len; - - if (snmp_varbind_length(varbind, &len) == ERR_OK) { - tot_len += 1 + len.vb_len_len + len.vb_value_len; - } - - varbind = varbind->next; - } - - trap->vbseqlen = tot_len; - snmp_asn1_enc_length_cnt(trap->vbseqlen, &tot_len_len); - tot_len += 1 + tot_len_len; - - return tot_len; -} - -/** - * Sums trap header field lengths from tail to head and - * returns trap_header_lengths for second encoding pass. - * - * @param vb_len varbind-list length - * @param thl points to returned header lengths - * @return the required length for encoding the trap header - */ -static u16_t -snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len) -{ - u16_t tot_len; - u16_t len; - u8_t lenlen; - - tot_len = vb_len; - - snmp_asn1_enc_u32t_cnt(trap->ts, &len); - snmp_asn1_enc_length_cnt(len, &lenlen); - tot_len += 1 + len + lenlen; - - snmp_asn1_enc_s32t_cnt(trap->spc_trap, &len); - snmp_asn1_enc_length_cnt(len, &lenlen); - tot_len += 1 + len + lenlen; - - snmp_asn1_enc_s32t_cnt(trap->gen_trap, &len); - snmp_asn1_enc_length_cnt(len, &lenlen); - tot_len += 1 + len + lenlen; - - if (IP_IS_V6_VAL(trap->sip)) { -#if LWIP_IPV6 - len = sizeof(ip_2_ip6(&trap->sip)->addr); -#endif - } else { -#if LWIP_IPV4 - len = sizeof(ip_2_ip4(&trap->sip)->addr); -#endif - } - snmp_asn1_enc_length_cnt(len, &lenlen); - tot_len += 1 + len + lenlen; - - snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &len); - snmp_asn1_enc_length_cnt(len, &lenlen); - tot_len += 1 + len + lenlen; - - trap->pdulen = tot_len; - snmp_asn1_enc_length_cnt(trap->pdulen, &lenlen); - tot_len += 1 + lenlen; - - trap->comlen = (u16_t)LWIP_MIN(strlen(snmp_community_trap), 0xFFFF); - snmp_asn1_enc_length_cnt(trap->comlen, &lenlen); - tot_len += 1 + lenlen + trap->comlen; - - snmp_asn1_enc_s32t_cnt(trap->snmp_version, &len); - snmp_asn1_enc_length_cnt(len, &lenlen); - tot_len += 1 + len + lenlen; - - trap->seqlen = tot_len; - snmp_asn1_enc_length_cnt(trap->seqlen, &lenlen); - tot_len += 1 + lenlen; - - return tot_len; -} - -static void -snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds) -{ - struct snmp_asn1_tlv tlv; - struct snmp_varbind *varbind; - - varbind = varbinds; - - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->vbseqlen); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - - while (varbind != NULL) { - snmp_append_outbound_varbind(pbuf_stream, varbind); - - varbind = varbind->next; - } -} - -/** - * Encodes trap header from head to tail. - */ -static void -snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream) -{ - struct snmp_asn1_tlv tlv; - - /* 'Message' sequence */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - - /* version */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); - snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version); - - /* community */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen); - - /* 'PDU' sequence */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - - /* object ID */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, 0, 0); - snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &tlv.value_len); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - snmp_asn1_enc_oid(pbuf_stream, trap->enterprise->id, trap->enterprise->len); - - /* IP addr */ - if (IP_IS_V6_VAL(trap->sip)) { -#if LWIP_IPV6 - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip6(&trap->sip)->addr)); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip6(&trap->sip)->addr, sizeof(ip_2_ip6(&trap->sip)->addr)); -#endif - } else { -#if LWIP_IPV4 - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip4(&trap->sip)->addr)); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip4(&trap->sip)->addr, sizeof(ip_2_ip4(&trap->sip)->addr)); -#endif - } - - /* trap length */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); - snmp_asn1_enc_s32t_cnt(trap->gen_trap, &tlv.value_len); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->gen_trap); - - /* specific trap */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); - snmp_asn1_enc_s32t_cnt(trap->spc_trap, &tlv.value_len); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->spc_trap); - - /* timestamp */ - SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_TIMETICKS, 0, 0); - snmp_asn1_enc_s32t_cnt(trap->ts, &tlv.value_len); - snmp_ans1_enc_tlv(pbuf_stream, &tlv); - snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->ts); -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/apps/snmp/snmpv3.c b/ext/lwip/src/apps/snmp/snmpv3.c deleted file mode 100644 index e5dfa32..0000000 --- a/ext/lwip/src/apps/snmp/snmpv3.c +++ /dev/null @@ -1,136 +0,0 @@ -/** - * @file - * Additional SNMPv3 functionality RFC3414 and RFC3826. - */ - -/* - * Copyright (c) 2016 Elias Oenal. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Elias Oenal - */ - -#include "snmpv3_priv.h" -#include "lwip/apps/snmpv3.h" -#include "lwip/sys.h" -#include - -#if LWIP_SNMP && LWIP_SNMP_V3 - -#ifdef LWIP_SNMPV3_INCLUDE_ENGINE -#include LWIP_SNMPV3_INCLUDE_ENGINE -#endif - -#define SNMP_MAX_TIME_BOOT 2147483647UL - -/** Call this if engine has been changed. Has to reset boots, see below */ -void -snmpv3_engine_id_changed(void) -{ - snmpv3_set_engine_boots(0); -} - -/** According to RFC3414 2.2.2. - * - * The number of times that the SNMP engine has - * (re-)initialized itself since snmpEngineID - * was last configured. - */ -u32_t -snmpv3_get_engine_boots_internal(void) -{ - if (snmpv3_get_engine_boots() == 0 || - snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT) { - return snmpv3_get_engine_boots(); - } - - snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT); - return snmpv3_get_engine_boots(); -} - -/** RFC3414 2.2.2. - * - * Once the timer reaches 2147483647 it gets reset to zero and the - * engine boot ups get incremented. - */ -u32_t -snmpv3_get_engine_time_internal(void) -{ - if (snmpv3_get_engine_time() >= SNMP_MAX_TIME_BOOT) { - snmpv3_reset_engine_time(); - - if (snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT - 1) { - snmpv3_set_engine_boots(snmpv3_get_engine_boots() + 1); - } else { - snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT); - } - } - - return snmpv3_get_engine_time(); -} - -#if LWIP_SNMP_V3_CRYPTO - -/* This function ignores the byte order suggestion in RFC3414 - * since it simply doesn't influence the effectiveness of an IV. - * - * Implementing RFC3826 priv param algorithm if LWIP_RAND is available. - * - * @todo: This is a potential thread safety issue. - */ -err_t -snmpv3_build_priv_param(u8_t* priv_param) -{ -#ifdef LWIP_RAND /* Based on RFC3826 */ - static u8_t init; - static u32_t priv1, priv2; - - /* Lazy initialisation */ - if (init == 0) { - init = 1; - priv1 = LWIP_RAND(); - priv2 = LWIP_RAND(); - } - - memcpy(&priv_param[0], &priv1, sizeof(priv1)); - memcpy(&priv_param[4], &priv2, sizeof(priv2)); - - /* Emulate 64bit increment */ - priv1++; - if (!priv1) { /* Overflow */ - priv2++; - } -#else /* Based on RFC3414 */ - static u32_t ctr; - u32_t boots = LWIP_SNMPV3_GET_ENGINE_BOOTS(); - memcpy(&priv_param[0], &boots, 4); - memcpy(&priv_param[4], &ctr, 4); - ctr++; -#endif - return ERR_OK; -} -#endif /* LWIP_SNMP_V3_CRYPTO */ - -#endif diff --git a/ext/lwip/src/apps/snmp/snmpv3_dummy.c b/ext/lwip/src/apps/snmp/snmpv3_dummy.c deleted file mode 100644 index bdfe844..0000000 --- a/ext/lwip/src/apps/snmp/snmpv3_dummy.c +++ /dev/null @@ -1,145 +0,0 @@ -/** - * @file - * Dummy SNMPv3 functions. - */ - -/* - * Copyright (c) 2016 Elias Oenal. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Elias Oenal - * Dirk Ziegelmeier - */ - -#include "lwip/apps/snmpv3.h" -#include "snmpv3_priv.h" -#include -#include "lwip/err.h" - -#if LWIP_SNMP && LWIP_SNMP_V3 - -/** - * @param username is a pointer to a string. - * @param auth_algo is a pointer to u8_t. The implementation has to set this if user was found. - * @param auth_key is a pointer to a pointer to a string. Implementation has to set this if user was found. - * @param priv_algo is a pointer to u8_t. The implementation has to set this if user was found. - * @param priv_key is a pointer to a pointer to a string. Implementation has to set this if user was found. - */ -err_t -snmpv3_get_user(const char* username, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key) -{ - const char* engine_id; - u8_t engine_id_len; - - if(strlen(username) == 0) { - return ERR_OK; - } - - if(memcmp(username, "lwip", 4) != 0) { - return ERR_VAL; - } - - snmpv3_get_engine_id(&engine_id, &engine_id_len); - - if(auth_key != NULL) { - snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10, - (const u8_t*)engine_id, engine_id_len, - auth_key); - *auth_algo = SNMP_V3_AUTH_ALGO_SHA; - } - if(priv_key != NULL) { - snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10, - (const u8_t*)engine_id, engine_id_len, - priv_key); - *priv_algo = SNMP_V3_PRIV_ALGO_DES; - } - return ERR_OK; -} - -/** - * Get engine ID from persistence - * @param id - * @param len - */ -void -snmpv3_get_engine_id(const char **id, u8_t *len) -{ - *id = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"; - *len = 12; -} - -/** - * Store engine ID in persistence - * @param id - * @param len - */ -err_t -snmpv3_set_engine_id(const char *id, u8_t len) -{ - LWIP_UNUSED_ARG(id); - LWIP_UNUSED_ARG(len); - return ERR_OK; -} - -/** - * Get engine boots from persistence. Must be increased on each boot. - * @return - */ -u32_t -snmpv3_get_engine_boots(void) -{ - return 0; -} - -/** - * Store engine boots in persistence - * @param boots - */ -void -snmpv3_set_engine_boots(u32_t boots) -{ - LWIP_UNUSED_ARG(boots); -} - -/** - * RFC3414 2.2.2. - * Once the timer reaches 2147483647 it gets reset to zero and the - * engine boot ups get incremented. - */ -u32_t -snmpv3_get_engine_time(void) -{ - return 0; -} - -/** - * Reset current engine time to 0 - */ -void -snmpv3_reset_engine_time(void) -{ -} - -#endif /* LWIP_SNMP && LWIP_SNMP_V3 */ diff --git a/ext/lwip/src/apps/snmp/snmpv3_mbedtls.c b/ext/lwip/src/apps/snmp/snmpv3_mbedtls.c deleted file mode 100644 index 2a0598b..0000000 --- a/ext/lwip/src/apps/snmp/snmpv3_mbedtls.c +++ /dev/null @@ -1,331 +0,0 @@ -/** - * @file - * SNMPv3 crypto/auth functions implemented for ARM mbedtls. - */ - -/* - * Copyright (c) 2016 Elias Oenal and Dirk Ziegelmeier. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Elias Oenal - * Dirk Ziegelmeier - */ - -#include "lwip/apps/snmpv3.h" -#include "snmpv3_priv.h" -#include "lwip/arch.h" -#include "snmp_msg.h" -#include "lwip/sys.h" -#include - -#if LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS - -#include "mbedtls/md.h" -#include "mbedtls/cipher.h" - -#include "mbedtls/md5.h" -#include "mbedtls/sha1.h" - -err_t -snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, - const u8_t* key, u8_t algo, u8_t* hmac_out) -{ - u32_t i; - u8_t key_len; - const mbedtls_md_info_t *md_info; - mbedtls_md_context_t ctx; - struct snmp_pbuf_stream read_stream; - snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length); - - if (algo == SNMP_V3_AUTH_ALGO_MD5) { - md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); - key_len = SNMP_V3_MD5_LEN; - } else if (algo == SNMP_V3_AUTH_ALGO_SHA) { - md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); - key_len = SNMP_V3_SHA_LEN; - } else { - return ERR_ARG; - } - - mbedtls_md_init(&ctx); - if(mbedtls_md_setup(&ctx, md_info, 1) != 0) { - return ERR_ARG; - } - - if (mbedtls_md_hmac_starts(&ctx, key, key_len) != 0) { - goto free_md; - } - - for (i = 0; i < length; i++) { - u8_t byte; - - if (snmp_pbuf_stream_read(&read_stream, &byte)) { - goto free_md; - } - - if (mbedtls_md_hmac_update(&ctx, &byte, 1) != 0) { - goto free_md; - } - } - - if (mbedtls_md_hmac_finish(&ctx, hmac_out) != 0) { - goto free_md; - } - - mbedtls_md_free(&ctx); - return ERR_OK; - -free_md: - mbedtls_md_free(&ctx); - return ERR_ARG; -} - -#if LWIP_SNMP_V3_CRYPTO - -err_t -snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, - const u8_t* key, const u8_t* priv_param, const u32_t engine_boots, - const u32_t engine_time, u8_t algo, u8_t mode) -{ - size_t i; - mbedtls_cipher_context_t ctx; - const mbedtls_cipher_info_t *cipher_info; - - struct snmp_pbuf_stream read_stream; - struct snmp_pbuf_stream write_stream; - snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length); - snmp_pbuf_stream_init(&write_stream, stream->pbuf, stream->offset, stream->length); - mbedtls_cipher_init(&ctx); - - if (algo == SNMP_V3_PRIV_ALGO_DES) { - u8_t iv_local[8]; - u8_t out_bytes[8]; - size_t out_len; - - /* RFC 3414 mandates padding for DES */ - if ((length & 0x07) != 0) { - return ERR_ARG; - } - - cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_DES_CBC); - if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) { - return ERR_ARG; - } - if(mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_NONE) != 0) { - return ERR_ARG; - } - if(mbedtls_cipher_setkey(&ctx, key, 8*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) { - goto error; - } - - /* Prepare IV */ - for (i = 0; i < LWIP_ARRAYSIZE(iv_local); i++) { - iv_local[i] = priv_param[i] ^ key[i + 8]; - } - if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) { - goto error; - } - - for (i = 0; i < length; i += 8) { - size_t j; - u8_t in_bytes[8]; - out_len = LWIP_ARRAYSIZE(out_bytes) ; - - for (j = 0; j < LWIP_ARRAYSIZE(in_bytes); j++) { - snmp_pbuf_stream_read(&read_stream, &in_bytes[j]); - } - - if(mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) { - goto error; - } - - snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len); - } - - out_len = LWIP_ARRAYSIZE(out_bytes); - if(mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) { - goto error; - } - snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len); - } else if (algo == SNMP_V3_PRIV_ALGO_AES) { - u8_t iv_local[16]; - - cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CFB128); - if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) { - return ERR_ARG; - } - if(mbedtls_cipher_setkey(&ctx, key, 16*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) { - goto error; - } - - /* - * IV is the big endian concatenation of boots, - * uptime and priv param - see RFC3826. - */ - iv_local[0 + 0] = (engine_boots >> 24) & 0xFF; - iv_local[0 + 1] = (engine_boots >> 16) & 0xFF; - iv_local[0 + 2] = (engine_boots >> 8) & 0xFF; - iv_local[0 + 3] = (engine_boots >> 0) & 0xFF; - iv_local[4 + 0] = (engine_time >> 24) & 0xFF; - iv_local[4 + 1] = (engine_time >> 16) & 0xFF; - iv_local[4 + 2] = (engine_time >> 8) & 0xFF; - iv_local[4 + 3] = (engine_time >> 0) & 0xFF; - memcpy(iv_local + 8, priv_param, 8); - if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) { - goto error; - } - - for (i = 0; i < length; i++) { - u8_t in_byte; - u8_t out_byte; - size_t out_len = sizeof(out_byte); - - snmp_pbuf_stream_read(&read_stream, &in_byte); - if(mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) { - goto error; - } - snmp_pbuf_stream_write(&write_stream, out_byte); - } - } else { - return ERR_ARG; - } - - mbedtls_cipher_free(&ctx); - return ERR_OK; - -error: - mbedtls_cipher_free(&ctx); - return ERR_OK; -} - -#endif /* LWIP_SNMP_V3_CRYPTO */ - -/* A.2.1. Password to Key Sample Code for MD5 */ -void -snmpv3_password_to_key_md5( - const u8_t *password, /* IN */ - u8_t passwordlen, /* IN */ - const u8_t *engineID, /* IN - pointer to snmpEngineID */ - u8_t engineLength,/* IN - length of snmpEngineID */ - u8_t *key) /* OUT - pointer to caller 16-octet buffer */ -{ - mbedtls_md5_context MD; - u8_t *cp, password_buf[64]; - u32_t password_index = 0; - u8_t i; - u32_t count = 0; - - mbedtls_md5_init(&MD); /* initialize MD5 */ - mbedtls_md5_starts(&MD); - - /**********************************************/ - /* Use while loop until we've done 1 Megabyte */ - /**********************************************/ - while (count < 1048576) { - cp = password_buf; - for (i = 0; i < 64; i++) { - /*************************************************/ - /* Take the next octet of the password, wrapping */ - /* to the beginning of the password as necessary.*/ - /*************************************************/ - *cp++ = password[password_index++ % passwordlen]; - } - mbedtls_md5_update(&MD, password_buf, 64); - count += 64; - } - mbedtls_md5_finish(&MD, key); /* tell MD5 we're done */ - - /*****************************************************/ - /* Now localize the key with the engineID and pass */ - /* through MD5 to produce final key */ - /* May want to ensure that engineLength <= 32, */ - /* otherwise need to use a buffer larger than 64 */ - /*****************************************************/ - memcpy(password_buf, key, 16); - memcpy(password_buf + 16, engineID, engineLength); - memcpy(password_buf + 16 + engineLength, key, 16); - - mbedtls_md5_starts(&MD); - mbedtls_md5_update(&MD, password_buf, 32 + engineLength); - mbedtls_md5_finish(&MD, key); - - mbedtls_md5_free(&MD); - return; -} - -/* A.2.2. Password to Key Sample Code for SHA */ -void -snmpv3_password_to_key_sha( - const u8_t *password, /* IN */ - u8_t passwordlen, /* IN */ - const u8_t *engineID, /* IN - pointer to snmpEngineID */ - u8_t engineLength,/* IN - length of snmpEngineID */ - u8_t *key) /* OUT - pointer to caller 20-octet buffer */ -{ - mbedtls_sha1_context SH; - u8_t *cp, password_buf[72]; - u32_t password_index = 0; - u8_t i; - u32_t count = 0; - - mbedtls_sha1_init(&SH); /* initialize SHA */ - mbedtls_sha1_starts(&SH); - - /**********************************************/ - /* Use while loop until we've done 1 Megabyte */ - /**********************************************/ - while (count < 1048576) { - cp = password_buf; - for (i = 0; i < 64; i++) { - /*************************************************/ - /* Take the next octet of the password, wrapping */ - /* to the beginning of the password as necessary.*/ - /*************************************************/ - *cp++ = password[password_index++ % passwordlen]; - } - mbedtls_sha1_update(&SH, password_buf, 64); - count += 64; - } - mbedtls_sha1_finish(&SH, key); /* tell SHA we're done */ - - /*****************************************************/ - /* Now localize the key with the engineID and pass */ - /* through SHA to produce final key */ - /* May want to ensure that engineLength <= 32, */ - /* otherwise need to use a buffer larger than 72 */ - /*****************************************************/ - memcpy(password_buf, key, 20); - memcpy(password_buf + 20, engineID, engineLength); - memcpy(password_buf + 20 + engineLength, key, 20); - - mbedtls_sha1_starts(&SH); - mbedtls_sha1_update(&SH, password_buf, 40 + engineLength); - mbedtls_sha1_finish(&SH, key); - - mbedtls_sha1_free(&SH); - return; -} - -#endif /* LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS */ diff --git a/ext/lwip/src/apps/snmp/snmpv3_priv.h b/ext/lwip/src/apps/snmp/snmpv3_priv.h deleted file mode 100644 index b87666d..0000000 --- a/ext/lwip/src/apps/snmp/snmpv3_priv.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * Additional SNMPv3 functionality RFC3414 and RFC3826 (internal API, do not use in client code). - */ - -/* - * Copyright (c) 2016 Elias Oenal. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Elias Oenal - */ - -#ifndef LWIP_HDR_APPS_SNMP_V3_PRIV_H -#define LWIP_HDR_APPS_SNMP_V3_PRIV_H - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP && LWIP_SNMP_V3 - -#include "snmp_pbuf_stream.h" - -/* According to RFC 3411 */ -#define SNMP_V3_MAX_ENGINE_ID_LENGTH 32 -#define SNMP_V3_MAX_USER_LENGTH 32 - -#define SNMP_V3_MAX_AUTH_PARAM_LENGTH 12 -#define SNMP_V3_MAX_PRIV_PARAM_LENGTH 8 - -#define SNMP_V3_AUTH_FLAG 0x01 -#define SNMP_V3_PRIV_FLAG 0x02 - -#define SNMP_V3_MD5_LEN 16 -#define SNMP_V3_SHA_LEN 20 - -u32_t snmpv3_get_engine_boots_internal(void); -u32_t snmpv3_get_engine_time_internal(void); -err_t snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, u8_t algo, u8_t* hmac_out); -err_t snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, - const u8_t* priv_param, const u32_t engine_boots, const u32_t engine_time, u8_t algo, u8_t mode); -err_t snmpv3_build_priv_param(u8_t* priv_param); - -#endif - -#endif /* LWIP_HDR_APPS_SNMP_V3_PRIV_H */ diff --git a/ext/lwip/src/apps/sntp/sntp.c b/ext/lwip/src/apps/sntp/sntp.c deleted file mode 100644 index 8d43eb0..0000000 --- a/ext/lwip/src/apps/sntp/sntp.c +++ /dev/null @@ -1,726 +0,0 @@ -/** - * @file - * SNTP client module - */ - -/* - * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Frédéric Bernon, Simon Goldschmidt - */ - - -/** - * @defgroup sntp SNTP - * @ingroup apps - * - * This is simple "SNTP" client for the lwIP raw API. - * It is a minimal implementation of SNTPv4 as specified in RFC 4330. - * - * For a list of some public NTP servers, see this link : - * http://support.ntp.org/bin/view/Servers/NTPPoolServers - * - * @todo: - * - set/change servers at runtime - * - complete SNTP_CHECK_RESPONSE checks 3 and 4 - */ - -#include "lwip/apps/sntp.h" - -#include "lwip/opt.h" -#include "lwip/timeouts.h" -#include "lwip/udp.h" -#include "lwip/dns.h" -#include "lwip/ip_addr.h" -#include "lwip/pbuf.h" -#include "lwip/dhcp.h" - -#include -#include - -#if LWIP_UDP - -/* Handle support for more than one server via SNTP_MAX_SERVERS */ -#if SNTP_MAX_SERVERS > 1 -#define SNTP_SUPPORT_MULTIPLE_SERVERS 1 -#else /* NTP_MAX_SERVERS > 1 */ -#define SNTP_SUPPORT_MULTIPLE_SERVERS 0 -#endif /* NTP_MAX_SERVERS > 1 */ - -#if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK) -#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!" -#endif - -/* Configure behaviour depending on microsecond or second precision */ -#ifdef SNTP_SET_SYSTEM_TIME_US -#define SNTP_CALC_TIME_US 1 -#define SNTP_RECEIVE_TIME_SIZE 2 -#else -#define SNTP_SET_SYSTEM_TIME_US(sec, us) -#define SNTP_CALC_TIME_US 0 -#define SNTP_RECEIVE_TIME_SIZE 1 -#endif - - -/* the various debug levels for this file */ -#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE) -#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE) -#define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING) -#define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE) -#define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS) - -#define SNTP_ERR_KOD 1 - -/* SNTP protocol defines */ -#define SNTP_MSG_LEN 48 - -#define SNTP_OFFSET_LI_VN_MODE 0 -#define SNTP_LI_MASK 0xC0 -#define SNTP_LI_NO_WARNING 0x00 -#define SNTP_LI_LAST_MINUTE_61_SEC 0x01 -#define SNTP_LI_LAST_MINUTE_59_SEC 0x02 -#define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */ - -#define SNTP_VERSION_MASK 0x38 -#define SNTP_VERSION (4/* NTP Version 4*/<<3) - -#define SNTP_MODE_MASK 0x07 -#define SNTP_MODE_CLIENT 0x03 -#define SNTP_MODE_SERVER 0x04 -#define SNTP_MODE_BROADCAST 0x05 - -#define SNTP_OFFSET_STRATUM 1 -#define SNTP_STRATUM_KOD 0x00 - -#define SNTP_OFFSET_ORIGINATE_TIME 24 -#define SNTP_OFFSET_RECEIVE_TIME 32 -#define SNTP_OFFSET_TRANSMIT_TIME 40 - -/* number of seconds between 1900 and 1970 (MSB=1)*/ -#define DIFF_SEC_1900_1970 (2208988800UL) -/* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */ -#define DIFF_SEC_1970_2036 (2085978496UL) - -/** - * SNTP packet format (without optional fields) - * Timestamps are coded as 64 bits: - * - 32 bits seconds since Jan 01, 1970, 00:00 - * - 32 bits seconds fraction (0-padded) - * For future use, if the MSB in the seconds part is set, seconds are based - * on Feb 07, 2036, 06:28:16. - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct sntp_msg { - PACK_STRUCT_FLD_8(u8_t li_vn_mode); - PACK_STRUCT_FLD_8(u8_t stratum); - PACK_STRUCT_FLD_8(u8_t poll); - PACK_STRUCT_FLD_8(u8_t precision); - PACK_STRUCT_FIELD(u32_t root_delay); - PACK_STRUCT_FIELD(u32_t root_dispersion); - PACK_STRUCT_FIELD(u32_t reference_identifier); - PACK_STRUCT_FIELD(u32_t reference_timestamp[2]); - PACK_STRUCT_FIELD(u32_t originate_timestamp[2]); - PACK_STRUCT_FIELD(u32_t receive_timestamp[2]); - PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/* function prototypes */ -static void sntp_request(void *arg); - -/** The operating mode */ -static u8_t sntp_opmode; - -/** The UDP pcb used by the SNTP client */ -static struct udp_pcb* sntp_pcb; -/** Names/Addresses of servers */ -struct sntp_server { -#if SNTP_SERVER_DNS - char* name; -#endif /* SNTP_SERVER_DNS */ - ip_addr_t addr; -}; -static struct sntp_server sntp_servers[SNTP_MAX_SERVERS]; - -#if SNTP_GET_SERVERS_FROM_DHCP -static u8_t sntp_set_servers_from_dhcp; -#endif /* SNTP_GET_SERVERS_FROM_DHCP */ -#if SNTP_SUPPORT_MULTIPLE_SERVERS -/** The currently used server (initialized to 0) */ -static u8_t sntp_current_server; -#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ -#define sntp_current_server 0 -#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ - -#if SNTP_RETRY_TIMEOUT_EXP -#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT -/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */ -static u32_t sntp_retry_timeout; -#else /* SNTP_RETRY_TIMEOUT_EXP */ -#define SNTP_RESET_RETRY_TIMEOUT() -#define sntp_retry_timeout SNTP_RETRY_TIMEOUT -#endif /* SNTP_RETRY_TIMEOUT_EXP */ - -#if SNTP_CHECK_RESPONSE >= 1 -/** Saves the last server address to compare with response */ -static ip_addr_t sntp_last_server_address; -#endif /* SNTP_CHECK_RESPONSE >= 1 */ - -#if SNTP_CHECK_RESPONSE >= 2 -/** Saves the last timestamp sent (which is sent back by the server) - * to compare against in response */ -static u32_t sntp_last_timestamp_sent[2]; -#endif /* SNTP_CHECK_RESPONSE >= 2 */ - -/** - * SNTP processing of received timestamp - */ -static void -sntp_process(u32_t *receive_timestamp) -{ - /* convert SNTP time (1900-based) to unix GMT time (1970-based) - * if MSB is 0, SNTP time is 2036-based! - */ - u32_t rx_secs = ntohl(receive_timestamp[0]); - int is_1900_based = ((rx_secs & 0x80000000) != 0); - u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036); - time_t tim = t; - -#if SNTP_CALC_TIME_US - u32_t us = ntohl(receive_timestamp[1]) / 4295; - SNTP_SET_SYSTEM_TIME_US(t, us); - /* display local time from GMT time */ - LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us)); - -#else /* SNTP_CALC_TIME_US */ - - /* change system time and/or the update the RTC clock */ - SNTP_SET_SYSTEM_TIME(t); - /* display local time from GMT time */ - LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim))); -#endif /* SNTP_CALC_TIME_US */ - LWIP_UNUSED_ARG(tim); -} - -/** - * Initialize request struct to be sent to server. - */ -static void -sntp_initialize_request(struct sntp_msg *req) -{ - memset(req, 0, SNTP_MSG_LEN); - req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT; - -#if SNTP_CHECK_RESPONSE >= 2 - { - u32_t sntp_time_sec, sntp_time_us; - /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */ - SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us); - sntp_last_timestamp_sent[0] = htonl(sntp_time_sec + DIFF_SEC_1900_1970); - req->transmit_timestamp[0] = sntp_last_timestamp_sent[0]; - /* we send/save us instead of fraction to be faster... */ - sntp_last_timestamp_sent[1] = htonl(sntp_time_us); - req->transmit_timestamp[1] = sntp_last_timestamp_sent[1]; - } -#endif /* SNTP_CHECK_RESPONSE >= 2 */ -} - -/** - * Retry: send a new request (and increase retry timeout). - * - * @param arg is unused (only necessary to conform to sys_timeout) - */ -static void -sntp_retry(void* arg) -{ - LWIP_UNUSED_ARG(arg); - - LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n", - sntp_retry_timeout)); - - /* set up a timer to send a retry and increase the retry delay */ - sys_timeout(sntp_retry_timeout, sntp_request, NULL); - -#if SNTP_RETRY_TIMEOUT_EXP - { - u32_t new_retry_timeout; - /* increase the timeout for next retry */ - new_retry_timeout = sntp_retry_timeout << 1; - /* limit to maximum timeout and prevent overflow */ - if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) && - (new_retry_timeout > sntp_retry_timeout)) { - sntp_retry_timeout = new_retry_timeout; - } - } -#endif /* SNTP_RETRY_TIMEOUT_EXP */ -} - -#if SNTP_SUPPORT_MULTIPLE_SERVERS -/** - * If Kiss-of-Death is received (or another packet parsing error), - * try the next server or retry the current server and increase the retry - * timeout if only one server is available. - * (implicitly, SNTP_MAX_SERVERS > 1) - * - * @param arg is unused (only necessary to conform to sys_timeout) - */ -static void -sntp_try_next_server(void* arg) -{ - u8_t old_server, i; - LWIP_UNUSED_ARG(arg); - - old_server = sntp_current_server; - for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) { - sntp_current_server++; - if (sntp_current_server >= SNTP_MAX_SERVERS) { - sntp_current_server = 0; - } - if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr) -#if SNTP_SERVER_DNS - || (sntp_servers[sntp_current_server].name != NULL) -#endif - ) { - LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n", - (u16_t)sntp_current_server)); - /* new server: reset retry timeout */ - SNTP_RESET_RETRY_TIMEOUT(); - /* instantly send a request to the next server */ - sntp_request(NULL); - return; - } - } - /* no other valid server found */ - sntp_current_server = old_server; - sntp_retry(NULL); -} -#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ -/* Always retry on error if only one server is supported */ -#define sntp_try_next_server sntp_retry -#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ - -/** UDP recv callback for the sntp pcb */ -static void -sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) -{ - u8_t mode; - u8_t stratum; - u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE]; - err_t err; - - LWIP_UNUSED_ARG(arg); - LWIP_UNUSED_ARG(pcb); - - /* packet received: stop retry timeout */ - sys_untimeout(sntp_try_next_server, NULL); - sys_untimeout(sntp_request, NULL); - - err = ERR_ARG; -#if SNTP_CHECK_RESPONSE >= 1 - /* check server address and port */ - if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) && - (port == SNTP_PORT)) -#else /* SNTP_CHECK_RESPONSE >= 1 */ - LWIP_UNUSED_ARG(addr); - LWIP_UNUSED_ARG(port); -#endif /* SNTP_CHECK_RESPONSE >= 1 */ - { - /* process the response */ - if (p->tot_len == SNTP_MSG_LEN) { - pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE); - mode &= SNTP_MODE_MASK; - /* if this is a SNTP response... */ - if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) || - ((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) { - pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM); - if (stratum == SNTP_STRATUM_KOD) { - /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ - err = SNTP_ERR_KOD; - LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n")); - } else { -#if SNTP_CHECK_RESPONSE >= 2 - /* check originate_timetamp against sntp_last_timestamp_sent */ - u32_t originate_timestamp[2]; - pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME); - if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) || - (originate_timestamp[1] != sntp_last_timestamp_sent[1])) - { - LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n")); - } else -#endif /* SNTP_CHECK_RESPONSE >= 2 */ - /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */ - { - /* correct answer */ - err = ERR_OK; - pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME); - } - } - } else { - LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode)); - /* wait for correct response */ - err = ERR_TIMEOUT; - } - } else { - LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len)); - } - } -#if SNTP_CHECK_RESPONSE >= 1 - else { - /* packet from wrong remote address or port, wait for correct response */ - err = ERR_TIMEOUT; - } -#endif /* SNTP_CHECK_RESPONSE >= 1 */ - pbuf_free(p); - if (err == ERR_OK) { - sntp_process(receive_timestamp); - - /* Set up timeout for next request (only if poll response was received)*/ - if (sntp_opmode == SNTP_OPMODE_POLL) { - /* Correct response, reset retry timeout */ - SNTP_RESET_RETRY_TIMEOUT(); - - sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL); - LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n", - (u32_t)SNTP_UPDATE_DELAY)); - } - } else if (err != ERR_TIMEOUT) { - /* Errors are only processed in case of an explicit poll response */ - if (sntp_opmode == SNTP_OPMODE_POLL) { - if (err == SNTP_ERR_KOD) { - /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ - sntp_try_next_server(NULL); - } else { - /* another error, try the same server again */ - sntp_retry(NULL); - } - } - } -} - -/** Actually send an sntp request to a server. - * - * @param server_addr resolved IP address of the SNTP server - */ -static void -sntp_send_request(const ip_addr_t *server_addr) -{ - struct pbuf* p; - p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM); - if (p != NULL) { - struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload; - LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n")); - /* initialize request message */ - sntp_initialize_request(sntpmsg); - /* send request */ - udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT); - /* free the pbuf after sending it */ - pbuf_free(p); - /* set up receive timeout: try next server or retry on timeout */ - sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL); -#if SNTP_CHECK_RESPONSE >= 1 - /* save server address to verify it in sntp_recv */ - ip_addr_set(&sntp_last_server_address, server_addr); -#endif /* SNTP_CHECK_RESPONSE >= 1 */ - } else { - LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n", - (u32_t)SNTP_RETRY_TIMEOUT)); - /* out of memory: set up a timer to send a retry */ - sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL); - } -} - -#if SNTP_SERVER_DNS -/** - * DNS found callback when using DNS names as server address. - */ -static void -sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg) -{ - LWIP_UNUSED_ARG(hostname); - LWIP_UNUSED_ARG(arg); - - if (ipaddr != NULL) { - /* Address resolved, send request */ - LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n")); - sntp_send_request(ipaddr); - } else { - /* DNS resolving failed -> try another server */ - LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n")); - sntp_try_next_server(NULL); - } -} -#endif /* SNTP_SERVER_DNS */ - -/** - * Send out an sntp request. - * - * @param arg is unused (only necessary to conform to sys_timeout) - */ -static void -sntp_request(void *arg) -{ - ip_addr_t sntp_server_address; - err_t err; - - LWIP_UNUSED_ARG(arg); - - /* initialize SNTP server address */ -#if SNTP_SERVER_DNS - if (sntp_servers[sntp_current_server].name) { - /* always resolve the name and rely on dns-internal caching & timeout */ - ip_addr_set_zero(&sntp_servers[sntp_current_server].addr); - err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address, - sntp_dns_found, NULL); - if (err == ERR_INPROGRESS) { - /* DNS request sent, wait for sntp_dns_found being called */ - LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n")); - return; - } else if (err == ERR_OK) { - sntp_servers[sntp_current_server].addr = sntp_server_address; - } - } else -#endif /* SNTP_SERVER_DNS */ - { - sntp_server_address = sntp_servers[sntp_current_server].addr; - err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK; - } - - if (err == ERR_OK) { - LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n", - ipaddr_ntoa(&sntp_server_address))); - sntp_send_request(&sntp_server_address); - } else { - /* address conversion failed, try another server */ - LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n")); - sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL); - } -} - -/** - * @ingroup sntp - * Initialize this module. - * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC). - */ -void -sntp_init(void) -{ -#ifdef SNTP_SERVER_ADDRESS -#if SNTP_SERVER_DNS - sntp_setservername(0, SNTP_SERVER_ADDRESS); -#else -#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0 -#endif -#endif /* SNTP_SERVER_ADDRESS */ - - if (sntp_pcb == NULL) { - sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); - LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL); - if (sntp_pcb != NULL) { - udp_recv(sntp_pcb, sntp_recv, NULL); - - if (sntp_opmode == SNTP_OPMODE_POLL) { - SNTP_RESET_RETRY_TIMEOUT(); -#if SNTP_STARTUP_DELAY - sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL); -#else - sntp_request(NULL); -#endif - } else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) { - ip_set_option(sntp_pcb, SOF_BROADCAST); - udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT); - } - } - } -} - -/** - * @ingroup sntp - * Stop this module. - */ -void -sntp_stop(void) -{ - if (sntp_pcb != NULL) { - sys_untimeout(sntp_request, NULL); - udp_remove(sntp_pcb); - sntp_pcb = NULL; - } -} - -/** - * @ingroup sntp - * Get enabled state. - */ -u8_t sntp_enabled(void) -{ - return (sntp_pcb != NULL)? 1 : 0; -} - -/** - * @ingroup sntp - * Sets the operating mode. - * @param operating_mode one of the available operating modes - */ -void -sntp_setoperatingmode(u8_t operating_mode) -{ - LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY); - LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL); - sntp_opmode = operating_mode; -} - -/** - * @ingroup sntp - * Gets the operating mode. - */ -u8_t -sntp_getoperatingmode(void) -{ - return sntp_opmode; -} - -#if SNTP_GET_SERVERS_FROM_DHCP -/** - * Config SNTP server handling by IP address, name, or DHCP; clear table - * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp - */ -void -sntp_servermode_dhcp(int set_servers_from_dhcp) -{ - u8_t new_mode = set_servers_from_dhcp ? 1 : 0; - if (sntp_set_servers_from_dhcp != new_mode) { - sntp_set_servers_from_dhcp = new_mode; - } -} -#endif /* SNTP_GET_SERVERS_FROM_DHCP */ - -/** - * @ingroup sntp - * Initialize one of the NTP servers by IP address - * - * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS - * @param server IP address of the NTP server to set - */ -void -sntp_setserver(u8_t idx, const ip_addr_t *server) -{ - if (idx < SNTP_MAX_SERVERS) { - if (server != NULL) { - sntp_servers[idx].addr = (*server); - } else { - ip_addr_set_zero(&sntp_servers[idx].addr); - } -#if SNTP_SERVER_DNS - sntp_servers[idx].name = NULL; -#endif - } -} - -#if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP -/** - * Initialize one of the NTP servers by IP address, required by DHCP - * - * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS - * @param dnsserver IP address of the NTP server to set - */ -void -dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server) -{ - LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n", - (sntp_set_servers_from_dhcp ? "Got" : "Rejected"), - ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num)); - if (sntp_set_servers_from_dhcp && num) { - u8_t i; - for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) { - ip_addr_t addr; - ip_addr_copy_from_ip4(addr, server[i]); - sntp_setserver(i, &addr); - } - for (i = num; i < SNTP_MAX_SERVERS; i++) { - sntp_setserver(i, NULL); - } - } -} -#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */ - -/** - * @ingroup sntp - * Obtain one of the currently configured by IP address (or DHCP) NTP servers - * - * @param idx the index of the NTP server - * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP - * server has not been configured by address (or at all). - */ -const ip_addr_t* -sntp_getserver(u8_t idx) -{ - if (idx < SNTP_MAX_SERVERS) { - return &sntp_servers[idx].addr; - } - return IP_ADDR_ANY; -} - -#if SNTP_SERVER_DNS -/** - * Initialize one of the NTP servers by name - * - * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS - * @param dnsserver DNS name of the NTP server to set, to be resolved at contact time - */ -void -sntp_setservername(u8_t idx, char *server) -{ - if (idx < SNTP_MAX_SERVERS) { - sntp_servers[idx].name = server; - } -} - -/** - * Obtain one of the currently configured by name NTP servers. - * - * @param numdns the index of the NTP server - * @return IP address of the indexed NTP server or NULL if the NTP - * server has not been configured by name (or at all) - */ -char * -sntp_getservername(u8_t idx) -{ - if (idx < SNTP_MAX_SERVERS) { - return sntp_servers[idx].name; - } - return NULL; -} -#endif /* SNTP_SERVER_DNS */ - -#endif /* LWIP_UDP */ diff --git a/ext/lwip/src/core/def.c b/ext/lwip/src/core/def.c deleted file mode 100644 index bb4b8e0..0000000 --- a/ext/lwip/src/core/def.c +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @file - * Common functions used throughout the stack. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - -#include "lwip/opt.h" -#include "lwip/def.h" - -/** - * These are reference implementations of the byte swapping functions. - * Again with the aim of being simple, correct and fully portable. - * Byte swapping is the second thing you would want to optimize. You will - * need to port it to your architecture and in your cc.h: - * - * #define LWIP_PLATFORM_BYTESWAP 1 - * #define LWIP_PLATFORM_HTONS(x) - * #define LWIP_PLATFORM_HTONL(x) - * - * Note ntohs() and ntohl() are merely references to the htonx counterparts. - */ - -#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) - -/** - * Convert an u16_t from host- to network byte order. - * - * @param n u16_t in host byte order - * @return n in network byte order - */ -u16_t -lwip_htons(u16_t n) -{ - return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); -} - -/** - * Convert an u16_t from network- to host byte order. - * - * @param n u16_t in network byte order - * @return n in host byte order - */ -u16_t -lwip_ntohs(u16_t n) -{ - return lwip_htons(n); -} - -/** - * Convert an u32_t from host- to network byte order. - * - * @param n u32_t in host byte order - * @return n in network byte order - */ -u32_t -lwip_htonl(u32_t n) -{ - return ((n & 0xff) << 24) | - ((n & 0xff00) << 8) | - ((n & 0xff0000UL) >> 8) | - ((n & 0xff000000UL) >> 24); -} - -/** - * Convert an u32_t from network- to host byte order. - * - * @param n u32_t in network byte order - * @return n in host byte order - */ -u32_t -lwip_ntohl(u32_t n) -{ - return lwip_htonl(n); -} - -#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */ diff --git a/ext/lwip/src/core/dns.c b/ext/lwip/src/core/dns.c deleted file mode 100644 index 9aed473..0000000 --- a/ext/lwip/src/core/dns.c +++ /dev/null @@ -1,1502 +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. - */ - -/** - * @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). - * - * All functions must be called from TCPIP thread. - * - * @see @ref netconn_common for thread-safe access. - */ - -/*----------------------------------------------------------------------------- - * RFC 1035 - Domain names - implementation and specification - * RFC 2181 - Clarifications to the DNS Specification - *----------------------------------------------------------------------------*/ - -/** @todo: define good default values (rfc compliance) */ -/** @todo: improve answer parsing, more checkings... */ -/** @todo: check RFC1035 - 7.3. Processing responses */ - -/*----------------------------------------------------------------------------- - * Includes - *----------------------------------------------------------------------------*/ - -#include "lwip/opt.h" - -#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/udp.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/dns.h" - -#include - -/** 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 server port address */ -#ifndef DNS_SERVER_PORT -#define DNS_SERVER_PORT 53 -#endif - -/** DNS maximum number of retries when asking for a name, before "timeout". */ -#ifndef DNS_MAX_RETRIES -#define DNS_MAX_RETRIES 4 -#endif - -/** DNS resource record max. TTL (one week as default) */ -#ifndef DNS_MAX_TTL -#define DNS_MAX_TTL 604800 -#elif DNS_MAX_TTL > 0x7FFFFFFF -#error DNS_MAX_TTL must be a positive 32-bit value -#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 -#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 -#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 */ - -/** 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 */ - -/** DNS field CLASS used for "Resource Records" */ -#define DNS_RRCLASS_IN 1 /* the Internet */ -#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ -#define DNS_RRCLASS_CH 3 /* the CHAOS class */ -#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ -#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ - -/* DNS protocol flags */ -#define DNS_FLAG1_RESPONSE 0x80 -#define DNS_FLAG1_OPCODE_STATUS 0x10 -#define DNS_FLAG1_OPCODE_INVERSE 0x08 -#define DNS_FLAG1_OPCODE_STANDARD 0x00 -#define DNS_FLAG1_AUTHORATIVE 0x04 -#define DNS_FLAG1_TRUNC 0x02 -#define DNS_FLAG1_RD 0x01 -#define DNS_FLAG2_RA 0x80 -#define DNS_FLAG2_ERR_MASK 0x0f -#define DNS_FLAG2_ERR_NONE 0x00 -#define DNS_FLAG2_ERR_NAME 0x03 - -/* DNS protocol states */ -#define DNS_STATE_UNUSED 0 -#define DNS_STATE_NEW 1 -#define DNS_STATE_ASKING 2 -#define DNS_STATE_DONE 3 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** DNS message header */ -struct dns_hdr { - PACK_STRUCT_FIELD(u16_t id); - PACK_STRUCT_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 - -/** 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 */ -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 */ -}; - -/** 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); -#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]; - -#ifndef LWIP_DNS_STRICMP -#define LWIP_DNS_STRICMP(str1, str2) dns_stricmp(str1, str2) -/** - * A small but sufficient implementation for case insensitive strcmp. - * This can be defined to e.g. stricmp for windows or strcasecmp for linux. */ -static int -dns_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 /* LWIP_DNS_STRICMP */ - -/** - * 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 - * 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. - * @return ERR_OK if found, ERR_ARG if not found - */ -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_DNS_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_DNS_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_DNS_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 || defined(DNS_LOOKUP_LOCAL_EXTERN) -#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */ -#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_DNS_STRICMP(name, 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(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). - * - * @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) -{ - unsigned char n; - u16_t response_offset = start_offset; - - do { - n = pbuf_get_at(p, 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) { - if ((*query) != pbuf_get_at(p, response_offset)) { - return 0xFFFF; - } - ++response_offset; - ++query; - --n; - } - ++query; - } - } while (pbuf_get_at(p, response_offset) != 0); - - return 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_parse_name(struct pbuf* p, u16_t query_idx) -{ - unsigned char n; - - do { - n = pbuf_get_at(p, query_idx++); - /** @see RFC 1035 - 4.1.4. Message compression */ - if ((n & 0xc0) == 0xc0) { - /* Compressed name */ - break; - } else { - /* Not compressed name */ - while (n > 0) { - ++query_idx; - --n; - } - } - } while (pbuf_get_at(p, query_idx) != 0); - - return query_idx + 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])) { - /* 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) { - /* fill dns header */ - memset(&hdr, 0, SIZEOF_DNS_HDR); - hdr.id = 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); - pbuf_put_at(p, query_idx, n); - pbuf_take_at(p, hostname_part, copy_len, query_idx + 1); - 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)); - err = udp_sendto(dns_pcbs[pcb_idx], p, &dns_servers[entry->server_idx], DNS_SERVER_PORT); - - /* free pbuf */ - pbuf_free(p); - } else { - err = ERR_MEM; - } - - return err; -} - -#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* ret; - - ret = udp_new_ip_type(IPADDR_TYPE_ANY); - if (ret == 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)) { - /* this port is not allowed, try again */ - err = ERR_USE; - continue; - } - err = udp_bind(ret, IP_ANY_TYPE, port); - } while (err == ERR_USE); - if (err != ERR_OK) { - udp_remove(ret); - return NULL; - } - udp_recv(ret, dns_recv, NULL); - return ret; -} - -/** - * 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 */ - for (i = 0, idx = 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; -} - -/** - * 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: { - u16_t txid; - /* initialize new entry */ - txid = dns_create_txid(); - entry->txid = 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 ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1])) { - /* 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(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. - * - * @params see udp.h - */ -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 memerr; - } - - /* 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 = htons(hdr.id); - for (i = 0; i < DNS_TABLE_SIZE; i++) { - const 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 = htons(hdr.numquestions); - nanswers = 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 memerr; /* ignore this packet */ - } - if (nquestions != 1) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); - goto memerr; /* ignore this packet */ - } - - /* 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 memerr; /* 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 memerr; /* ignore this packet */ - } - - /* check if "question" part matches the request */ - pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx); - 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 memerr; /* ignore this packet */ - } - /* skip the rest of the "question" part */ - 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)); - } else { - while ((nanswers > 0) && (res_idx < p->tot_len)) { - /* skip answer resource record's host name */ - res_idx = dns_parse_name(p, res_idx); - - /* Check for IP address type and Internet class. Others are discarded. */ - pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx); - 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 */ - pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx); - ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr); - pbuf_free(p); - /* handle correct response */ - dns_correct_response(i, 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_t)))) { -#if LWIP_IPV4 && LWIP_IPV6 - if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - { - ip6_addr_t ip6addr; - /* read the IP address after answer resource record's header */ - pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_t), res_idx); - ip_addr_copy_from_ip6(dns_table[i].ipaddr, ip6addr); - pbuf_free(p); - /* handle correct response */ - dns_correct_response(i, ntohl(ans.ttl)); - return; - } - } -#endif /* LWIP_IPV6 */ - } - /* skip this answer */ - res_idx += 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; - } - } - } - -memerr: - /* 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 @return a 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)) -{ - 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_DNS_STRICMP(name, 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) { - if ((u8_t)(dns_seqno - entry->seqno) > lseq) { - lseq = dns_seqno - entry->seqno; - lseqi = i; - } - } - } - - /* if we don't have found an unused entry, use the oldest completed one */ - if (i == DNS_TABLE_SIZE) { - if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { - /* no entry can 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 - - 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; - /* 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 */ - - /* 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)); -} - -#endif /* LWIP_DNS */ diff --git a/ext/lwip/src/core/inet_chksum.c b/ext/lwip/src/core/inet_chksum.c deleted file mode 100644 index 57cbad7..0000000 --- a/ext/lwip/src/core/inet_chksum.c +++ /dev/null @@ -1,612 +0,0 @@ -/** - * @file - * Incluse internet checksum functions. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/opt.h" - -#include "lwip/inet_chksum.h" -#include "lwip/def.h" -#include "lwip/ip_addr.h" - -#include -#include - -/* These are some reference implementations of the checksum algorithm, with the - * aim of being simple, correct and fully portable. Checksumming is the - * first thing you would want to optimize for your platform. If you create - * your own version, link it in and in your cc.h put: - * - * #define LWIP_CHKSUM - * - * Or you can select from the implementations below by defining - * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3. - */ - -#ifndef LWIP_CHKSUM -# define LWIP_CHKSUM lwip_standard_chksum -# ifndef LWIP_CHKSUM_ALGORITHM -# define LWIP_CHKSUM_ALGORITHM 2 -# endif -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 htons() - instead of ntohs() since it has a little less call overhead. - The caller must invert bits for Internet sum ! */ - return htons((u16_t)acc); -} -#endif - -#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */ -/* - * Curt McDowell - * Broadcom Corp. - * csm@broadcom.com - * - * IP checksum two bytes at a time with support for - * unaligned buffer. - * Works for len up to and including 0x20000. - * by Curt McDowell, Broadcom Corp. 12/08/2005 - * - * @param dataptr points to start of data to be summed at any boundary - * @param len length of data to be summed - * @return host order (!) lwip checksum (non-inverted Internet sum) - */ -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; - u8_t swapped = 0; - - /* iterate through all pbuf in chain */ - for (q = p; q != NULL; q = q->next) { - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", - (void *)q, (void *)q->next)); - acc += LWIP_CHKSUM(q->payload, q->len); - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ - /* just executing this next line is probably faster that the if statement needed - to check whether we really need to execute it, and does no harm */ - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ - } - - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - - acc += (u32_t)htons((u16_t)proto); - acc += (u32_t)htons(proto_len); - - /* Fold 32-bit sum to 16 bits - calling this twice is probably faster than if statements... */ - 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 += ((addr >> 16) & 0xffffUL); - addr = ip4_addr_get_u32(dest); - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - /* fold down to 16 bits */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - - return inet_cksum_pseudo_base(p, proto, proto_len, acc); -} -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -/** - * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. - * IPv6 addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param proto ipv6 protocol/next header (used for checksum of pseudo header) - * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) - * @param src source ipv6 address (used for checksum of pseudo header) - * @param dest destination ipv6 address (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, - const ip6_addr_t *src, const ip6_addr_t *dest) -{ - u32_t acc = 0; - u32_t addr; - u8_t addr_part; - - for (addr_part = 0; addr_part < 4; addr_part++) { - addr = src->addr[addr_part]; - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - addr = dest->addr[addr_part]; - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - } - /* fold down to 16 bits */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - - return inet_cksum_pseudo_base(p, proto, proto_len, acc); -} -#endif /* LWIP_IPV6 */ - -/* ip_chksum_pseudo: - * - * Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * IP addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, - const ip_addr_t *src, const ip_addr_t *dest) -{ -#if LWIP_IPV6 - if (IP_IS_V6(dest)) { - return ip6_chksum_pseudo(p, proto, proto_len, ip_2_ip6(src), ip_2_ip6(dest)); - } -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 && LWIP_IPV6 - else -#endif /* LWIP_IPV4 && LWIP_IPV6 */ -#if LWIP_IPV4 - { - return inet_chksum_pseudo(p, proto, proto_len, ip_2_ip4(src), ip_2_ip4(dest)); - } -#endif /* LWIP_IPV4 */ -} - -/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ -static u16_t -inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, u32_t acc) -{ - struct pbuf *q; - u8_t swapped = 0; - 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 -= chklen; - LWIP_ASSERT("delete me", chksum_len < 0x7fff); - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ - /* fold the upper bit down */ - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ - } - - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - - acc += (u32_t)htons((u16_t)proto); - acc += (u32_t)htons(proto_len); - - /* Fold 32-bit sum to 16 bits - calling this twice is probably faster than if statements... */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); - return (u16_t)~(acc & 0xffffUL); -} - -#if LWIP_IPV4 -/* inet_chksum_pseudo_partial: - * - * Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * IP addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, const ip4_addr_t *src, const ip4_addr_t *dest) -{ - u32_t acc; - u32_t addr; - - addr = ip4_addr_get_u32(src); - acc = (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - addr = ip4_addr_get_u32(dest); - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - /* fold down to 16 bits */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - - return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); -} -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -/** - * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. - * IPv6 addresses are expected to be in network byte order. Will only compute for a - * portion of the payload. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param proto ipv6 protocol/next header (used for checksum of pseudo header) - * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) - * @param chksum_len number of payload bytes used to compute chksum - * @param src source ipv6 address (used for checksum of pseudo header) - * @param dest destination ipv6 address (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, const ip6_addr_t *src, const ip6_addr_t *dest) -{ - u32_t acc = 0; - u32_t addr; - u8_t addr_part; - - for (addr_part = 0; addr_part < 4; addr_part++) { - addr = src->addr[addr_part]; - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - addr = dest->addr[addr_part]; - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - } - /* fold down to 16 bits */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - - return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); -} -#endif /* LWIP_IPV6 */ - -/* ip_chksum_pseudo_partial: - * - * Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest) -{ -#if LWIP_IPV6 - if (IP_IS_V6(dest)) { - return ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip6(src), ip_2_ip6(dest)); - } -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 && LWIP_IPV6 - else -#endif /* LWIP_IPV4 && LWIP_IPV6 */ -#if LWIP_IPV4 - { - return inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip4(src), ip_2_ip4(dest)); - } -#endif /* LWIP_IPV4 */ -} - -/* 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; - u8_t swapped; - - acc = 0; - swapped = 0; - for (q = p; q != NULL; q = q->next) { - acc += LWIP_CHKSUM(q->payload, q->len); - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - } - - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - return (u16_t)~(acc & 0xffffUL); -} - -/* These are some implementations for LWIP_CHKSUM_COPY, which copies data - * like MEMCPY but generates a checksum at the same time. Since this is a - * performance-sensitive function, you might want to create your own version - * in assembly targeted at your hardware by defining it in lwipopts.h: - * #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len) - */ - -#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */ -/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM. - * For architectures with big caches, data might still be in cache when - * generating the checksum after copying. - */ -u16_t -lwip_chksum_copy(void *dst, const void *src, u16_t len) -{ - MEMCPY(dst, src, len); - return LWIP_CHKSUM(dst, len); -} -#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */ diff --git a/ext/lwip/src/core/init.c b/ext/lwip/src/core/init.c deleted file mode 100644 index 092cd2b..0000000 --- a/ext/lwip/src/core/init.c +++ /dev/null @@ -1,388 +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 - */ - -/** - * @defgroup lwip_nosys Mainloop mode ("NO_SYS") - * @ingroup lwip - * Use this mode if you do not run an OS on your system. \#define NO_SYS to 1. - * Feed incoming packets to netif->input(pbuf, netif) function from mainloop, - * *not* *from* *interrupt* *context*. You can allocate a @ref pbuf in interrupt - * context and put them into a queue which is processed from mainloop.\n - * Call sys_check_timeouts() periodically in the mainloop.\n - * Porting: implement all functions in @ref sys_time and @ref sys_prot.\n - * You can only use @ref callbackstyle_api in this mode. - * - * @defgroup lwip_os OS mode (TCPIP thread) - * @ingroup lwip - * Use this mode if you run an OS on your system. It is recommended to - * use an RTOS that correctly handles priority inversion and - * to use LWIP_TCPIP_CORE_LOCKING.\n - * Porting: implement all functions in @ref sys_layer.\n - * You can use @ref callbackstyle_api together with \#define tcpip_callback, - * and all @ref threadsafe_api. - */ - -#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/autoip.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" -#include "lwip/timeouts.h" -#include "lwip/etharp.h" -#include "lwip/ip6.h" -#include "lwip/nd6.h" -#include "lwip/mld6.h" -#include "lwip/api.h" - -#include "netif/ppp/ppp_opts.h" -#include "netif/ppp/ppp_impl.h" - -/* Compile-time sanity checks for configuration errors. - * These can be done independently of LWIP_DEBUG, without penalty. - */ -#ifndef BYTE_ORDER - #error "BYTE_ORDER is not defined, you have to define it in your cc.h" -#endif -#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) - #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" -#endif -#if (!LWIP_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_MULTICAST_TX_OPTIONS) - #error "If you want to use IGMP/LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 in your lwipopts.h" -#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_MULTICAST_TX_OPTIONS && !LWIP_IPV4) - #error "LWIP_MULTICAST_TX_OPTIONS needs LWIP_IPV4 enabled in your lwipopts.h" -#endif -#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0)) - #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" -#endif -/* There must be sufficient timeouts, taking into account requirements of the subsystems. */ -#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0))) - #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 && LWIP_WND_SCALE && (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_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 (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_IGMP || LWIP_IPV6) && !defined(LWIP_RAND) - #error "When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value" -#endif -#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING - #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" -#endif -#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE - #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" -#endif -#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF - #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues" -#endif -#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 -/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ -#if SO_REUSEADDR != SOF_REUSEADDR - #error "WARNING: SO_REUSEADDR != SOF_REUSEADDR" -#endif -#if SO_KEEPALIVE != SOF_KEEPALIVE - #error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE" -#endif -#if SO_BROADCAST != SOF_BROADCAST - #error "WARNING: SO_BROADCAST != SOF_BROADCAST" -#endif -#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_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 && (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) -{ - /* 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_AUTOIP - autoip_init(); -#endif /* LWIP_AUTOIP */ -#if LWIP_IGMP - igmp_init(); -#endif /* LWIP_IGMP */ -#if LWIP_DNS - dns_init(); -#endif /* LWIP_DNS */ -#if PPP_SUPPORT - ppp_init(); -#endif - -#if LWIP_TIMERS - sys_timeouts_init(); -#endif /* LWIP_TIMERS */ -} diff --git a/ext/lwip/src/core/ip.c b/ext/lwip/src/core/ip.c deleted file mode 100644 index a1685e3..0000000 --- a/ext/lwip/src/core/ip.c +++ /dev/null @@ -1,124 +0,0 @@ -/** - * @file ip.c - * Common IPv4 and IPv6 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 - * - */ - -/** - * @defgroup ip4 IPv4 - * @ingroup callbackstyle_api - * - * @defgroup ip6 IPv6 - * @ingroup callbackstyle_api - * - * @defgroup ipaddr IP address handling - * @ingroup infrastructure - * - * @defgroup ip4addr IPv4 only - * @ingroup ipaddr - * - * @defgroup ip6addr IPv6 only - * @ingroup ipaddr - */ - -#include "lwip/opt.h" - -#if LWIP_IPV4 || LWIP_IPV6 - -#include "lwip/ip_addr.h" -#include "lwip/ip.h" - -/** Global data for both IPv4 and IPv6 */ -struct ip_globals ip_data; - -#if LWIP_IPV4 && LWIP_IPV6 - -const ip_addr_t ip_addr_any_type = IPADDR_ANY_TYPE_INIT; - -/** - * @ingroup ipaddr - * Convert IP address string (both versions) to numeric. - * The version is auto-detected from the string. - * - * @param cp IP address string to convert - * @param addr conversion result is stored here - * @return 1 on success, 0 on error - */ -int -ipaddr_aton(const char *cp, ip_addr_t *addr) -{ - if (cp != NULL) { - const char* c; - for (c = cp; *c != 0; c++) { - if (*c == ':') { - /* contains a colon: IPv6 address */ - if (addr) { - IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6); - } - return ip6addr_aton(cp, ip_2_ip6(addr)); - } else if (*c == '.') { - /* contains a dot: IPv4 address */ - break; - } - } - /* call ip4addr_aton as fallback or if IPv4 was found */ - if (addr) { - IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4); - } - return ip4addr_aton(cp, ip_2_ip4(addr)); - } - return 0; -} - -/** - * @ingroup lwip_nosys - * If both IP versions are enabled, this function can dispatch packets to the correct one. - * Don't call directly, pass to netif_add() and call netif->input(). - */ -err_t -ip_input(struct pbuf *p, struct netif *inp) -{ - if (p != NULL) { - if (IP_HDR_GET_VERSION(p->payload) == 6) { - return ip6_input(p, inp); - } - return ip4_input(p, inp); - } - return ERR_VAL; -} - -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - -#endif /* LWIP_IPV4 || LWIP_IPV6 */ diff --git a/ext/lwip/src/core/ipv4/autoip.c b/ext/lwip/src/core/ipv4/autoip.c deleted file mode 100644 index 8ca2671..0000000 --- a/ext/lwip/src/core/ipv4/autoip.c +++ /dev/null @@ -1,546 +0,0 @@ -/** - * @file - * AutoIP Automatic LinkLocal IP Configuration - * - */ - -/* - * - * Copyright (c) 2007 Dominik Spies - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dominik Spies - * - * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform - * with RFC 3927. - * - * - * Please coordinate changes and requests with Dominik Spies - * - */ - -/******************************************************************************* - * USAGE: - * - * define LWIP_AUTOIP 1 in your lwipopts.h - * - * If you don't use tcpip.c (so, don't call, you don't call tcpip_init): - * - First, call autoip_init(). - * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces, - * that should be defined in autoip.h. - * I recommend a value of 100. The value must divide 1000 with a remainder almost 0. - * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... - * - * Without DHCP: - * - Call autoip_start() after netif_add(). - * - * With DHCP: - * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h. - * - Configure your DHCP Client. - * - */ - -/** - * @defgroup autoip AUTOIP - * @ingroup ip4 - * AUTOIP related functions - * @see netifapi_autoip - */ - -#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 -#include - -/* 169.254.0.0 */ -#define AUTOIP_NET 0xA9FE0000 -/* 169.254.1.0 */ -#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) -/* 169.254.254.255 */ -#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) - -/* RFC 3927 Constants */ -#define PROBE_WAIT 1 /* second (initial random delay) */ -#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ -#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ -#define PROBE_NUM 3 /* (number of probe packets) */ -#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ -#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ -#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ -#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ -#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ -#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ - -/* AutoIP client states */ -#define AUTOIP_STATE_OFF 0 -#define AUTOIP_STATE_PROBING 1 -#define AUTOIP_STATE_ANNOUNCING 2 -#define AUTOIP_STATE_BOUND 3 - -/** Pseudo random macro based on netif informations. - * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ -#ifndef LWIP_AUTOIP_RAND -#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ - ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ - ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ - ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ - (netif->autoip?netif->autoip->tried_llipaddr:0)) -#endif /* LWIP_AUTOIP_RAND */ - -/** - * Macro that generates the initial IP address to be tried by AUTOIP. - * If you want to override this, define it to something else in lwipopts.h. - */ -#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR -#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ - htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \ - ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) -#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ - -/* static functions */ -static 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("netif != NULL", netif != NULL); - LWIP_ASSERT("autoip != NULL", autoip != NULL); - LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL); - - /* clear data structure */ - memset(autoip, 0, sizeof(struct autoip)); - /* autoip->state = AUTOIP_STATE_OFF; */ - netif->autoip = autoip; -} - -/** Restart AutoIP client and check the next address (conflict detected) - * - * @param netif The netif under AutoIP control - */ -static void -autoip_restart(struct netif *netif) -{ - netif->autoip->tried_llipaddr++; - autoip_start(netif); -} - -/** - * Handle a IP address conflict after an ARP conflict detection - */ -static void -autoip_handle_arp_conflict(struct netif *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 (netif->autoip->lastconflict > 0) { - /* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); - - /* 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); - 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) -{ - /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 - * compliant to RFC 3927 Section 2.1 - * We have 254 * 256 possibilities */ - - u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); - addr += netif->autoip->tried_llipaddr; - addr = AUTOIP_NET | (addr & 0xffff); - /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ - - if (addr < AUTOIP_RANGE_START) { - addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; - } - if (addr > AUTOIP_RANGE_END) { - addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; - } - LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && - (addr <= AUTOIP_RANGE_END)); - ip4_addr_set_u32(ipaddr, htonl(addr)); - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), - ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); -} - -/** - * Sends an ARP probe from a network interface - * - * @param netif network interface used to send the probe - */ -static err_t -autoip_arp_probe(struct netif *netif) -{ - /* this works because netif->ip_addr is ANY */ - return etharp_request(netif, &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; - 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; - err_t result = ERR_OK; - - 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_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY); - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], - netif->name[1], (u16_t)netif->num)); - if (autoip == NULL) { - /* no AutoIP client attached yet? */ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_start(): starting new AUTOIP client\n")); - autoip = (struct autoip *)mem_malloc(sizeof(struct autoip)); - if (autoip == NULL) { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_start(): could not allocate autoip\n")); - return ERR_MEM; - } - memset(autoip, 0, sizeof(struct autoip)); - /* store this AutoIP client in the netif */ - netif->autoip = autoip; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); - } else { - autoip->state = AUTOIP_STATE_OFF; - autoip->ttw = 0; - autoip->sent_num = 0; - 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; - - autoip->state = AUTOIP_STATE_PROBING; - autoip->sent_num = 0; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), - ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); - - /* time to wait to first probe, this is randomly - * 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) -{ - if (netif->autoip && netif->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) -{ - if (netif->autoip) { - netif->autoip->state = AUTOIP_STATE_OFF; - if (ip4_addr_islinklocal(netif_ip4_addr(netif))) { - netif_set_addr(netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY); - } - } - return ERR_OK; -} - -/** - * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds - */ -void -autoip_tmr(void) -{ - struct netif *netif = netif_list; - /* loop through netif's */ - while (netif != NULL) { - /* only act on AutoIP configured interfaces */ - if (netif->autoip != NULL) { - if (netif->autoip->lastconflict > 0) { - netif->autoip->lastconflict--; - } - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", - (u16_t)(netif->autoip->state), netif->autoip->ttw)); - - if (netif->autoip->ttw > 0) { - netif->autoip->ttw--; - } - - switch(netif->autoip->state) { - case AUTOIP_STATE_PROBING: - if (netif->autoip->ttw == 0) { - if (netif->autoip->sent_num >= PROBE_NUM) { - /* Switch to ANNOUNCING: now we can bind to an IP address and use it */ - netif->autoip->state = AUTOIP_STATE_ANNOUNCING; - autoip_bind(netif); - /* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP - which counts as an announcement */ - netif->autoip->sent_num = 1; - netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), - ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); - } else { - autoip_arp_probe(netif); - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n")); - netif->autoip->sent_num++; - if (netif->autoip->sent_num == PROBE_NUM) { - /* calculate time to wait to for announce */ - netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; - } else { - /* calculate time to wait to next probe */ - netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % - ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + - PROBE_MIN * AUTOIP_TICKS_PER_SECOND); - } - } - } - break; - - case AUTOIP_STATE_ANNOUNCING: - if (netif->autoip->ttw == 0) { - autoip_arp_announce(netif); - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n")); - netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; - netif->autoip->sent_num++; - - if (netif->autoip->sent_num >= ANNOUNCE_NUM) { - netif->autoip->state = AUTOIP_STATE_BOUND; - netif->autoip->sent_num = 0; - netif->autoip->ttw = 0; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), - ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); - } - } - break; - - default: - /* nothing to do in other states */ - break; - } - } - /* proceed to next network interface */ - netif = netif->next; - } -} - -/** - * Handles every incoming ARP Packet, called by etharp_arp_input. - * - * @param netif network interface to use for autoip processing - * @param hdr Incoming ARP packet - */ -void -autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) -{ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); - if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { - /* when ip.src == llipaddr && hw.src != netif->hwaddr - * - * when probing ip.dst == llipaddr && hw.src != netif->hwaddr - * we have a conflict and must solve it - */ - ip4_addr_t sipaddr, dipaddr; - struct eth_addr netifaddr; - ETHADDR16_COPY(netifaddr.addr, netif->hwaddr); - - /* Copy struct ip4_addr2 to aligned ip4_addr, to support compilers without - * structure packing (not using structure copy which breaks strict-aliasing rules). - */ - IPADDR2_COPY(&sipaddr, &hdr->sipaddr); - IPADDR2_COPY(&dipaddr, &hdr->dipaddr); - - if (netif->autoip->state == AUTOIP_STATE_PROBING) { - /* 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, &netif->autoip->llipaddr)) || - (ip4_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && - !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, - ("autoip_arp_reply(): Probe Conflict detected\n")); - autoip_restart(netif); - } - } else { - /* RFC 3927 Section 2.5: - * in any state we have a conflict if - * ip.src == llipaddr && hw.src != own hwaddr - */ - if (ip4_addr_cmp(&sipaddr, &netif->autoip->llipaddr) && - !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, - ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); - autoip_handle_arp_conflict(netif); - } - } - } -} - -/** 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 != NULL)) { - if ((netif->autoip->state == AUTOIP_STATE_BOUND) || - (netif->autoip->state == AUTOIP_STATE_ANNOUNCING)) { - return 1; - } - } - return 0; -} - -#endif /* LWIP_IPV4 && LWIP_AUTOIP */ diff --git a/ext/lwip/src/core/ipv4/dhcp.c b/ext/lwip/src/core/ipv4/dhcp.c deleted file mode 100644 index b3307da..0000000 --- a/ext/lwip/src/core/ipv4/dhcp.c +++ /dev/null @@ -1,1924 +0,0 @@ -/** - * @file - * Dynamic Host Configuration Protocol client - * - */ - -/* - * Copyright (c) 2001-2004 Leon Woestenberg - * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is 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 - * - * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform - * with RFC 2131 and RFC 2132. - * - * @todo: - * - Support for interfaces other than Ethernet (SLIP, PPP, ...) - * - * Please coordinate changes and requests with Leon Woestenberg - * - * - * Integration with your code: - * - * In lwip/dhcp.h - * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) - * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) - * - * Then have your application call dhcp_coarse_tmr() and - * dhcp_fine_tmr() on the defined intervals. - * - * dhcp_start(struct netif *netif); - * starts a DHCP client instance which configures the interface by - * obtaining an IP address lease and maintaining it. - * - * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif) - * to remove the DHCP client. - * - */ - -/** - * @defgroup dhcp4 DHCPv4 - * @ingroup ip4 - * DHCP (IPv4) related functions - * @see netifapi_dhcp4 - */ - -#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 - -/** 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 - -/** Option handling: options are parsed in dhcp_parse_reply - * and saved in an array where other functions can load them from. - * This might be moved into the struct dhcp (not necessarily since - * lwIP is single-threaded and the array is only used while in recv - * callback). */ -#define DHCP_OPTION_IDX_OVERLOAD 0 -#define DHCP_OPTION_IDX_MSG_TYPE 1 -#define DHCP_OPTION_IDX_SERVER_ID 2 -#define DHCP_OPTION_IDX_LEASE_TIME 3 -#define DHCP_OPTION_IDX_T1 4 -#define DHCP_OPTION_IDX_T2 5 -#define DHCP_OPTION_IDX_SUBNET_MASK 6 -#define DHCP_OPTION_IDX_ROUTER 7 -#define DHCP_OPTION_IDX_DNS_SERVER 8 -#if LWIP_DHCP_GET_NTP_SRV -#define DHCP_OPTION_IDX_NTP_SERVER (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS) -#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS) -#else /* LWIP_DHCP_GET_NTP_SRV */ -#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS) -#endif /* LWIP_DHCP_GET_NTP_SRV */ - -/** 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, - DHCP_OPTION_DNS_SERVER -#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 err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type); -/* free a DHCP request */ -static void dhcp_delete_msg(struct dhcp *dhcp); -/* add a DHCP option (type, then length in bytes) */ -static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); -/* add option values */ -static void dhcp_option_byte(struct dhcp *dhcp, u8_t value); -static void dhcp_option_short(struct dhcp *dhcp, u16_t value); -static void dhcp_option_long(struct dhcp *dhcp, u32_t value); -#if LWIP_NETIF_HOSTNAME -static void dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif); -#endif /* LWIP_NETIF_HOSTNAME */ -/* always add the DHCP options trailer to end and pad */ -static void dhcp_option_trailer(struct dhcp *dhcp); - -/** 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, IP_ADDR_ANY, DHCP_CLIENT_PORT); - udp_connect(dhcp_pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); - 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; - 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_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY); - /* 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; - 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 = (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 *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", - (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - /* obtain the server address */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { - ip_addr_set_ip4_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID))); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", - ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)))); - /* remember offered address */ - ip4_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", - ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_select(netif); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void*)netif)); - } -} - -/** - * Select a DHCP server offer out of all offers. - * - * Simply select the first offer received. - * - * @param netif the netif under DHCP control - * @return lwIP specific error (see error.h) - */ -static err_t -dhcp_select(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - u8_t i; - - 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 */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - - /* MUST request the offered IP address */ - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)))); - - dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); - for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { - dhcp_option_byte(dhcp, dhcp_discover_request_options[i]); - } - -#if LWIP_NETIF_HOSTNAME - dhcp_option_hostname(dhcp, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - - dhcp_option_trailer(dhcp); - /* shrink the pbuf to the actual content length */ - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* send broadcast to any DHCP server */ - udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n")); - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - -/** - * The DHCP timer that checks for lease renewal/rebind timeouts. - */ -void -dhcp_coarse_tmr(void) -{ - struct netif *netif = netif_list; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); - /* iterate through all network interfaces */ - while (netif != NULL) { - /* only act on DHCP configured interfaces */ - struct dhcp* dhcp = netif->dhcp; - 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(netif); - dhcp_discover(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); - } - } - /* proceed to next netif */ - netif = netif->next; - } -} - -/** - * DHCP transaction timeout handling - * - * A DHCP server is expected to respond within a short period of time. - * This timer checks whether an outstanding DHCP request is timed out. - */ -void -dhcp_fine_tmr(void) -{ - struct netif *netif = netif_list; - /* loop through netif's */ - while (netif != NULL) { - /* only act on DHCP configured interfaces */ - if (netif->dhcp != NULL) { - /* timer is active (non zero), and is about to trigger now */ - if (netif->dhcp->request_timeout > 1) { - netif->dhcp->request_timeout--; - } - else if (netif->dhcp->request_timeout == 1) { - netif->dhcp->request_timeout--; - /* { netif->dhcp->request_timeout == 0 } */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); - /* this client's request timeout triggered */ - dhcp_timeout(netif); - } - } - /* proceed to next network interface */ - netif = netif->next; - } -} - -/** - * A DHCP negotiation transaction, or ARP request, has timed out. - * - * The timer that was started with the DHCP or ARP request has - * timed out, indicating no response was received in time. - * - * @param netif the netif under DHCP control - */ -static void -dhcp_timeout(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n")); - /* back-off period has passed, or server selection timed out */ - if ((dhcp->state == DHCP_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(netif); - dhcp_discover(netif); - } -#if DHCP_DOES_ARP_CHECK - /* received no ARP reply for the offered address (which is good) */ - } else if (dhcp->state == DHCP_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; - 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 (((netif->dhcp->t2_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) - { - netif->dhcp->t1_renew_time = ((netif->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; - 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 (((netif->dhcp->t0_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) - { - netif->dhcp->t2_rebind_time = ((netif->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 *dhcp = netif->dhcp; -#if LWIP_DNS || LWIP_DHCP_GET_NTP_SRV - u8_t n; -#endif /* LWIP_DNS || 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, dhcp->msg_in->yiaddr); - -#if LWIP_DHCP_BOOTP_FILE - /* copy boot server address, - boot file name copied in dhcp_parse_reply if not overloaded */ - ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr); -#endif /* LWIP_DHCP_BOOTP_FILE */ - - /* subnet mask given? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { - /* remember given subnet mask */ - ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK))); - dhcp->subnet_mask_given = 1; - } else { - dhcp->subnet_mask_given = 0; - } - - /* gateway router */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) { - ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER))); - } - -#if LWIP_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], 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_DNS - /* DNS servers */ - for (n = 0; (n < DNS_MAX_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) { - ip_addr_t dns_addr; - ip_addr_set_ip4_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n))); - dns_setserver(n, &dns_addr); - } -#endif /* LWIP_DNS */ -} - -/** - * @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("netif != NULL", netif != NULL); - LWIP_ASSERT("dhcp != NULL", dhcp != NULL); - LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL); - - /* clear data structure */ - memset(dhcp, 0, sizeof(struct dhcp)); - /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ - netif->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("netif != NULL", netif != NULL); - - if (netif->dhcp != NULL) { - mem_free(netif->dhcp); - netif->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_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; - 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(): starting new DHCP client\n")); - dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); - if (dhcp == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); - return ERR_MEM; - } - - /* store this dhcp client in the netif */ - netif->dhcp = dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp")); - /* already has DHCP client attached */ - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n")); - LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL); - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL ); - - 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 LWIP_DHCP_CHECK_LINK_UP - 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; - } -#endif /* LWIP_DHCP_CHECK_LINK_UP */ - - - /* (re)start the DHCP negotiation */ - result = dhcp_discover(netif); - if (result != ERR_OK) { - /* free resources allocated above */ - dhcp_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; - err_t result = ERR_OK; - - 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 */ - result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM); - if (result == ERR_OK) { - dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif)); - - dhcp_option_trailer(&dhcp); - - pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); - - udp_sendto_if(dhcp_pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - - dhcp_delete_msg(&dhcp); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n")); - } - - 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; - 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: - /* 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. - * - * @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) -{ - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); - /* is a DHCP client doing an ARP check? */ - if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_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, &netif->dhcp->offered_ip_addr)) { - /* we will not accept the offered address */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, - ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); - dhcp_decline(netif); - } - } -} - -/** - * Decline an offered lease. - * - * Tell the DHCP server we do not accept the offered address. - * One reason to decline the lease is when we find out the address - * is already in use by another host (through ARP). - * - * @param netif the netif under DHCP control - */ -static err_t -dhcp_decline(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result = ERR_OK; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); - dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_option_trailer(dhcp); - /* resize pbuf to reflect true size of options */ - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* per section 4.4.4, broadcast DECLINE messages */ - udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_decline: could not allocate DHCP request\n")); - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = 10*1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} -#endif /* DHCP_DOES_ARP_CHECK */ - - -/** - * Start the DHCP process, discover a DHCP server. - * - * @param netif the netif under DHCP control - */ -static err_t -dhcp_discover(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result = ERR_OK; - u16_t msecs; - u8_t i; - 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 */ - result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER); - if (result == ERR_OK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); - - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - - dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); - for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { - dhcp_option_byte(dhcp, dhcp_discover_request_options[i]); - } - dhcp_option_trailer(dhcp); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n")); - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); - udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n")); - } - 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 = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - - -/** - * Bind the interface to the offered IP address. - * - * @param netif network interface to bind to the offered address - */ -static void -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; - 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; - err_t result; - u16_t msecs; - u8_t i; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n")); - dhcp_set_state(dhcp, DHCP_STATE_RENEWING); - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - - dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); - for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { - dhcp_option_byte(dhcp, dhcp_discover_request_options[i]); - } - -#if LWIP_NETIF_HOSTNAME - dhcp_option_hostname(dhcp, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - - /* append DHCP message trailer */ - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - udp_sendto_if(dhcp_pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n")); - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - /* back-off on retries, but to a maximum of 20 seconds */ - msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - -/** - * Rebind with a DHCP server for an existing DHCP lease. - * - * @param netif network interface which must rebind with a DHCP server - */ -static err_t -dhcp_rebind(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - u8_t i; - 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 */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - - dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); - for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { - dhcp_option_byte(dhcp, dhcp_discover_request_options[i]); - } - -#if LWIP_NETIF_HOSTNAME - dhcp_option_hostname(dhcp, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* broadcast to server */ - udp_sendto_if(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n")); - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - -/** - * Enter REBOOTING state to verify an existing lease - * - * @param netif network interface which must reboot - */ -static err_t -dhcp_reboot(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - u8_t i; - 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 */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, 576); - - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); - for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { - dhcp_option_byte(dhcp, dhcp_discover_request_options[i]); - } - - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* broadcast to server */ - udp_sendto_if(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n")); - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - - -/** - * @ingroup dhcp4 - * Release a DHCP lease. - * - * @param netif network interface which must release its lease - */ -err_t -dhcp_release(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - ip_addr_t server_ip_addr; - u8_t is_dhcp_supplied_address; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n")); - if (dhcp == NULL) { - return ERR_ARG; - } - ip_addr_copy(server_ip_addr, dhcp->server_ip_addr); - - is_dhcp_supplied_address = dhcp_supplied_address(netif); - - /* idle DHCP client */ - dhcp_set_state(dhcp, DHCP_STATE_OFF); - /* 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; - - if (!is_dhcp_supplied_address) { - /* don't issue release message when address is not dhcp-assigned */ - return ERR_OK; - } - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(ip_2_ip4(&server_ip_addr)))); - - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - udp_sendto_if(dhcp_pcb, dhcp->p_out, &server_ip_addr, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_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_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY); - - return result; -} - -/** - * @ingroup dhcp4 - * Remove the DHCP client from the interface. - * - * @param netif The network interface to stop DHCP on - */ -void -dhcp_stop(struct netif *netif) -{ - struct dhcp *dhcp; - LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); - dhcp = netif->dhcp; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n")); - /* netif is DHCP configured? */ - if (dhcp != NULL) { -#if LWIP_DHCP_AUTOIP_COOP - if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); - 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; - } - } -} - -/* - * 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 void -dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len) -{ - LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = option_type; - dhcp->msg_out->options[dhcp->options_out_len++] = option_len; -} -/* - * Concatenate a single byte to the outgoing DHCP message. - * - */ -static void -dhcp_option_byte(struct dhcp *dhcp, u8_t value) -{ - LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = value; -} - -static void -dhcp_option_short(struct dhcp *dhcp, u16_t value) -{ - LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU); -} - -static void -dhcp_option_long(struct dhcp *dhcp, u32_t value) -{ - LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL)); -} - -#if LWIP_NETIF_HOSTNAME -static void -dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif) -{ - if (netif->hostname != NULL) { - size_t namelen = strlen(netif->hostname); - if (namelen > 0) { - u8_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 - dhcp->options_out_len - 3; - LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); - len = LWIP_MIN(namelen, available); - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, len); - while (len--) { - dhcp_option_byte(dhcp, *p++); - } - } - } -} -#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 dhcp *dhcp, struct pbuf *p) -{ - u8_t *options; - u16_t offset; - u16_t offset_max; - u16_t options_idx; - u16_t options_idx_max; - struct pbuf *q; - int parse_file_as_options = 0; - int parse_sname_as_options = 0; - - /* clear received options */ - dhcp_clear_all_options(dhcp); - /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */ - if (p->len < DHCP_SNAME_OFS) { - return ERR_BUF; - } - dhcp->msg_in = (struct dhcp_msg *)p->payload; -#if LWIP_DHCP_BOOTP_FILE - /* clear boot file name */ - dhcp->boot_file_name[0] = 0; -#endif /* LWIP_DHCP_BOOTP_FILE */ - - /* parse options */ - - /* start with options field */ - options_idx = DHCP_OPTIONS_OFS; - /* parse options to the end of the received packet */ - options_idx_max = p->tot_len; -again: - q = p; - while ((q != NULL) && (options_idx >= q->len)) { - options_idx -= q->len; - options_idx_max -= q->len; - q = q->next; - } - if (q == NULL) { - return ERR_BUF; - } - offset = options_idx; - offset_max = options_idx_max; - options = (u8_t*)q->payload; - /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ - while ((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) { - u8_t op = options[offset]; - u8_t len; - u8_t decode_len = 0; - int decode_idx = -1; - u16_t val_offset = offset + 2; - /* len byte might be in the next pbuf */ - if (offset + 1 < q->len) { - len = options[offset + 1]; - } else { - len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0); - } - /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ - decode_len = len; - switch(op) { - /* case(DHCP_OPTION_END): handled above */ - case(DHCP_OPTION_PAD): - /* special option: no len encoded */ - decode_len = len = 0; - /* will be increased below */ - offset--; - break; - case(DHCP_OPTION_SUBNET_MASK): - LWIP_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; - 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; - 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_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)); - break; - } - offset += len + 2; - if (decode_len > 0) { - u32_t value = 0; - u16_t copy_len; -decode_next: - LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); - if (!dhcp_option_given(dhcp, decode_idx)) { - copy_len = LWIP_MIN(decode_len, 4); - pbuf_copy_partial(q, &value, copy_len, val_offset); - if (decode_len > 4) { - /* decode more than one u32_t */ - LWIP_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, htonl(value)); - decode_len -= 4; - val_offset += 4; - decode_idx++; - goto decode_next; - } else if (decode_len == 4) { - value = 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 -= q->len; - offset_max -= q->len; - if ((offset < offset_max) && offset_max) { - q = q->next; - LWIP_ASSERT("next pbuf was null", q); - options = (u8_t*)q->payload; - } else { - /* We've run out of bytes, probably no end marker. Don't proceed. */ - break; - } - } - } - /* is this an overloaded message? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) { - u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD); - dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD); - if (overload == DHCP_OVERLOAD_FILE) { - parse_file_as_options = 1; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); - } else if (overload == DHCP_OVERLOAD_SNAME) { - parse_sname_as_options = 1; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); - } else if (overload == DHCP_OVERLOAD_SNAME_FILE) { - parse_sname_as_options = 1; - parse_file_as_options = 1; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload)); - } -#if LWIP_DHCP_BOOTP_FILE - if (!parse_file_as_options) { - /* only do this for ACK messages */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && - (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) - /* copy bootp file name, don't care for sname (server hostname) */ - pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS); - /* make sure the string is really NULL-terminated */ - dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; - } -#endif /* LWIP_DHCP_BOOTP_FILE */ - } - if (parse_file_as_options) { - /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */ - parse_file_as_options = 0; - options_idx = DHCP_FILE_OFS; - options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN; - goto again; - } else if (parse_sname_as_options) { - parse_sname_as_options = 0; - options_idx = DHCP_SNAME_OFS; - options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN; - goto again; - } - return ERR_OK; -} - -/** - * If an incoming DHCP message is in response to us, then trigger the state machine - */ -static void -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; - struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; - u8_t msg_type; - u8_t i; - - 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); - - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); - - if (p->len < DHCP_MIN_REPLY_LEN) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n")); - goto free_pbuf_and_return; - } - - if (reply_msg->op != DHCP_BOOTREPLY) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); - goto free_pbuf_and_return; - } - /* iterate through hardware address and match against DHCP message */ - for (i = 0; i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN && i < DHCP_CHADDR_LEN; i++) { - if (netif->hwaddr[i] != reply_msg->chaddr[i]) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", - (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); - goto free_pbuf_and_return; - } - } - /* match transaction ID against what we expected */ - if (ntohl(reply_msg->xid) != dhcp->xid) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid)); - goto free_pbuf_and_return; - } - /* option fields could be unfold? */ - if (dhcp_parse_reply(dhcp, p) != ERR_OK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("problem unfolding DHCP message - too short on memory?\n")); - goto free_pbuf_and_return; - } - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); - /* obtain pointer to DHCP message type */ - if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); - goto free_pbuf_and_return; - } - - /* read DHCP message type */ - msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE); - /* message type is DHCP ACK? */ - if (msg_type == DHCP_ACK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n")); - /* in requesting state? */ - if (dhcp->state == DHCP_STATE_REQUESTING) { - dhcp_handle_ack(netif); -#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); - 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")); - dhcp->request_timeout = 0; - /* remember offered lease */ - dhcp_handle_offer(netif); - } - -free_pbuf_and_return: - if (dhcp != NULL) { - dhcp->msg_in = NULL; - } - pbuf_free(p); -} - -/** - * Create a DHCP request, fill in common headers - * - * @param netif the netif under DHCP control - * @param dhcp dhcp control struct - * @param message_type message type of the request - */ -static err_t -dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type) -{ - u16_t i; -#ifndef DHCP_GLOBAL_XID - /** default global transaction identifier starting value (easy to match - * with a packet analyser). We simply increment for each new request. - * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one - * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ -#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 ERR_ARG;); - LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); - LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL); - LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL); - dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); - if (dhcp->p_out == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_create_msg(): could not allocate pbuf\n")); - return ERR_MEM; - } - LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg", - (dhcp->p_out->len >= sizeof(struct dhcp_msg))); - - /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER */ - if (message_type != DHCP_REQUEST) { - /* 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)); - - dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; - - dhcp->msg_out->op = DHCP_BOOTREQUEST; - /* @todo: make link layer independent */ - dhcp->msg_out->htype = DHCP_HTYPE_ETH; - dhcp->msg_out->hlen = netif->hwaddr_len; - dhcp->msg_out->hops = 0; - dhcp->msg_out->xid = htonl(dhcp->xid); - dhcp->msg_out->secs = 0; - /* we don't need the broadcast flag since we can receive unicast traffic - before being fully configured! */ - dhcp->msg_out->flags = 0; - ip4_addr_set_zero(&dhcp->msg_out->ciaddr); - /* set ciaddr to netif->ip_addr based on message_type and state */ - if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || (message_type == DHCP_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(dhcp->msg_out->ciaddr, *netif_ip4_addr(netif)); - } - ip4_addr_set_zero(&dhcp->msg_out->yiaddr); - ip4_addr_set_zero(&dhcp->msg_out->siaddr); - ip4_addr_set_zero(&dhcp->msg_out->giaddr); - for (i = 0; i < DHCP_CHADDR_LEN; i++) { - /* copy netif hardware address, pad with zeroes */ - dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN) ? netif->hwaddr[i] : 0/* pad byte*/; - } - for (i = 0; i < DHCP_SNAME_LEN; i++) { - dhcp->msg_out->sname[i] = 0; - } - for (i = 0; i < DHCP_FILE_LEN; i++) { - dhcp->msg_out->file[i] = 0; - } - dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE); - dhcp->options_out_len = 0; - /* fill options field with an incrementing array (for debugging purposes) */ - for (i = 0; i < DHCP_OPTIONS_LEN; i++) { - dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */ - } - /* Add option MESSAGE_TYPE */ - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, message_type); - return ERR_OK; -} - -/** - * Free previously allocated memory used to send a DHCP request. - * - * @param dhcp the dhcp struct to free the request from - */ -static void -dhcp_delete_msg(struct dhcp *dhcp) -{ - LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;); - LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL); - LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL); - if (dhcp->p_out != NULL) { - pbuf_free(dhcp->p_out); - } - dhcp->p_out = NULL; - dhcp->msg_out = NULL; -} - -/** - * Add a DHCP message trailer - * - * Adds the END option to the DHCP message, and if - * necessary, up to three padding bytes. - * - * @param dhcp DHCP state structure - */ -static void -dhcp_option_trailer(struct dhcp *dhcp) -{ - LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;); - LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL); - LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END; - /* packet is too small, or not 4 byte aligned? */ - while (((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) && - (dhcp->options_out_len < DHCP_OPTIONS_LEN)) { - /* add a fill/padding byte */ - dhcp->msg_out->options[dhcp->options_out_len++] = 0; - } -} - -/** 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 != NULL)) { - if ((netif->dhcp->state == DHCP_STATE_BOUND) || - (netif->dhcp->state == DHCP_STATE_RENEWING)) { - return 1; - } - } - return 0; -} - -#endif /* LWIP_IPV4 && LWIP_DHCP */ diff --git a/ext/lwip/src/core/ipv4/etharp.c b/ext/lwip/src/core/ipv4/etharp.c deleted file mode 100644 index 5481d3b..0000000 --- a/ext/lwip/src/core/ipv4/etharp.c +++ /dev/null @@ -1,1385 +0,0 @@ -/** - * @file - * Address Resolution Protocol module for IP over Ethernet - * - * Functionally, ARP is divided into two parts. The first maps an IP address - * to a physical address when sending a packet, and the second part answers - * requests from other machines for our physical address. - * - * This implementation complies with RFC 826 (Ethernet ARP). It supports - * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 - * if an interface calls etharp_gratuitous(our_netif) upon address change. - */ - -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * Copyright (c) 2003-2004 Leon Woestenberg - * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - */ - -#include "lwip/opt.h" - -#if LWIP_ARP || LWIP_ETHERNET - -#include "lwip/etharp.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" - -#include - -#if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ - -/** 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 - -#define HWTYPE_ETHERNET 1 - -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 u8_t etharp_cached_entry; -#endif /* !LWIP_NETIF_HWADDRHINT */ - -/** Try hard to create a new entry - we want the IP address to appear in - the cache (even if this means removing an active entry or so). */ -#define ETHARP_FLAG_TRY_HARD 1 -#define ETHARP_FLAG_FIND_ONLY 2 -#if ETHARP_SUPPORT_STATIC_ENTRIES -#define ETHARP_FLAG_STATIC_ENTRY 4 -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - -#if LWIP_NETIF_HWADDRHINT -#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \ - *((netif)->addr_hint) = (hint); -#else /* LWIP_NETIF_HWADDRHINT */ -#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint)) -#endif /* LWIP_NETIF_HWADDRHINT */ - - -/* Some checks, instead of etharp_init(): */ -#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) - #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h" -#endif - - -static err_t etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr* hw_dst_addr); - - -#if ARP_QUEUEING -/** - * Free a complete queue of etharp entries - * - * @param q a qeueue of etharp_q_entry's to free - */ -static void -free_etharp_q(struct etharp_q_entry *q) -{ - struct etharp_q_entry *r; - LWIP_ASSERT("q != NULL", q != NULL); - LWIP_ASSERT("q->p != NULL", q->p != NULL); - while (q) { - r = q; - q = q->next; - LWIP_ASSERT("r->p != NULL", (r->p != NULL)); - pbuf_free(r->p); - memp_free(MEMP_ARP_QUEUE, r); - } -} -#else /* ARP_QUEUEING */ - -/** Compatibility define: free the queued pbuf */ -#define free_etharp_q(q) pbuf_free(q) - -#endif /* ARP_QUEUEING */ - -/** Clean up ARP table entries */ -static void -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) -{ - u8_t i; - - LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); - /* remove expired entries from the ARP table */ - for (i = 0; i < ARP_TABLE_SIZE; ++i) { - u8_t state = arp_table[i].state; - if (state != ETHARP_STATE_EMPTY -#if ETHARP_SUPPORT_STATIC_ENTRIES - && (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 %"U16_F".\n", - arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)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 definition of ETHARP_FLAG_* - * @param netif netif related to this address (used for NETIF_HWADDRHINT) - * - * @return The ARP entry index that matched or is created, ERR_MEM if no - * entry is found or could be recycled. - */ -static s8_t -etharp_find_entry(const ip4_addr_t *ipaddr, u8_t flags, struct netif* netif) -{ - s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; - s8_t empty = ARP_TABLE_SIZE; - u8_t i = 0; - /* oldest entry with packets on queue */ - s8_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 %"U16_F"\n", (u16_t)i)); - /* remember first empty entry */ - empty = i; - } else if (state != ETHARP_STATE_EMPTY) { - LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", - state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); - /* if given, does IP address match IP address in ARP entry? */ - if (ipaddr && 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 %"U16_F"\n", (u16_t)i)); - /* found exact IP address match, simply bail out */ - return i; - } - /* pending entry? */ - if (state == ETHARP_STATE_PENDING) { - /* pending with queued packets? */ - if (arp_table[i].q != NULL) { - if (arp_table[i].ctime >= age_queue) { - old_queue = i; - age_queue = arp_table[i].ctime; - } - } else - /* pending without queued packets? */ - { - if (arp_table[i].ctime >= age_pending) { - old_pending = i; - age_pending = arp_table[i].ctime; - } - } - /* stable entry? */ - } else if (state >= ETHARP_STATE_STABLE) { -#if ETHARP_SUPPORT_STATIC_ENTRIES - /* don't record old_stable for static entries since they never expire */ - if (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 (s8_t)ERR_MEM; - } - - /* b) choose the least destructive entry to recycle: - * 1) empty entry - * 2) oldest stable entry - * 3) oldest pending entry without queued packets - * 4) oldest pending entry with queued packets - * - * { ETHARP_FLAG_TRY_HARD is set at this point } - */ - - /* 1) empty entry available? */ - if (empty < ARP_TABLE_SIZE) { - i = empty; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); - } else { - /* 2) found recyclable stable entry? */ - if (old_stable < ARP_TABLE_SIZE) { - /* recycle oldest stable*/ - i = old_stable; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); - /* no queued packets should exist on stable entries */ - LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); - /* 3) found recyclable pending entry without queued packets? */ - } else if (old_pending < ARP_TABLE_SIZE) { - /* recycle oldest pending */ - i = old_pending; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); - /* 4) found recyclable pending entry with queued packets? */ - } else if (old_queue < ARP_TABLE_SIZE) { - /* recycle oldest pending (queued packets are free in etharp_free_entry) */ - i = old_queue; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); - /* no empty or recyclable entries found */ - } else { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n")); - return (s8_t)ERR_MEM; - } - - /* { empty or recyclable entry found } */ - LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); - 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 (err_t)i; -} - -/** - * Send an IP packet on the network using netif->linkoutput - * The ethernet header is filled in before sending. - * - * @params netif the lwIP network interface on which to send the packet - * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header - * @params src the source MAC address to be copied into the ethernet header - * @params dst the destination MAC address to be copied into the ethernet header - * @return ERR_OK if the packet was sent, any other err_t on failure - */ -static err_t -etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, const struct eth_addr *dst) -{ - struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) - struct eth_vlan_hdr *vlanhdr; -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - - LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!", - (netif->hwaddr_len == ETH_HWADDR_LEN)); -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) - ethhdr->type = PP_HTONS(ETHTYPE_VLAN); - vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR); - vlanhdr->prio_vid = 0; - vlanhdr->tpid = PP_HTONS(ETHTYPE_IP); - if (!LWIP_HOOK_VLAN_SET(netif, ethhdr, vlanhdr)) { - /* packet shall not contain VLAN header, so hide it and set correct ethertype */ - pbuf_header(p, -SIZEOF_VLAN_HDR); - ethhdr = (struct eth_hdr *)p->payload; -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - ethhdr->type = PP_HTONS(ETHTYPE_IP); -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) - } -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - ETHADDR32_COPY(ðhdr->dest, dst); - ETHADDR16_COPY(ðhdr->src, src); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p)); - /* send the packet */ - return netif->linkoutput(netif, p); -} - -/** - * Update (or insert) a IP/MAC address pair in the ARP cache. - * - * If a pending entry is resolved, any queued packets will be sent - * at this point. - * - * @param netif netif related to this entry (used for NETIF_ADDRHINT) - * @param ipaddr IP address of the inserted ARP entry. - * @param ethaddr Ethernet address of the inserted ARP entry. - * @param flags @see definition of ETHARP_FLAG_* - * - * @return - * - ERR_OK 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) -{ - s8_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", (s16_t)i)); - /* update address */ - ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr); - /* reset time stamp */ - arp_table[i].ctime = 0; - /* this is where we will send out queued packets! */ -#if ARP_QUEUEING - while (arp_table[i].q != NULL) { - struct pbuf *p; - /* remember remainder of queue */ - struct etharp_q_entry *q = arp_table[i].q; - /* pop first item off the queue */ - arp_table[i].q = q->next; - /* get the packet pointer */ - p = q->p; - /* now queue entry can be freed */ - memp_free(MEMP_ARP_QUEUE, q); -#else /* ARP_QUEUEING */ - if (arp_table[i].q != NULL) { - struct pbuf *p = arp_table[i].q; - arp_table[i].q = NULL; -#endif /* ARP_QUEUEING */ - /* send the queued IP packet */ - etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); - /* free the queued IP packet */ - pbuf_free(p); - } - return ERR_OK; -} - -#if ETHARP_SUPPORT_STATIC_ENTRIES -/** Add a new static entry to the ARP table. If an entry exists for the - * specified IP address, this entry is overwritten. - * If packets are queued for the specified IP address, they are sent out. - * - * @param ipaddr IP address for the new static entry - * @param ethaddr ethernet address for the new static entry - * @return @see return values of etharp_add_static_entry - */ -err_t -etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr) -{ - struct netif *netif; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", - ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), - (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) -{ - s8_t i; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); - - /* find or create ARP entry */ - i = 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) -{ - u8_t i; - - for (i = 0; i < ARP_TABLE_SIZE; ++i) { - u8_t state = arp_table[i].state; - if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) { - 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 - */ -s8_t -etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr, - struct eth_addr **eth_ret, const ip4_addr_t **ip_ret) -{ - s8_t i; - - LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", - eth_ret != NULL && ip_ret != NULL); - - LWIP_UNUSED_ARG(netif); - - i = 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 - */ -u8_t -etharp_get_entry(u8_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; - } -} - -#if ETHARP_TRUST_IP_MAC -/** - * Updates the ARP table using the given IP packet. - * - * Uses the incoming IP packet's source address to update the - * ARP cache for the local network. The function does not alter - * or free the packet. This function must be called before the - * packet p is passed to the IP layer. - * - * @param netif The lwIP network interface on which the IP packet pbuf arrived. - * @param p The IP packet that arrived on netif. - * - * @return NULL - * - * @see pbuf_free() - */ -void -etharp_ip_input(struct netif *netif, struct pbuf *p) -{ - struct eth_hdr *ethhdr; - struct ip_hdr *iphdr; - ip4_addr_t iphdr_src; - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - - /* Only insert an entry if the source IP address of the - incoming IP packet comes from a host on the local network. */ - ethhdr = (struct eth_hdr *)p->payload; - iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); -#if ETHARP_SUPPORT_VLAN - if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) { - iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); - } -#endif /* ETHARP_SUPPORT_VLAN */ - - ip4_addr_copy(iphdr_src, iphdr->src); - - /* source is not on the local network? */ - if (!ip4_addr_netcmp(&iphdr_src, netif_ip4_addr(netif), netif_ip4_netmask(netif))) { - /* do nothing */ - return; - } - - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); - /* update the source IP address in the cache, if present */ - /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk - * back soon (for example, if the destination IP address is ours. */ - etharp_update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY); -} -#endif /* ETHARP_TRUST_IP_MAC */ - -/** - * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache - * send out queued IP packets. Updates cache with snooped address pairs. - * - * Should be called for incoming ARP packets. The pbuf in the argument - * is freed by this function. - * - * @param netif The lwIP network interface on which the ARP packet pbuf arrived. - * @param ethaddr Ethernet address of netif. - * @param p The ARP packet that arrived on netif. Is freed by this function. - * - * @return NULL - * - * @see pbuf_free() - */ -void -etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) -{ - struct etharp_hdr *hdr; - struct eth_hdr *ethhdr; - /* these are aligned properly, whereas the ARP header fields might not be */ - ip4_addr_t sipaddr, dipaddr; - u8_t for_us; -#if LWIP_AUTOIP - const u8_t * ethdst_hwaddr; -#endif /* LWIP_AUTOIP */ - - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - - /* drop short ARP packets: we have to check for p->len instead of p->tot_len here - since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */ - if (p->len < SIZEOF_ETHARP_PACKET) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, - (s16_t)SIZEOF_ETHARP_PACKET)); - ETHARP_STATS_INC(etharp.lenerr); - ETHARP_STATS_INC(etharp.drop); - pbuf_free(p); - return; - } - - ethhdr = (struct eth_hdr *)p->payload; - hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); -#if ETHARP_SUPPORT_VLAN - if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) { - hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); - } -#endif /* ETHARP_SUPPORT_VLAN */ - - /* RFC 826 "Packet Reception": */ - if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) || - (hdr->hwlen != 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_arp_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_addr2 to aligned ip4_addr, to support compilers without - * structure packing (not using structure copy which breaks strict-aliasing rules). */ - IPADDR2_COPY(&sipaddr, &hdr->sipaddr); - IPADDR2_COPY(&dipaddr, &hdr->dipaddr); - - /* this interface is not configured? */ - if (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_arp_input: incoming ARP request\n")); - /* ARP request for our address? */ - if (for_us) { - - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n")); - /* Re-use pbuf to send ARP reply. - Since we are re-using an existing pbuf, we can't call etharp_raw since - that would allocate a new pbuf. */ - hdr->opcode = htons(ARP_REPLY); - - IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr); - IPADDR2_COPY(&hdr->sipaddr, netif_ip4_addr(netif)); - - LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!", - (netif->hwaddr_len == ETH_HWADDR_LEN)); -#if LWIP_AUTOIP - /* If we are using Link-Local, all ARP packets that contain a Link-Local - * 'sender IP address' MUST be sent using link-layer broadcast instead of - * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ - ethdst_hwaddr = ip4_addr_islinklocal(netif_ip4_addr(netif)) ? (const u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr; -#endif /* LWIP_AUTOIP */ - - ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr); -#if LWIP_AUTOIP - ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); -#else /* LWIP_AUTOIP */ - ETHADDR16_COPY(ðhdr->dest, &hdr->shwaddr); -#endif /* LWIP_AUTOIP */ - ETHADDR16_COPY(&hdr->shwaddr, ethaddr); - ETHADDR16_COPY(ðhdr->src, ethaddr); - - /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header - are already correct, we tested that before */ - - /* return ARP reply */ - netif->linkoutput(netif, p); - /* 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_arp_input: we are unconfigured, ARP request ignored.\n")); - /* request was not directed to us */ - } else { - /* { for_us == 0 and netif->ip_addr.addr != 0 } */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n")); - } - break; - case PP_HTONS(ARP_REPLY): - /* ARP reply. We already updated the ARP cache earlier. */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n")); -#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) - /* DHCP wants to know about ARP replies from any host with an - * IP address also offered to us by the DHCP server. We do not - * want to take a duplicate IP address on a single network. - * @todo How should we handle redundant (fail-over) interfaces? */ - dhcp_arp_reply(netif, &sipaddr); -#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ - break; - default: - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); - ETHARP_STATS_INC(etharp.err); - break; - } - /* free ARP packet */ - pbuf_free(p); -} - -/** Just a small helper function that sends a pbuf to an ethernet address - * in the arp_table specified by the index 'arp_idx'. - */ -static err_t -etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx) -{ - LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE", - arp_table[arp_idx].state >= ETHARP_STATE_STABLE); - /* if arp table entry is about to expire: re-request it, - but only if its state is ETHARP_STATE_STABLE to prevent flooding the - network with ARP requests if this address is used frequently. */ - if (arp_table[arp_idx].state == ETHARP_STATE_STABLE) { - 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 etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), - &arp_table[arp_idx].ethaddr); -} - -/** - * Resolve and fill-in Ethernet address header for outgoing IP packet. - * - * For IP multicast and broadcast, corresponding Ethernet addresses - * are selected and the packet is transmitted on the link. - * - * For unicast addresses, the packet is submitted to etharp_query(). In - * case the IP address is outside the local network, the IP address of - * the gateway is used. - * - * @param netif The lwIP network interface which the IP packet will be sent on. - * @param q The pbuf(s) containing the IP packet to be sent. - * @param ipaddr The IP address of the packet destination. - * - * @return - * - ERR_RTE No route to destination (no gateway to external networks), - * or the return type of either etharp_query() or etharp_send_ip(). - */ -err_t -etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) -{ - const struct eth_addr *dest; - struct eth_addr mcastaddr; - const ip4_addr_t *dst_addr = ipaddr; - - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("q != NULL", q != NULL); - LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); - - /* make room for Ethernet header - should not fail */ -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) - if (pbuf_header(q, sizeof(struct eth_hdr) + SIZEOF_VLAN_HDR) != 0) { -#else /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - /* bail out */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("etharp_output: could not allocate room for header.\n")); - LINK_STATS_INC(link.lenerr); - return ERR_BUF; - } - - /* 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 { - s8_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 = (struct ip_hdr*)((u8_t*)q->payload + -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) - SIZEOF_VLAN_HDR + -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - sizeof(struct eth_hdr)); - /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with - a link-local source address must always be "directly to its destination - on the same physical link. The host MUST NOT send the packet to any - router for forwarding". */ - if (!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->addr_hint != NULL) { - /* per-pcb cached entry was given */ - u8_t etharp_cached_entry = *(netif->addr_hint); - if (etharp_cached_entry < ARP_TABLE_SIZE) { -#endif /* LWIP_NETIF_HWADDRHINT */ - if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && - (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) && - (ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { - /* found an existing, stable entry */ - ETHARP_SET_HINT(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 etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest); -} - -/** - * Send an ARP request for the given IP address and/or queue a packet. - * - * If the IP address was not yet in the cache, a pending ARP cache entry - * is added and an ARP request is sent for the given address. The packet - * is queued on this entry. - * - * If the IP address was already pending in the cache, a new ARP request - * is sent for the given address. The packet is queued on this entry. - * - * If the IP address was already stable in the cache, and a packet is - * given, it is directly sent and no ARP request is sent out. - * - * If the IP address was already stable in the cache, and no packet is - * given, an ARP request is sent out. - * - * @param netif The lwIP network interface on which ipaddr - * must be queried for. - * @param ipaddr The IP address to be resolved. - * @param q If non-NULL, a pbuf that must be delivered to the IP address. - * q is not freed by this function. - * - * @note q must only be ONE packet, not a packet queue! - * - * @return - * - ERR_BUF Could not make room for Ethernet header. - * - ERR_MEM Hardware address unknown, and no more ARP entries available - * to query for address or queue the packet. - * - ERR_MEM Could not queue packet due to memory shortage. - * - ERR_RTE No route to destination (no gateway to external networks). - * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. - * - */ -err_t -etharp_query(struct netif *netif, 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; - s8_t i; /* ARP entry index */ - - /* 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 = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD, netif); - - /* could not find or create entry? */ - if (i < 0) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n")); - if (q) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n")); - ETHARP_STATS_INC(etharp.memerr); - } - return (err_t)i; - } - - /* mark a fresh entry as pending (we just sent a request) */ - if (arp_table[i].state == ETHARP_STATE_EMPTY) { - 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_HINT(netif, i); - /* send the packet */ - result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr)); - /* pending entry? (either just created or already pending */ - } else if (arp_table[i].state == ETHARP_STATE_PENDING) { - /* entry is still pending, queue the given packet 'q' */ - struct pbuf *p; - int copy_needed = 0; - /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but - * to copy the whole queue into a new PBUF_RAM (see bug #11400) - * PBUF_ROMs can be left as they are, since ROM must not get changed. */ - p = q; - while (p) { - LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); - if (p->type != PBUF_ROM) { - copy_needed = 1; - break; - } - p = p->next; - } - if (copy_needed) { - /* copy the whole packet into new pbufs */ - p = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM); - if (p != NULL) { - if (pbuf_copy(p, q) != ERR_OK) { - pbuf_free(p); - p = NULL; - } - } - } else { - /* referencing the old pbuf is enough */ - p = q; - pbuf_ref(p); - } - /* packet could be taken over? */ - if (p != NULL) { - /* queue packet ... */ -#if ARP_QUEUEING - struct etharp_q_entry *new_entry; - /* allocate a new arp queue entry */ - new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); - if (new_entry != NULL) { - unsigned int qlen = 0; - new_entry->next = 0; - new_entry->p = p; - if (arp_table[i].q != NULL) { - /* queue was already existent, append the new entry to the end */ - struct etharp_q_entry *r; - r = arp_table[i].q; - qlen++; - while (r->next != NULL) { - r = r->next; - qlen++; - } - r->next = new_entry; - } else { - /* queue did not exist, first item in queue */ - arp_table[i].q = new_entry; - } -#if 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 %"S16_F"\n", (void *)q, (s16_t)i)); - result = ERR_OK; - } else { - /* the pool MEMP_ARP_QUEUE is empty */ - pbuf_free(p); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); - result = ERR_MEM; - } -#else /* ARP_QUEUEING */ - /* always queue one packet per ARP request only, freeing a previously queued packet */ - if (arp_table[i].q != NULL) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); - pbuf_free(arp_table[i].q); - } - arp_table[i].q = p; - result = ERR_OK; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); -#endif /* ARP_QUEUEING */ - } else { - ETHARP_STATS_INC(etharp.memerr); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); - result = ERR_MEM; - } - } - return result; -} - -/** - * Send a raw ARP packet (opcode and all addresses can be modified) - * - * @param netif the lwip network interface on which to send the ARP packet - * @param ethsrc_addr the source MAC address for the ethernet header - * @param ethdst_addr the destination MAC address for the ethernet header - * @param hwsrc_addr the source MAC address for the ARP protocol header - * @param ipsrc_addr the source IP address for the ARP protocol header - * @param hwdst_addr the destination MAC address for the ARP protocol header - * @param ipdst_addr the destination IP address for the ARP protocol header - * @param opcode the type of the ARP packet - * @return ERR_OK if the ARP packet has been sent - * ERR_MEM if the ARP packet couldn't be allocated - * any other err_t on failure - */ -#if !LWIP_AUTOIP -static -#endif /* LWIP_AUTOIP */ -err_t -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 eth_hdr *ethhdr; -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) - struct eth_vlan_hdr *vlanhdr; -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - struct etharp_hdr *hdr; -#if LWIP_AUTOIP - const u8_t * ethdst_hwaddr; -#endif /* LWIP_AUTOIP */ - - LWIP_ASSERT("netif != NULL", netif != NULL); - - /* allocate a pbuf for the outgoing ARP request packet */ - p = pbuf_alloc(PBUF_RAW_TX, SIZEOF_ETHARP_PACKET_TX, PBUF_RAM); - /* could allocate a pbuf for an ARP request? */ - if (p == NULL) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("etharp_raw: could not allocate pbuf for ARP request.\n")); - ETHARP_STATS_INC(etharp.memerr); - return ERR_MEM; - } - LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", - (p->len >= SIZEOF_ETHARP_PACKET_TX)); - - ethhdr = (struct eth_hdr *)p->payload; -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) - vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR); - hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); -#else /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); - hdr->opcode = htons(opcode); - - LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!", - (netif->hwaddr_len == ETH_HWADDR_LEN)); -#if LWIP_AUTOIP - /* If we are using Link-Local, all ARP packets that contain a Link-Local - * 'sender IP address' MUST be sent using link-layer broadcast instead of - * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ - ethdst_hwaddr = ip4_addr_islinklocal(ipsrc_addr) ? (const u8_t*)(ethbroadcast.addr) : ethdst_addr->addr; -#endif /* LWIP_AUTOIP */ - /* Write the ARP MAC-Addresses */ - ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr); - ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr); - /* Copy struct ip4_addr2 to aligned ip4_addr, to support compilers without - * structure packing. */ - IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr); - IPADDR2_COPY(&hdr->dipaddr, ipdst_addr); - - hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET); - hdr->proto = PP_HTONS(ETHTYPE_IP); - /* set hwlen and protolen */ - hdr->hwlen = ETH_HWADDR_LEN; - hdr->protolen = sizeof(ip4_addr_t); - -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) - ethhdr->type = PP_HTONS(ETHTYPE_VLAN); - vlanhdr->tpid = PP_HTONS(ETHTYPE_ARP); - vlanhdr->prio_vid = 0; - if (!LWIP_HOOK_VLAN_SET(netif, ethhdr, vlanhdr)) { - /* packet shall not contain VLAN header, so hide it and set correct ethertype */ - pbuf_header(p, -SIZEOF_VLAN_HDR); - ethhdr = (struct eth_hdr *)p->payload; -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - ethhdr->type = PP_HTONS(ETHTYPE_ARP); -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) - } -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - - /* Write the Ethernet MAC-Addresses */ -#if LWIP_AUTOIP - ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); -#else /* LWIP_AUTOIP */ - ETHADDR16_COPY(ðhdr->dest, ethdst_addr); -#endif /* LWIP_AUTOIP */ - ETHADDR16_COPY(ðhdr->src, ethsrc_addr); - - /* send ARP query */ - result = netif->linkoutput(netif, p); - ETHARP_STATS_INC(etharp.xmit); - /* free ARP query packet */ - pbuf_free(p); - p = NULL; - /* could not allocate pbuf for ARP request */ - - return result; -} - -/** - * Send an ARP request packet asking for ipaddr 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 */ - -#endif /* LWIP_ARP || LWIP_ETHERNET */ diff --git a/ext/lwip/src/core/ipv4/icmp.c b/ext/lwip/src/core/ipv4/icmp.c deleted file mode 100644 index d6348d8..0000000 --- a/ext/lwip/src/core/ipv4/icmp.c +++ /dev/null @@ -1,393 +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 - -/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be - * used to modify and send a response packet (and to 1 if this is not the case, - * e.g. when link header is stripped of when receiving) */ -#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN -#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 -#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ - -/* The amount of data from the original packet to return in a dest-unreachable */ -#define ICMP_DEST_UNREACH_DATASIZE 8 - -static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); - -/** - * Processes ICMP input packets, called from ip_input(). - * - * Currently only processes icmp echo requests and sends - * out the echo response. - * - * @param p the icmp echo request packet, p->payload pointing to the 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; - s16_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(iphdr_in) * 4; - if (hlen < IP_HLEN) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short IP header (%"S16_F" bytes) received\n", hlen)); - goto lenerr; - } - if (p->len < sizeof(u16_t)*2) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); - goto lenerr; - } - - type = *((u8_t *)p->payload); -#ifdef LWIP_DEBUG - code = *(((u8_t *)p->payload)+1); -#endif /* LWIP_DEBUG */ - switch (type) { - case ICMP_ER: - /* This is OK, echo reply might have been parsed by a raw PCB - (as obviously, an echo request has been sent, too). */ - 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_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; - /* allocate new packet buffer with space for link headers */ - r = pbuf_alloc(PBUF_LINK, p->tot_len + hlen, 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_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_header(p, -(s16_t)(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_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 += PP_HTONS(ICMP_ECHO << 8) + 1; - } else { - iecho->chksum += PP_HTONS(ICMP_ECHO << 8); - } - } -#if LWIP_CHECKSUM_CTRL_PER_NETIF - else { - iecho->chksum = 0; - } -#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ -#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, 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.icmpindestunreachs); - } 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_src, &iphdr_dst); - } -#else - netif = ip4_route(&iphdr_src); -#endif - if (netif != NULL) { - /* calculate checksum */ - icmphdr->chksum = 0; -#if CHECKSUM_GEN_ICMP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP) { - icmphdr->chksum = inet_chksum(icmphdr, q->len); - } -#endif - ICMP_STATS_INC(icmp.xmit); - ip4_output_if(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP, netif); - } - pbuf_free(q); -} - -#endif /* LWIP_IPV4 && LWIP_ICMP */ diff --git a/ext/lwip/src/core/ipv4/igmp.c b/ext/lwip/src/core/ipv4/igmp.c deleted file mode 100644 index 50c5d9d..0000000 --- a/ext/lwip/src/core/ipv4/igmp.c +++ /dev/null @@ -1,841 +0,0 @@ -/** - * @file - * IGMP - Internet Group Management Protocol - * - */ - -/* - * Copyright (c) 2002 CITEL Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This file is a contribution to the lwIP TCP/IP stack. - * The Swedish Institute of Computer Science and Adam Dunkels - * are specifically granted permission to redistribute this - * source code. -*/ - -/** - * @defgroup igmp IGMP - * @ingroup ip4 - * To be called from TCPIP thread - */ - -/*------------------------------------------------------------- -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 "string.h" - -/* - * 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 - - -static struct igmp_group *igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr); -static err_t igmp_remove_group(struct igmp_group *group); -static void igmp_timeout( struct igmp_group *group); -static void igmp_start_timer(struct igmp_group *group, u8_t max_time); -static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); -static err_t igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif); -static void igmp_send(struct igmp_group *group, u8_t type); - - -static struct igmp_group* igmp_group_list; -static 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, IGMP_ADD_MAC_FILTER); - } - - return ERR_OK; - } - - return ERR_MEM; -} - -/** - * Stop IGMP processing on interface - * - * @param netif network interface on which stop IGMP processing - */ -err_t -igmp_stop(struct netif *netif) -{ - struct igmp_group *group = igmp_group_list; - struct igmp_group *prev = NULL; - struct igmp_group *next; - - /* look for groups joined on this interface further down the list */ - while (group != NULL) { - next = group->next; - /* is it a group joined on this interface? */ - if (group->netif == netif) { - /* is it the first group of the list? */ - if (group == igmp_group_list) { - igmp_group_list = next; - } - /* is there a "previous" group defined? */ - if (prev != NULL) { - prev->next = next; - } - /* disable the group at the MAC level */ - if (netif->igmp_mac_filter != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); - ip4_addr_debug_print(IGMP_DEBUG, &group->group_address); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif)); - netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); - } - /* free group */ - memp_free(MEMP_IGMP_GROUP, group); - } else { - /* change the "previous" */ - prev = group; - } - /* move to "next" */ - group = next; - } - return ERR_OK; -} - -/** - * Report IGMP memberships for this interface - * - * @param netif network interface on which report IGMP memberships - */ -void -igmp_report_groups(struct netif *netif) -{ - struct igmp_group *group = igmp_group_list; - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", (void*)netif)); - - while (group != NULL) { - if ((group->netif == netif) && (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) { - igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); - } - group = group->next; - } -} - -/** - * Search for a group in the global igmp_group_list - * - * @param ifp the network interface for which to look - * @param addr the group ip address to search for - * @return a struct igmp_group* if the group has been found, - * NULL if the group wasn't found. - */ -struct igmp_group * -igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr) -{ - struct igmp_group *group = igmp_group_list; - - while (group != NULL) { - if ((group->netif == ifp) && (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. - */ -struct igmp_group * -igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr) -{ - struct igmp_group *group; - - /* Search if the group already exists */ - group = igmp_lookfor_group(ifp, addr); - if (group != NULL) { - /* Group already exists. */ - return group; - } - - /* Group doesn't exist yet, create a new one */ - group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); - if (group != NULL) { - group->netif = ifp; - 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; - group->next = igmp_group_list; - - igmp_group_list = group; - } - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); - ip4_addr_debug_print(IGMP_DEBUG, addr); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)ifp)); - - return group; -} - -/** - * Remove a group in the global igmp_group_list - * - * @param group the group to remove from the global igmp_group_list - * @return ERR_OK if group was removed from the list, an err_t otherwise - */ -static err_t -igmp_remove_group(struct igmp_group *group) -{ - err_t err = ERR_OK; - - /* Is it the first group? */ - if (igmp_group_list == group) { - igmp_group_list = group->next; - } else { - /* look for group further down the list */ - struct igmp_group *tmpGroup; - for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { - if (tmpGroup->next == group) { - tmpGroup->next = group->next; - break; - } - } - /* Group not found in the global igmp_group_list */ - if (tmpGroup == NULL) { - err = ERR_ARG; - } - } - /* free group */ - memp_free(MEMP_IGMP_GROUP, group); - - return err; -} - -/** - * Called from ip_input() if a new IGMP packet is received. - * - * @param p received igmp packet, p->payload pointing to the 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(IGMP_DEBUG, &(ip4_current_header()->src)); - LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); - ip4_addr_debug_print(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 = igmp_group_list; - while (groupref) { - /* Do not send messages on the all systems group address! */ - if ((groupref->netif == inp) && (!(ip4_addr_cmp(&(groupref->group_address), &allsystems)))) { - igmp_delaying_member(groupref, igmp->igmp_maxresp); - } - groupref = groupref->next; - } - } else { - /* IGMP_MEMB_QUERY to a specific group ? */ - if (!ip4_addr_isany(&igmp->igmp_group_address)) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); - ip4_addr_debug_print(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*)group->netif)); - 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; - - /* 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 = netif_list; - while (netif != NULL) { - /* 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; - } - } - /* proceed to next network interface */ - netif = netif->next; - } - - 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; - - /* 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, IGMP_ADD_MAC_FILTER); - } - - IGMP_STATS_INC(igmp.tx_join); - igmp_send(group, IGMP_V2_MEMB_REPORT); - - igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); - - /* Need to work out where this timer comes from */ - group->group_state = IGMP_GROUP_DELAYING_MEMBER; - } - /* Increment group use */ - group->use++; - /* Join on this interface */ - 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; - - /* 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 = netif_list; - while (netif != NULL) { - /* 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; - } - } - /* proceed to next network interface */ - netif = netif->next; - } - - 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; - - /* 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) { - /* 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(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, IGMP_DEL_MAC_FILTER); - } - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: remove group: ")); - ip4_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, ("\n")); - - /* Free the group */ - igmp_remove_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 igmp_group *group = igmp_group_list; - - while (group != NULL) { - if (group->timer > 0) { - group->timer--; - if (group->timer == 0) { - igmp_timeout(group); - } - } - group = group->next; - } -} - -/** - * Called if a timeout for one group is reached. - * Sends a report for this group. - * - * @param group an igmp_group for which a timeout is reached - */ -static void -igmp_timeout(struct igmp_group *group) -{ - /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group - (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(IGMP_DEBUG, &(group->group_address)); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)group->netif)); - - IGMP_STATS_INC(igmp.tx_report); - igmp_send(group, IGMP_V2_MEMB_REPORT); - } -} - -/** - * Start a timer for an igmp group - * - * @param group the igmp_group for which to start a timer - * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with - * every call to igmp_tmr()) - */ -static void -igmp_start_timer(struct igmp_group *group, u8_t max_time) -{ -#ifdef LWIP_RAND - group->timer = 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 == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * @param netif the netif on which to send this packet - * @return ERR_OK if the packet was sent OK - * ERR_BUF if p doesn't have enough space for IP/LINK headers - * returns errors returned by netif->output - */ -static err_t -igmp_ip_output_if(struct pbuf *p, 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 igmp_group *group, u8_t type) -{ - struct pbuf* p = NULL; - struct igmp_msg* igmp = NULL; - ip4_addr_t src = *IP4_ADDR_ANY; - 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(group->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, group->netif); - } - - pbuf_free(p); - } else { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); - IGMP_STATS_INC(igmp.memerr); - } -} - -#endif /* LWIP_IPV4 && LWIP_IGMP */ diff --git a/ext/lwip/src/core/ipv4/ip4.c b/ext/lwip/src/core/ipv4/ip4.c deleted file mode 100644 index ed2cf20..0000000 --- a/ext/lwip/src/core/ipv4/ip4.c +++ /dev/null @@ -1,1073 +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/raw.h" -#include "lwip/udp.h" -#include "lwip/priv/tcp_priv.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/stats.h" - -#include - -/** Set this to 0 in the rare case of wanting to call an extra function to - * generate the IP checksum (in contrast to calculating it on-the-fly). */ -#ifndef LWIP_INLINE_IP_CHKSUM -#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(DHCP_CLIENT_PORT)) \ - || (LWIP_IP_ACCEPT_UDP_PORT(port))) -#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ -/* accept custom port only */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(port)) -#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ -/* accept DHCP client port only */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT)) -#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ - -#else /* LWIP_DHCP */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 -#endif /* LWIP_DHCP */ - -/** The 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; - -/** 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 he parameters. - */ -struct netif * -ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src) -{ - if (src != NULL) { - /* when src==NULL, the hook is called from ip4_route(dest) */ - struct netif *netif = LWIP_HOOK_IP4_ROUTE_SRC(dest, src); - 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) -{ - struct netif *netif; - -#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 */ - - /* iterate through netifs */ - for (netif = netif_list; netif != NULL; netif = netif->next) { - /* 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_is_up(netif_default)) { - return netif_default; - } - /* default netif is not up, just use any netif for loopback traffic */ - for (netif = netif_list; netif != NULL; netif = netif->next) { - 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(dest, NULL); - if (netif != NULL) { - return netif; - } -#elif defined(LWIP_HOOK_IP4_ROUTE) - netif = LWIP_HOOK_IP4_ROUTE(dest); - if (netif != NULL) { - return netif; - } -#endif - - if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) || - ip4_addr_isany_val(*netif_ip4_addr(netif_default))) { - /* 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 - * @param dest the destination IP address - * @return 1: can forward 0: discard - */ -static int -ip4_canforward(struct pbuf *p) -{ - u32_t addr = htonl(ip4_addr_get_u32(ip4_current_dest_addr())); - - 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 unless the destination address is an IP - multicast address */ - 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; - - 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_dest_addr(), ip4_current_src_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, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1); - } else { - IPH_CHKSUM_SET(iphdr, 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 */ - -/** - * 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) -{ - 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 */ - - 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 number of 32-bit words */ - iphdr_hlen = IPH_HL(iphdr); - /* calculate IP header length in bytes */ - iphdr_hlen *= 4; - /* obtain ip length in bytes */ - iphdr_len = ntohs(IPH_LEN(iphdr)); - - /* 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. - 'first' is used as a boolean to mark whether we started walking the list */ - int first = 1; - netif = inp; - do { - LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", - ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(netif_ip4_addr(netif)), - ip4_addr_get_u32(&iphdr->dest) & 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(&iphdr->dest) & ~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])); - /* break out of for loop */ - break; - } -#if LWIP_AUTOIP - /* connections to link-local addresses must persist after changing - the netif's address (RFC3927 ch. 1.9) */ - if ((netif->autoip != NULL) && - ip4_addr_cmp(ip4_current_dest_addr(), &(netif->autoip->llipaddr))) { - LWIP_DEBUGF(IP_DEBUG, ("ip4_input: LLA packet accepted on interface %c%c\n", - netif->name[0], netif->name[1])); - /* break out of for loop */ - break; - } -#endif /* LWIP_AUTOIP */ - } - if (first) { - first = 0; - netif = netif_list; - } else { - netif = netif->next; - } - if (netif == inp) { - netif = netif->next; - } - } while (netif != NULL); - } - -#if IP_ACCEPT_LINK_LAYER_ADDRESSING - /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed - * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. - * According to RFC 1542 section 3.1.1, referred by RFC 2131). - * - * If you want to accept private broadcast communication while a netif is down, - * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.: - * - * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345)) - */ - if (netif == NULL) { - /* remote port is DHCP server? */ - if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { - struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen); - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: UDP packet to DHCP client port %"U16_F"\n", - ntohs(udphdr->dest))); - if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("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, iphdr, inp); - } else -#endif /* IP_FORWARD */ - { - 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", - ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), (u16_t)!!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (u16_t)((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 = (struct ip_hdr *)p->payload; -#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ - pbuf_free(p); - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", - ntohs(IPH_OFFSET(iphdr)))); - IP_STATS_INC(ip.opterr); - IP_STATS_INC(ip.drop); - /* unsupported protocol feature */ - 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(iphdr) * 4; - -#if LWIP_RAW - /* raw input did not eat the packet? */ - if (raw_input(p, inp) == 0) -#endif /* LWIP_RAW */ - { - pbuf_header(p, -(s16_t)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_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, iphdr_hlen); /* Move to ip header, no check necessary. */ - p->payload = iphdr; - icmp_dest_unreach(p, ICMP_DUR_PROTO); - } -#endif /* LWIP_ICMP */ - pbuf_free(p); - - LWIP_DEBUGF(IP_DEBUG | 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); - } - } - - /* @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 IP_HDRINCL, p is assumed to already - * include an IP header and p->payload points to it instead of the data. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param tos the TOS value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * @param netif the netif on which to send this packet - * @return ERR_OK if the packet was sent OK - * ERR_BUF if p doesn't have enough space for IP/LINK headers - * returns errors returned by netif->output - * - * @note ip_id: RFC791 "some host may be able to simply use - * unique identifiers independent of destination" - */ -err_t -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 != 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_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 != IP_HDRINCL) { - u16_t ip_hlen = IP_HLEN; -#if IP_OPTIONS_SEND - u16_t optlen_aligned = 0; - if (optlen != 0) { -#if CHECKSUM_GEN_IP_INLINE - int i; -#endif /* CHECKSUM_GEN_IP_INLINE */ - /* round up to a multiple of 4 */ - optlen_aligned = ((optlen + 3) & ~3); - ip_hlen += optlen_aligned; - /* First write in the IP options */ - if (pbuf_header(p, optlen_aligned)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("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, optlen_aligned - optlen); - } -#if CHECKSUM_GEN_IP_INLINE - for (i = 0; i < optlen_aligned/2; i++) { - chk_sum += ((u16_t*)p->payload)[i]; - } -#endif /* CHECKSUM_GEN_IP_INLINE */ - } -#endif /* IP_OPTIONS_SEND */ - /* generate IP header */ - if (pbuf_header(p, IP_HLEN)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("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 += LWIP_MAKE_U16(proto, ttl); -#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 += LWIP_MAKE_U16(tos, iphdr->_v_hl); -#endif /* CHECKSUM_GEN_IP_INLINE */ - IPH_LEN_SET(iphdr, htons(p->tot_len)); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += iphdr->_len; -#endif /* CHECKSUM_GEN_IP_INLINE */ - IPH_OFFSET_SET(iphdr, 0); - IPH_ID_SET(iphdr, htons(ip_id)); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += iphdr->_id; -#endif /* CHECKSUM_GEN_IP_INLINE */ - ++ip_id; - - if (src == NULL) { - ip4_addr_copy(iphdr->src, *IP4_ADDR_ANY); - } 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 */ - 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 == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param tos the TOS value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * - * @return ERR_RTE if no route is found - * see ip_output_if() for more return values - */ -err_t -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(dest, src)) == 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_HWADDRHINT -/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint - * before calling ip_output_if. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param tos the TOS value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * @param addr_hint address hint pointer set to netif->addr_hint before - * calling ip_output_if() - * - * @return ERR_RTE if no route is found - * see ip_output_if() for more return values - */ -err_t -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, u8_t *addr_hint) -{ - struct netif *netif; - err_t err; - - LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); - - if ((netif = ip4_route_src(dest, src)) == 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_HWADDRHINT(netif, addr_hint); - err = ip4_output_if(p, src, dest, ttl, tos, proto, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - - return err; -} -#endif /* LWIP_NETIF_HWADDRHINT*/ - -#if IP_DEBUG -/* Print an IP header by using LWIP_DEBUGF - * @param p an IP packet, p->payload pointing to the IP header - */ -void -ip4_debug_print(struct pbuf *p) -{ - #if defined(LWIP_DEBUG) - 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), - ntohs(IPH_LEN(iphdr)))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", - ntohs(IPH_ID(iphdr)), - (u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 15 & 1), - (u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 14 & 1), - (u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 13 & 1), - (u16_t)(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), - ntohs(IPH_CHKSUM(iphdr)))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", - ip4_addr1_16(&iphdr->src), - ip4_addr2_16(&iphdr->src), - ip4_addr3_16(&iphdr->src), - ip4_addr4_16(&iphdr->src))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", - ip4_addr1_16(&iphdr->dest), - ip4_addr2_16(&iphdr->dest), - ip4_addr3_16(&iphdr->dest), - ip4_addr4_16(&iphdr->dest))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - #endif -} -#endif /* IP_DEBUG */ - -#endif /* LWIP_IPV4 */ diff --git a/ext/lwip/src/core/ipv4/ip4_addr.c b/ext/lwip/src/core/ipv4/ip4_addr.c deleted file mode 100644 index 7fe35c9..0000000 --- a/ext/lwip/src/core/ipv4/ip4_addr.c +++ /dev/null @@ -1,331 +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 IP_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; -} - -/* Here for now until needed in other places in lwIP */ -#ifndef isprint -#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) -#define isprint(c) in_range(c, 0x20, 0x7f) -#define isdigit(c) in_range(c, '0', '9') -#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) -#define islower(c) in_range(c, 'a', 'z') -#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') -#endif - -/** - * Ascii internet address interpretation routine. - * The value returned is in network order. - * - * @param cp IP address in ascii 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 (!isdigit(c)) { - return 0; - } - val = 0; - base = 10; - if (c == '0') { - c = *++cp; - if (c == 'x' || c == 'X') { - base = 16; - c = *++cp; - } else { - base = 8; - } - } - for (;;) { - if (isdigit(c)) { - val = (val * base) + (int)(c - '0'); - c = *++cp; - } else if (base == 16 && isxdigit(c)) { - val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A')); - c = *++cp; - } else { - break; - } - } - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3) { - return 0; - } - *pp++ = val; - c = *++cp; - } else { - break; - } - } - /* - * Check for trailing characters. - */ - if (c != '\0' && !isspace(c)) { - return 0; - } - /* - * Concoct the address according to - * the number of parts specified. - */ - switch (pp - parts + 1) { - - case 0: - return 0; /* initial nondigit */ - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffffUL) { - return 0; - } - 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, 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 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* -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++] = '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/ext/lwip/src/core/ipv4/ip4_frag.c b/ext/lwip/src/core/ipv4/ip4_frag.c deleted file mode 100644 index b18d904..0000000 --- a/ext/lwip/src/core/ipv4/ip4_frag.c +++ /dev/null @@ -1,897 +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 - -/** 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; - u8_t clen; - struct pbuf *p; - struct ip_reass_helper *iprh; - - LWIP_ASSERT("prev != ipr", prev != ipr); - if (prev != NULL) { - LWIP_ASSERT("prev->next == ipr", prev->next == ipr); - } - - 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 += clen; - pbuf_free(p); - } -#endif /* LWIP_ICMP */ - - /* First, free all received pbufs. The individual pbufs need to be released - separately as they have not yet been chained */ - p = ipr->p; - while (p != NULL) { - struct pbuf *pcur; - iprh = (struct ip_reass_helper *)p->payload; - pcur = p; - /* get the next pointer before freeing */ - p = iprh->next_pbuf; - clen = pbuf_clen(pcur); - LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); - pbufs_freed += clen; - pbuf_free(pcur); - } - /* Then, unchain the struct ip_reassdata from the list and free it. */ - ip_reass_dequeue_datagram(ipr, prev); - LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed); - ip_reass_pbufcount -= pbufs_freed; - - return pbufs_freed; -} - -#if IP_REASS_FREE_OLDEST -/** - * Free the oldest datagram to make room for enqueueing new fragments. - * The datagram 'fraghdr' belongs to is not freed! - * - * @param fraghdr IP header of the current fragment - * @param pbufs_needed number of pbufs needed to enqueue - * (used for freeing other datagrams if not enough space) - * @return the number of pbufs freed - */ -static int -ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed) -{ - /* @todo Can't we simply remove the last datagram in the - * linked list behind reassdatagrams? - */ - struct ip_reassdata *r, *oldest, *prev, *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 root_p points to the 'root' pbuf for the current datagram being assembled. - * @param new_p points to the pbuf for the current fragment - * @return 0 if invalid, >0 otherwise - */ -static int -ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p) -{ - struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; - struct pbuf *q; - u16_t offset,len; - struct ip_hdr *fraghdr; - int valid = 1; - - /* Extract length and fragment offset from current fragment */ - fraghdr = (struct ip_hdr*)new_p->payload; - len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; - offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; - - /* overwrite the fragment's ip header from the pbuf with our helper struct, - * and setup the embedded helper structure. */ - /* make sure the struct ip_reass_helper fits into the IP header */ - LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN", - sizeof(struct ip_reass_helper) <= IP_HLEN); - iprh = (struct ip_reass_helper*)new_p->payload; - iprh->next_pbuf = NULL; - iprh->start = offset; - iprh->end = offset + len; - - /* Iterate through until we either get to the end of the list (append), - * or we find 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 */ - goto freepbuf; - } -#endif /* IP_REASS_CHECK_OVERLAP */ - iprh_prev->next_pbuf = new_p; - } else { - /* fragment with the lowest offset */ - ipr->p = new_p; - } - break; - } else if (iprh->start == iprh_tmp->start) { - /* received the same datagram twice: no need to keep the datagram */ - goto freepbuf; -#if IP_REASS_CHECK_OVERLAP - } else if (iprh->start < iprh_tmp->end) { - /* overlap: no need to keep the new datagram */ - goto freepbuf; -#endif /* IP_REASS_CHECK_OVERLAP */ - } else { - /* Check if the fragments received so far have no 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 ((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); - LWIP_ASSERT("validate_datagram:datagram end!=datagram len", - iprh->end == ipr->datagram_len); - } - } - } - /* If valid is 0 here, there are some fragments missing in the middle - * (since MF == 0 has already arrived). Such datagrams simply time out if - * no more fragments are received... */ - return valid; - } - /* If we come here, not all fragments were received, yet! */ - return 0; /* not yet valid! */ -#if IP_REASS_CHECK_OVERLAP -freepbuf: - ip_reass_pbufcount -= pbuf_clen(new_p); - pbuf_free(new_p); - return 0; -#endif /* IP_REASS_CHECK_OVERLAP */ -} - -/** - * Reassembles incoming IP fragments into an IP datagram. - * - * @param p points to a pbuf chain of the fragment - * @return NULL if reassembly is incomplete, ? otherwise - */ -struct pbuf * -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; - u8_t clen; - - IPFRAG_STATS_INC(ip_frag.recv); - MIB2_STATS_INC(mib2.ipreasmreqds); - - fraghdr = (struct ip_hdr*)p->payload; - - if ((IPH_HL(fraghdr) * 4) != IP_HLEN) { - LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: IP options currently not supported!\n")); - IPFRAG_STATS_INC(ip_frag.err); - goto nullreturn; - } - - offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; - len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; - - /* Check if we are allowed to enqueue more datagrams. */ - clen = pbuf_clen(p); - if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { -#if IP_REASS_FREE_OLDEST - if (!ip_reass_remove_oldest_datagram(fraghdr, clen) || - ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)) -#endif /* IP_REASS_FREE_OLDEST */ - { - /* No datagram could be freed and still too many pbufs enqueued */ - LWIP_DEBUGF(IP_REASS_DEBUG,("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", - 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 (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && - ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) { - /* ipr->iphdr is not the header from the first fragment, but fraghdr is - * -> copy fraghdr into ipr->iphdr since we want to have the header - * of the first fragment (for ICMP time exceeded and later, for copying - * all options, if supported)*/ - SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN); - } - } - /* Track the current number of pbufs current 'in-flight', in order to limit - the number of fragments that may be enqueued at any one time */ - ip_reass_pbufcount += clen; - - /* At this point, we have either created a new entry or pointing - * to an existing one */ - - /* check for 'no more fragments', and update queue entry*/ - if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) { - ipr->flags |= IP_REASS_FLAG_LASTFRAG; - ipr->datagram_len = offset + len; - LWIP_DEBUGF(IP_REASS_DEBUG, - ("ip4_reass: last fragment seen, total len %"S16_F"\n", - ipr->datagram_len)); - } - /* find the right place to insert this pbuf */ - /* @todo: trim pbufs if fragments are overlapping */ - if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) { - struct ip_reassdata *ipr_prev; - /* the totally last fragment (flag more fragments = 0) was received at least - * once AND all fragments are received */ - ipr->datagram_len += IP_HLEN; - - /* save the second pbuf before copying the header over the pointer */ - r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf; - - /* copy the original ip header back to the first pbuf */ - fraghdr = (struct ip_hdr*)(ipr->p->payload); - SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN); - IPH_LEN_SET(fraghdr, htons(ipr->datagram_len)); - IPH_OFFSET_SET(fraghdr, 0); - IPH_CHKSUM_SET(fraghdr, 0); - /* @todo: do we need to set/calculate the correct checksum? */ -#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_header(r, -IP_HLEN); - pbuf_cat(p, r); - r = iprh->next_pbuf; - } - - /* find the previous entry in the linked list */ - if (ipr == reassdatagrams) { - ipr_prev = NULL; - } else { - for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { - if (ipr_prev->next == ipr) { - break; - } - } - } - - /* release the sources allocate for the fragment queue entry */ - ip_reass_dequeue_datagram(ipr, ipr_prev); - - /* and adjust the number of pbufs currently queued for reassembly. */ - ip_reass_pbufcount -= pbuf_clen(p); - - MIB2_STATS_INC(mib2.ipreasmoks); - - /* Return the pbuf chain */ - return p; - } - /* the datagram is not (yet?) reassembled completely */ - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount)); - return NULL; - -nullreturn: - LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: nullreturn\n")); - IPFRAG_STATS_INC(ip_frag.drop); - pbuf_free(p); - return NULL; -} -#endif /* IP_REASSEMBLY */ - -#if IP_FRAG -#if IP_FRAG_USES_STATIC_BUF -static LWIP_DECLARE_MEMORY_ALIGNED(buf, IP_FRAG_MAX_MTU); -#else /* IP_FRAG_USES_STATIC_BUF */ - -#if !LWIP_NETIF_TX_SINGLE_PBUF -/** Allocate a new struct pbuf_custom_ref */ -static struct pbuf_custom_ref* -ip_frag_alloc_pbuf_custom_ref(void) -{ - return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); -} - -/** Free a struct pbuf_custom_ref */ -static void -ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) -{ - LWIP_ASSERT("p != NULL", p != NULL); - memp_free(MEMP_FRAG_PBUF, p); -} - -/** Free-callback function to free a 'struct pbuf_custom_ref', called by - * pbuf_free. */ -static void -ipfrag_free_pbuf_custom(struct pbuf *p) -{ - struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; - LWIP_ASSERT("pcr != NULL", pcr != NULL); - LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); - if (pcr->original != NULL) { - pbuf_free(pcr->original); - } - ip_frag_free_pbuf_custom_ref(pcr); -} -#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ -#endif /* IP_FRAG_USES_STATIC_BUF */ - -/** - * Fragment an IP datagram if too large for the netif. - * - * Chop the datagram in MTU sized chunks and send them in order - * by using a fixed size static memory buffer (PBUF_REF) or - * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF). - * - * @param p ip packet to send - * @param netif the netif on which to send - * @param dest destination ip address to which to send - * - * @return ERR_OK if sent successfully, err_t otherwise - */ -err_t -ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest) -{ - struct pbuf *rambuf; -#if IP_FRAG_USES_STATIC_BUF - struct pbuf *header; -#else -#if !LWIP_NETIF_TX_SINGLE_PBUF - struct pbuf *newpbuf; -#endif - struct ip_hdr *original_iphdr; -#endif - struct ip_hdr *iphdr; - u16_t nfb; - u16_t left, cop; - u16_t mtu = netif->mtu; - u16_t ofo, omf; - u16_t last; - u16_t poff = IP_HLEN; - u16_t tmp; -#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF - u16_t newpbuflen = 0; - u16_t left_to_copy; -#endif - - /* Get a RAM based MTU sized pbuf */ -#if IP_FRAG_USES_STATIC_BUF - /* When using a static buffer, we use a PBUF_REF, which we will - * use to reference the packet (without link header). - * Layer and length is irrelevant. - */ - rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF); - if (rambuf == NULL) { - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n")); - goto memerr; - } - rambuf->tot_len = rambuf->len = mtu; - rambuf->payload = LWIP_MEM_ALIGN((void *)buf); - - /* Copy the IP header in it */ - iphdr = (struct ip_hdr *)rambuf->payload; - SMEMCPY(iphdr, p->payload, IP_HLEN); -#else /* IP_FRAG_USES_STATIC_BUF */ - original_iphdr = (struct ip_hdr *)p->payload; - iphdr = original_iphdr; -#endif /* IP_FRAG_USES_STATIC_BUF */ - - /* Save original offset */ - tmp = ntohs(IPH_OFFSET(iphdr)); - ofo = tmp & IP_OFFMASK; - omf = tmp & IP_MF; - - left = p->tot_len - IP_HLEN; - - nfb = (mtu - IP_HLEN) / 8; - - while (left) { - last = (left <= mtu - IP_HLEN); - - /* Set new offset and MF flag */ - tmp = omf | (IP_OFFMASK & (ofo)); - if (!last) { - tmp = tmp | IP_MF; - } - - /* Fill this fragment */ - cop = last ? left : nfb * 8; - -#if IP_FRAG_USES_STATIC_BUF - poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff); -#else /* IP_FRAG_USES_STATIC_BUF */ -#if LWIP_NETIF_TX_SINGLE_PBUF - rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM); - if (rambuf == NULL) { - 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, cop, poff); - /* make room for the IP header */ - if (pbuf_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!", - (p->len >= (IP_HLEN))); - SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); - iphdr = (struct ip_hdr *)rambuf->payload; - - /* Can just adjust p directly for needed offset. */ - p->payload = (u8_t *)p->payload + poff; - p->len -= poff; - - left_to_copy = cop; - while (left_to_copy) { - struct pbuf_custom_ref *pcr; - newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; - /* Is this pbuf already empty? */ - if (!newpbuflen) { - p = p->next; - continue; - } - pcr = ip_frag_alloc_pbuf_custom_ref(); - if (pcr == NULL) { - pbuf_free(rambuf); - goto memerr; - } - /* Mirror this pbuf, although we might not need all of it. */ - newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); - if (newpbuf == NULL) { - ip_frag_free_pbuf_custom_ref(pcr); - pbuf_free(rambuf); - 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 -= newpbuflen; - if (left_to_copy) { - p = p->next; - } - } - poff = newpbuflen; -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ -#endif /* IP_FRAG_USES_STATIC_BUF */ - - /* Correct header */ - IPH_OFFSET_SET(iphdr, htons(tmp)); - IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); - IPH_CHKSUM_SET(iphdr, 0); -#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 */ - -#if IP_FRAG_USES_STATIC_BUF - if (last) { - pbuf_realloc(rambuf, left + IP_HLEN); - } - - /* This part is ugly: we alloc a RAM based pbuf for - * the link level header for each chunk and then - * free it. A PBUF_ROM style pbuf for which pbuf_header - * worked would make things simpler. - */ - header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM); - if (header != NULL) { - pbuf_chain(header, rambuf); - netif->output(netif, header, dest); - IPFRAG_STATS_INC(ip_frag.xmit); - MIB2_STATS_INC(mib2.ipfragcreates); - pbuf_free(header); - } else { - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n")); - pbuf_free(rambuf); - goto memerr; - } -#else /* IP_FRAG_USES_STATIC_BUF */ - /* No need for separate header pbuf - we allowed room for it in rambuf - * when allocated. - */ - netif->output(netif, rambuf, dest); - IPFRAG_STATS_INC(ip_frag.xmit); - - /* Unfortunately we can't reuse rambuf - the hardware may still be - * using the buffer. Instead we free it (and the ensuing chain) and - * recreate it next time round the loop. If we're lucky the hardware - * will have already sent the packet, the free will really free, and - * there will be zero memory penalty. - */ - - pbuf_free(rambuf); -#endif /* IP_FRAG_USES_STATIC_BUF */ - left -= cop; - ofo += nfb; - } -#if IP_FRAG_USES_STATIC_BUF - pbuf_free(rambuf); -#endif /* IP_FRAG_USES_STATIC_BUF */ - 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/ext/lwip/src/core/ipv6/README b/ext/lwip/src/core/ipv6/README deleted file mode 100644 index 3620004..0000000 --- a/ext/lwip/src/core/ipv6/README +++ /dev/null @@ -1 +0,0 @@ -IPv6 support in lwIP is very experimental. diff --git a/ext/lwip/src/core/ipv6/dhcp6.c b/ext/lwip/src/core/ipv6/dhcp6.c deleted file mode 100644 index f27a725..0000000 --- a/ext/lwip/src/core/ipv6/dhcp6.c +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file - * - * DHCPv6. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#include "lwip/opt.h" - -#if LWIP_IPV6 && LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/ip6_addr.h" -#include "lwip/def.h" - - -#endif /* LWIP_IPV6 && LWIP_IPV6_DHCP6 */ diff --git a/ext/lwip/src/core/ipv6/ethip6.c b/ext/lwip/src/core/ipv6/ethip6.c deleted file mode 100644 index 442c62b..0000000 --- a/ext/lwip/src/core/ipv6/ethip6.c +++ /dev/null @@ -1,157 +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" - - - -#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 "netif/ethernet.h" - -#include - -/** - * Send an IPv6 packet on the network using netif->linkoutput - * The ethernet header is filled in before sending. - * - * @params netif the lwIP network interface on which to send the packet - * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header - * @params src the source MAC address to be copied into the ethernet header - * @params dst the destination MAC address to be copied into the ethernet header - * @return ERR_OK if the packet was sent, any other err_t on failure - */ -static err_t -ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) -{ - struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; - - LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!", - (netif->hwaddr_len == 6)); - SMEMCPY(ðhdr->dest, dst, 6); - SMEMCPY(ðhdr->src, src, 6); - ethhdr->type = PP_HTONS(ETHTYPE_IPV6); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p)); - /* send the packet */ - return netif->linkoutput(netif, p); -} - -/** - * Resolve and fill-in Ethernet address header for outgoing IPv6 packet. - * - * For IPv6 multicast, corresponding Ethernet addresses - * are selected and the packet is transmitted on the link. - * - * For unicast addresses, ... - * - * @todo anycast addresses - * - * @param netif The lwIP network interface which the IP packet will be sent on. - * @param q The pbuf(s) containing the IP packet to be sent. - * @param ip6addr The IP address of the packet destination. - * - * @return - * - ERR_RTE No route to destination (no gateway to external networks), - * or the return type of either etharp_query() or etharp_send_ip(). - */ -err_t -ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) -{ - struct eth_addr dest; - s8_t i; - - /* make room for Ethernet header - should not fail */ - if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { - /* bail out */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("etharp_output: could not allocate room for header.\n")); - return ERR_BUF; - } - - /* multicast destination IP address? */ - if (ip6_addr_ismulticast(ip6addr)) { - /* Hash IP multicast address to MAC address.*/ - dest.addr[0] = 0x33; - dest.addr[1] = 0x33; - dest.addr[2] = ((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 ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); - } - - /* We have a unicast destination IP address */ - /* @todo anycast? */ - /* Get next hop record. */ - i = nd6_get_next_hop_entry(ip6addr, netif); - if (i < 0) { - /* failed to get a next hop neighbor record. */ - return ERR_MEM; - } - - /* Now that we have a destination record, send or queue the packet. */ - if (neighbor_cache[i].state == ND6_STALE) { - /* Switch to delay state. */ - neighbor_cache[i].state = ND6_DELAY; - neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; - } - /* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */ - if ((neighbor_cache[i].state == ND6_REACHABLE) || - (neighbor_cache[i].state == ND6_DELAY) || - (neighbor_cache[i].state == ND6_PROBE)) { - - /* Send out. */ - SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6); - return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); - } - /* We should queue packet on this interface. */ - pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR); - return nd6_queue_packet(i, q); -} - diff --git a/ext/lwip/src/core/ipv6/icmp6.c b/ext/lwip/src/core/ipv6/icmp6.c deleted file mode 100644 index 397d2d6..0000000 --- a/ext/lwip/src/core/ipv6/icmp6.c +++ /dev/null @@ -1,349 +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/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 - -#ifndef LWIP_ICMP6_DATASIZE -#define LWIP_ICMP6_DATASIZE 8 -#endif -#if LWIP_ICMP6_DATASIZE == 0 -#define LWIP_ICMP6_DATASIZE 8 -#endif - -/* Forward declarations */ -static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type); - - -/** - * Process an input ICMPv6 message. Called by ip6_input. - * - * Will generate a reply for echo requests. Other messages are forwarded - * to nd6_input, or mld6_input. - * - * @param p the mld packet, p->payload pointing to the icmpv6 header - * @param inp the netif on which this packet was received - */ -void -icmp6_input(struct pbuf *p, struct netif *inp) -{ - 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; - break; - case ICMP6_TYPE_RS: -#if LWIP_IPV6_FORWARD - /* @todo implement router functionality */ -#endif - break; -#if LWIP_IPV6_MLD - case ICMP6_TYPE_MLQ: - case ICMP6_TYPE_MLR: - case ICMP6_TYPE_MLD: - mld6_input(p, inp); - return; - break; -#endif - case ICMP6_TYPE_EREQ: -#if !LWIP_MULTICAST_PING - /* multicast destination address? */ - if (ip6_addr_ismulticast(ip6_current_dest_addr())) { - /* drop */ - pbuf_free(p); - ICMP6_STATS_INC(icmp6.drop); - return; - } -#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. - * - * @param p the input packet for which the 'unreachable' should be sent, - * p->payload pointing to the IPv6 header - * @param c ICMPv6 code for the unreachable type - */ -void -icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) -{ - icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR); -} - -/** - * Send an icmpv6 'packet too big' packet. - * - * @param p the input packet for which the 'packet too big' should be sent, - * p->payload pointing to the IPv6 header - * @param mtu the maximum mtu that we can accept - */ -void -icmp6_packet_too_big(struct pbuf *p, u32_t mtu) -{ - icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB); -} - -/** - * Send an icmpv6 'time exceeded' packet. - * - * @param p the input packet for which the 'unreachable' should be sent, - * p->payload pointing to the IPv6 header - * @param c ICMPv6 code for the time exceeded type - */ -void -icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) -{ - icmp6_send_response(p, c, 0, ICMP6_TYPE_TE); -} - -/** - * Send an icmpv6 'parameter problem' packet. - * - * @param p the input packet for which the 'param problem' should be sent, - * p->payload pointing to the IP header - * @param c ICMPv6 code for the param problem type - * @param pointer the pointer to the byte where the parameter is found - */ -void -icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer) -{ - icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP); -} - -/** - * Send an ICMPv6 packet in response to an incoming packet. - * - * @param p the input packet for which the response should be sent, - * p->payload pointing to the IPv6 header - * @param code Code of the ICMPv6 header - * @param data Additional 32-bit parameter in the ICMPv6 header - * @param type Type of the ICMPv6 header - */ -static void -icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) -{ - struct pbuf *q; - struct icmp6_hdr *icmp6hdr; - const ip6_addr_t *reply_src; - ip6_addr_t *reply_dest; - ip6_addr_t reply_src_local, reply_dest_local; - struct ip6_hdr *ip6hdr; - struct netif *netif; - - /* 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 = data; - - /* copy fields from original packet */ - SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload, - IP6_HLEN + LWIP_ICMP6_DATASIZE); - - /* Get the destination address and netif for this ICMP message. */ - if ((ip_current_netif() == NULL) || - ((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) { - /* Special case, as ip6_current_xxx is either NULL, or points - * to a different packet than the one that expired. - * We must use the addresses that are stored in the expired packet. */ - ip6hdr = (struct ip6_hdr *)p->payload; - /* copy from packed address to aligned address */ - ip6_addr_copy(reply_dest_local, ip6hdr->src); - ip6_addr_copy(reply_src_local, ip6hdr->dest); - reply_dest = &reply_dest_local; - reply_src = &reply_src_local; - netif = ip6_route(reply_src, reply_dest); - if (netif == NULL) { - /* drop */ - pbuf_free(q); - ICMP6_STATS_INC(icmp6.rterr); - return; - } - } - else { - netif = ip_current_netif(); - reply_dest = ip6_current_src_addr(); - - /* Select an address to use as source. */ - reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest)); - if (reply_src == NULL) { - /* drop */ - pbuf_free(q); - ICMP6_STATS_INC(icmp6.rterr); - return; - } - } - - /* 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/ext/lwip/src/core/ipv6/inet6.c b/ext/lwip/src/core/ipv6/inet6.c deleted file mode 100644 index d9a992c..0000000 --- a/ext/lwip/src/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/ext/lwip/src/core/ipv6/ip6.c b/ext/lwip/src/core/ipv6/ip6.c deleted file mode 100644 index 3f604df..0000000 --- a/ext/lwip/src/core/ipv6/ip6.c +++ /dev/null @@ -1,1108 +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/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/ip6_frag.h" -#include "lwip/icmp6.h" -#include "lwip/raw.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" - -/** - * 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 link-local address, try to match the src address to a netif. - * this is a tricky case because with multiple netifs, link-local addresses only have - * meaning within a particular subnet/link. - * 3) tries to match the destination subnet to a configured address - * 4) tries to find a router - * 5) tries to match the source address to the netif - * 6) returns the default netif, if configured - * - * @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) -{ - struct netif *netif; - s8_t i; - - /* 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)) { - return NULL; - } - return netif_list; - } - - /* Special processing for link-local addresses. */ - if (ip6_addr_islinklocal(dest)) { - if (ip6_addr_isany(src)) { - /* Use default netif, if Up. */ - if (!netif_is_up(netif_default) || !netif_is_link_up(netif_default)) { - return NULL; - } - return netif_default; - } - - /* Try to find the netif for the source address, checking that link is up. */ - for (netif = netif_list; netif != NULL; netif = netif->next) { - 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; - } - } - } - - /* netif not found, use default netif, if up */ - if (!netif_is_up(netif_default) || !netif_is_link_up(netif_default)) { - return NULL; - } - return netif_default; - } - - /* we come here for non-link-local addresses */ -#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. */ - for (netif = netif_list; netif != NULL; netif = netif->next) { - 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))) { - return netif; - } - } - } - - /* Get the netif for a suitable router. */ - i = nd6_select_router(dest, NULL); - if (i >= 0) { - if (default_router_list[i].neighbor_entry != NULL) { - if (default_router_list[i].neighbor_entry->netif != NULL) { - if (netif_is_up(default_router_list[i].neighbor_entry->netif) && netif_is_link_up(default_router_list[i].neighbor_entry->netif)) { - return default_router_list[i].neighbor_entry->netif; - } - } - } - } - - /* try with the netif that matches the source address. */ - if (!ip6_addr_isany(src)) { - for (netif = netif_list; netif != NULL; netif = netif->next) { - 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_is_up(netif_default)) { - return netif_default; - } - /* default netif is not up, just use any netif for loopback traffic */ - for (netif = netif_list; netif != NULL; netif = netif->next) { - if (netif_is_up(netif)) { - return netif; - } - } - return NULL; - } -#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ - - /* 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; -} - -/** - * Select the best IPv6 source address for a given destination - * IPv6 address. Loosely follows RFC 3484. "Strong host" behavior - * is assumed. - * - * @param netif the netif on which to send a packet - * @param dest the destination we are trying to reach - * @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 *src = NULL; - u8_t i; - - /* If dest is link-local, choose a link-local source. */ - if (ip6_addr_islinklocal(dest) || ip6_addr_ismulticast_linklocal(dest) || ip6_addr_ismulticast_iflocal(dest)) { - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_islinklocal(netif_ip6_addr(netif, i))) { - return netif_ip_addr6(netif, i); - } - } - } - - /* Choose a site-local with matching prefix. */ - if (ip6_addr_issitelocal(dest) || ip6_addr_ismulticast_sitelocal(dest)) { - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_issitelocal(netif_ip6_addr(netif, i)) && - ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { - return netif_ip_addr6(netif, i); - } - } - } - - /* Choose a unique-local with matching prefix. */ - if (ip6_addr_isuniquelocal(dest) || ip6_addr_ismulticast_orglocal(dest)) { - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_isuniquelocal(netif_ip6_addr(netif, i)) && - ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { - return netif_ip_addr6(netif, i); - } - } - } - - /* Choose a global with best matching prefix. */ - if (ip6_addr_isglobal(dest) || ip6_addr_ismulticast_global(dest)) { - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_isglobal(netif_ip6_addr(netif, i))) { - if (src == NULL) { - src = netif_ip_addr6(netif, i); - } - else { - /* Replace src only if we find a prefix match. */ - /* @todo find longest matching prefix. */ - if ((!(ip6_addr_netcmp(ip_2_ip6(src), dest))) && - ip6_addr_netcmp(netif_ip6_addr(netif, i), dest)) { - src = netif_ip_addr6(netif, i); - } - } - } - } - if (src != NULL) { - return src; - } - } - - /* Last resort: see if arbitrary prefix matches. */ - 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))) { - return netif_ip_addr6(netif, i); - } - } - - return 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 addresses */ - if (ip6_addr_islinklocal(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; - } - /* 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 */ - -/** - * 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; - u8_t nexth; - u16_t hlen; /* the current header length */ - u8_t i; -#if 0 /*IP_ACCEPT_LINK_LAYER_ADDRESSING*/ - @todo - int check_ip_src=1; -#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ - - 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) + IP6_HLEN) > p->tot_len)) { - 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, IP6_HLEN + IP6H_PLEN(ip6hdr)); - - /* copy IP addresses to aligned ip6_addr_t */ - ip_addr_copy_from_ip6(ip_data.current_iphdr_dest, ip6hdr->dest); - ip_addr_copy_from_ip6(ip_data.current_iphdr_src, ip6hdr->src); - - /* Don't accept virtual IPv6 mapped IPv4 addresses */ - if (ip6_addr_isipv6mappedipv4(ip_2_ip6(&ip_data.current_iphdr_dest)) || - ip6_addr_isipv6mappedipv4(ip_2_ip6(&ip_data.current_iphdr_src)) ) { - IP6_STATS_INC(ip6.err); - IP6_STATS_INC(ip6.drop); - return ERR_OK; - } - - /* 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())) { - /* 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. - 'first' is used as a boolean to mark whether we started walking the list */ - int first = 1; - netif = inp; - do { - /* interface is up? */ - if (netif_is_up(netif)) { - /* unicast to this interface address? address configured? */ - 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))) { - /* exit outer loop */ - goto netif_found; - } - } - } - if (ip6_addr_islinklocal(ip6_current_dest_addr())) { - /* Do not match link-local addresses to other netifs. */ - netif = NULL; - break; - } - if (first) { - first = 0; - netif = netif_list; - } else { - netif = netif->next; - } - if (netif == inp) { - netif = netif->next; - } - } while (netif != NULL); -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 = ip_data.current_ip_header_tot_len = IP6_HLEN; - - /* Move to payload. */ - pbuf_header(p, -IP6_HLEN); - - /* Process known option extension headers, if present. */ - while (nexth != IP6_NEXTH_NONE) - { - switch (nexth) { - case IP6_NEXTH_HOPBYHOP: - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n")); - /* Get next header type. */ - nexth = *((u8_t *)p->payload); - - /* Get the header length. */ - hlen = 8 * (1 + *((u8_t *)p->payload + 1)); - ip_data.current_ip_header_tot_len += hlen; - - /* Skip over this header. */ - 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_STATS_INC(ip6.lenerr); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - - pbuf_header(p, -(s16_t)hlen); - break; - case IP6_NEXTH_DESTOPTS: - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n")); - /* Get next header type. */ - nexth = *((u8_t *)p->payload); - - /* Get the header length. */ - hlen = 8 * (1 + *((u8_t *)p->payload + 1)); - ip_data.current_ip_header_tot_len += hlen; - - /* Skip over this header. */ - 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_STATS_INC(ip6.lenerr); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - - pbuf_header(p, -(s16_t)hlen); - break; - case IP6_NEXTH_ROUTING: - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n")); - /* Get next header type. */ - nexth = *((u8_t *)p->payload); - - /* Get the header length. */ - hlen = 8 * (1 + *((u8_t *)p->payload + 1)); - ip_data.current_ip_header_tot_len += hlen; - - /* Skip over this header. */ - 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_STATS_INC(ip6.lenerr); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - - pbuf_header(p, -(s16_t)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 = frag_hdr->_nexth; - - /* Fragment Header length. */ - hlen = 8; - ip_data.current_ip_header_tot_len += hlen; - - /* 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; - } - - /* 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, usually a packet that we have - * already reassembled. Skip this header anc continue. */ - pbuf_header(p, -(s16_t)hlen); - } else { -#if LWIP_IPV6_REASS - - /* reassemble the packet */ - 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 = ip_data.current_ip_header_tot_len = IP6_HLEN; - pbuf_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; - break; - } - } -options_done: - - /* p points to IPv6 header again. */ - pbuf_header_force(p, ip_data.current_ip_header_tot_len); - - /* 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)); - -#if LWIP_RAW - /* raw input did not eat the packet? */ - if (raw_input(p, inp) == 0) -#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 */ - /* Point to payload. */ - pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); - udp_input(p, inp); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case IP6_NEXTH_TCP: - /* Point to payload. */ - pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); - tcp_input(p, inp); - break; -#endif /* LWIP_TCP */ -#if LWIP_ICMP6 - case IP6_NEXTH_ICMP6: - /* Point to payload. */ - pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); - icmp6_input(p, inp); - break; -#endif /* LWIP_ICMP */ - default: -#if LWIP_ICMP6 - /* 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, ip_data.current_ip_header_tot_len - hlen); - } -#endif /* LWIP_ICMP */ - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", (u16_t)IP6H_NEXTH(ip6hdr))); - pbuf_free(p); - IP6_STATS_INC(ip6.proterr); - IP6_STATS_INC(ip6.drop); - 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 - * 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 == 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 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 - */ -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 != IP_HDRINCL) { - if (src != NULL && ip6_addr_isany(src)) { - src = ip_2_ip6(ip6_select_source_address(netif, dest)); - if ((src == NULL) || ip6_addr_isany(src)) { - /* 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_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); - - /* Should the IPv6 header be generated or is it already included in p? */ - if (dest != IP_HDRINCL) { - /* generate IPv6 header */ - if (pbuf_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(ip6hdr->dest, *dest); - - IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); - IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN); - - if (src == NULL) { - src = IP6_ADDR_ANY6; - } - /* src cannot be NULL here */ - ip6_addr_copy(ip6hdr->src, *src); - - } else { - /* IP header already included in p */ - ip6hdr = (struct ip6_hdr *)p->payload; - ip6_addr_copy(dest_addr, ip6hdr->dest); - 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); - } - } - } -#endif /* ENABLE_LOOPBACK */ -#if LWIP_IPV6_FRAG - /* don't fragment if interface has mtu set to 0 [loopif] */ - if (netif->mtu && (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 == 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 != IP_HDRINCL) { - netif = ip6_route(src, dest); - } else { - /* IP header included in p, read addresses. */ - ip6hdr = (struct ip6_hdr *)p->payload; - ip6_addr_copy(src_addr, ip6hdr->src); - ip6_addr_copy(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_HWADDRHINT -/** 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 == 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 addr_hint address hint pointer set to netif->addr_hint before - * calling ip_output_if() - * - * @return ERR_RTE if no route is found - * see ip_output_if() for more return values - */ -err_t -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, u8_t *addr_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 != IP_HDRINCL) { - netif = ip6_route(src, dest); - } else { - /* IP header included in p, read addresses. */ - ip6hdr = (struct ip6_hdr *)p->payload; - ip6_addr_copy(src_addr, ip6hdr->src); - ip6_addr_copy(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_HWADDRHINT(netif, addr_hint); - err = ip6_output_if(p, src, dest, hl, tc, nexth, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - - return err; -} -#endif /* LWIP_NETIF_HWADDRHINT*/ - -#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) -{ - struct ip6_hbh_hdr * hbh_hdr; - - /* Move pointer to make room for hop-by-hop options header. */ - if (pbuf_header(p, sizeof(struct ip6_hbh_hdr))) { - LWIP_DEBUGF(IP6_DEBUG, ("ip6_options: no space for options header\n")); - IP6_STATS_INC(ip6.err); - return ERR_BUF; - } - - hbh_hdr = (struct ip6_hbh_hdr *)p->payload; - - /* Set fields. */ - hbh_hdr->_nexth = nexth; - hbh_hdr->_hlen = 0; - hbh_hdr->_ra_opt_type = IP6_ROUTER_ALERT_OPTION; - hbh_hdr->_ra_opt_dlen = 2; - hbh_hdr->_ra_opt_data = value; - hbh_hdr->_padn_opt_type = IP6_PADN_ALERT_OPTION; - hbh_hdr->_padn_opt_dlen = 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/ext/lwip/src/core/ipv6/ip6_addr.c b/ext/lwip/src/core/ipv6/ip6_addr.c deleted file mode 100644 index 7f14db4..0000000 --- a/ext/lwip/src/core/ipv6/ip6_addr.c +++ /dev/null @@ -1,292 +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" - -/* used by IP6_ADDR_ANY(6) in ip6_addr.h */ -const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul); - -#ifndef isprint -#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) -#define isprint(c) in_range(c, 0x20, 0x7f) -#define isdigit(c) in_range(c, '0', '9') -#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) -#define islower(c) in_range(c, 'a', 'z') -#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') -#define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10) -#endif - -/** - * Check whether "cp" is a valid ascii representation - * of an IPv6 address and convert to a binary address. - * Returns 1 if the address is valid, 0 if not. - * - * @param cp IPv6 address in ascii representation (e.g. "FF01::1") - * @param addr pointer to which to save the ip address in network order - * @return 1 if cp could be converted to addr, 0 on failure - */ -int -ip6addr_aton(const char *cp, ip6_addr_t *addr) -{ - u32_t addr_index, zero_blocks, current_block_index, current_block_value; - const char * s; - - /* Count the number of colons, to count the number of blocks in a "::" sequence - zero_blocks may be 1 even if there are no :: sequences */ - zero_blocks = 8; - for (s = cp; *s != 0; s++) { - if (*s == ':') { - zero_blocks--; - } else if (!isxdigit(*s)) { - break; - } - } - - /* parse each block */ - addr_index = 0; - current_block_index = 0; - current_block_value = 0; - for (s = cp; *s != 0; s++) { - if (*s == ':') { - if (addr) { - if (current_block_index & 0x1) { - addr->addr[addr_index++] |= current_block_value; - } - else { - addr->addr[addr_index] = current_block_value << 16; - } - } - current_block_index++; - current_block_value = 0; - if (current_block_index > 7) { - /* address too long! */ - return 0; - } - if (s[1] == ':') { - if (s[2] == ':') { - /* invalid format: three successive colons */ - return 0; - } - s++; - /* "::" found, set zeros */ - while (zero_blocks > 0) { - zero_blocks--; - if (current_block_index & 0x1) { - addr_index++; - } else { - if (addr) { - addr->addr[addr_index] = 0; - } - } - current_block_index++; - if (current_block_index > 7) { - /* address too long! */ - return 0; - } - } - } - } else if (isxdigit(*s)) { - /* add current digit */ - current_block_value = (current_block_value << 4) + - (isdigit(*s) ? *s - '0' : - 10 + (islower(*s) ? *s - 'a' : *s - 'A')); - } else { - /* unexpected digit, space? CRLF? */ - break; - } - } - - if (addr) { - if (current_block_index & 0x1) { - addr->addr[addr_index++] |= current_block_value; - } - else { - addr->addr[addr_index] = current_block_value << 16; - } - } - - /* convert to network byte order. */ - if (addr) { - for (addr_index = 0; addr_index < 4; addr_index++) { - addr->addr[addr_index] = htonl(addr->addr[addr_index]); - } - } - - 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; - - 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 = 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 = htonl(addr->addr[(current_block_index + 1) >> 1]); - if ((current_block_index & 0x1) == 0x01) { - next_block_value = next_block_value >> 16; - } - next_block_value &= 0xffff; - if (next_block_value == 0) { - empty_block_flag = 1; - buf[i++] = ':'; - if (i >= buflen) { - return NULL; - } - continue; /* move on to next block. */ - } - } else if (empty_block_flag == 1) { - /* move on to next block. */ - continue; - } - } else if (empty_block_flag == 1) { - /* Set this flag value so we don't produce multiple empty blocks. */ - empty_block_flag = 2; - } - - if (current_block_index > 0) { - buf[i++] = ':'; - if (i >= buflen) { - return NULL; - } - } - - if ((current_block_value & 0xf000) == 0) { - zero_flag = 1; - } else { - buf[i++] = xchar(((current_block_value & 0xf000) >> 12)); - zero_flag = 0; - if (i >= buflen) { - return NULL; - } - } - - if (((current_block_value & 0xf00) == 0) && (zero_flag)) { - /* do nothing */ - } else { - buf[i++] = xchar(((current_block_value & 0xf00) >> 8)); - zero_flag = 0; - if (i >= buflen) { - return NULL; - } - } - - if (((current_block_value & 0xf0) == 0) && (zero_flag)) { - /* do nothing */ - } - else { - buf[i++] = xchar(((current_block_value & 0xf0) >> 4)); - zero_flag = 0; - if (i >= buflen) { - return NULL; - } - } - - buf[i++] = xchar((current_block_value & 0xf)); - if (i >= buflen) { - return NULL; - } - } - - buf[i] = 0; - - return buf; -} - -#endif /* LWIP_IPV6 */ diff --git a/ext/lwip/src/core/ipv6/ip6_frag.c b/ext/lwip/src/core/ipv6/ip6_frag.c deleted file mode 100644 index f574d38..0000000 --- a/ext/lwip/src/core/ipv6/ip6_frag.c +++ /dev/null @@ -1,776 +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 -#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; - u8_t clen; - struct pbuf *p; - struct ip6_reass_helper *iprh; - -#if LWIP_ICMP6 - iprh = (struct ip6_reass_helper *)ipr->p->payload; - if (iprh->start == 0) { - /* The first fragment was received, send ICMP time exceeded. */ - /* First, de-queue the first pbuf from r->p. */ - p = ipr->p; - ipr->p = iprh->next_pbuf; - /* Then, move back to the original ipv6 header (we are now pointing to Fragment header). - This cannot fail since we already checked when receiving this fragment. */ - if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)IPV6_FRAG_HDRREF(ipr->iphdr)))) { - LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0); - } - else { - icmp6_time_exceeded(p, ICMP6_TE_FRAG); - } - clen = pbuf_clen(p); - LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); - pbufs_freed += clen; - pbuf_free(p); - } -#endif /* LWIP_ICMP6 */ - - /* First, free all received pbufs. The individual pbufs need to be released - separately as they have not yet been chained */ - p = ipr->p; - while (p != NULL) { - struct pbuf *pcur; - iprh = (struct ip6_reass_helper *)p->payload; - pcur = p; - /* get the next pointer before freeing */ - p = iprh->next_pbuf; - clen = pbuf_clen(pcur); - LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); - pbufs_freed += clen; - pbuf_free(pcur); - } - - /* Then, unchain the struct ip6_reassdata from the list and free it. */ - if (ipr == reassdatagrams) { - reassdatagrams = ipr->next; - } else { - prev = reassdatagrams; - while (prev != NULL) { - if (prev->next == ipr) { - break; - } - prev = prev->next; - } - if (prev != NULL) { - prev->next = ipr->next; - } - } - memp_free(MEMP_IP6_REASSDATA, ipr); - - /* Finally, update number of pbufs in reassembly queue */ - LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed); - ip6_reass_pbufcount -= pbufs_freed; -} - -#if IP_REASS_FREE_OLDEST -/** - * Free the oldest datagram to make room for enqueueing new fragments. - * The datagram ipr is not freed! - * - * @param ipr ip6_reassdata for the current fragment - * @param pbufs_needed number of pbufs needed to enqueue - * (used for freeing other datagrams if not enough space) - */ -static void -ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed) -{ - struct ip6_reassdata *r, *oldest; - - /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, - * but don't free the current datagram! */ - do { - r = oldest = reassdatagrams; - while (r != NULL) { - if (r != ipr) { - if (r->timer <= oldest->timer) { - /* older than the previous oldest */ - oldest = r; - } - } - r = r->next; - } - if (oldest == ipr) { - /* nothing to free, ipr is the only element on the list */ - return; - } - if (oldest != NULL) { - ip6_reass_free_complete_datagram(oldest); - } - } while (((ip6_reass_pbufcount + pbufs_needed) > IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL)); -} -#endif /* IP_REASS_FREE_OLDEST */ - -/** - * Reassembles incoming IPv6 fragments into an IPv6 datagram. - * - * @param p points to the IPv6 Fragment Header - * @return NULL if reassembly is incomplete, pbuf pointing to - * IPv6 Header if reassembly is complete - */ -struct pbuf * -ip6_reass(struct pbuf *p) -{ - struct ip6_reassdata *ipr, *ipr_prev; - struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; - struct ip6_frag_hdr * frag_hdr; - u16_t offset, len; - u8_t clen, valid = 1; - struct pbuf *q; - - IP6_FRAG_STATS_INC(ip6_frag.recv); - - if ((const void*)ip6_current_header() != ((u8_t*)p->payload) - IP6_HLEN) { - /* ip6_frag_hdr must be in the first pbuf, not chained */ - IP6_FRAG_STATS_INC(ip6_frag.proterr); - IP6_FRAG_STATS_INC(ip6_frag.drop); - goto nullreturn; - } - - frag_hdr = (struct ip6_frag_hdr *) p->payload; - - clen = pbuf_clen(p); - - offset = ntohs(frag_hdr->_fragment_offset); - - /* Calculate fragment length from IPv6 payload length. - * Adjust for headers before Fragment Header. - * And finally adjust by Fragment Header length. */ - len = ntohs(ip6_current_header()->_plen); - len -= (u16_t)(((u8_t*)p->payload - (const u8_t*)ip6_current_header()) - IP6_HLEN); - len -= IP6_FRAG_HLEN; - - /* Look for the datagram the fragment belongs to in the current datagram queue, - * remembering the previous in the queue for later dequeueing. */ - for (ipr = reassdatagrams, ipr_prev = NULL; ipr != NULL; ipr = ipr->next) { - /* Check if the incoming fragment matches the one currently present - in the reassembly buffer. If so, we proceed with copying the - fragment into the buffer. */ - if ((frag_hdr->_identification == ipr->identification) && - ip6_addr_cmp(ip6_current_src_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->src)) && - ip6_addr_cmp(ip6_current_dest_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->dest))) { - IP6_FRAG_STATS_INC(ip6_frag.cachehit); - break; - } - ipr_prev = ipr; - } - - if (ipr == NULL) { - /* Enqueue a new datagram into the datagram queue */ - ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); - if (ipr == NULL) { -#if IP_REASS_FREE_OLDEST - /* Make room and try again. */ - ip6_reass_remove_oldest_datagram(ipr, clen); - ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); - if (ipr != NULL) { - /* re-search ipr_prev since it might have been removed */ - for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { - if (ipr_prev->next == ipr) { - break; - } - } - } else -#endif /* IP_REASS_FREE_OLDEST */ - { - IP6_FRAG_STATS_INC(ip6_frag.memerr); - IP6_FRAG_STATS_INC(ip6_frag.drop); - goto nullreturn; - } - } - - memset(ipr, 0, sizeof(struct ip6_reassdata)); - ipr->timer = IP_REASS_MAXAGE; - - /* enqueue the new structure to the front of the list */ - ipr->next = reassdatagrams; - reassdatagrams = ipr; - - /* Use the current IPv6 header for src/dest address reference. - * Eventually, we will replace it when we get the first fragment - * (it might be this one, in any case, it is done later). */ -#if IPV6_FRAG_COPYHEADER - MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN); -#else /* IPV6_FRAG_COPYHEADER */ - /* need to use the none-const pointer here: */ - ipr->iphdr = ip_data.current_ip6_header; -#endif /* IPV6_FRAG_COPYHEADER */ - - /* copy the fragmented packet id. */ - ipr->identification = frag_hdr->_identification; - - /* copy the nexth field */ - ipr->nexth = frag_hdr->_nexth; - } - - /* Check if we are allowed to enqueue more datagrams. */ - if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { -#if IP_REASS_FREE_OLDEST - ip6_reass_remove_oldest_datagram(ipr, clen); - if ((ip6_reass_pbufcount + clen) <= IP_REASS_MAX_PBUFS) { - /* re-search ipr_prev since it might have been removed */ - for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { - if (ipr_prev->next == ipr) { - break; - } - } - } else -#endif /* IP_REASS_FREE_OLDEST */ - { - /* @todo: send ICMPv6 time exceeded here? */ - /* drop this pbuf */ - IP6_FRAG_STATS_INC(ip6_frag.memerr); - IP6_FRAG_STATS_INC(ip6_frag.drop); - goto nullreturn; - } - } - - /* Overwrite Fragment Header with our own helper struct. */ -#if IPV6_FRAG_COPYHEADER - if (IPV6_FRAG_REQROOM > 0) { - /* Make room for struct ip6_reass_helper (only required if sizeof(void*) > 4). - This cannot fail since we already checked when receiving this fragment. */ - err_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM); - LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK); - } -#else /* IPV6_FRAG_COPYHEADER */ - LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1", - sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN); -#endif /* IPV6_FRAG_COPYHEADER */ - iprh = (struct ip6_reass_helper *)p->payload; - iprh->next_pbuf = NULL; - iprh->start = (offset & IP6_FRAG_OFFSET_MASK); - iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len; - - /* find the right place to insert this pbuf */ - /* Iterate through until we either get to the end of the list (append), - * or we find on with a larger offset (insert). */ - for (q = ipr->p; q != NULL;) { - iprh_tmp = (struct ip6_reass_helper*)q->payload; - if (iprh->start < iprh_tmp->start) { -#if IP_REASS_CHECK_OVERLAP - if (iprh->end > iprh_tmp->start) { - /* fragment overlaps with following, throw away */ - IP6_FRAG_STATS_INC(ip6_frag.proterr); - IP6_FRAG_STATS_INC(ip6_frag.drop); - goto nullreturn; - } - if (iprh_prev != NULL) { - if (iprh->start < iprh_prev->end) { - /* fragment overlaps with previous, throw away */ - IP6_FRAG_STATS_INC(ip6_frag.proterr); - IP6_FRAG_STATS_INC(ip6_frag.drop); - goto nullreturn; - } - } -#endif /* IP_REASS_CHECK_OVERLAP */ - /* the new pbuf should be inserted before this */ - iprh->next_pbuf = q; - if (iprh_prev != NULL) { - /* not the fragment with the lowest offset */ - iprh_prev->next_pbuf = p; - } else { - /* fragment with the lowest offset */ - ipr->p = p; - } - break; - } else if (iprh->start == iprh_tmp->start) { - /* received the same datagram twice: no need to keep the datagram */ - IP6_FRAG_STATS_INC(ip6_frag.drop); - goto nullreturn; -#if IP_REASS_CHECK_OVERLAP - } else if (iprh->start < iprh_tmp->end) { - /* overlap: no need to keep the new datagram */ - IP6_FRAG_STATS_INC(ip6_frag.proterr); - IP6_FRAG_STATS_INC(ip6_frag.drop); - goto nullreturn; -#endif /* IP_REASS_CHECK_OVERLAP */ - } else { - /* Check if the fragments received so far have no gaps. */ - if (iprh_prev != NULL) { - if (iprh_prev->end != iprh_tmp->start) { - /* There is a fragment missing between the current - * and the previous fragment */ - valid = 0; - } - } - } - q = iprh_tmp->next_pbuf; - iprh_prev = iprh_tmp; - } - - /* If q is NULL, then we made it to the end of the list. Determine what to do now */ - if (q == NULL) { - if (iprh_prev != NULL) { - /* this is (for now), the fragment with the highest offset: - * chain it to the last fragment */ -#if IP_REASS_CHECK_OVERLAP - LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); -#endif /* IP_REASS_CHECK_OVERLAP */ - iprh_prev->next_pbuf = p; - if (iprh_prev->end != iprh->start) { - valid = 0; - } - } else { -#if IP_REASS_CHECK_OVERLAP - LWIP_ASSERT("no previous fragment, this must be the first fragment!", - ipr->p == NULL); -#endif /* IP_REASS_CHECK_OVERLAP */ - /* this is the first fragment we ever received for this ip datagram */ - ipr->p = p; - } - } - - /* Track the current number of pbufs current 'in-flight', in order to limit - the number of fragments that may be enqueued at any one time */ - ip6_reass_pbufcount += clen; - - /* Remember IPv6 header if this is the first fragment. */ - if (iprh->start == 0) { -#if IPV6_FRAG_COPYHEADER - if (iprh->next_pbuf != NULL) { - MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN); - } -#else /* IPV6_FRAG_COPYHEADER */ - /* need to use the none-const pointer here: */ - ipr->iphdr = ip_data.current_ip6_header; -#endif /* IPV6_FRAG_COPYHEADER */ - } - - /* If this is the last fragment, calculate total packet length. */ - if ((offset & IP6_FRAG_MORE_FLAG) == 0) { - ipr->datagram_len = iprh->end; - } - - /* Additional validity tests: we have received first and last fragment. */ - iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload; - if (iprh_tmp->start != 0) { - valid = 0; - } - if (ipr->datagram_len == 0) { - valid = 0; - } - - /* Final validity test: no gaps between current and last fragment. */ - iprh_prev = iprh; - q = iprh->next_pbuf; - while ((q != NULL) && valid) { - iprh = (struct ip6_reass_helper*)q->payload; - if (iprh_prev->end != iprh->start) { - valid = 0; - break; - } - iprh_prev = iprh; - q = iprh->next_pbuf; - } - - if (valid) { - /* All fragments have been received */ - struct ip6_hdr* iphdr_ptr; - - /* chain together the pbufs contained within the ip6_reassdata list. */ - iprh = (struct ip6_reass_helper*) ipr->p->payload; - while (iprh != NULL) { - struct pbuf* next_pbuf = iprh->next_pbuf; - if (next_pbuf != NULL) { - /* Save next helper struct (will be hidden in next step). */ - iprh_tmp = (struct ip6_reass_helper*)next_pbuf->payload; - - /* hide the fragment header for every succeeding fragment */ - pbuf_header(next_pbuf, -IP6_FRAG_HLEN); -#if IPV6_FRAG_COPYHEADER - if (IPV6_FRAG_REQROOM > 0) { - /* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */ - err_t hdrerr = pbuf_header(next_pbuf, -(s16_t)(IPV6_FRAG_REQROOM)); - LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK); - } -#endif - pbuf_cat(ipr->p, next_pbuf); - } - else { - iprh_tmp = NULL; - } - - iprh = iprh_tmp; - } - -#if IPV6_FRAG_COPYHEADER - if (IPV6_FRAG_REQROOM > 0) { - /* get back room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */ - err_t hdrerr = pbuf_header(ipr->p, -(s16_t)(IPV6_FRAG_REQROOM)); - LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK); - } - iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->p->payload - IP6_HLEN); - MEMCPY(iphdr_ptr, &ipr->iphdr, IP6_HLEN); -#else - iphdr_ptr = ipr->iphdr; -#endif - - /* Adjust datagram length by adding header lengths. */ - ipr->datagram_len += (u16_t)(((u8_t*)ipr->p->payload - (u8_t*)iphdr_ptr) - + IP6_FRAG_HLEN - - IP6_HLEN); - - /* Set payload length in ip header. */ - iphdr_ptr->_plen = htons(ipr->datagram_len); - - /* Get the first pbuf. */ - p = ipr->p; - - /* Restore Fragment Header in first pbuf. Mark as "single fragment" - * packet. Restore nexth. */ - frag_hdr = (struct ip6_frag_hdr *) p->payload; - frag_hdr->_nexth = ipr->nexth; - frag_hdr->reserved = 0; - frag_hdr->_fragment_offset = 0; - frag_hdr->_identification = 0; - - /* release the sources allocate for the fragment queue entry */ - if (reassdatagrams == ipr) { - /* it was the first in the list */ - reassdatagrams = ipr->next; - } else { - /* it wasn't the first, so it must have a valid 'prev' */ - LWIP_ASSERT("sanity check linked list", ipr_prev != NULL); - ipr_prev->next = ipr->next; - } - memp_free(MEMP_IP6_REASSDATA, ipr); - - /* adjust the number of pbufs currently queued for reassembly. */ - ip6_reass_pbufcount -= pbuf_clen(p); - - /* Move pbuf back to IPv6 header. - This cannot fail since we already checked when receiving this fragment. */ - if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)iphdr_ptr))) { - LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0); - pbuf_free(p); - return NULL; - } - - /* Return the pbuf chain */ - return p; - } - /* the datagram is not (yet?) reassembled completely */ - return NULL; - -nullreturn: - pbuf_free(p); - return NULL; -} - -#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ - -#if LWIP_IPV6 && LWIP_IPV6_FRAG - -/** Allocate a new struct pbuf_custom_ref */ -static struct pbuf_custom_ref* -ip6_frag_alloc_pbuf_custom_ref(void) -{ - return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); -} - -/** Free a struct pbuf_custom_ref */ -static void -ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) -{ - LWIP_ASSERT("p != NULL", p != NULL); - memp_free(MEMP_FRAG_PBUF, p); -} - -/** Free-callback function to free a 'struct pbuf_custom_ref', called by - * pbuf_free. */ -static void -ip6_frag_free_pbuf_custom(struct pbuf *p) -{ - struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; - LWIP_ASSERT("pcr != NULL", pcr != NULL); - LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); - if (pcr->original != NULL) { - pbuf_free(pcr->original); - } - ip6_frag_free_pbuf_custom_ref(pcr); -} - -/** - * Fragment an IPv6 datagram if too large for the netif or path MTU. - * - * Chop the datagram in MTU sized chunks and send them in order - * by pointing PBUF_REFs into p - * - * @param p ipv6 packet to send - * @param netif the netif on which to send - * @param dest destination ipv6 address to which to send - * - * @return ERR_OK if sent successfully, err_t otherwise - */ -err_t -ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest) -{ - struct ip6_hdr *original_ip6hdr; - struct ip6_hdr *ip6hdr; - struct ip6_frag_hdr * frag_hdr; - struct pbuf *rambuf; - struct pbuf *newpbuf; - static u32_t identification; - u16_t nfb; - u16_t left, cop; - u16_t mtu; - u16_t fragment_offset = 0; - u16_t last; - u16_t poff = IP6_HLEN; - u16_t newpbuflen = 0; - u16_t left_to_copy; - - identification++; - - original_ip6hdr = (struct ip6_hdr *)p->payload; - - mtu = nd6_get_destination_mtu(dest, netif); - - /* @todo we assume there are no options in the unfragmentable part (IPv6 header). */ - left = p->tot_len - IP6_HLEN; - - nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK; - - while (left) { - last = (left <= nfb); - - /* Fill this fragment */ - cop = last ? left : nfb; - - /* When not using a static buffer, create a chain of pbufs. - * The first will be a PBUF_RAM holding the link, IPv6, and Fragment header. - * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, - * but limited to the size of an mtu. - */ - rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM); - if (rambuf == NULL) { - IP6_FRAG_STATS_INC(ip6_frag.memerr); - return ERR_MEM; - } - LWIP_ASSERT("this needs a pbuf in one piece!", - (p->len >= (IP6_HLEN + IP6_FRAG_HLEN))); - SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); - ip6hdr = (struct ip6_hdr *)rambuf->payload; - frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); - - /* Can just adjust p directly for needed offset. */ - p->payload = (u8_t *)p->payload + poff; - p->len -= poff; - p->tot_len -= poff; - - left_to_copy = cop; - while (left_to_copy) { - struct pbuf_custom_ref *pcr; - newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; - /* Is this pbuf already empty? */ - if (!newpbuflen) { - p = p->next; - continue; - } - pcr = ip6_frag_alloc_pbuf_custom_ref(); - if (pcr == NULL) { - pbuf_free(rambuf); - IP6_FRAG_STATS_INC(ip6_frag.memerr); - return ERR_MEM; - } - /* Mirror this pbuf, although we might not need all of it. */ - newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); - if (newpbuf == NULL) { - ip6_frag_free_pbuf_custom_ref(pcr); - pbuf_free(rambuf); - IP6_FRAG_STATS_INC(ip6_frag.memerr); - return ERR_MEM; - } - pbuf_ref(p); - pcr->original = p; - pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom; - - /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain - * so that it is removed when pbuf_dechain is later called on rambuf. - */ - pbuf_cat(rambuf, newpbuf); - left_to_copy -= newpbuflen; - if (left_to_copy) { - p = p->next; - } - } - poff = newpbuflen; - - /* Set headers */ - frag_hdr->_nexth = original_ip6hdr->_nexth; - frag_hdr->reserved = 0; - frag_hdr->_fragment_offset = htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG)); - frag_hdr->_identification = htonl(identification); - - IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT); - IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN); - - /* No need for separate header pbuf - we allowed room for it in rambuf - * when allocated. - */ - IP6_FRAG_STATS_INC(ip6_frag.xmit); - netif->output_ip6(netif, rambuf, dest); - - /* Unfortunately we can't reuse rambuf - the hardware may still be - * using the buffer. Instead we free it (and the ensuing chain) and - * recreate it next time round the loop. If we're lucky the hardware - * will have already sent the packet, the free will really free, and - * there will be zero memory penalty. - */ - - pbuf_free(rambuf); - left -= cop; - fragment_offset += cop; - } - return ERR_OK; -} - -#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ diff --git a/ext/lwip/src/core/ipv6/mld6.c b/ext/lwip/src/core/ipv6/mld6.c deleted file mode 100644 index ef854e7..0000000 --- a/ext/lwip/src/core/ipv6/mld6.c +++ /dev/null @@ -1,598 +0,0 @@ -/** - * @file - */ - -/* - * 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 - * - */ - -/** - * @defgroup mld6 MLD6 - * @ingroup ip6 - * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. - * No support for MLDv2.\n - * To be called from TCPIP thread - */ - -/* 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/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 - - -/* The list of joined groups. */ -static struct mld_group* mld_group_list; - - -/* Forward declarations. */ -static struct mld_group * mld6_new_group(struct netif *ifp, const ip6_addr_t *addr); -static err_t mld6_free_group(struct mld_group *group); -static void mld6_delayed_report(struct mld_group *group, u16_t maxresp); -static void mld6_send(struct mld_group *group, u8_t type); - - -/** - * Stop MLD processing on interface - * - * @param netif network interface on which stop MLD processing - */ -err_t -mld6_stop(struct netif *netif) -{ - struct mld_group *group = mld_group_list; - struct mld_group *prev = NULL; - struct mld_group *next; - - /* look for groups joined on this interface further down the list */ - while (group != NULL) { - next = group->next; - /* is it a group joined on this interface? */ - if (group->netif == netif) { - /* is it the first group of the list? */ - if (group == mld_group_list) { - mld_group_list = next; - } - /* is there a "previous" group defined? */ - if (prev != NULL) { - prev->next = next; - } - /* disable the group at the MAC level */ - if (netif->mld_mac_filter != NULL) { - netif->mld_mac_filter(netif, &(group->group_address), MLD6_DEL_MAC_FILTER); - } - /* free group */ - memp_free(MEMP_MLD6_GROUP, group); - } else { - /* change the "previous" */ - prev = group; - } - /* move to "next" */ - group = next; - } - return ERR_OK; -} - -/** - * Report MLD memberships for this interface - * - * @param netif network interface on which report MLD memberships - */ -void -mld6_report_groups(struct netif *netif) -{ - struct mld_group *group = mld_group_list; - - while (group != NULL) { - if (group->netif == netif) { - mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); - } - group = group->next; - } -} - -/** - * Search for a group that is joined on a netif - * - * @param ifp the network interface for which to look - * @param addr the group ipv6 address to search for - * @return a struct mld_group* if the group has been found, - * NULL if the group wasn't found. - */ -struct mld_group * -mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr) -{ - struct mld_group *group = mld_group_list; - - while (group != NULL) { - if ((group->netif == ifp) && (ip6_addr_cmp(&(group->group_address), addr))) { - return group; - } - group = group->next; - } - - return NULL; -} - - -/** - * create a new group - * - * @param ifp the network interface for which to create - * @param addr the new group ipv6 - * @return a struct mld_group*, - * NULL on memory error. - */ -static struct mld_group * -mld6_new_group(struct netif *ifp, const ip6_addr_t *addr) -{ - struct mld_group *group; - - group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP); - if (group != NULL) { - group->netif = ifp; - ip6_addr_set(&(group->group_address), addr); - group->timer = 0; /* Not running */ - group->group_state = MLD6_GROUP_IDLE_MEMBER; - group->last_reporter_flag = 0; - group->use = 0; - group->next = mld_group_list; - - mld_group_list = group; - } - - return group; -} - -/** - * Remove a group in the mld_group_list and free - * - * @param group the group to remove - * @return ERR_OK if group was removed from the list, an err_t otherwise - */ -static err_t -mld6_free_group(struct mld_group *group) -{ - err_t err = ERR_OK; - - /* Is it the first group? */ - if (mld_group_list == group) { - mld_group_list = group->next; - } else { - /* look for group further down the list */ - struct mld_group *tmpGroup; - for (tmpGroup = mld_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { - if (tmpGroup->next == group) { - tmpGroup->next = group->next; - break; - } - } - /* Group not find group */ - if (tmpGroup == NULL) { - err = ERR_ARG; - } - } - /* free group */ - memp_free(MEMP_MLD6_GROUP, group); - - return err; -} - - -/** - * Process an input MLD message. Called by icmp6_input. - * - * @param p the mld packet, p->payload pointing to the icmpv6 header - * @param inp the netif on which this packet was received - */ -void -mld6_input(struct pbuf *p, struct netif *inp) -{ - struct mld_header * mld_hdr; - struct mld_group* group; - - MLD6_STATS_INC(mld6.recv); - - /* Check that mld header fits in packet. */ - if (p->len < sizeof(struct mld_header)) { - /* @todo debug message */ - pbuf_free(p); - MLD6_STATS_INC(mld6.lenerr); - MLD6_STATS_INC(mld6.drop); - return; - } - - mld_hdr = (struct mld_header *)p->payload; - - switch (mld_hdr->type) { - case ICMP6_TYPE_MLQ: /* Multicast listener query. */ - /* Is it a general query? */ - if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) && - ip6_addr_isany(&(mld_hdr->multicast_address))) { - MLD6_STATS_INC(mld6.rx_general); - /* Report all groups, except all nodes group, and if-local groups. */ - group = mld_group_list; - while (group != NULL) { - if ((group->netif == inp) && - (!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) && - (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) { - mld6_delayed_report(group, mld_hdr->max_resp_delay); - } - group = group->next; - } - } else { - /* Have we joined this group? - * We use IP6 destination address to have a memory aligned copy. - * mld_hdr->multicast_address should be the same. */ - MLD6_STATS_INC(mld6.rx_group); - group = mld6_lookfor_group(inp, ip6_current_dest_addr()); - if (group != NULL) { - /* Schedule a report. */ - mld6_delayed_report(group, mld_hdr->max_resp_delay); - } - } - break; /* ICMP6_TYPE_MLQ */ - case ICMP6_TYPE_MLR: /* Multicast listener report. */ - /* Have we joined this group? - * We use IP6 destination address to have a memory aligned copy. - * mld_hdr->multicast_address should be the same. */ - MLD6_STATS_INC(mld6.rx_report); - group = mld6_lookfor_group(inp, ip6_current_dest_addr()); - if (group != NULL) { - /* If we are waiting to report, cancel it. */ - if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { - group->timer = 0; /* stopped */ - group->group_state = MLD6_GROUP_IDLE_MEMBER; - group->last_reporter_flag = 0; - } - } - break; /* ICMP6_TYPE_MLR */ - case ICMP6_TYPE_MLD: /* Multicast listener done. */ - /* Do nothing, router will query us. */ - break; /* ICMP6_TYPE_MLD */ - default: - MLD6_STATS_INC(mld6.proterr); - MLD6_STATS_INC(mld6.drop); - break; - } - - pbuf_free(p); -} - -/** - * @ingroup mld6 - * Join a group on a network interface. - * - * @param srcaddr ipv6 address of the network interface which should - * join a new group. If IP6_ADDR_ANY, join on all netifs - * @param groupaddr the ipv6 address of the group to join - * @return ERR_OK if group was joined on the netif(s), an err_t otherwise - */ -err_t -mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) -{ - err_t err = ERR_VAL; /* no matching interface */ - struct netif *netif; - - /* loop through netif's */ - netif = netif_list; - while (netif != NULL) { - /* Should we join this interface ? */ - if (ip6_addr_isany(srcaddr) || - netif_get_ip6_addr_match(netif, srcaddr) >= 0) { - err = mld6_joingroup_netif(netif, groupaddr); - if (err != ERR_OK) { - return err; - } - } - - /* proceed to next network interface */ - netif = netif->next; - } - - return err; -} - -/** - * @ingroup mld6 - * Join a group on a network interface. - * - * @param netif the network interface which should join a new group. - * @param groupaddr the ipv6 address of the group to join - * @return ERR_OK if group was joined on the netif, an err_t otherwise - */ -err_t -mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr) -{ - struct mld_group *group; - - /* find group or create a new one if not found */ - group = mld6_lookfor_group(netif, groupaddr); - - if (group == NULL) { - /* Joining a new group. Create a new group entry. */ - group = mld6_new_group(netif, groupaddr); - if (group == NULL) { - return ERR_MEM; - } - - /* Activate this address on the MAC layer. */ - if (netif->mld_mac_filter != NULL) { - netif->mld_mac_filter(netif, groupaddr, MLD6_ADD_MAC_FILTER); - } - - /* Report our membership. */ - MLD6_STATS_INC(mld6.tx_report); - mld6_send(group, ICMP6_TYPE_MLR); - mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); - } - - /* Increment group use */ - group->use++; - return ERR_OK; -} - -/** - * @ingroup mld6 - * Leave a group on a network interface. - * - * @param srcaddr ipv6 address of the network interface which should - * leave the group. If IP6_ISANY, leave on all netifs - * @param groupaddr the ipv6 address of the group to leave - * @return ERR_OK if group was left on the netif(s), an err_t otherwise - */ -err_t -mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) -{ - err_t err = ERR_VAL; /* no matching interface */ - struct netif *netif; - - /* loop through netif's */ - netif = netif_list; - while (netif != NULL) { - /* Should we leave this interface ? */ - if (ip6_addr_isany(srcaddr) || - netif_get_ip6_addr_match(netif, srcaddr) >= 0) { - err_t res = mld6_leavegroup_netif(netif, groupaddr); - if (err != ERR_OK) { - /* Store this result if we have not yet gotten a success */ - err = res; - } - } - /* proceed to next network interface */ - netif = netif->next; - } - - return err; -} - -/** - * @ingroup mld6 - * Leave a group on a network interface. - * - * @param netif the network interface which should leave the group. - * @param groupaddr the ipv6 address of the group to leave - * @return ERR_OK if group was left on the netif, an err_t otherwise - */ -err_t -mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr) -{ - struct mld_group *group; - - /* find group */ - group = mld6_lookfor_group(netif, groupaddr); - - if (group != NULL) { - /* Leave if there is no other use of the group */ - if (group->use <= 1) { - /* If we are the last reporter for this group */ - if (group->last_reporter_flag) { - MLD6_STATS_INC(mld6.tx_leave); - mld6_send(group, ICMP6_TYPE_MLD); - } - - /* Disable the group at the MAC level */ - if (netif->mld_mac_filter != NULL) { - netif->mld_mac_filter(netif, groupaddr, MLD6_DEL_MAC_FILTER); - } - - /* Free the group */ - mld6_free_group(group); - } else { - /* Decrement group use */ - group->use--; - } - - /* 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 mld_group *group = mld_group_list; - - while (group != NULL) { - if (group->timer > 0) { - group->timer--; - if (group->timer == 0) { - /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */ - if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { - MLD6_STATS_INC(mld6.tx_report); - mld6_send(group, ICMP6_TYPE_MLR); - group->group_state = MLD6_GROUP_IDLE_MEMBER; - } - } - } - group = group->next; - } -} - -/** - * Schedule a delayed membership report for a group - * - * @param group the mld_group for which "delaying" membership report - * should be sent - * @param maxresp the max resp delay provided in the query - */ -static void -mld6_delayed_report(struct mld_group *group, u16_t maxresp) -{ - /* Convert maxresp from milliseconds to tmr ticks */ - maxresp = maxresp / MLD6_TMR_INTERVAL; - if (maxresp == 0) { - maxresp = 1; - } - -#ifdef LWIP_RAND - /* Randomize maxresp. (if LWIP_RAND is supported) */ - maxresp = LWIP_RAND() % maxresp; - if (maxresp == 0) { - maxresp = 1; - } -#endif /* LWIP_RAND */ - - /* Apply timer value if no report has been scheduled already. */ - if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) || - ((group->group_state == MLD6_GROUP_DELAYING_MEMBER) && - ((group->timer == 0) || (maxresp < group->timer)))) { - group->timer = maxresp; - group->group_state = MLD6_GROUP_DELAYING_MEMBER; - } -} - -/** - * Send a MLD message (report or done). - * - * An IPv6 hop-by-hop options header with a router alert option - * is prepended. - * - * @param group the group to report or quit - * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done) - */ -static void -mld6_send(struct mld_group *group, u8_t type) -{ - struct mld_header * mld_hdr; - struct pbuf * p; - const ip6_addr_t * src_addr; - - /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */ - p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM); - if (p == NULL) { - MLD6_STATS_INC(mld6.memerr); - return; - } - - /* Move to make room for Hop-by-hop options header. */ - if (pbuf_header(p, -IP6_HBH_HLEN)) { - pbuf_free(p); - MLD6_STATS_INC(mld6.lenerr); - return; - } - - /* Select our source address. */ - if (!ip6_addr_isvalid(netif_ip6_addr_state(group->netif, 0))) { - /* This is a special case, when we are performing duplicate address detection. - * We must join the multicast group, but we don't have a valid address yet. */ - src_addr = IP6_ADDR_ANY6; - } else { - /* Use link-local address as source address. */ - src_addr = netif_ip6_addr(group->netif, 0); - } - - /* MLD message header pointer. */ - mld_hdr = (struct mld_header *)p->payload; - - /* Set fields. */ - mld_hdr->type = type; - mld_hdr->code = 0; - mld_hdr->chksum = 0; - mld_hdr->max_resp_delay = 0; - mld_hdr->reserved = 0; - ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address)); - -#if CHECKSUM_GEN_ICMP6 - IF__NETIF_CHECKSUM_ENABLED(group->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); - - /* Send the packet out. */ - MLD6_STATS_INC(mld6.xmit); - ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address), - MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, group->netif); - pbuf_free(p); -} - -#endif /* LWIP_IPV6 */ diff --git a/ext/lwip/src/core/ipv6/nd6.c b/ext/lwip/src/core/ipv6/nd6.c deleted file mode 100644 index af17aea..0000000 --- a/ext/lwip/src/core/ipv6/nd6.c +++ /dev/null @@ -1,1884 +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/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/ip.h" -#include "lwip/stats.h" - -#include - - -/* 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 u8_t nd6_cached_destination_index; - -/* Multicast address holder. */ -static ip6_addr_t multicast_address; - -/* Static buffer to parse RA packet options (size of a prefix option, biggest option) */ -static u8_t nd6_ra_buffer[sizeof(struct prefix_option)]; - -/* 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 s8_t nd6_find_destination_cache_entry(const ip6_addr_t * ip6addr); -static s8_t nd6_new_destination_cache_entry(void); -static s8_t nd6_is_prefix_in_netif(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(ip6_addr_t * prefix, struct netif * netif); -static s8_t nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif); - -#define ND6_SEND_FLAG_MULTICAST_DEST 0x01 -#define ND6_SEND_FLAG_ALLNODES_DEST 0x02 -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); -#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); - - -/** - * 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; - - 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; - - /* 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; - - /* Unsolicited NA?*/ - if (ip6_addr_ismulticast(ip6_current_dest_addr())) { - /* This is an unsolicited NA. - * link-layer changed? - * part of DAD mechanism? */ - - /* 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; - } - - /* Override ip6_current_dest_addr() so that we have an aligned copy. */ - ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); - -#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_cmp(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { - /* We are using a duplicate address. */ - netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); - -#if LWIP_IPV6_MLD - /* Leave solicited node multicast group. */ - ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(inp, i)->addr[3]); - mld6_leavegroup(netif_ip6_addr(inp, i), &multicast_address); -#endif /* LWIP_IPV6_MLD */ - -#if LWIP_IPV6_AUTOCONFIG - /* Check to see if this address was autoconfigured. */ - if (!ip6_addr_islinklocal(ip6_current_dest_addr())) { - i = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp); - if (i >= 0) { - /* Mark this prefix as duplicate, so that we don't use it - * to generate this address again. */ - prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE; - } - } -#endif /* LWIP_IPV6_AUTOCONFIG */ - - pbuf_free(p); - return; - } - } -#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */ - - /* This is an unsolicited NA, most likely there was a LLADDR change. */ - i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr()); - 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? */ - - /* Override ip6_current_dest_addr() so that we have an aligned copy. */ - ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); - - /* Find the cache entry corresponding to this na. */ - i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr()); - if (i < 0) { - /* We no longer care about this target address. drop it. */ - pbuf_free(p); - return; - } - - /* Update cache entry. */ - neighbor_cache[i].netif = inp; - neighbor_cache[i].counter.reachable_time = reachable_time; - 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].state = ND6_REACHABLE; - - /* 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; - 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; - - /* 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(&(ns_hdr->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(&(ns_hdr->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. */ - netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); - } - } - } - } 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; - } - } 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; - } - - /* Override ip6_current_dest_addr() so that we have an aligned copy. */ - ip6_addr_set(ip6_current_dest_addr(), &(ns_hdr->target_address)); - - /* Send back a NA for us. Allocate the reply pbuf. */ - nd6_send_na(inp, ip6_current_dest_addr(), 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; - - /* 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; - - /* If we are sending RS messages, stop. */ -#if LWIP_IPV6_SEND_ROUTER_SOLICIT - /* ensure at least one solicitation is sent */ - if ((inp->rs_count < LWIP_ND6_MAX_MULTICAST_SOLICIT) || - (nd6_send_rs(inp) == ERR_OK)) { - inp->rs_count = 0; - } -#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 = htons(ra_hdr->router_lifetime); - - /* Re-set default timer values. */ -#if LWIP_ND6_ALLOW_RA_UPDATES - if (ra_hdr->retrans_timer > 0) { - retrans_timer = htonl(ra_hdr->retrans_timer); - } - if (ra_hdr->reachable_time > 0) { - reachable_time = 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; - - /* Offset to options. */ - offset = sizeof(struct ra_header); - - /* Process each option. */ - while ((p->tot_len - offset) > 0) { - if (p->len == p->tot_len) { - /* no need to copy from contiguous pbuf */ - buffer = &((u8_t*)p->payload)[offset]; - } else { - buffer = nd6_ra_buffer; - pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset); - } - if (buffer[1] == 0) { - /* zero-length extension. drop packet */ - pbuf_free(p); - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - return; - } - switch (buffer[0]) { - case ND6_OPTION_TYPE_SOURCE_LLADDR: - { - struct lladdr_option * lladdr_opt; - 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; - mtu_opt = (struct mtu_option *)buffer; - if (htonl(mtu_opt->mtu) >= 1280) { -#if LWIP_ND6_ALLOW_RA_UPDATES - inp->mtu = (u16_t)htonl(mtu_opt->mtu); -#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ - } - break; - } - case ND6_OPTION_TYPE_PREFIX_INFO: - { - struct prefix_option * prefix_opt; - prefix_opt = (struct prefix_option *)buffer; - - if (prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) { - /* Add to on-link prefix list. */ - s8_t prefix; - - /* Get a memory-aligned copy of the prefix. */ - ip6_addr_set(ip6_current_dest_addr(), &(prefix_opt->prefix)); - - /* find cache entry for this prefix. */ - prefix = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp); - if (prefix < 0) { - /* Create a new cache entry. */ - prefix = nd6_new_onlink_prefix(ip6_current_dest_addr(), inp); - } - if (prefix >= 0) { - prefix_list[prefix].invalidation_timer = htonl(prefix_opt->valid_lifetime); - -#if LWIP_IPV6_AUTOCONFIG - if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) { - /* Mark prefix as autonomous, so that address autoconfiguration can take place. - * Only OR flag, so that we don't over-write other flags (such as ADDRESS_DUPLICATE)*/ - prefix_list[prefix].flags |= ND6_PREFIX_AUTOCONFIG_AUTONOMOUS; - } -#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; - 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 * ((u16_t)buffer[1]); - } - - break; /* ICMP6_TYPE_RA */ - } - case ICMP6_TYPE_RD: /* Redirect */ - { - struct redirect_header * redir_hdr; - struct lladdr_option * lladdr_opt; - - /* 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; - - 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; - } - - /* Copy original destination address to current source address, to have an aligned copy. */ - ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->destination_address)); - - /* Find dest address in cache */ - i = nd6_find_destination_cache_entry(ip6_current_src_addr()); - if (i < 0) { - /* Destination not in cache, drop packet. */ - pbuf_free(p); - return; - } - - /* Set the new target address. */ - ip6_addr_set(&(destination_cache[i].next_hop_addr), &(redir_hdr->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) { - /* Copy target address to current source address, to have an aligned copy. */ - ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->target_address)); - - i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); - 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_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; - } - } - 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; - } - } - } - } - 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; - - /* 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)); - - /* Copy original destination address to current source address, to have an aligned copy. */ - ip6_addr_set(ip6_current_src_addr(), &(ip6hdr->dest)); - - /* Look for entry in destination cache. */ - i = nd6_find_destination_cache_entry(ip6_current_src_addr()); - if (i < 0) { - /* Destination not in cache, drop packet. */ - pbuf_free(p); - return; - } - - /* Change the Path MTU. */ - pmtu = htonl(icmp6hdr->data); - destination_cache[i].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); -} - - -/** - * 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 - * - 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_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), 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 += ND6_TMR_INTERVAL; - break; - case ND6_DELAY: - if (neighbor_cache[i].counter.delay_time <= ND6_TMR_INTERVAL) { - /* Change to PROBE state. */ - neighbor_cache[i].state = ND6_PROBE; - neighbor_cache[i].counter.probes_sent = 0; - } else { - neighbor_cache[i].counter.delay_time -= ND6_TMR_INTERVAL; - } - 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_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), 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 > 0) { - default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; - } - if (default_router_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) { - /* Less than 1 second remaining. Clear this entry. */ - 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; - } - } - } - - /* 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; - -#if LWIP_IPV6_AUTOCONFIG - /* If any addresses were configured with this prefix, remove them */ - if (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED) - { - s8_t j; - - for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) { - if ((netif_ip6_addr_state(prefix_list[i].netif, j) != IP6_ADDR_INVALID) && - ip6_addr_netcmp(&prefix_list[i].prefix, netif_ip6_addr(prefix_list[i].netif, j))) { - netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_INVALID); - prefix_list[i].flags = 0; - - /* Exit loop. */ - break; - } - } - } -#endif /* LWIP_IPV6_AUTOCONFIG */ - - prefix_list[i].netif = NULL; - prefix_list[i].flags = 0; - } else { - prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; - -#if LWIP_IPV6_AUTOCONFIG - /* Initiate address autoconfiguration for this prefix, if conditions are met. */ - if (prefix_list[i].netif->ip6_autoconfig_enabled && - (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_AUTONOMOUS) && - !(prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED)) { - s8_t j; - /* Try to get an address on this netif that is invalid. - * Skip 0 index (link-local address) */ - for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) { - if (netif_ip6_addr_state(prefix_list[i].netif, j) == IP6_ADDR_INVALID) { - /* Generate an address using this prefix and interface ID from link-local address. */ - IP_ADDR6(&prefix_list[i].netif->ip6_addr[j], - prefix_list[i].prefix.addr[0], prefix_list[i].prefix.addr[1], - netif_ip6_addr(prefix_list[i].netif, 0)->addr[2], netif_ip6_addr(prefix_list[i].netif, 0)->addr[3]); - - /* Mark it as tentative (DAD will be performed if configured). */ - netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_TENTATIVE); - - /* Mark this prefix with ADDRESS_GENERATED, so that we don't try again. */ - prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED; - - /* Exit loop. */ - break; - } - } - } -#endif /* LWIP_IPV6_AUTOCONFIG */ - } - } - } - - - /* Process our own addresses, if DAD configured. */ - for (netif = netif_list; netif != NULL; netif = netif->next) { - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { - if (ip6_addr_istentative(netif->ip6_addr_state[i])) { - if ((netif->ip6_addr_state[i] & 0x07) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { - /* No NA received in response. Mark address as valid. */ - netif->ip6_addr_state[i] = IP6_ADDR_PREFERRED; - /* @todo implement preferred and valid lifetimes. */ - } else if (netif->flags & NETIF_FLAG_UP) { -#if LWIP_IPV6_MLD - if ((netif->ip6_addr_state[i] & 0x07) == 0) { - /* Join solicited node multicast group. */ - ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, i)->addr[3]); - mld6_joingroup(netif_ip6_addr(netif, i), &multicast_address); - } -#endif /* LWIP_IPV6_MLD */ - /* Send a NS for this address. */ - nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST); - netif->ip6_addr_state[i]++; - /* @todo send max 1 NS per tmr call? enable return*/ - /*return;*/ - } - } - } - } - -#if LWIP_IPV6_SEND_ROUTER_SOLICIT - /* Send router solicitation messages, if necessary. */ - for (netif = netif_list; netif != NULL; netif = netif->next) { - if ((netif->rs_count > 0) && (netif->flags & NETIF_FLAG_UP) && - (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)))) { - if (nd6_send_rs(netif) == ERR_OK) { - netif->rs_count--; - } - } - } -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ - -} - -/** - * 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; - - if (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_set(&(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]); - 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, - LWIP_ICMP6_HL, 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; - - /* Use link-local address as source address. */ - /* src_addr = &(netif->ip6_addr[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_set(&(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]); - dest_addr = &multicast_address; - } else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) { - ip6_addr_set_allnodes_linklocal(&multicast_address); - 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, - LWIP_ICMP6_HL, 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); - - /* 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, - LWIP_ICMP6_HL, 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 s8_t -nd6_find_destination_cache_entry(const ip6_addr_t * ip6addr) -{ - s8_t i; - 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 s8_t -nd6_new_destination_cache_entry(void) -{ - s8_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; -} - -/** - * Determine whether an address matches an on-link prefix. - * - * @param ip6addr the IPv6 address to match - * @return 1 if the address is on-link, 0 otherwise - */ -static s8_t -nd6_is_prefix_in_netif(const ip6_addr_t * ip6addr, struct netif * netif) -{ - s8_t i; - 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 address. */ - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { - return 1; - } - } - return 0; -} - -/** - * Select a default router for a destination. - * - * @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 - */ -s8_t -nd6_select_router(const ip6_addr_t * ip6addr, struct netif * netif) -{ - s8_t i; - /* last_router is used for round-robin router selection (as recommended - * in RFC). This is more robust in case one router is not reachable, - * we are not stuck trying to resolve it. */ - static s8_t last_router; - (void)ip6addr; /* @todo match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */ - - /* @todo: implement default router preference */ - - /* Look for reachable routers. */ - for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { - if (++last_router >= LWIP_ND6_NUM_ROUTERS) { - last_router = 0; - } - if ((default_router_list[i].neighbor_entry != NULL) && - (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && - (default_router_list[i].invalidation_timer > 0) && - (default_router_list[i].neighbor_entry->state == ND6_REACHABLE)) { - return i; - } - } - - /* Look for router in other reachability states, but still valid according to timer. */ - for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { - if (++last_router >= LWIP_ND6_NUM_ROUTERS) { - last_router = 0; - } - if ((default_router_list[i].neighbor_entry != NULL) && - (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && - (default_router_list[i].invalidation_timer > 0)) { - return i; - } - } - - /* Look for any router for which we have any information at all. */ - for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { - if (++last_router >= LWIP_ND6_NUM_ROUTERS) { - last_router = 0; - } - if (default_router_list[i].neighbor_entry != NULL && - (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1)) { - return i; - } - } - - /* no suitable router found. */ - return -1; -} - -/** - * 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; - - /* 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 neighbor_index; - - /* 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 = 0; - } - - /* Mark neighbor as router. */ - neighbor_cache[neighbor_index].isrouter = 1; - - /* Look for empty entry. */ - for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { - if (default_router_list[router_index].neighbor_entry == NULL) { - default_router_list[router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); - return 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(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(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); -#if LWIP_IPV6_AUTOCONFIG - prefix_list[i].flags = 0; -#endif /* LWIP_IPV6_AUTOCONFIG */ - 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 - */ -s8_t -nd6_get_next_hop_entry(const ip6_addr_t * ip6addr, struct netif * netif) -{ - s8_t i; - -#if LWIP_NETIF_HWADDRHINT - if (netif->addr_hint != NULL) { - /* per-pcb cached entry was given */ - u8_t addr_hint = *(netif->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. */ - i = nd6_find_destination_cache_entry(ip6addr); - if (i >= 0) { - /* found destination entry. make it our new cached index. */ - nd6_cached_destination_index = i; - } else { - /* Not found. Create a new destination entry. */ - i = nd6_new_destination_cache_entry(); - if (i >= 0) { - /* got new destination entry. make it our new cached index. */ - nd6_cached_destination_index = i; - } 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->mtu; - ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); - } 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->mtu; /* 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->addr_hint != NULL) { - /* per-pcb cached entry was given */ - *(netif->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 = 0; - } - } - - /* 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 - */ -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_REF, PBUF_POOL or PBUF_RAM, we have no choice but - * to copy the whole queue into a new PBUF_RAM (see bug #11400) - * PBUF_ROMs can be left as they are, since ROM must not get changed. */ - p = q; - while (p) { - if (p->type != PBUF_ROM) { - copy_needed = 1; - break; - } - p = p->next; - } - if (copy_needed) { - /* copy the whole packet into new pbufs */ - p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); - 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_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); - } - if (p != NULL) { - if (pbuf_copy(p, q) != ERR_OK) { - pbuf_free(p); - p = NULL; - } - } - } else { - /* referencing the old pbuf is enough */ - p = q; - pbuf_ref(p); - } - /* packet 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; -#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); - /* Override ip6_current_dest_addr() so that we have an aligned copy. */ - ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); - /* send the queued IPv6 packet */ - (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, ip6_current_dest_addr()); - /* 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); - /* Override ip6_current_dest_addr() so that we have an aligned copy. */ - ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); - /* send the queued IPv6 packet */ - (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, ip6_current_dest_addr()); - /* free the queued IP packet */ - pbuf_free(neighbor_cache[i].q); - neighbor_cache[i].q = NULL; - } -#endif /* LWIP_ND6_QUEUEING */ -} - - -/** - * 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) -{ - s8_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->mtu; - } - - 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; - - /* Find destination in cache. */ - if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { - i = nd6_cached_destination_index; - ND6_STATS_INC(nd6.cachehit); - } else { - i = nd6_find_destination_cache_entry(ip6addr); - } - if (i < 0) { - return; - } - - /* Find next hop neighbor in cache. */ - if (ip6_addr_cmp(&(destination_cache[i].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[i].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; - prefix_list[i].flags = 0; - } - } - 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); - } - } -} - -#endif /* LWIP_IPV6 */ diff --git a/ext/lwip/src/core/mem.c b/ext/lwip/src/core/mem.c deleted file mode 100644 index 070d103..0000000 --- a/ext/lwip/src/core/mem.c +++ /dev/null @@ -1,777 +0,0 @@ -/** - * @file - * Dynamic memory manager - * - * This is a lightweight replacement for the standard C library malloc(). - * - * If you want to use the standard C library malloc() instead, define - * MEM_LIBC_MALLOC to 1 in your lwipopts.h - * - * To let mem_malloc() use pools (prevents fragmentation and is much faster than - * a heap but might waste some memory), define MEM_USE_POOLS to 1, define - * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list - * of pools like this (more pools can be added between _START and _END): - * - * Define three pools with sizes 256, 512, and 1512 bytes - * LWIP_MALLOC_MEMPOOL_START - * LWIP_MALLOC_MEMPOOL(20, 256) - * LWIP_MALLOC_MEMPOOL(10, 512) - * LWIP_MALLOC_MEMPOOL(5, 1512) - * LWIP_MALLOC_MEMPOOL_END - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * Simon Goldschmidt - * - */ - -#include "lwip/opt.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/sys.h" -#include "lwip/stats.h" -#include "lwip/err.h" - -#include - -#if MEM_LIBC_MALLOC || MEM_USE_POOLS -/** mem_init is not used when using pools instead of a heap or using - * C library malloc(). - */ -void -mem_init(void) -{ -} - -/** mem_trim is not used when using pools instead of a heap or using - * C library malloc(): we can't free part of a pool element and the stack - * support mem_trim() to return a different pointer - */ -void* -mem_trim(void *mem, mem_size_t size) -{ - LWIP_UNUSED_ARG(size); - return mem; -} -#endif /* MEM_LIBC_MALLOC || MEM_USE_POOLS */ - -#if MEM_LIBC_MALLOC -/* lwIP heap implemented using C library malloc() */ - -/* in case C library malloc() needs extra protection, - * allow these defines to be overridden. - */ -#ifndef mem_clib_free -#define mem_clib_free free -#endif -#ifndef mem_clib_malloc -#define mem_clib_malloc malloc -#endif -#ifndef mem_clib_calloc -#define mem_clib_calloc calloc -#endif - -#if LWIP_STATS && MEM_STATS -#define MEM_LIBC_STATSHELPER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(mem_size_t)) -#else -#define MEM_LIBC_STATSHELPER_SIZE 0 -#endif - -/** - * Allocate a block of memory with a minimum of 'size' bytes. - * - * @param size is the minimum size of the requested block in bytes. - * @return pointer to allocated memory or NULL if no free memory was found. - * - * Note that the returned value must always be aligned (as defined by MEM_ALIGNMENT). - */ -void * -mem_malloc(mem_size_t size) -{ - void* ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE); - if (ret == NULL) { - MEM_STATS_INC(err); - } else { - LWIP_ASSERT("malloc() must return aligned memory", LWIP_MEM_ALIGN(ret) == ret); -#if LWIP_STATS && MEM_STATS - *(mem_size_t*)ret = size; - ret = (u8_t*)ret + MEM_LIBC_STATSHELPER_SIZE; - MEM_STATS_INC_USED(used, size); -#endif - } - return ret; -} - -/** Put memory back on the heap - * - * @param rmem is the pointer as returned by a previous call to mem_malloc() - */ -void -mem_free(void *rmem) -{ - LWIP_ASSERT("rmem != NULL", (rmem != NULL)); - LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); -#if LWIP_STATS && MEM_STATS - rmem = (u8_t*)rmem - MEM_LIBC_STATSHELPER_SIZE; - MEM_STATS_DEC_USED(used, *(mem_size_t*)rmem); -#endif - mem_clib_free(rmem); -} - -#elif MEM_USE_POOLS - -/* lwIP heap implemented with different sized pools */ - -/** - * 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; - memp_t poolnr; - mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); - - for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { -#if MEM_USE_POOLS_TRY_BIGGER_POOL -again: -#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ - /* is this pool big enough to hold an element of the required size - plus a struct memp_malloc_helper that saves the pool this element came from? */ - if (required_size <= memp_pools[poolnr]->size) { - break; - } - } - if (poolnr > MEMP_POOL_LAST) { - LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); - MEM_STATS_INC(err); - return NULL; - } - element = (struct memp_malloc_helper*)memp_malloc(poolnr); - if (element == NULL) { - /* No need to DEBUGF or ASSERT: This error is already - taken care of in memp.c */ -#if MEM_USE_POOLS_TRY_BIGGER_POOL - /** Try a bigger pool if this one is empty! */ - if (poolnr < MEMP_POOL_LAST) { - poolnr++; - goto again; - } -#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ - MEM_STATS_INC(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(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(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; -}; - -/** 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; -/** pointer to the lowest free block, this is used for faster search */ -static struct mem *lfree; - -/** 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) - -#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - -/* Protect the heap only by using a semaphore */ -#define LWIP_MEM_FREE_DECL_PROTECT() -#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) -#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) -/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ -#define LWIP_MEM_ALLOC_DECL_PROTECT() -#define LWIP_MEM_ALLOC_PROTECT() -#define LWIP_MEM_ALLOC_UNPROTECT() - -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - - -/** - * "Plug holes" by combining adjacent empty struct mems. - * After this function is through, there should not exist - * one empty struct mem pointing to another empty struct mem. - * - * @param mem this points to a struct mem which just has been freed - * @internal this function is only called by mem_free() and mem_trim() - * - * This assumes access to the heap is protected by the calling function - * already. - */ -static void -plug_holes(struct mem *mem) -{ - struct mem *nmem; - struct mem *pmem; - - LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); - LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); - LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); - - /* plug hole forward */ - LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); - - nmem = (struct mem *)(void *)&ram[mem->next]; - if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { - /* if mem->next is unused and not end of ram, combine mem and mem->next */ - if (lfree == nmem) { - lfree = mem; - } - mem->next = nmem->next; - ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram); - } - - /* plug hole backward */ - pmem = (struct mem *)(void *)&ram[mem->prev]; - if (pmem != mem && pmem->used == 0) { - /* if mem->prev is unused, combine mem and mem->prev */ - if (lfree == mem) { - lfree = pmem; - } - pmem->next = mem->next; - ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram); - } -} - -/** - * Zero the heap and initialize start, end and lowest-free - */ -void -mem_init(void) -{ - struct mem *mem; - - LWIP_ASSERT("Sanity check alignment", - (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); - - /* align the heap */ - ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); - /* initialize the start of the heap */ - mem = (struct mem *)(void *)ram; - mem->next = MEM_SIZE_ALIGNED; - mem->prev = 0; - mem->used = 0; - /* initialize the end of the heap */ - ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED]; - ram_end->used = 1; - ram_end->next = MEM_SIZE_ALIGNED; - ram_end->prev = MEM_SIZE_ALIGNED; - - /* initialize the lowest-free pointer to the start of the heap */ - lfree = (struct mem *)(void *)ram; - - MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); - - if (sys_mutex_new(&mem_mutex) != ERR_OK) { - LWIP_ASSERT("failed to create mem_mutex", 0); - } -} - -/** - * Put a struct mem back on the heap - * - * @param rmem is the data portion of a struct mem as returned by a previous - * call to mem_malloc() - */ -void -mem_free(void *rmem) -{ - struct mem *mem; - LWIP_MEM_FREE_DECL_PROTECT(); - - if (rmem == NULL) { - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); - return; - } - LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); - - LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && - (u8_t *)rmem < (u8_t *)ram_end); - - if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { - SYS_ARCH_DECL_PROTECT(lev); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); - /* protect mem stats from concurrent access */ - SYS_ARCH_PROTECT(lev); - MEM_STATS_INC(illegal); - SYS_ARCH_UNPROTECT(lev); - return; - } - /* protect the heap from concurrent access */ - LWIP_MEM_FREE_PROTECT(); - /* Get the corresponding struct mem ... */ - /* cast through void* to get rid of alignment warnings */ - mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); - /* ... which has to be in a used state ... */ - LWIP_ASSERT("mem_free: mem->used", mem->used); - /* ... and is now unused. */ - mem->used = 0; - - if (mem < lfree) { - /* the newly freed struct is now the lowest */ - lfree = mem; - } - - MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); - - /* finally, see if prev or next are free also */ - plug_holes(mem); -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 1; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_MEM_FREE_UNPROTECT(); -} - -/** - * Shrink memory returned by mem_malloc(). - * - * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked - * @param newsize required size after shrinking (needs to be smaller than or - * equal to the previous size) - * @return for compatibility reasons: is always == rmem, at the moment - * or NULL if newsize is > old size, in which case rmem is NOT touched - * or freed! - */ -void * -mem_trim(void *rmem, mem_size_t newsize) -{ - mem_size_t size; - mem_size_t ptr, ptr2; - struct mem *mem, *mem2; - /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ - LWIP_MEM_FREE_DECL_PROTECT(); - - /* Expand the size of the allocated memory region so that we can - adjust for alignment. */ - newsize = LWIP_MEM_ALIGN_SIZE(newsize); - - if (newsize < MIN_SIZE_ALIGNED) { - /* every data block must be at least MIN_SIZE_ALIGNED long */ - newsize = MIN_SIZE_ALIGNED; - } - - if (newsize > MEM_SIZE_ALIGNED) { - return NULL; - } - - LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && - (u8_t *)rmem < (u8_t *)ram_end); - - if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { - SYS_ARCH_DECL_PROTECT(lev); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); - /* protect mem stats from concurrent access */ - SYS_ARCH_PROTECT(lev); - MEM_STATS_INC(illegal); - SYS_ARCH_UNPROTECT(lev); - return rmem; - } - /* Get the corresponding struct mem ... */ - /* cast through void* to get rid of alignment warnings */ - mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); - /* ... and its offset pointer */ - ptr = (mem_size_t)((u8_t *)mem - ram); - - size = mem->next - ptr - SIZEOF_STRUCT_MEM; - LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); - if (newsize > size) { - /* not supported */ - return NULL; - } - if (newsize == size) { - /* No change in size, simply return */ - return rmem; - } - - /* protect the heap from concurrent access */ - LWIP_MEM_FREE_PROTECT(); - - mem2 = (struct mem *)(void *)&ram[mem->next]; - if (mem2->used == 0) { - /* The next struct is unused, we can simply move it at little */ - mem_size_t next; - /* remember the old next pointer */ - next = mem2->next; - /* create new struct mem which is moved directly after the shrinked mem */ - ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; - if (lfree == mem2) { - lfree = (struct mem *)(void *)&ram[ptr2]; - } - mem2 = (struct mem *)(void *)&ram[ptr2]; - mem2->used = 0; - /* restore the next pointer */ - mem2->next = next; - /* link it back to mem */ - mem2->prev = ptr; - /* link mem to it */ - mem->next = ptr2; - /* last thing to restore linked list: as we have moved mem2, - * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not - * the end of the heap */ - if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; - } - MEM_STATS_DEC_USED(used, (size - newsize)); - /* no need to plug holes, we've already done that */ - } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { - /* Next struct is used but there's room for another struct mem with - * at least MIN_SIZE_ALIGNED of data. - * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem - * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). - * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty - * region that couldn't hold data, but when mem->next gets freed, - * the 2 regions would be combined, resulting in more free memory */ - ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; - mem2 = (struct mem *)(void *)&ram[ptr2]; - if (mem2 < lfree) { - lfree = mem2; - } - mem2->used = 0; - mem2->next = mem->next; - mem2->prev = ptr; - mem->next = ptr2; - if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; - } - MEM_STATS_DEC_USED(used, (size - newsize)); - /* the original mem->next is used, so no need to plug holes! */ - } - /* else { - next struct mem is used but size between mem and mem2 is not big enough - to create another struct mem - -> don't do anyhting. - -> the remaining space stays unused since it is too small - } */ -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 1; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_MEM_FREE_UNPROTECT(); - return rmem; -} - -/** - * Allocate a block of memory with a minimum of 'size' bytes. - * - * @param size is the minimum size of the requested block in bytes. - * @return pointer to allocated memory or NULL if no free memory was found. - * - * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). - */ -void * -mem_malloc(mem_size_t size) -{ - mem_size_t ptr, ptr2; - struct mem *mem, *mem2; -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - u8_t local_mem_free_count = 0; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_MEM_ALLOC_DECL_PROTECT(); - - if (size == 0) { - return NULL; - } - - /* Expand the size of the allocated memory region so that we can - adjust for alignment. */ - size = LWIP_MEM_ALIGN_SIZE(size); - - if (size < MIN_SIZE_ALIGNED) { - /* every data block must be at least MIN_SIZE_ALIGNED long */ - size = MIN_SIZE_ALIGNED; - } - - if (size > MEM_SIZE_ALIGNED) { - return NULL; - } - - /* protect the heap from concurrent access */ - sys_mutex_lock(&mem_mutex); - LWIP_MEM_ALLOC_PROTECT(); -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - /* run as long as a mem_free disturbed mem_malloc 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_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size; - ptr = ((struct mem *)(void *)&ram[ptr])->next) { - mem = (struct mem *)(void *)&ram[ptr]; -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 0; - LWIP_MEM_ALLOC_UNPROTECT(); - /* allow mem_free 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 = ptr + SIZEOF_STRUCT_MEM + size; - /* create mem2 struct */ - mem2 = (struct mem *)(void *)&ram[ptr2]; - mem2->used = 0; - mem2->next = mem->next; - mem2->prev = ptr; - /* and insert it between mem and mem->next */ - mem->next = ptr2; - mem->used = 1; - - if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; - } - MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); - } else { - /* (a mem2 struct does no fit into the user data space of mem and mem->next will always - * be used at this point: if not we have 2 unused structs in a row, plug_holes should have - * take care of this). - * -> near fit or 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_size_t)((u8_t *)mem - ram)); - } -#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 = (struct mem *)(void *)&ram[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); - - return (u8_t *)mem + SIZEOF_STRUCT_MEM; - } - } -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - /* if we got interrupted by a mem_free, try again */ - } while (local_mem_free_count != 0); -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); - MEM_STATS_INC(err); - LWIP_MEM_ALLOC_UNPROTECT(); - sys_mutex_unlock(&mem_mutex); - return NULL; -} - -#endif /* MEM_USE_POOLS */ - -#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; - - /* allocate 'count' objects of size 'size' */ - p = mem_malloc(count * size); - if (p) { - /* zero the memory */ - memset(p, 0, (size_t)count * (size_t)size); - } - return p; -} -#endif /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ diff --git a/ext/lwip/src/core/memp.c b/ext/lwip/src/core/memp.c deleted file mode 100644 index 5d2c4fb..0000000 --- a/ext/lwip/src/core/memp.c +++ /dev/null @@ -1,501 +0,0 @@ -/** - * @file - * Dynamic pool memory manager - * - * lwIP has dedicated pools for many structures (netconn, protocol control blocks, - * packet buffers, ...). All these pools are managed here. - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -/** - * @defgroup mempool Memory pools - * @ingroup infrastructure - * Custom memory pools - */ - -#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/ip4_frag.h" -#include "lwip/netbuf.h" -#include "lwip/api.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/api_msg.h" -#include "lwip/sockets.h" -#include "lwip/netifapi.h" -#include "lwip/etharp.h" -#include "lwip/igmp.h" -#include "lwip/timeouts.h" -/* needed by default MEMP_NUM_SYS_TIMEOUT */ -#include "netif/ppp/ppp_opts.h" -#include "lwip/netdb.h" -#include "lwip/dns.h" -#include "lwip/nd6.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" -}; - -#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 - * (e.g. the restricted area after it has been altered) - * - * @param p the memp element to check - * @param memp_type the pool p comes from - */ -static void -memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *desc) -{ - u16_t k; - u8_t *m; -#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE + desc->size; - for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { - if (m[k] != 0xcd) { - char errstr[128] = "detected memp overflow in pool "; - strcat(errstr, desc->desc); - LWIP_ASSERT(errstr, 0); - } - } -#endif -} - -/** - * Check if a memp element was victim of an underflow - * (e.g. the restricted area before it has been altered) - * - * @param p the memp element to check - * @param memp_type the pool p comes from - */ -static void -memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *desc) -{ - u16_t k; - u8_t *m; -#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; - for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { - if (m[k] != 0xcd) { - char errstr[128] = "detected memp underflow in pool "; - strcat(errstr, desc->desc); - LWIP_ASSERT(errstr, 0); - } - } -#endif -} - -/** - * Initialize the restricted area of on memp element. - */ -static void -memp_overflow_init_element(struct memp *p, const struct memp_desc *desc) -{ - u8_t *m; -#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; - memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED); -#endif -#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE + desc->size; - memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); -#endif -} - -#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 *)(size_t)(memp_pools[i]->base); - for (j = 0; j < memp_pools[i]->num; ++j) { - memp_overflow_check_element_overflow(p, memp_pools[i]); - memp_overflow_check_element_underflow(p, memp_pools[i]); - p = (struct memp*)(size_t)((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED); - } - } - SYS_ARCH_UNPROTECT(old_level); -} -#endif /* MEMP_OVERFLOW_CHECK >= 2 */ - -#if !MEMP_MEM_MALLOC -/** - * Initialize the restricted areas of all memp elements in a pool. - */ -static void -memp_overflow_init(const struct memp_desc *desc) -{ - u16_t i; - struct memp *p; - - p = (struct memp *)(size_t)(desc->base); - for (i = 0; i < desc->num; ++i) { - memp_overflow_init_element(p, desc); - p = (struct memp*)(size_t)((u8_t*)p + MEMP_SIZE + desc->size + MEMP_SANITY_REGION_AFTER_ALIGNED); - } -} -#endif /* !MEMP_MEM_MALLOC */ -#endif /* MEMP_OVERFLOW_CHECK */ - -/** - * Initialize custom memory pool. - * Related functions: memp_malloc_pool, memp_free_pool - * - * @param desc pool to initialize - */ -void -memp_init_pool(const struct memp_desc *desc) -{ -#if MEMP_MEM_MALLOC - LWIP_UNUSED_ARG(desc); -#else - int i; - struct memp *memp; - - *desc->tab = NULL; - memp = (struct memp*)LWIP_MEM_ALIGN(desc->base); - /* create a linked list of memp elements */ - for (i = 0; i < desc->num; ++i) { - memp->next = *desc->tab; - *desc->tab = memp; - /* cast through void* to get rid of alignment warnings */ - memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size -#if MEMP_OVERFLOW_CHECK - + MEMP_SANITY_REGION_AFTER_ALIGNED -#endif - ); - } - -#if MEMP_OVERFLOW_CHECK - memp_overflow_init(desc); -#endif /* MEMP_OVERFLOW_CHECK */ -#endif /* !MEMP_MEM_MALLOC */ - -#if MEMP_STATS -#if !MEMP_MEM_MALLOC - desc->stats->avail = desc->num; -#endif /* !MEMP_MEM_MALLOC */ - -#if defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY - desc->stats->name = desc->desc; -#endif /* defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY */ -#endif /* MEMP_STATS */ -} - -/** - * 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; - -#if MEMP_OVERFLOW_CHECK == 1 - memp_overflow_check_element_overflow(memp, desc); - memp_overflow_check_element_underflow(memp, desc); -#endif /* MEMP_OVERFLOW_CHECK */ -#endif /* MEMP_MEM_MALLOC */ - - if (memp != NULL) { -#if !MEMP_MEM_MALLOC - *desc->tab = memp->next; -#if MEMP_OVERFLOW_CHECK - memp->next = NULL; -#endif /* MEMP_OVERFLOW_CHECK */ -#endif /* !MEMP_MEM_MALLOC */ -#if MEMP_OVERFLOW_CHECK - memp->file = file; - memp->line = line; -#if MEMP_MEM_MALLOC - memp_overflow_init_element(memp, desc); -#endif /* MEMP_MEM_MALLOC */ -#endif /* MEMP_OVERFLOW_CHECK */ - LWIP_ASSERT("memp_malloc: memp properly aligned", - ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0); -#if MEMP_STATS - desc->stats->used++; - if (desc->stats->used > desc->stats->max) { - desc->stats->max = desc->stats->used; - } -#endif - SYS_ARCH_UNPROTECT(old_level); - /* cast through u8_t* to get rid of alignment warnings */ - return ((u8_t*)memp + MEMP_SIZE); - } else { - LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", desc->desc)); -#if MEMP_STATS - desc->stats->err++; -#endif - } - - SYS_ARCH_UNPROTECT(old_level); - return NULL; -} - -/** - * Get an element from a custom pool. - * - * @param desc the pool to get an element from - * - * @return a pointer to the allocated memory or a NULL pointer on error - */ -void * -#if !MEMP_OVERFLOW_CHECK -memp_malloc_pool(const struct memp_desc *desc) -#else -memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int line) -#endif -{ - LWIP_ASSERT("invalid pool desc", desc != NULL); - if (desc == NULL) { - return NULL; - } - -#if !MEMP_OVERFLOW_CHECK - return do_memp_malloc_pool(desc); -#else - return do_memp_malloc_pool_fn(desc, file, line); -#endif -} - -/** - * 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_overflow(memp, desc); - memp_overflow_check_element_underflow(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 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/ext/lwip/src/core/netif.c b/ext/lwip/src/core/netif.c deleted file mode 100644 index 4a18b7e..0000000 --- a/ext/lwip/src/core/netif.c +++ /dev/null @@ -1,1078 +0,0 @@ -/** - * @file - * lwIP network interface abstraction - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - */ - -/** - * @defgroup netif Network interface (NETIF) - * @ingroup callbackstyle_api - */ - -#include "lwip/opt.h" - -#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/snmp.h" -#include "lwip/igmp.h" -#include "lwip/etharp.h" -#include "lwip/stats.h" -#include "lwip/sys.h" -#if ENABLE_LOOPBACK -#include "lwip/sys.h" -#if LWIP_NETIF_LOOPBACK_MULTITHREADING -#include "lwip/tcpip.h" -#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ -#endif /* ENABLE_LOOPBACK */ - -#if LWIP_AUTOIP -#include "lwip/autoip.h" -#endif /* LWIP_AUTOIP */ -#if LWIP_DHCP -#include "lwip/dhcp.h" -#endif /* LWIP_DHCP */ -#if LWIP_IPV6_DHCP6 -#include "lwip/dhcp6.h" -#endif /* LWIP_IPV6_DHCP6 */ -#if LWIP_IPV6_MLD -#include "lwip/mld6.h" -#endif /* LWIP_IPV6_MLD */ -#if LWIP_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 */ - -struct netif *netif_list; -struct netif *netif_default; - -static u8_t netif_num; - -#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_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) -{ - /* 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->flags |= NETIF_FLAG_IGMP; -#endif - 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(loop_netif.ip6_addr, 0, 0, 0, PP_HTONL(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) -{ -#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. - * - * @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! - * - * @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 - u32_t i; -#endif - - LWIP_ASSERT("No init function given", init != NULL); - - /* reset new interface configuration state */ -#if LWIP_IPV4 - ip_addr_set_zero_ip4(&netif->ip_addr); - ip_addr_set_zero_ip4(&netif->netmask); - ip_addr_set_zero_ip4(&netif->gw); -#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_set_state(netif, i, IP6_ADDR_INVALID); - } - netif->output_ip6 = netif_null_output_ip6; -#endif /* LWIP_IPV6 */ - NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL); - netif->flags = 0; -#if LWIP_DHCP - /* netif not under DHCP control by default */ - netif->dhcp = NULL; -#endif /* LWIP_DHCP */ -#if LWIP_AUTOIP - /* netif not under AutoIP control by default */ - netif->autoip = NULL; -#endif /* LWIP_AUTOIP */ -#if LWIP_IPV6_AUTOCONFIG - /* IPv6 address autoconfiguration not enabled by default */ - netif->ip6_autoconfig_enabled = 0; -#endif /* LWIP_IPV6_AUTOCONFIG */ -#if LWIP_IPV6_SEND_ROUTER_SOLICIT - netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -#if LWIP_IPV6_DHCP6 - /* netif not under DHCPv6 control by default */ - netif->dhcp6 = NULL; -#endif /* LWIP_IPV6_DHCP6 */ -#if LWIP_NETIF_STATUS_CALLBACK - netif->status_callback = NULL; -#endif /* LWIP_NETIF_STATUS_CALLBACK */ -#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_SET_HWADDRHINT(netif, NULL); -#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; - } - - /* add this netif to the list */ - netif->next = netif_list; - netif_list = 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")); - return netif; -} - -#if LWIP_IPV4 -/** - * @ingroup netif - * Change IP address configuration for a network interface (including netmask - * and default gateway). - * - * @param netif the network interface to change - * @param ipaddr the new IP address - * @param netmask the new netmask - * @param gw the new default gateway - */ -void -netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, - const ip4_addr_t *gw) -{ - if (ip4_addr_isany(ipaddr)) { - /* when removing an address, we have to remove it *before* changing netmask/gw - to ensure that tcp RST segment can be sent correctly */ - netif_set_ipaddr(netif, ipaddr); - netif_set_netmask(netif, netmask); - netif_set_gw(netif, gw); - } else { - netif_set_netmask(netif, netmask); - netif_set_gw(netif, gw); - /* set ipaddr last to ensure netmask/gw have been set when status callback is called */ - netif_set_ipaddr(netif, ipaddr); - } -} -#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 (netif == NULL) { - return; - } - -#if LWIP_IPV4 - if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { -#if LWIP_TCP - tcp_netif_ipv4_addr_changed(netif_ip4_addr(netif), NULL); -#endif /* LWIP_TCP */ - /* cannot do this for UDP, as there is no 'err' callback in udp pcbs */ - } - -#if LWIP_IGMP - /* stop IGMP processing */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_stop(netif); - } -#endif /* LWIP_IGMP */ -#endif /* LWIP_IPV4*/ - -#if LWIP_IPV6 && LWIP_IPV6_MLD - /* stop MLD processing */ - mld6_stop(netif); -#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - if (netif_is_up(netif)) { - /* set netif down before removing (call callback function) */ - netif_set_down(netif); - } - - mib2_remove_ip4(netif); - - /* this netif is default? */ - if (netif_default == netif) { - /* reset default netif */ - netif_set_default(NULL); - } - /* 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; - for (tmp_netif = netif_list; tmp_netif != NULL; tmp_netif = tmp_netif->next) { - if (tmp_netif->next == netif) { - tmp_netif->next = netif->next; - break; - } - } - if (tmp_netif == NULL) { - return; /* netif is not on the list */ - } - } - 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 - * 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; - - if (name == NULL) { - return NULL; - } - - num = name[2] - '0'; - - for (netif = netif_list; netif != NULL; netif = netif->next) { - if (num == netif->num && - name[0] == netif->name[0] && - name[1] == netif->name[1]) { - LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); - return netif; - } - } - LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); - return NULL; -} - -#if LWIP_IPV4 -/** - * @ingroup netif - * 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) -{ - ip4_addr_t new_addr = (ipaddr ? *ipaddr : *IP4_ADDR_ANY); - /* address is actually being changed? */ - if (ip4_addr_cmp(&new_addr, netif_ip4_addr(netif)) == 0) { - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); -#if LWIP_TCP - tcp_netif_ipv4_addr_changed(netif_ip4_addr(netif), ipaddr); -#endif /* LWIP_TCP */ -#if LWIP_UDP - udp_netif_ipv4_addr_changed(netif_ip4_addr(netif), ipaddr); -#endif /* LWIP_UDP */ - - 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); - } - - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - netif->name[0], netif->name[1], - ip4_addr1_16(netif_ip4_addr(netif)), - ip4_addr2_16(netif_ip4_addr(netif)), - ip4_addr3_16(netif_ip4_addr(netif)), - ip4_addr4_16(netif_ip4_addr(netif)))); -} - -/** - * @ingroup netif - * 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) -{ - 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)))); -} - -/** - * @ingroup netif - * 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) -{ - 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)))); -} -#endif /* LWIP_IPV4 */ - -/** - * @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) -{ - 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) -{ - if (!(netif->flags & NETIF_FLAG_UP)) { - netif->flags |= NETIF_FLAG_UP; - - MIB2_COPY_SYSUPTIME_TO(&netif->ts); - - NETIF_STATUS_CALLBACK(netif); - - if (netif->flags & NETIF_FLAG_LINK_UP) { - netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4|NETIF_REPORT_TYPE_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) -{ -#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 */ -#if LWIP_IPV6_SEND_ROUTER_SOLICIT - /* Send Router Solicitation messages. */ - netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ - } -#endif /* LWIP_IPV6 */ -} - -/** - * @ingroup netif - * Bring an interface down, disabling any traffic processing. - */ -void -netif_set_down(struct netif *netif) -{ - if (netif->flags & NETIF_FLAG_UP) { - netif->flags &= ~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) -{ - 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) -{ - 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) -{ - if (!(netif->flags & NETIF_FLAG_LINK_UP)) { - netif->flags |= NETIF_FLAG_LINK_UP; - -#if LWIP_DHCP - if (netif->dhcp) { - dhcp_network_changed(netif); - } -#endif /* LWIP_DHCP */ - -#if LWIP_AUTOIP - if (netif->autoip) { - autoip_network_changed(netif); - } -#endif /* LWIP_AUTOIP */ - - if (netif->flags & NETIF_FLAG_UP) { - netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4|NETIF_REPORT_TYPE_IPV6); - } - NETIF_LINK_CALLBACK(netif); - } -} - -/** - * @ingroup netif - * Called by a driver when its link goes down - */ -void -netif_set_link_down(struct netif *netif ) -{ - if (netif->flags & NETIF_FLAG_LINK_UP) { - netif->flags &= ~NETIF_FLAG_LINK_UP; - NETIF_LINK_CALLBACK(netif); - } -} - -#if LWIP_NETIF_LINK_CALLBACK -/** - * @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) -{ - 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 - u8_t clen = 0; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - /* If we have a loopif, SNMP counters are adjusted for it, - * if not they are adjusted for 'netif'. */ -#if 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); - - /* 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_LOOPBACK_MAX_PBUFS)) { - 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 += 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); - - SYS_ARCH_PROTECT(lev); - if (netif->loop_first != NULL) { - LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); - netif->loop_last->next = r; - netif->loop_last = last; - } else { - netif->loop_first = r; - netif->loop_last = last; - } - SYS_ARCH_UNPROTECT(lev); - - LINK_STATS_INC(link.xmit); - 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 */ - tcpip_callback_with_block((tcpip_callback_fn)netif_poll, netif, 0); -#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) -{ - struct pbuf *in; - /* 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); - - do { - /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ - SYS_ARCH_PROTECT(lev); - in = netif->loop_first; - if (in != NULL) { - struct pbuf *in_end = in; -#if LWIP_LOOPBACK_MAX_PBUFS - u8_t clen = 1; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - while (in_end->len != in_end->tot_len) { - LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); - in_end = in_end->next; -#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 -= 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); - - if (in != NULL) { - 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); - } - /* Don't reference the packet any more! */ - in = NULL; - } - /* go on while there is a packet on the list */ - } while (netif->loop_first != NULL); -} - -#if !LWIP_NETIF_LOOPBACK_MULTITHREADING -/** - * Calls netif_poll() for every netif on the netif_list. - */ -void -netif_poll_all(void) -{ - struct netif *netif = netif_list; - /* loop through netifs */ - while (netif != NULL) { - netif_poll(netif); - /* proceed to next network interface */ - netif = netif->next; - } -} -#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ -#endif /* ENABLE_LOOPBACK */ - -#if LWIP_IPV6 -/** - * Checks if a specific address is assigned to the netif and returns its - * index. - * - * @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; - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp(netif_ip6_addr(netif, i), ip6addr)) { - return i; - } - } - return -1; -} - -/** - * @ingroup netif - * 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) -{ - LWIP_DEBUGF(1, ("netif_create_ip6_linklocal_address\n")); - u8_t i, addr_index; - - /* 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] = 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] = htonl((0xfeul << 24) | - ((u32_t)(netif->hwaddr[3]) << 16) | - ((u32_t)(netif->hwaddr[4]) << 8) | - (netif->hwaddr[5])); - } else { - /* Use hwaddr directly as interface ID. */ - 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] |= ((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03)); - } - } - - /* Set address state. */ -#if LWIP_IPV6_DUP_DETECT_ATTEMPTS - /* Will perform duplicate address detection (DAD). */ - netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE; -#else - /* Consider address valid. */ - netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED; -#endif /* LWIP_IPV6_AUTOCONFIG */ -} - -/** - * @ingroup netif - * 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; - - 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 -- musn't be the first one (reserved for link local) */ - for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (!ip6_addr_isvalid(netif->ip6_addr_state[i])) { - ip_addr_copy_from_ip6(netif->ip6_addr[i], *ip6addr); - 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 */ diff --git a/ext/lwip/src/core/pbuf.c b/ext/lwip/src/core/pbuf.c deleted file mode 100644 index 84c8536..0000000 --- a/ext/lwip/src/core/pbuf.c +++ /dev/null @@ -1,1367 +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). - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/opt.h" - -#include "lwip/stats.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/pbuf.h" -#include "lwip/sys.h" -#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) - -#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_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \ - SYS_ARCH_PROTECT(old_level); \ - pbuf_free_ooseq_pending = 0; \ - SYS_ARCH_UNPROTECT(old_level); \ - } } 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 (NULL != pcb->ooseq) { - /** Free the ooseq pbufs of one PCB only */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n")); - tcp_segs_free(pcb->ooseq); - pcb->ooseq = NULL; - return; - } - } -} - -#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 */ - -/** - * @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 flag to define header size - * @param length size of the pbuf's payload - * @param type this parameter decides how and where the pbuf - * should be allocated as follows: - * - * - PBUF_RAM: buffer memory for pbuf is allocated as one large - * chunk. This includes protocol headers as well. - * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for - * protocol headers. Additional headers must be prepended - * by allocating another pbuf and chain in to the front of - * the ROM pbuf. It is assumed that the memory used is really - * similar to ROM in that it is immutable and will not be - * changed. Memory which is dynamic should generally not - * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. - * - PBUF_REF: no buffer memory is allocated for the pbuf, even for - * protocol headers. It is assumed that the pbuf is only - * being used in a single thread. If the pbuf gets queued, - * then pbuf_take should be called to copy the buffer. - * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from - * the pbuf pool that is allocated during pbuf_init(). - * - * @return the allocated pbuf. If multiple pbufs where allocated, this - * is the first pbuf of a pbuf chain. - */ -struct pbuf * -pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) -{ - struct pbuf *p, *q, *r; - u16_t offset; - s32_t rem_len; /* remaining length */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); - - /* determine header offset */ - switch (layer) { - case PBUF_TRANSPORT: - /* add room for transport (often TCP) layer header */ - offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; - break; - case PBUF_IP: - /* add room for IP layer header */ - offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN; - break; - case PBUF_LINK: - /* add room for link layer header */ - offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; - break; - case PBUF_RAW_TX: - /* add room for encapsulating link layer headers (e.g. 802.11) */ - offset = PBUF_LINK_ENCAPSULATION_HLEN; - break; - case PBUF_RAW: - /* no offset (e.g. RX buffers or chain successors) */ - offset = 0; - break; - default: - LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); - return NULL; - } - switch (type) { - case PBUF_POOL: - /* allocate head of pbuf chain into p */ - p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); - if (p == NULL) { - PBUF_POOL_IS_EMPTY(); - return NULL; - } - p->type = type; - p->next = NULL; - - /* make the payload pointer point 'offset' bytes into pbuf data memory */ - p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset))); - LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", - ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); - /* the total length of the pbuf chain is the requested size */ - p->tot_len = length; - /* set the length of the first pbuf in the chain */ - p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)); - LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", - ((u8_t*)p->payload + p->len <= - (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); - LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", - (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); - /* set reference count (needed here in case we fail) */ - p->ref = 1; - - /* now allocate the tail of the pbuf chain */ - - /* remember first pbuf for linkage in next iteration */ - r = p; - /* remaining length to be allocated */ - rem_len = length - p->len; - /* any remaining pbufs to be allocated? */ - while (rem_len > 0) { - - q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); - if (q == NULL) { - PBUF_POOL_IS_EMPTY(); - /* free chain so far allocated */ - - pbuf_free(p); - - /* bail out unsuccessfully */ - return NULL; - } - - q->type = type; - q->flags = 0; - q->next = NULL; - /* make previous pbuf point to this pbuf */ - r->next = q; - /* set total length of this pbuf and next in chain */ - LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); - q->tot_len = (u16_t)rem_len; - /* this pbuf length is pool size, unless smaller sized tail */ - q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); - q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); - LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", - ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); - LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", - ((u8_t*)p->payload + p->len <= - (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); - q->ref = 1; - /* calculate remaining length to be allocated */ - rem_len -= q->len; - /* remember this pbuf for linkage in next iteration */ - r = q; - } - /* end of chain */ - /*r->next = NULL;*/ - - break; - case PBUF_RAM: - - /* If pbuf is to be allocated in RAM, allocate memory for it. */ - p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); - if (p == NULL) { - return NULL; - } - /* Set up internal structure of the pbuf. */ - p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); - p->len = p->tot_len = length; - p->next = NULL; - p->type = type; - - LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", - ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); - break; - /* pbuf references existing (non-volatile static constant) ROM payload? */ - case PBUF_ROM: - /* pbuf references existing (externally allocated) RAM payload? */ - case PBUF_REF: - /* only allocate memory for the pbuf structure */ - - p = (struct pbuf *)memp_malloc(MEMP_PBUF); - - if (p == NULL) { - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", - (type == PBUF_ROM) ? "ROM" : "REF")); - return NULL; - } - - /* caller must set this field properly, afterwards */ - p->payload = NULL; - p->len = p->tot_len = length; - p->next = NULL; - p->type = type; - break; - default: - LWIP_ASSERT("pbuf_alloc: erroneous type", 0); - return NULL; - } - /* set reference count */ - p->ref = 1; - /* set flags */ - p->flags = 0; - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); - - return p; -} - -#if LWIP_SUPPORT_CUSTOM_PBUF -/** - * @ingroup pbuf - * Initialize a custom pbuf (already allocated). - * - * @param l flag to define header size - * @param length size of the pbuf's payload - * @param type type of the pbuf (only used to treat the pbuf accordingly, as - * this function allocates no memory) - * @param p pointer to the custom pbuf to initialize (already allocated) - * @param payload_mem pointer to the buffer that is used for payload and headers, - * must be at least big enough to hold 'length' plus the header size, - * may be NULL if set later. - * 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; - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); - - /* determine header offset */ - switch (l) { - case PBUF_TRANSPORT: - /* add room for transport (often TCP) layer header */ - offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; - break; - case PBUF_IP: - /* add room for IP layer header */ - offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN; - break; - case PBUF_LINK: - /* add room for link layer header */ - offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; - break; - case PBUF_RAW_TX: - /* add room for encapsulating link layer headers (e.g. 802.11) */ - offset = PBUF_LINK_ENCAPSULATION_HLEN; - break; - case PBUF_RAW: - offset = 0; - break; - default: - LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0); - return NULL; - } - - if (LWIP_MEM_ALIGN_SIZE(offset) + length > payload_mem_len) { - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); - return NULL; - } - - p->pbuf.next = NULL; - if (payload_mem != NULL) { - p->pbuf.payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset); - } else { - p->pbuf.payload = NULL; - } - p->pbuf.flags = PBUF_FLAG_IS_CUSTOM; - p->pbuf.len = p->pbuf.tot_len = length; - p->pbuf.type = type; - p->pbuf.ref = 1; - return &p->pbuf; -} -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - -/** - * @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 */ - s32_t grow; - - LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); - LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || - p->type == PBUF_ROM || - p->type == PBUF_RAM || - p->type == PBUF_REF); - - /* desired length larger than current length? */ - if (new_len >= p->tot_len) { - /* enlarging not yet supported */ - return; - } - - /* the pbuf chain grows by (new_len - p->tot_len) bytes - * (which may be negative in case of shrinking) */ - grow = new_len - p->tot_len; - - /* first, step over any pbufs that should remain in the chain */ - rem_len = new_len; - q = p; - /* should this pbuf be kept? */ - while (rem_len > q->len) { - /* decrease remaining length by pbuf length */ - rem_len -= q->len; - /* decrease total length indicator */ - LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); - q->tot_len += (u16_t)grow; - /* proceed to next pbuf in chain */ - q = q->next; - LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); - } - /* we have now reached the new last pbuf (in q) */ - /* rem_len == desired length for pbuf q */ - - /* shrink allocated memory for PBUF_RAM */ - /* (other types merely adjust their length fields */ - if ((q->type == PBUF_RAM) && (rem_len != q->len) -#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, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len); - LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); - } - /* adjust length fields for new last pbuf */ - q->len = rem_len; - q->tot_len = q->len; - - /* any remaining pbufs in chain? */ - if (q->next != NULL) { - /* free remaining pbufs in chain */ - pbuf_free(q->next); - } - /* q is last packet in chain */ - q->next = NULL; - -} - -/** - * Adjusts the payload pointer to hide or reveal headers in the payload. - * @see pbuf_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_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force) -{ - u16_t type; - void *payload; - u16_t increment_magnitude; - - LWIP_ASSERT("p != NULL", p != NULL); - if ((header_size_increment == 0) || (p == NULL)) { - return 0; - } - - if (header_size_increment < 0) { - increment_magnitude = -header_size_increment; - /* Check that we aren't going to move off the end of the pbuf */ - LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); - } else { - increment_magnitude = header_size_increment; -#if 0 - /* Can't assert these as some callers speculatively call - pbuf_header() to see if it's OK. Will return 1 below instead. */ - /* Check that we've got the correct type of pbuf to work with */ - LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", - p->type == PBUF_RAM || p->type == PBUF_POOL); - /* Check that we aren't going to move off the beginning of the pbuf */ - LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF", - (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); -#endif - } - - type = p->type; - /* remember current payload pointer */ - payload = p->payload; - - /* pbuf types containing payloads? */ - if (type == PBUF_RAM || type == PBUF_POOL) { - /* set new payload pointer */ - p->payload = (u8_t *)p->payload - header_size_increment; - /* boundary check fails? */ - if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { - LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, - ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", - (void *)p->payload, (void *)((u8_t *)p + SIZEOF_STRUCT_PBUF))); - /* restore old payload pointer */ - p->payload = payload; - /* bail out unsuccessfully */ - return 1; - } - /* pbuf types referring to external payloads? */ - } else if (type == PBUF_REF || type == PBUF_ROM) { - /* hide a header in the payload? */ - if ((header_size_increment < 0) && (increment_magnitude <= p->len)) { - /* increase payload pointer */ - p->payload = (u8_t *)p->payload - header_size_increment; - } else if ((header_size_increment > 0) && force) { - p->payload = (u8_t *)p->payload - header_size_increment; - } else { - /* cannot expand payload to front (yet!) - * bail out unsuccessfully */ - return 1; - } - } else { - /* Unknown type */ - LWIP_ASSERT("bad pbuf type", 0); - return 1; - } - /* modify pbuf length fields */ - p->len += header_size_increment; - p->tot_len += header_size_increment; - - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n", - (void *)payload, (void *)p->payload, header_size_increment)); - - return 0; -} - -/** - * Adjusts the payload pointer to hide or reveal headers in the payload. - * - * Adjusts the ->payload pointer so that space for a header - * (dis)appears in the pbuf payload. - * - * The ->payload, ->tot_len and ->len fields are adjusted. - * - * @param p pbuf to change the header size. - * @param header_size_increment Number of bytes to increment header size which - * increases the size of the pbuf. New space is on the front. - * (Using a negative value decreases the header size.) - * If hdr_size_inc is 0, this function does nothing and returns successful. - * - * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so - * the call will fail. A check is made that the increase in header size does - * not move the payload pointer in front of the start of the buffer. - * @return non-zero on failure, zero on success. - * - */ -u8_t -pbuf_header(struct pbuf *p, s16_t header_size_increment) -{ - return pbuf_header_impl(p, header_size_increment, 0); -} - -/** - * Same as pbuf_header but does not check if 'header_size > 0' is allowed. - * This is used internally only, to allow PBUF_REF for RX. - */ -u8_t -pbuf_header_force(struct pbuf *p, s16_t header_size_increment) -{ - return pbuf_header_impl(p, header_size_increment, 1); -} - -/** - * @ingroup pbuf - * Dereference a pbuf chain or queue and deallocate any no-longer-used - * pbufs at the head of this chain or queue. - * - * Decrements the pbuf reference count. If it reaches zero, the pbuf is - * deallocated. - * - * For a pbuf chain, this is repeated for each pbuf in the chain, - * up to the first pbuf which has a non-zero reference count after - * decrementing. So, when all reference counts are one, the whole - * chain is free'd. - * - * @param p The pbuf (chain) to be dereferenced. - * - * @return the number of pbufs that were de-allocated - * from the head of the chain. - * - * @note MUST NOT be called on a packet queue (Not verified to work yet). - * @note the reference counter of a pbuf equals the number of pointers - * that refer to the pbuf (or into the pbuf). - * - * @internal examples: - * - * Assuming existing chains a->b->c with the following reference - * counts, calling pbuf_free(a) results in: - * - * 1->2->3 becomes ...1->3 - * 3->3->3 becomes 2->3->3 - * 1->1->2 becomes ......1 - * 2->1->1 becomes 1->1->1 - * 1->1->1 becomes ....... - * - */ -u8_t -pbuf_free(struct pbuf *p) -{ - u16_t type; - struct pbuf *q; - u8_t count; - - if (p == NULL) { - LWIP_ASSERT("p != NULL", p != NULL); - /* if assertions are disabled, proceed with debug output */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("pbuf_free(p == NULL) was called.\n")); - return 0; - } - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); - - PERF_START; - - LWIP_ASSERT("pbuf_free: sane type", - p->type == PBUF_RAM || p->type == PBUF_ROM || - p->type == PBUF_REF || p->type == PBUF_POOL); - - count = 0; - /* de-allocate all consecutive pbufs from the head of the chain that - * obtain a zero reference count after decrementing*/ - while (p != NULL) { - u16_t ref; - SYS_ARCH_DECL_PROTECT(old_level); - /* Since decrementing ref cannot be guaranteed to be a single machine operation - * we must protect it. We put the new ref into a local variable to prevent - * further protection. */ - SYS_ARCH_PROTECT(old_level); - /* all pbufs in a chain are referenced at least once */ - LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); - /* decrease reference count (number of pointers to pbuf) */ - ref = --(p->ref); - SYS_ARCH_UNPROTECT(old_level); - /* this pbuf is no longer referenced to? */ - if (ref == 0) { - /* remember next pbuf in chain for next iteration */ - q = p->next; - LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); - type = p->type; -#if LWIP_SUPPORT_CUSTOM_PBUF - /* is this a custom pbuf? */ - if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { - struct pbuf_custom *pc = (struct pbuf_custom*)p; - LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); - pc->custom_free_function(p); - } else -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - { - /* is this a pbuf from the pool? */ - if (type == PBUF_POOL) { - memp_free(MEMP_PBUF_POOL, p); - /* is this a ROM or RAM referencing pbuf? */ - } else if (type == PBUF_ROM || type == PBUF_REF) { - memp_free(MEMP_PBUF, p); - /* type == PBUF_RAM */ - } else { - mem_free(p); - } - } - count++; - /* proceed to next pbuf */ - p = q; - /* p->ref > 0, this pbuf is still referenced to */ - /* (and so the remaining pbufs in chain as well) */ - } else { - LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); - /* stop walking through the chain */ - p = NULL; - } - } - PERF_STOP("pbuf_free"); - /* return number of de-allocated pbufs */ - return count; -} - -/** - * Count number of pbufs in a chain - * - * @param p first pbuf of chain - * @return the number of pbufs in a chain - */ -u8_t -pbuf_clen(struct pbuf *p) -{ - u8_t len; - - len = 0; - while (p != NULL) { - ++len; - p = p->next; - } - return len; -} - -/** - * @ingroup pbuf - * Increment the reference count of the pbuf. - * - * @param p pbuf to increase reference counter of - * - */ -void -pbuf_ref(struct pbuf *p) -{ - SYS_ARCH_DECL_PROTECT(old_level); - /* pbuf given? */ - if (p != NULL) { - SYS_ARCH_PROTECT(old_level); - ++(p->ref); - SYS_ARCH_UNPROTECT(old_level); - } -} - -/** - * @ingroup pbuf - * Concatenate two pbufs (each may be a pbuf chain) and take over - * the caller's reference of the tail pbuf. - * - * @note The caller MAY NOT reference the tail pbuf afterwards. - * Use pbuf_chain() for that purpose. - * - * @see pbuf_chain() - */ -void -pbuf_cat(struct pbuf *h, struct pbuf *t) -{ - struct pbuf *p; - - LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", - ((h != NULL) && (t != NULL)), return;); - - /* proceed to last pbuf of chain */ - for (p = h; p->next != NULL; p = p->next) { - /* add total length of second chain to all totals of first chain */ - p->tot_len += t->tot_len; - } - /* { p is last pbuf of first h chain, p->next == NULL } */ - LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); - LWIP_ASSERT("p->next == NULL", p->next == NULL); - /* add total length of second chain to last pbuf total of first chain */ - p->tot_len += t->tot_len; - /* chain last pbuf of head (p) with first of tail (t) */ - p->next = t; - /* p->next now references t, but the caller will drop its reference to t, - * so netto there is no change to the reference count of t. - */ -} - -/** - * @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 = 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, struct pbuf *p_from) -{ - u16_t offset_to=0, offset_from=0, len; - - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", - (void*)p_to, (void*)p_from)); - - /* is the target big enough to hold the source? */ - LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && - (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); - - /* iterate through pbuf chain */ - do - { - /* 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(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) -{ - struct pbuf *p; - u16_t left; - u16_t buf_copy_len; - u16_t copied_total = 0; - - LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); - LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); - - left = 0; - - if ((buf == NULL) || (dataptr == NULL)) { - return 0; - } - - /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ - for (p = buf; len != 0 && p != NULL; p = p->next) { - if ((offset != 0) && (offset >= p->len)) { - /* don't copy from this buffer -> on to the next */ - offset -= p->len; - } else { - /* copy from this buffer. maybe only partially. */ - buf_copy_len = p->len - offset; - if (buf_copy_len > len) - buf_copy_len = len; - /* copy the necessary parts of the buffer */ - MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); - copied_total += buf_copy_len; - left += buf_copy_len; - len -= buf_copy_len; - offset = 0; - } - } - return copied_total; -} - -#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE -/** - * This method modifies a 'pbuf chain', so that its total length is - * smaller than 64K. The remainder of the original pbuf chain is stored - * in *rest. - * This function never creates new pbufs, but splits an existing chain - * in two parts. The tot_len of the modified packet queue will likely be - * smaller than 64K. - * 'packet queues' are not supported by this function. - * - * @param p the pbuf queue to be split - * @param rest pointer to store the remainder (after the first 64K) - */ -void pbuf_split_64k(struct pbuf *p, struct pbuf **rest) -{ - *rest = NULL; - if ((p != NULL) && (p->next != NULL)) { - u16_t tot_len_front = p->len; - struct pbuf *i = p; - struct pbuf *r = p->next; - - /* continue until the total length (summed up as u16_t) overflows */ - while ((r != NULL) && ((u16_t)(tot_len_front + r->len) > tot_len_front)) { - tot_len_front += r->len; - i = r; - r = r->next; - } - /* i now points to last packet of the first segment. Set next - pointer to NULL */ - i->next = NULL; - - if (r != NULL) { - /* Update the tot_len field in the first part */ - for (i = p; i != NULL; i = i->next) { - i->tot_len -= r->tot_len; - LWIP_ASSERT("tot_len/len mismatch in last pbuf", - (i->next != NULL) || (i->tot_len == i->len)); - } - if (p->flags & PBUF_FLAG_TCP_FIN) { - r->flags |= PBUF_FLAG_TCP_FIN; - } - - /* tot_len field in rest does not need modifications */ - /* reference counters do not need modifications */ - *rest = r; - } - } -} -#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - -/** - * @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) -{ - u16_t offset_left = in_offset; - struct pbuf* q = in; - - /* get the correct pbuf */ - while ((q != NULL) && (q->len <= offset_left)) { - offset_left -= q->len; - q = q->next; - } - if (out_offset != NULL) { - *out_offset = offset_left; - } - return q; -} - -/** - * @ingroup pbuf - * Copy application supplied data into a pbuf. - * This function can only be used to copy the equivalent of buf->tot_len data. - * - * @param buf pbuf to fill with data - * @param dataptr application supplied data buffer - * @param len length of the application supplied data buffer - * - * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough - */ -err_t -pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) -{ - struct pbuf *p; - u16_t buf_copy_len; - u16_t total_copy_len = len; - u16_t copied_total = 0; - - LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 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_MIN(q->len - target_offset, len); - MEMCPY(((u8_t*)q->payload) + target_offset, dataptr, first_copy_len); - remaining_len -= first_copy_len; - src_ptr += first_copy_len; - if (remaining_len > 0) { - return pbuf_take(q->next, src_ptr, remaining_len); - } - return ERR_OK; - } - return ERR_MEM; -} - -/** - * @ingroup pbuf - * Creates a single pbuf out of a queue of pbufs. - * - * @remark: Either the source pbuf 'p' is freed by this function or the original - * pbuf 'p' is returned, therefore the caller has to check the result! - * - * @param p the source pbuf - * @param layer pbuf_layer of the new pbuf - * - * @return a new, single pbuf (p->next is NULL) - * or the old pbuf if allocation fails - */ -struct pbuf* -pbuf_coalesce(struct pbuf *p, pbuf_layer layer) -{ - struct pbuf *q; - err_t err; - if (p->next == NULL) { - return p; - } - q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); - if (q == NULL) { - /* @todo: what do we do now? */ - return p; - } - err = pbuf_copy(q, p); - LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); - pbuf_free(p); - return q; -} - -#if LWIP_CHECKSUM_ON_COPY -/** - * Copies data into a single pbuf (*not* into a pbuf queue!) and updates - * the checksum while copying - * - * @param p the pbuf to copy data into - * @param start_offset offset of p->payload where to copy the data to - * @param dataptr data to copy into the pbuf - * @param len length of data to copy into the pbuf - * @param chksum pointer to the checksum which is updated - * @return ERR_OK if successful, another error if the data does not fit - * within the (first) pbuf (no pbuf queues!) - */ -err_t -pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, - u16_t len, u16_t *chksum) -{ - u32_t acc; - u16_t copy_chksum; - char *dst_ptr; - LWIP_ASSERT("p != NULL", p != NULL); - LWIP_ASSERT("dataptr != NULL", dataptr != NULL); - LWIP_ASSERT("chksum != NULL", chksum != NULL); - LWIP_ASSERT("len != 0", len != 0); - - if ((start_offset >= p->len) || (start_offset + len > p->len)) { - return ERR_ARG; - } - - dst_ptr = ((char*)p->payload) + start_offset; - copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); - if ((start_offset & 1) != 0) { - copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); - } - acc = *chksum; - acc += copy_chksum; - *chksum = FOLD_U32T(acc); - return ERR_OK; -} -#endif /* LWIP_CHECKSUM_ON_COPY */ - -/** - * @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(struct pbuf* p, u16_t offset) -{ - u16_t q_idx; - struct pbuf* q = pbuf_skip(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 0; -} - -/** - * @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(struct pbuf* p, u16_t offset, const void* s2, u16_t n) -{ - u16_t start = offset; - struct pbuf* q = p; - - /* get the correct pbuf */ - while ((q != NULL) && (q->len <= start)) { - start -= q->len; - q = q->next; - } - /* return requested data if pbuf is OK */ - if ((q != NULL) && (q->len > start)) { - u16_t i; - for (i = 0; i < n; i++) { - u8_t a = pbuf_get_at(q, start + i); - u8_t b = ((const u8_t*)s2)[i]; - if (a != b) { - return i+1; - } - } - return 0; - } - return 0xffff; -} - -/** - * @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(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset) -{ - u16_t i; - u16_t max = p->tot_len - mem_len; - if (p->tot_len >= mem_len + start_offset) { - for (i = start_offset; i <= max; i++) { - 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(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/ext/lwip/src/core/raw.c b/ext/lwip/src/core/raw.c deleted file mode 100644 index 90f2e30..0000000 --- a/ext/lwip/src/core/raw.c +++ /dev/null @@ -1,504 +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 - */ - -/* - * 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 raw_api RAW API - * @ingroup callbackstyle_api - * @verbinclude "rawapi.txt" - */ - -/** - * @defgroup raw_raw RAW - * @ingroup raw_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 raw_api - */ - -#include "lwip/opt.h" - -#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/raw.h" -#include "lwip/stats.h" -#include "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_match(struct raw_pcb *pcb, u8_t broadcast) -{ - LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ - -#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). - * - */ -u8_t -raw_input(struct pbuf *p, struct netif *inp) -{ - struct raw_pcb *pcb, *prev; - s16_t proto; - u8_t eaten = 0; - 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 ((eaten == 0) && (pcb != NULL)) { - if ((pcb->protocol == proto) && raw_input_match(pcb, broadcast)) { - /* receive callback function available? */ - if (pcb->recv != NULL) { -#ifndef LWIP_NOASSERT - void* old_payload = p->payload; -#endif - /* 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; - eaten = 1; - if (prev != NULL) { - /* move the pcb to the front of raw_pcbs so that is - found faster next time */ - prev->next = pcb->next; - pcb->next = raw_pcbs; - raw_pcbs = pcb; - } - } 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 eaten; -} - -/** - * @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 IP_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) -{ - if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) { - return ERR_VAL; - } - ip_addr_set_ipaddr(&pcb->local_ip, ipaddr); - return ERR_OK; -} - -/** - * @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) -{ - if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) { - return ERR_VAL; - } - ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr); - return ERR_OK; -} - -/** - * @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. - * - * @return non-zero if the packet was free()d, zero if the packet remains - * available for others. - */ -void -raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) -{ - /* remember recv() callback and user data */ - pcb->recv = recv; - pcb->recv_arg = recv_arg; -} - -/** - * @ingroup raw_raw - * Send the raw IP packet to the given address. Note that actually you cannot - * modify the IP headers (this is inconsistent with the receive callback where - * you actually get the IP headers), you can only specify the IP payload here. - * It requires some more changes in lwIP. (there will be a raw_send() function - * then.) - * - * @param pcb the raw pcb which to send - * @param p the IP payload to send - * @param ipaddr the destination address of the IP packet - * - */ -err_t -raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) -{ - err_t err; - struct netif *netif; - const ip_addr_t *src_ip; - struct pbuf *q; /* q will be sent down the stack */ - s16_t header_size; - const ip_addr_t *dst_ip = ipaddr; - - 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")); - - header_size = ( -#if LWIP_IPV4 && LWIP_IPV6 - IP_IS_V6(ipaddr) ? IP6_HLEN : IP_HLEN); -#elif LWIP_IPV4 - IP_HLEN); -#else - IP6_HLEN); -#endif - - /* not enough space to add an IP header to first pbuf in given p chain? */ - if (pbuf_header(p, header_size)) { - /* allocate header in new pbuf */ - q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); - /* new header pbuf could not be allocated? */ - if (q == NULL) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); - return ERR_MEM; - } - if (p->tot_len != 0) { - /* chain header q in front of given pbuf p */ - pbuf_chain(q, p); - } - /* { first pbuf q points to header pbuf } */ - LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); - } else { - /* first pbuf q equals given pbuf */ - q = p; - if (pbuf_header(q, -header_size)) { - LWIP_ASSERT("Can't restore header we just removed!", 0); - return ERR_MEM; - } - } - - netif = ip_route(&pcb->local_ip, dst_ip); - 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, dst_ip); - /* free any temporary header pbuf allocated by pbuf_header() */ - if (q != p) { - pbuf_free(q); - } - return ERR_RTE; - } - -#if IP_SOF_BROADCAST - if (IP_IS_V4(ipaddr)) - { - /* broadcast filter? */ - if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); - /* free any temporary header pbuf allocated by pbuf_header() */ - if (q != p) { - pbuf_free(q); - } - return ERR_VAL; - } - } -#endif /* IP_SOF_BROADCAST */ - - if (ip_addr_isany(&pcb->local_ip)) { - /* use outgoing network interface IP address as source address */ - src_ip = ip_netif_get_local_ip(netif, dst_ip); -#if LWIP_IPV6 - if (src_ip == NULL) { - if (q != p) { - pbuf_free(q); - } - return ERR_RTE; - } -#endif /* LWIP_IPV6 */ - } else { - /* use RAW PCB local IP address as source address */ - src_ip = &pcb->local_ip; - } - -#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 - - NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); - err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, pcb->protocol, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - - /* 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; - /* 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")); - - 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; - 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 IPADDR_TYPE_XX definitions. - * @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; - 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; -} - -#endif /* LWIP_RAW */ diff --git a/ext/lwip/src/core/stats.c b/ext/lwip/src/core/stats.c deleted file mode 100644 index e218d69..0000000 --- a/ext/lwip/src/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\t", 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: %"U32_F"\n\t", (u32_t)mem->avail)); - LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used)); - LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max)); - LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err)); -} - -#if MEMP_STATS -void -stats_display_memp(struct stats_mem *mem, int index) -{ - if (index < 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: %"U32_F"\n\t", (u32_t)sys->sem.used)); - LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max)); - LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err)); - LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used)); - LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max)); - LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err)); - LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); - LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max)); - LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err)); -} -#endif /* SYS_STATS */ - -void -stats_display(void) -{ - s16_t i; - - LINK_STATS_DISPLAY(); - ETHARP_STATS_DISPLAY(); - IPFRAG_STATS_DISPLAY(); - IP6_FRAG_STATS_DISPLAY(); - IP_STATS_DISPLAY(); - ND6_STATS_DISPLAY(); - IP6_STATS_DISPLAY(); - IGMP_STATS_DISPLAY(); - MLD6_STATS_DISPLAY(); - ICMP_STATS_DISPLAY(); - ICMP6_STATS_DISPLAY(); - UDP_STATS_DISPLAY(); - TCP_STATS_DISPLAY(); - MEM_STATS_DISPLAY(); - for (i = 0; i < MEMP_MAX; i++) { - MEMP_STATS_DISPLAY(i); - } - SYS_STATS_DISPLAY(); -} -#endif /* LWIP_STATS_DISPLAY */ - -#endif /* LWIP_STATS */ - diff --git a/ext/lwip/src/core/sys.c b/ext/lwip/src/core/sys.c deleted file mode 100644 index f177737..0000000 --- a/ext/lwip/src/core/sys.c +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file - * lwIP Operating System abstraction - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/opt.h" - -#include "lwip/sys.h" - -/* Most of the functions defined in sys.h must be implemented in the - * architecture-dependent file sys_arch.c */ - -#if !NO_SYS - -#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/ext/lwip/src/core/tcp.c b/ext/lwip/src/core/tcp.c deleted file mode 100644 index 3734828..0000000 --- a/ext/lwip/src/core/tcp.c +++ /dev/null @@ -1,2098 +0,0 @@ -/** - * @file - * Transmission Control Protocol for IP - * 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 - * - */ - -/** - * @defgroup tcp_raw TCP - * @ingroup raw_api - * Transmission Control Protocol for IP\n - * @see @ref raw_api and @ref netconn - * - * Common functions for the TCP implementation, such as functinos - * for manipulating the data structures and the TCP timer functions. TCP functions - * related to input and output is found in tcp_in.c and tcp_out.c respectively.\n - */ - -#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 - -#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) & ~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 - -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; -const u8_t tcp_backoff[13] = - { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; - /* Times per slowtmr hits */ -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); - -/** - * Initialize this module. - */ -void -tcp_init(void) -{ -#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) - tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); -#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ -} - -/** - * 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; - 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); - if ((pcb->flags & TF_BACKLOGPEND) == 0) { - if (pcb->listener != NULL) { - pcb->listener->accepts_pending++; - LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); - pcb->flags |= 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); - if ((pcb->flags & TF_BACKLOGPEND) != 0) { - if (pcb->listener != NULL) { - LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); - pcb->listener->accepts_pending--; - pcb->flags &= ~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) -{ - err_t err; - - 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->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); - if (pcb->state == ESTABLISHED) { - /* move to TIME_WAIT since we close actively */ - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); - } else { - /* CLOSE_WAIT: 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 { - memp_free(MEMP_TCP_PCB, pcb); - } - } - return ERR_OK; - } - } - - switch (pcb->state) { - case CLOSED: - /* Closing a pcb in the CLOSED state might seem erroneous, - * however, it is in this state once allocated and as yet unused - * and the user needs some way to free it should the need arise. - * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) - * or for a pcb that has been used and then entered the CLOSED state - * is erroneous, but this should never happen as the pcb has in those cases - * been freed, and so any remaining handles are bogus. */ - err = ERR_OK; - if (pcb->local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } - memp_free(MEMP_TCP_PCB, pcb); - pcb = NULL; - break; - case LISTEN: - err = ERR_OK; - tcp_listen_closed(pcb); - tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb); - memp_free(MEMP_TCP_PCB_LISTEN, pcb); - pcb = NULL; - break; - case SYN_SENT: - err = ERR_OK; - TCP_PCB_REMOVE_ACTIVE(pcb); - memp_free(MEMP_TCP_PCB, pcb); - pcb = NULL; - MIB2_STATS_INC(mib2.tcpattemptfails); - break; - 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. */ - err = ERR_OK; - pcb = NULL; - break; - } - - if (pcb != NULL && err == ERR_OK) { - /* To ensure all data has been sent when tcp_close returns, we have - to make sure tcp_output doesn't fail. - Since we don't really have to ensure all data has been sent when tcp_close - returns (unsent data is sent from tcp timer functions, also), we don't care - for the return value of tcp_output for now. */ - tcp_output(pcb); - } - 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). - * - * @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_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... */ - pcb->flags |= 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, - * the PCB should 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) -{ - if (pcb->state == LISTEN) { - return ERR_CONN; - } - if (shut_rx) { - /* shut down the receive side: set a flag not to receive any more data... */ - pcb->flags |= 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; - - /* pcb->state LISTEN not allowed here */ - LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs", - pcb->state != LISTEN); - /* Figure out on which TCP PCB list we are, and remove us. If we - are in an active state, call the receive function associated with - the PCB with a NULL argument, and send an RST to the remote end. */ - if (pcb->state == TIME_WAIT) { - tcp_pcb_remove(&tcp_tw_pcbs, pcb); - memp_free(MEMP_TCP_PCB, pcb); - } else { - int send_rst = 0; - u16_t local_port = 0; - 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(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port); - } - memp_free(MEMP_TCP_PCB, pcb); - TCP_EVENT_ERR(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 == NULL), the IP address of - * the outgoing network interface is used instead. - * - * @param pcb the tcp_pcb to bind (no check is done whether this pcb is - * already bound!) - * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind - * to any local address - * @param port the local port to bind to - * @return ERR_USE if the port is already in use - * ERR_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_IPV4 - /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ - if (ipaddr == NULL) { - ipaddr = IP_ADDR_ANY; - } -#endif /* LWIP_IPV4 */ - - /* still need to check for ipaddr == NULL in IPv6 only case */ - if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) { - return ERR_VAL; - } - - 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 (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)) { - 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; -} -#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); - - 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. - * - * @param pcb the original tcp_pcb - * @param backlog the incoming connections queue limit - * @return tcp_pcb used for listening, consumes less memory. - * - * @note The original tcp_pcb is freed. This function therefore has to be - * called like this: - * tpcb = tcp_listen(tpcb); - */ -struct tcp_pcb * -tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) -{ - struct tcp_pcb_listen *lpcb; - - LWIP_UNUSED_ARG(backlog); - LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL); - - /* already listening? */ - if (pcb->state == LISTEN) { - return pcb; - } -#if SO_REUSE - if (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 */ - return NULL; - } - } - } -#endif /* SO_REUSE */ - lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); - if (lpcb == NULL) { - return NULL; - } - lpcb->callback_arg = pcb->callback_arg; - lpcb->local_port = pcb->local_port; - lpcb->state = LISTEN; - lpcb->prio = pcb->prio; - lpcb->so_options = pcb->so_options; - lpcb->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); - } - memp_free(MEMP_TCP_PCB, pcb); -#if LWIP_CALLBACK_API - lpcb->accept = tcp_accept_null; -#endif /* LWIP_CALLBACK_API */ -#if TCP_LISTEN_BACKLOG - lpcb->accepts_pending = 0; - lpcb->backlog = backlog; -#endif /* TCP_LISTEN_BACKLOG */ - TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); - return (struct tcp_pcb *)lpcb; -} - -/** - * Update the state that tracks the available window space to advertise. - * - * Returns how much extra window would be advertised if we sent an - * update now. - */ -u32_t -tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) -{ - u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; - - if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { - /* we can advertise more window */ - pcb->rcv_ann_wnd = pcb->rcv_wnd; - return new_right_edge - pcb->rcv_ann_right_edge; - } else { - if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { - /* Can happen due to other end sending out of advertised window, - * but within actual available (but not yet advertised) window */ - pcb->rcv_ann_wnd = 0; - } else { - /* keep the right edge of window constant */ - u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; -#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) -{ - int wnd_inflation; - - /* pcb->state LISTEN not allowed here */ - LWIP_ASSERT("don't call tcp_recved for listen-pcbs", - pcb->state != LISTEN); - - pcb->rcv_wnd += len; - if (pcb->rcv_wnd > TCP_WND_MAX(pcb)) { - pcb->rcv_wnd = TCP_WND_MAX(pcb); - } else if (pcb->rcv_wnd == 0) { - /* rcv_wnd overflowed */ - if ((pcb->state == CLOSE_WAIT) || (pcb->state == LAST_ACK)) { - /* In passive close, we allow this, since the FIN bit is added to rcv_wnd - by the stack itself, since it is not mandatory for an application - to call tcp_recved() for the FIN bit, but e.g. the netconn API does so. */ - pcb->rcv_wnd = TCP_WND_MAX(pcb); - } else { - LWIP_ASSERT("tcp_recved: len wrapped rcv_wnd\n", 0); - } - } - - 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: - 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) { - 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. - * - * @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) -{ - err_t ret; - u32_t iss; - u16_t old_local_port; - - if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) { - return ERR_VAL; - } - - 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; - - /* check if we have a route to the remote host */ - if (ip_addr_isany(&pcb->local_ip)) { - /* no local IP address set, yet. */ - struct netif *netif; - const ip_addr_t *local_ip; - ip_route_get_local_ip(&pcb->local_ip, &pcb->remote_ip, netif, local_ip); - if ((netif == NULL) || (local_ip == NULL)) { - /* Don't even try to send a SYN packet if we have no route - since that will fail. */ - return ERR_RTE; - } - /* Use the address as local address of the pcb. */ - ip_addr_copy(pcb->local_ip, *local_ip); - } - - 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->rcv_nxt = 0; - pcb->snd_nxt = iss; - pcb->lastack = 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(pcb->mss, &pcb->local_ip, &pcb->remote_ip); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - pcb->cwnd = 1; - pcb->ssthresh = TCP_WND; -#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 */ - 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) { - /* If snd_wnd is zero, use persist timer to send 1 byte probes - * instead of using the standard retransmission mechanism. */ - 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) { - if (tcp_zero_window_probe(pcb) == ERR_OK) { - 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; - } - - if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { - /* Time for a retransmission. */ - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F - " pcb->rto %"S16_F"\n", - pcb->rtime, pcb->rto)); - - /* Double retransmission time-out unless we are trying to - * connect to somebody (i.e., we are in SYN_SENT). */ - if (pcb->state != SYN_SENT) { - pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; - } - - /* 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 = (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)); - - /* The following needs to be called AFTER cwnd is set to one - mss - STJ */ - tcp_rexmit_rto(pcb); - } - } - } - /* Check if this PCB has stayed too long in FIN-WAIT-2 */ - if (pcb->state == FIN_WAIT_2) { - /* If 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(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 && - (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) { - tcp_segs_free(pcb->ooseq); - pcb->ooseq = NULL; - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); - } -#endif /* TCP_QUEUE_OOSEQ */ - - /* Check if this PCB has stayed too long in SYN-RCVD */ - if (pcb->state == SYN_RCVD) { - if ((u32_t)(tcp_ticks - pcb->tmr) > - TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); - } - } - - /* Check if this PCB has stayed too long in LAST-ACK */ - if (pcb->state == LAST_ACK) { - if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); - } - } - - /* If the PCB should be removed, do it. */ - if (pcb_remove) { - struct tcp_pcb *pcb2; - tcp_err_fn err_fn; - void *err_arg; - tcp_pcb_purge(pcb); - /* Remove PCB from tcp_active_pcbs list. */ - if (prev != NULL) { - LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); - prev->next = pcb->next; - } else { - /* This PCB was the first. */ - LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); - tcp_active_pcbs = pcb->next; - } - - if (pcb_reset) { - tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); - } - - err_fn = pcb->errf; - err_arg = pcb->callback_arg; - pcb2 = pcb; - pcb = pcb->next; - memp_free(MEMP_TCP_PCB, pcb2); - - tcp_active_pcbs_changed = 0; - TCP_EVENT_ERR(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; - memp_free(MEMP_TCP_PCB, pcb2); - } else { - prev = pcb; - pcb = pcb->next; - } - } -} - -/** - * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously - * "refused" by upper layer (application) and sends delayed ACKs. - * - * Automatically called from tcp_tmr(). - */ -void -tcp_fasttmr(void) -{ - struct tcp_pcb *pcb; - - ++tcp_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); - pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - } - - 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; - 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); - } -} - -/** - * Sets the priority of a connection. - * - * @param pcb the tcp_pcb to manipulate - * @param prio new priority - */ -void -tcp_setprio(struct tcp_pcb *pcb, u8_t prio) -{ - pcb->prio = prio; -} - -#if TCP_QUEUE_OOSEQ -/** - * Returns a copy of the given TCP segment. - * The pbuf and data are not copied, only the pointers - * - * @param seg the old tcp_seg - * @return a copy of seg - */ -struct tcp_seg * -tcp_seg_copy(struct tcp_seg *seg) -{ - struct tcp_seg *cseg; - - cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); - if (cseg == NULL) { - return NULL; - } - SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); - pbuf_ref(cseg->p); - return cseg; -} -#endif /* TCP_QUEUE_OOSEQ */ - -#if LWIP_CALLBACK_API -/** - * Default receive callback that is called if the user didn't register - * a recv callback for the pcb. - */ -err_t -tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) -{ - LWIP_UNUSED_ARG(arg); - if (p != NULL) { - tcp_recved(pcb, p->tot_len); - pbuf_free(p); - } else if (err == ERR_OK) { - return tcp_close(pcb); - } - return ERR_OK; -} -#endif /* LWIP_CALLBACK_API */ - -/** - * Kills the oldest active connection that has the same or 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 kill the oldest active connection that has lower priority than prio. */ - inactivity = 0; - inactive = NULL; - for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->prio <= 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); - } -} - -/** - * 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; - u32_t iss; - - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); - if (pcb == NULL) { - /* Try killing oldest connection in TIME-WAIT. */ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); - tcp_kill_timewait(); - /* Try to allocate a tcp_pcb again. */ - pcb = (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 active connections with lower priority than the new one. */ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio)); - tcp_kill_prio(prio); - /* Try to allocate a tcp_pcb again. */ - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); - if (pcb != NULL) { - /* adjust err stats: memp_malloc failed 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; - iss = tcp_next_iss(); - pcb->snd_wl2 = iss; - pcb->snd_nxt = iss; - pcb->lastack = iss; - pcb->snd_lbb = iss; - pcb->tmr = tcp_ticks; - pcb->last_timer = tcp_timer_ctr; - -#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(). - * - * @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 IPADDR_TYPE_XX definitions. - * @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 - * Used to specify the argument that should be passed callback - * functions. - * - * @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) -{ - /* 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 - * Used to specify the function that should be called when a TCP - * connection receives data. - * - * @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) -{ - if (pcb != NULL) { - LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN); - pcb->recv = recv; - } -} - -/** - * @ingroup tcp_raw - * Used to specify the function that should be called when TCP data - * has been successfully delivered to the remote host. - * - * @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) -{ - 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. - * - * @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) -{ - 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) -{ - 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 - * Used to specify the function that should be called periodically - * from TCP. The interval is specified in terms of the TCP coarse - * timer interval, which is called twice a second. - * - */ -void -tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) -{ - 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) -{ - 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_segs_free(pcb->ooseq); - pcb->ooseq = NULL; -#endif /* TCP_QUEUE_OOSEQ */ - - /* Stop the retransmission timer as it will expect data on unacked - queue if it fires */ - pcb->rtime = -1; - - tcp_segs_free(pcb->unsent); - tcp_segs_free(pcb->unacked); - pcb->unacked = pcb->unsent = NULL; -#if TCP_OVERSIZE - pcb->unsent_oversize = 0; -#endif /* TCP_OVERSIZE */ - } -} - -/** - * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. - * - * @param pcblist PCB list to purge. - * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated! - */ -void -tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) -{ - TCP_RMV(pcblist, pcb); - - tcp_pcb_purge(pcb); - - /* if there is an outstanding delayed ACKs, send it */ - if (pcb->state != TIME_WAIT && - pcb->state != LISTEN && - pcb->flags & TF_ACK_DELAY) { - pcb->flags |= TF_ACK_NOW; - tcp_output(pcb); - } - - if (pcb->state != LISTEN) { - LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); - LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); -#if TCP_QUEUE_OOSEQ - LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); -#endif /* TCP_QUEUE_OOSEQ */ - } - - pcb->state = CLOSED; - /* 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(void) -{ - static u32_t iss = 6510; - - iss += tcp_ticks; /* XXX */ - return iss; -} - -#if TCP_CALCULATE_EFF_SEND_MSS -/** - * Calculates the effective send mss that can be used for a specific IP address - * by using ip_route to determine the netif used to send to the address and - * calculating the minimum of TCP_MSS and that netif's mtu (if set). - */ -u16_t -tcp_eff_send_mss_impl(u16_t sendmss, const ip_addr_t *dest -#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING - , const ip_addr_t *src -#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ - ) -{ - u16_t mss_s; - struct netif *outif; - s16_t mtu; - - outif = ip_route(src, dest); -#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) { -#if LWIP_IPV6 -#if LWIP_IPV4 - if (IP_IS_V6(dest)) -#endif /* LWIP_IPV4 */ - { - mss_s = mtu - IP6_HLEN - TCP_HLEN; - } -#if LWIP_IPV4 - else -#endif /* LWIP_IPV4 */ -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 - { - mss_s = mtu - IP_HLEN - TCP_HLEN; - } -#endif /* LWIP_IPV4 */ - /* RFC 1122, chap 4.2.2.6: - * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize - * We correct for TCP options in tcp_write(), and don't support IP options. - */ - sendmss = LWIP_MIN(sendmss, mss_s); - } - return sendmss; -} -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - -#if LWIP_IPV4 -/** Helper function for tcp_netif_ipv4_addr_changed() that iterates a pcb list */ -static void -tcp_netif_ipv4_addr_changed_pcblist(const ip4_addr_t* old_addr, struct tcp_pcb* pcb_list) -{ - struct tcp_pcb *pcb; - pcb = pcb_list; - while (pcb != NULL) { - /* PCB bound to current local interface address? */ - if (IP_IS_V4_VAL(pcb->local_ip) && ip4_addr_cmp(ip_2_ip4(&pcb->local_ip), old_addr) -#if LWIP_AUTOIP - /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ - && !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 IPv4 address of the netif before change - * @param new_addr IPv4 address of the netif after change or NULL if netif has been removed - */ -void -tcp_netif_ipv4_addr_changed(const ip4_addr_t* old_addr, const ip4_addr_t* new_addr) -{ - struct tcp_pcb_listen *lpcb, *next; - - tcp_netif_ipv4_addr_changed_pcblist(old_addr, tcp_active_pcbs); - tcp_netif_ipv4_addr_changed_pcblist(old_addr, tcp_bound_pcbs); - - if (!ip4_addr_isany(new_addr)) { - /* PCB bound to current local interface address? */ - for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = next) { - next = lpcb->next; - /* Is this an IPv4 pcb? */ - if (IP_IS_V4_VAL(lpcb->local_ip)) { - /* PCB bound to current local interface address? */ - if ((!(ip4_addr_isany(ip_2_ip4(&lpcb->local_ip)))) && - (ip4_addr_cmp(ip_2_ip4(&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_from_ip4(lpcb->local_ip, *new_addr); - } - } - } - } -} -#endif /* LWIP_IPV4 */ - -const char* -tcp_debug_state_str(enum tcp_state s) -{ - return tcp_state_str[s]; -} - -#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG -/** - * Print a tcp header for debugging purposes. - * - * @param tcphdr pointer to a struct tcp_hdr - */ -void -tcp_debug_print(struct tcp_hdr *tcphdr) -{ - LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", - ntohs(tcphdr->src), ntohs(tcphdr->dest))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", - ntohl(tcphdr->seqno))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", - ntohl(tcphdr->ackno))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", - TCPH_HDRLEN(tcphdr), - (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), - ntohs(tcphdr->wnd))); - tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); - LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", - ntohs(tcphdr->chksum), ntohs(tcphdr->urgp))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); -} - -/** - * Print a tcp state for debugging purposes. - * - * @param s enum tcp_state to print - */ -void -tcp_debug_print_state(enum tcp_state s) -{ - LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s])); -} - -/** - * Print tcp flags for debugging purposes. - * - * @param flags tcp flags, all active flags are printed - */ -void -tcp_debug_print_flags(u8_t flags) -{ - if (flags & TCP_FIN) { - LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); - } - if (flags & TCP_SYN) { - LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); - } - if (flags & TCP_RST) { - LWIP_DEBUGF(TCP_DEBUG, ("RST ")); - } - if (flags & TCP_PSH) { - LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); - } - if (flags & TCP_ACK) { - LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); - } - if (flags & TCP_URG) { - LWIP_DEBUGF(TCP_DEBUG, ("URG ")); - } - if (flags & TCP_ECE) { - LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); - } - if (flags & TCP_CWR) { - LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); - } - LWIP_DEBUGF(TCP_DEBUG, ("\n")); -} - -/** - * Print all tcp_pcbs in every list for debugging purposes. - */ -void -tcp_debug_print_pcbs(void) -{ - struct tcp_pcb *pcb; - 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 */ - -#endif /* LWIP_TCP */ diff --git a/ext/lwip/src/core/tcp_in.c b/ext/lwip/src/core/tcp_in.c deleted file mode 100644 index 80e47ba..0000000 --- a/ext/lwip/src/core/tcp_in.c +++ /dev/null @@ -1,1816 +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" -#include "lwip/inet_chksum.h" -#if LWIP_ND6_TCP_REACHABILITY_HINTS -#include "lwip/nd6.h" -#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ - -/** Initial CWND calculation as defined RFC 2581 */ -#define LWIP_TCP_CALC_INITIAL_CWND(mss) LWIP_MIN((4U * (mss)), LWIP_MAX((2U * (mss)), 4380U)); -/** Initial slow start threshold value: we use the full window */ -#define LWIP_TCP_INITIAL_SSTHRESH(pcb) ((pcb)->snd_wnd) - -/* 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); - -/** - * 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); - - 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(tcphdr) * 4; - 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 = hdrlen_bytes - TCP_HLEN; - tcphdr_opt2 = NULL; - if (p->len >= hdrlen_bytes) { - /* all options are in the first pbuf */ - tcphdr_opt1len = tcphdr_optlen; - pbuf_header(p, -(s16_t)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_header(p, -TCP_HLEN); - - /* determine how long the first and second parts of the options are */ - tcphdr_opt1len = p->len; - opt2len = 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_header(p, -(s16_t)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_header(p->next, -(s16_t)opt2len); - 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 = ntohs(tcphdr->src); - tcphdr->dest = ntohs(tcphdr->dest); - seqno = tcphdr->seqno = ntohl(tcphdr->seqno); - ackno = tcphdr->ackno = ntohl(tcphdr->ackno); - tcphdr->wnd = ntohs(tcphdr->wnd); - - flags = TCPH_FLAGS(tcphdr); - tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0); - - /* Demultiplex an incoming segment. First, we check if it is destined - for an active connection. */ - prev = NULL; - - for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); - LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); - LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); - if (pcb->remote_port == tcphdr->src && - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&pcb->remote_ip, 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); - 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")); - 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 (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")); - 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 */ - - - 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 */ - 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->errf, pcb->callback_arg, ERR_RST); - tcp_pcb_remove(&tcp_active_pcbs, pcb); - memp_free(MEMP_TCP_PCB, pcb); - } else { - err = ERR_OK; - /* If the application has registered a "sent" function to be - called when new send buffer space is available, we call it - now. */ - if (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 (recv_flags & TF_CLOSED) { - /* The connection has been closed and we will deallocate the - PCB. */ - if (!(pcb->flags & TF_RXCLOSED)) { - /* Connection closed although the application has only shut down the - tx side: call the PCB's err callback and indicate the closure to - ensure the application doesn't continue using the PCB. */ - TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_CLSD); - } - tcp_pcb_remove(&tcp_active_pcbs, pcb); - memp_free(MEMP_TCP_PCB, pcb); - 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; - /* 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(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 by tcp_input() when a segment arrives for a listening - * connection (from tcp_input()). - * - * @param pcb the tcp_pcb_listen for which a segment arrived - * @return ERR_OK if the segment was processed - * another err_t on error - * - * @note the return value is not (yet?) used in tcp_input() - * @note the segment which arrived is saved in global variables, therefore only the pcb - * involved is passed as a parameter to this function - */ -static void -tcp_listen_input(struct tcp_pcb_listen *pcb) -{ - struct tcp_pcb *npcb; - err_t rc; - - if (flags & TCP_RST) { - /* An incoming RST should be ignored. Return. */ - return; - } - - /* In the LISTEN state, we check for incoming SYN segments, - creates a new PCB, and responds with a SYN|ACK. */ - if (flags & TCP_ACK) { - /* For incoming segments with the ACK flag set, respond with a - RST. */ - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); - tcp_rst(ackno, 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++; - npcb->flags |= 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; - npcb->remote_port = tcphdr->src; - npcb->state = SYN_RCVD; - npcb->rcv_nxt = seqno + 1; - npcb->rcv_ann_right_edge = npcb->rcv_nxt; - 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; - /* 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 = SND_WND_SCALE(npcb, tcphdr->wnd); - npcb->snd_wnd_max = npcb->snd_wnd; - npcb->ssthresh = LWIP_TCP_INITIAL_SSTHRESH(npcb); - -#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); - - /* 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; - } - /* - 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(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 */ - pcb->flags |= TF_ACK_NOW; - 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; - - /* 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 only send an ACK - and wait for a re-send with matching sequence number. - This violates RFC 793, but is required to protection against - CVE-2004-0230 (RST spoofing attack). */ - 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; - pcb->flags &= ~TF_ACK_DELAY; - return ERR_RST; - } else { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", - seqno, pcb->rcv_nxt)); - LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", - seqno, pcb->rcv_nxt)); - return ERR_OK; - } - } - - if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { - /* Cope with new connection attempt after remote end crashed */ - tcp_ack_now(pcb); - return ERR_OK; - } - - if ((pcb->flags & TF_RXCLOSED) == 0) { - /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ - pcb->tmr = tcp_ticks; - } - pcb->keep_cnt_sent = 0; - - tcp_parseopt(pcb); - - /* Do different things depending on the TCP state. */ - switch (pcb->state) { - case SYN_SENT: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, - pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno))); - /* received SYN ACK with expected sequence number? */ - if ((flags & TCP_ACK) && (flags & TCP_SYN) - && (ackno == pcb->lastack + 1)) { - pcb->rcv_nxt = seqno + 1; - pcb->rcv_ann_right_edge = pcb->rcv_nxt; - pcb->lastack = ackno; - pcb->snd_wnd = SND_WND_SCALE(pcb, 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 */ - - /* Set ssthresh again after changing 'mss' and 'snd_wnd' */ - pcb->ssthresh = LWIP_TCP_INITIAL_SSTHRESH(pcb); - - 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(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 */ - 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 - LWIP_ASSERT("pcb->listener->accept != NULL", - (pcb->listener == NULL) || (pcb->listener->accept != NULL)); - if (pcb->listener == NULL) { - /* listen pcb might be closed by now */ - err = ERR_VAL; - } else -#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); - - /* passive open: update initial ssthresh now that the correct window is - known: if the remote side supports window scaling, the window sent - with the initial SYN can be smaller than the one used later */ - pcb->ssthresh = LWIP_TCP_INITIAL_SSTHRESH(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(ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } - } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { - /* Looks like another copy of the SYN - retransmit our SYN-ACK */ - tcp_rexmit(pcb); - } - break; - case CLOSE_WAIT: - /* FALLTHROUGH */ - case ESTABLISHED: - tcp_receive(pcb); - if (recv_flags & TF_GOT_FIN) { /* passive close */ - tcp_ack_now(pcb); - pcb->state = CLOSE_WAIT; - } - break; - case FIN_WAIT_1: - tcp_receive(pcb); - if (recv_flags & TF_GOT_FIN) { - if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { - LWIP_DEBUGF(TCP_DEBUG, - ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_ack_now(pcb); - tcp_pcb_purge(pcb); - TCP_RMV_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->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) { - 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) { - 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; - - if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { - /* received segment overlaps all following segments */ - tcp_segs_free(next); - next = NULL; - } else { - /* delete some following segments - oos queue may have segments with FIN flag */ - while (next && - TCP_SEQ_GEQ((seqno + cseg->len), - (next->tcphdr->seqno + next->len))) { - /* cseg with FIN already processed */ - if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { - TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); - } - old_seg = next; - next = next->next; - tcp_seg_free(old_seg); - } - if (next && - TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { - /* We need to trim the incoming segment. */ - cseg->len = (u16_t)(next->tcphdr->seqno - seqno); - pbuf_realloc(cseg->p, cseg->len); - } - } - cseg->next = next; -} -#endif /* TCP_QUEUE_OOSEQ */ - -/** - * Called by tcp_process. Checks if the given segment is an ACK for outstanding - * data, and if so frees the memory of the buffered data. Next, 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) -{ - struct tcp_seg *next; -#if TCP_QUEUE_OOSEQ - struct tcp_seg *prev, *cseg; -#endif /* TCP_QUEUE_OOSEQ */ - struct pbuf *p; - s32_t off; - s16_t m; - u32_t right_wnd_edge; - u16_t new_tot_len; - int found_dupack = 0; -#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS - u32_t ooseq_blen; - u16_t ooseq_qlen; -#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ - - 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; - if (pcb->snd_wnd == 0) { - if (pcb->persist_backoff == 0) { - /* start persist timer */ - pcb->persist_cnt = 0; - pcb->persist_backoff = 1; - } - } else if (pcb->persist_backoff > 0) { - /* stop persist timer */ - pcb->persist_backoff = 0; - } - 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, but not if it means that - the value overflows. */ - if ((tcpwnd_size_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { - pcb->cwnd += pcb->mss; - } - } else if (pcb->dupacks == 3) { - /* Do fast retransmit */ - tcp_rexmit_fast(pcb); - } - } - } - } - } - /* If Clause (1) or more is true, but not a duplicate ack, reset - * count of consecutive duplicate acks */ - if (!found_dupack) { - pcb->dupacks = 0; - } - } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { - /* We come here when the ACK acknowledges new data. */ - - /* 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) { - pcb->flags &= ~TF_INFR; - pcb->cwnd = pcb->ssthresh; - } - - /* Reset the number of retransmissions. */ - pcb->nrtx = 0; - - /* Reset the retransmission time-out. */ - pcb->rto = (pcb->sa >> 3) + pcb->sv; - - /* Reset the fast retransmit variables. */ - pcb->dupacks = 0; - pcb->lastack = ackno; - - /* Update the congestion control variables (cwnd and - ssthresh). */ - if (pcb->state >= ESTABLISHED) { - if (pcb->cwnd < pcb->ssthresh) { - if ((tcpwnd_size_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { - pcb->cwnd += pcb->mss; - } - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); - } else { - tcpwnd_size_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd); - if (new_cwnd > pcb->cwnd) { - pcb->cwnd = new_cwnd; - } - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"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? - ntohl(pcb->unacked->tcphdr->seqno): 0, - pcb->unacked != NULL? - ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); - - /* Remove segment from the unacknowledged list if the incoming - ACK acknowledges them. */ - while (pcb->unacked != NULL && - TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + - TCP_TCPLEN(pcb->unacked), ackno)) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", - ntohl(pcb->unacked->tcphdr->seqno), - ntohl(pcb->unacked->tcphdr->seqno) + - TCP_TCPLEN(pcb->unacked))); - - next = pcb->unacked; - pcb->unacked = pcb->unacked->next; - - 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 >= pbuf_clen(next->p))); - - pcb->snd_queuelen -= pbuf_clen(next->p); - recv_acked += next->len; - tcp_seg_free(next); - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing unacked)\n", (tcpwnd_size_t)pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || - pcb->unsent != NULL); - } - } - - /* If there's nothing left to acknowledge, stop the retransmit - timer, otherwise reset it to start again */ - if (pcb->unacked == NULL) { - pcb->rtime = -1; - } else { - pcb->rtime = 0; - } - - pcb->polltmr = 0; - -#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 { - /* Out of sequence ACK, didn't really ack anything */ - tcp_send_empty_ack(pcb); - } - - /* 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. */ - while (pcb->unsent != NULL && - TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + - TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", - ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + - TCP_TCPLEN(pcb->unsent))); - - next = pcb->unsent; - pcb->unsent = pcb->unsent->next; -#if TCP_OVERSIZE - if (pcb->unsent == NULL) { - pcb->unsent_oversize = 0; - } -#endif /* TCP_OVERSIZE */ - 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 >= pbuf_clen(next->p))); - /* Prevent ACK for FIN to generate a sent event */ - pcb->snd_queuelen -= pbuf_clen(next->p); - recv_acked += next->len; - tcp_seg_free(next); - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing unsent)\n", (tcpwnd_size_t)pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_receive: valid queue length", - pcb->unacked != NULL || pcb->unsent != NULL); - } - } - pcb->snd_buf += recv_acked; - /* End of ACK for new data processing. */ - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", - pcb->rttest, pcb->rtseq, ackno)); - - /* RTT estimation calculations. This is done by checking if the - incoming segment acknowledges the segment we use to take a - round-trip time measurement. */ - if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { - /* 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 = m - (pcb->sa >> 3); - pcb->sa += m; - if (m < 0) { - m = -m; - } - m = m - (pcb->sv >> 2); - pcb->sv += m; - pcb->rto = (pcb->sa >> 3) + pcb->sv; - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", - pcb->rto, (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.*/ - - off = pcb->rcv_nxt - seqno; - p = inseg.p; - LWIP_ASSERT("inseg.p != NULL", inseg.p); - LWIP_ASSERT("insane offset!", (off < 0x7fff)); - if (inseg.p->len < off) { - LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); - new_tot_len = (u16_t)(inseg.p->tot_len - off); - while (p->len < off) { - off -= p->len; - /* KJM following line changed (with addition of new_tot_len var) - to fix bug #9076 - inseg.p->tot_len -= p->len; */ - p->tot_len = new_tot_len; - p->len = 0; - p = p->next; - } - if (pbuf_header(p, (s16_t)-off)) { - /* Do we need to cope with this failing? Assert for now */ - LWIP_ASSERT("pbuf_header failed", 0); - } - } else { - if (pbuf_header(inseg.p, (s16_t)-off)) { - /* Do we need to cope with this failing? Assert for now */ - LWIP_ASSERT("pbuf_header failed", 0); - } - } - inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); - inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; - } - else { - if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)) { - /* 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 { - next = pcb->ooseq; - /* Remove all segments on ooseq that are covered by inseg already. - * FIN is copied from ooseq to inseg if present. */ - while (next && - TCP_SEQ_GEQ(seqno + tcplen, - next->tcphdr->seqno + next->len)) { - /* inseg cannot have FIN here (already processed above) */ - if (TCPH_FLAGS(next->tcphdr) & TCP_FIN && - (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { - TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); - tcplen = TCP_TCPLEN(&inseg); - } - prev = next; - next = next->next; - tcp_seg_free(prev); - } - /* Now trim right side of inseg if it overlaps with the first - * segment on ooseq */ - if (next && - TCP_SEQ_GT(seqno + tcplen, - next->tcphdr->seqno)) { - /* inseg cannot have FIN here (already processed above) */ - inseg.len = (u16_t)(next->tcphdr->seqno - seqno); - if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { - inseg.len -= 1; - } - pbuf_realloc(inseg.p, inseg.len); - tcplen = TCP_TCPLEN(&inseg); - LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", - (seqno + tcplen) == next->tcphdr->seqno); - } - pcb->ooseq = next; - } - } -#endif /* TCP_QUEUE_OOSEQ */ - - pcb->rcv_nxt = seqno + tcplen; - - /* Update the receiver's (our) window. */ - LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); - pcb->rcv_wnd -= tcplen; - - tcp_update_rcv_ann_wnd(pcb); - - /* If there is data in the segment, we make preparations to - pass this up to the application. The ->recv_data variable - is used for holding the pbuf that goes to the - application. The code for reassembling out-of-sequence data - chains its data on this pbuf as well. - - If the segment was a FIN, we set the TF_GOT_FIN flag that will - be used to indicate to the application that the remote side has - closed its end of the connection. */ - if (inseg.p->tot_len > 0) { - recv_data = inseg.p; - /* Since this pbuf now is the responsibility of the - application, we delete our reference to it so that we won't - (mistakingly) deallocate it. */ - inseg.p = NULL; - } - if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); - recv_flags |= TF_GOT_FIN; - } - -#if TCP_QUEUE_OOSEQ - /* We now check if we have segments on the ->ooseq queue that - are now in sequence. */ - while (pcb->ooseq != NULL && - pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { - - cseg = pcb->ooseq; - seqno = pcb->ooseq->tcphdr->seqno; - - pcb->rcv_nxt += TCP_TCPLEN(cseg); - LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", - pcb->rcv_wnd >= TCP_TCPLEN(cseg)); - pcb->rcv_wnd -= TCP_TCPLEN(cseg); - - tcp_update_rcv_ann_wnd(pcb); - - if (cseg->p->tot_len > 0) { - /* Chain this pbuf onto the pbuf that we will pass to - the application. */ - /* 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); - } -#endif /* TCP_QUEUE_OOSEQ */ - - - /* Acknowledge the segment(s). */ - tcp_ack(pcb); - -#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. */ - tcp_send_empty_ack(pcb); -#if TCP_QUEUE_OOSEQ - /* We queue the segment on the ->ooseq queue. */ - if (pcb->ooseq == NULL) { - pcb->ooseq = tcp_seg_copy(&inseg); - } else { - /* If the queue is not empty, we walk through the queue and - try to find a place where the sequence number of the - incoming segment is between the sequence numbers of the - previous and the next segment on the ->ooseq queue. That is - the place where we put the incoming segment. If needed, we - trim the second edges of the previous and the incoming - segment so that it will fit into the sequence. - - If the incoming segment has the same sequence number as a - segment on the ->ooseq queue, we discard the segment that - contains less data. */ - - prev = NULL; - for (next = pcb->ooseq; next != NULL; next = next->next) { - if (seqno == next->tcphdr->seqno) { - /* The sequence number of the incoming segment is the - same as the sequence number of the segment on - ->ooseq. We check the lengths to see which one to - discard. */ - if (inseg.len > next->len) { - /* The incoming segment is larger than the old - segment. We replace some segments with the new - one. */ - cseg = tcp_seg_copy(&inseg); - 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. */ - cseg = tcp_seg_copy(&inseg); - if (cseg != NULL) { - pcb->ooseq = cseg; - tcp_oos_insert_segment(cseg, next); - } - break; - } - } else { - /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && - TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ - if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) { - /* The sequence number of the incoming segment is in - between the sequence numbers of the previous and - the next segment on ->ooseq. We trim trim the previous - segment, delete next segments that included in received segment - and trim received, if needed. */ - cseg = tcp_seg_copy(&inseg); - if (cseg != NULL) { - if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { - /* We need to trim the prev segment. */ - prev->len = (u16_t)(seqno - prev->tcphdr->seqno); - pbuf_realloc(prev->p, prev->len); - } - prev->next = cseg; - tcp_oos_insert_segment(cseg, next); - } - break; - } - } - /* If the "next" segment is the last segment on the - ooseq queue, we add the incoming segment to the end - of the list. */ - if (next->next == NULL && - TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { - if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { - /* segment "next" already contains all data */ - break; - } - next->next = tcp_seg_copy(&inseg); - if (next->next != NULL) { - if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { - /* We need to trim the last segment. */ - next->len = (u16_t)(seqno - next->tcphdr->seqno); - pbuf_realloc(next->p, next->len); - } - /* check if the remote side overruns our receive window */ - if (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; - } - } - prev = next; - } - } -#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS - /* Check that the data on ooseq doesn't exceed one of the limits - and throw away everything above that limit. */ - ooseq_blen = 0; - ooseq_qlen = 0; - prev = NULL; - for (next = pcb->ooseq; next != NULL; prev = next, next = next->next) { - struct pbuf *p = next->p; - ooseq_blen += p->tot_len; - ooseq_qlen += pbuf_clen(p); - if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) || - (ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) { - /* 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_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ -#endif /* TCP_QUEUE_OOSEQ */ - } - } 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_getoptbyte(void) -{ - if ((tcphdr_opt2 == NULL) || (tcp_optidx < tcphdr_opt1len)) { - u8_t* opts = (u8_t *)tcphdr + TCP_HLEN; - return opts[tcp_optidx++]; - } else { - u8_t idx = (u8_t)(tcp_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 - - /* Parse the TCP MSS option, if present. */ - if (tcphdr_optlen != 0) { - for (tcp_optidx = 0; tcp_optidx < tcphdr_optlen; ) { - u8_t opt = tcp_getoptbyte(); - 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_getoptbyte() != 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 = (tcp_getoptbyte() << 8); - mss |= tcp_getoptbyte(); - /* 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_getoptbyte() != 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; - } - /* 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)) { - /* An WND_SCALE option with the right option length. */ - data = tcp_getoptbyte(); - pcb->snd_scale = data; - if (pcb->snd_scale > 14U) { - pcb->snd_scale = 14U; - } - pcb->rcv_scale = TCP_RCV_SCALE; - pcb->flags |= 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 -#if LWIP_TCP_TIMESTAMPS - case LWIP_TCP_OPT_TS: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); - if (tcp_getoptbyte() != 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_getoptbyte(); - tsval |= (tcp_getoptbyte() << 8); - tsval |= (tcp_getoptbyte() << 16); - tsval |= (tcp_getoptbyte() << 24); - if (flags & TCP_SYN) { - pcb->ts_recent = ntohl(tsval); - /* Enable sending timestamps in every segment now that we know - the remote host supports it. */ - pcb->flags |= TF_TIMESTAMP; - } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) { - pcb->ts_recent = ntohl(tsval); - } - /* Advance to next option (6 bytes already read) */ - tcp_optidx += LWIP_TCP_OPT_LEN_TS - 6; - break; -#endif - default: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); - data = tcp_getoptbyte(); - 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; -} - -#endif /* LWIP_TCP */ diff --git a/ext/lwip/src/core/tcp_out.c b/ext/lwip/src/core/tcp_out.c deleted file mode 100644 index 3028979..0000000 --- a/ext/lwip/src/core/tcp_out.c +++ /dev/null @@ -1,1608 +0,0 @@ -/** - * @file - * Transmission Control Protocol, outgoing traffic - * - * The output functions of TCP. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/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" -#include "lwip/inet_chksum.h" -#if LWIP_TCP_TIMESTAMPS -#include "lwip/sys.h" -#endif - -#include - -/* 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); - -/** 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 tcp_hdr *tcphdr; - struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM); - if (p != NULL) { - LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", - (p->len >= TCP_HLEN + optlen)); - tcphdr = (struct tcp_hdr *)p->payload; - tcphdr->src = htons(pcb->local_port); - tcphdr->dest = htons(pcb->remote_port); - tcphdr->seqno = seqno_be; - tcphdr->ackno = htonl(pcb->rcv_nxt); - TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK); - tcphdr->wnd = htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd))); - tcphdr->chksum = 0; - tcphdr->urgp = 0; - - /* If we're sending a packet, update the announced right window edge */ - pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; - } - return p; -} - -/** - * Called by tcp_close() to send a segment including FIN flag but not data. - * - * @param pcb the tcp_pcb over which to send a segment - * @return ERR_OK if sent, another err_t otherwise - */ -err_t -tcp_send_fin(struct tcp_pcb *pcb) -{ - /* first, try to add the fin to the last unsent segment */ - if (pcb->unsent != NULL) { - struct tcp_seg *last_unsent; - for (last_unsent = pcb->unsent; last_unsent->next != NULL; - last_unsent = last_unsent->next); - - if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { - /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ - TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN); - pcb->flags |= TF_FIN; - return ERR_OK; - } - } - /* no data, no length, flags, copy=1, no optdata */ - return tcp_enqueue_flags(pcb, TCP_FIN); -} - -/** - * Create a TCP segment with prefilled header. - * - * Called by tcp_write and tcp_enqueue_flags. - * - * @param pcb Protocol control block for the TCP connection. - * @param p pbuf that is used to hold the TCP header. - * @param flags TCP flags for header. - * @param seqno TCP sequence number of this packet - * @param optflags options to include in TCP header - * @return a new tcp_seg pointing to p, or NULL. - * The TCP header is filled in except ackno and wnd. - * p is freed on failure. - */ -static struct tcp_seg * -tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags) -{ - struct tcp_seg *seg; - u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags); - - if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 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_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 = htons(pcb->local_port); - seg->tcphdr->dest = htons(pcb->remote_port); - seg->tcphdr->seqno = htonl(seqno); - /* ackno is set in tcp_output */ - TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags); - /* wnd and chksum are set in tcp_output */ - seg->tcphdr->urgp = 0; - return seg; -} - -/** - * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end. - * - * This function is like pbuf_alloc(layer, length, PBUF_RAM) except - * there may be extra bytes available at the end. - * - * @param layer flag to define header size. - * @param length size of the pbuf's payload. - * @param max_length maximum usable size of payload+oversize. - * @param oversize pointer to a u16_t that will receive the number of usable tail bytes. - * @param pcb The TCP connection that willo enqueue the pbuf. - * @param apiflags API flags given to tcp_write. - * @param first_seg true when this pbuf will be used in the first enqueued segment. - */ -#if TCP_OVERSIZE -static struct pbuf * -tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, - u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags, - u8_t first_seg) -{ - struct pbuf *p; - u16_t alloc = length; - -#if LWIP_NETIF_TX_SINGLE_PBUF - LWIP_UNUSED_ARG(max_length); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(apiflags); - LWIP_UNUSED_ARG(first_seg); - /* always create MSS-sized pbufs */ - alloc = 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 */ -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) -{ - /* 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)); - pcb->flags |= 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 >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { - 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); - pcb->flags |= TF_NAGLEMEMERR; - return ERR_MEM; - } - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty", - pcb->unacked != NULL || pcb->unsent != NULL); - } else { - LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty", - pcb->unacked == NULL && pcb->unsent == NULL); - } - return ERR_OK; -} - -/** - * Write data for sending (but does not send it immediately). - * - * It waits in the expectation of more data being sent soon (as - * it can send them more efficiently by combining them together). - * To prompt the system to send data now, call tcp_output() after - * calling tcp_write(). - * - * @param pcb Protocol control block for the TCP connection to enqueue data for. - * @param arg Pointer to the data to be enqueued for sending. - * @param len Data length in bytes - * @param apiflags combination of following flags : - * - 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 = 0; - u8_t optflags = 0; -#if TCP_OVERSIZE - u16_t oversize = 0; - u16_t oversize_used = 0; -#endif /* TCP_OVERSIZE */ -#if TCP_CHECKSUM_ON_COPY - u16_t concat_chksum = 0; - u8_t concat_chksum_swapped = 0; - u16_t concat_chksummed = 0; -#endif /* TCP_CHECKSUM_ON_COPY */ - err_t err; - /* don't allocate segments bigger than half the maximum window we ever received */ - u16_t mss_local = LWIP_MIN(pcb->mss, TCPWND_MIN16(pcb->snd_wnd_max/2)); - mss_local = mss_local ? mss_local : pcb->mss; - -#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(TF_SEG_OPTS_TS); - /* ensure that segments can hold at least one data byte... */ - mss_local = LWIP_MAX(mss_local, LWIP_TCP_OPT_LEN_TS + 1); - } -#endif /* LWIP_TCP_TIMESTAMPS */ - - - /* - * TCP segmentation is done in three phases with increasing complexity: - * - * 1. Copy data directly into an oversized pbuf. - * 2. Chain a new pbuf to the end of pcb->unsent. - * 3. Create new segments. - * - * We may run out of memory at any point. In that case we must - * return ERR_MEM and not change anything in pcb. Therefore, all - * changes are recorded in local variables and committed at the end - * of the function. Some pcb fields are maintained in local copies: - * - * queuelen = pcb->snd_queuelen - * oversize = pcb->unsent_oversize - * - * These variables are set consistently by the phases: - * - * seg points to the last segment tampered with. - * - * pos records progress as data is segmented. - */ - - /* Find the tail of the unsent queue. */ - if (pcb->unsent != NULL) { - u16_t space; - u16_t unsent_optlen; - - /* @todo: this could be sped up by keeping last_unsent in the pcb */ - for (last_unsent = pcb->unsent; last_unsent->next != NULL; - last_unsent = last_unsent->next); - - /* Usable space at the end of the last unsent segment */ - unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags); - 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->unsent_oversize */ - LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)", - pcb->unsent_oversize == last_unsent->oversize_left); -#endif /* TCP_OVERSIZE_DBGCHECK */ - oversize = pcb->unsent_oversize; - if (oversize > 0) { - LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space); - seg = last_unsent; - oversize_used = 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("inconsistend oversize vs. len", (oversize == 0) || (pos == len)); -#endif /* TCP_OVERSIZE */ - - /* - * Phase 2: Chain a new pbuf to the end of pcb->unsent. - * - * We don't extend segments containing SYN/FIN flags or options - * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at - * the end. - */ - if ((pos < len) && (space > 0) && (last_unsent->len > 0)) { - u16_t seglen = space < len - pos ? space : len - pos; - seg = last_unsent; - - /* Create a pbuf with a copy or reference to seglen bytes. We - * can use PBUF_RAW here since the data appears in the middle of - * a segment. A header will never be prepended. */ - if (apiflags & TCP_WRITE_FLAG_COPY) { - /* Data is copied */ - if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", - seglen)); - goto memerr; - } -#if TCP_OVERSIZE_DBGCHECK - last_unsent->oversize_left += oversize; -#endif /* TCP_OVERSIZE_DBGCHECK */ - TCP_DATA_COPY2(concat_p->payload, (const u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped); -#if TCP_CHECKSUM_ON_COPY - concat_chksummed += seglen; -#endif /* TCP_CHECKSUM_ON_COPY */ - } else { - /* Data is not copied */ - if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 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 */ - 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 */ - /* reference the non-volatile payload data */ - ((struct pbuf_rom*)concat_p)->payload = (const u8_t*)arg + pos; - } - - pos += seglen; - queuelen += pbuf_clen(concat_p); - } - } else { -#if TCP_OVERSIZE - LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)", - pcb->unsent_oversize == 0); -#endif /* TCP_OVERSIZE */ - } - - /* - * Phase 3: Create new segments. - * - * The new segments are chained together in the local 'queue' - * variable, ready to be appended to pcb->unsent. - */ - while (pos < len) { - struct pbuf *p; - u16_t left = len - pos; - u16_t max_len = mss_local - optlen; - u16_t seglen = left > max_len ? max_len : left; -#if TCP_CHECKSUM_ON_COPY - u16_t chksum = 0; - u8_t chksum_swapped = 0; -#endif /* TCP_CHECKSUM_ON_COPY */ - - if (apiflags & TCP_WRITE_FLAG_COPY) { - /* If copy is set, memory should be allocated and data copied - * into pbuf */ - if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, 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 > TCP_SND_QUEUELEN) || (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", - ntohl(seg->tcphdr->seqno), - ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); - - pos += seglen; - } - - /* - * All three segmentation phases were successful. We can commit the - * transaction. - */ - - /* - * Phase 1: If data has been added to the preallocated tail of - * last_unsent, we update the length fields of the pbuf chain. - */ -#if TCP_OVERSIZE - if (oversize_used > 0) { - struct pbuf *p; - /* Bump tot_len of whole chain, len of tail */ - for (p = last_unsent->p; p; p = p->next) { - p->tot_len += oversize_used; - if (p->next == NULL) { - TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent); - p->len += oversize_used; - } - } - last_unsent->len += oversize_used; -#if TCP_OVERSIZE_DBGCHECK - 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 - */ - if (concat_p != NULL) { - LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty", - (last_unsent != NULL)); - pbuf_cat(last_unsent->p, concat_p); - last_unsent->len += concat_p->tot_len; -#if TCP_CHECKSUM_ON_COPY - if (concat_chksummed) { - /*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: - pcb->flags |= TF_NAGLEMEMERR; - TCP_STATS_INC(tcp.memerr); - - if (concat_p != NULL) { - pbuf_free(concat_p); - } - if (queue != NULL) { - tcp_segs_free(queue); - } - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || - pcb->unsent != NULL); - } - LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); - return ERR_MEM; -} - -/** - * Enqueue TCP options for transmission. - * - * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl(). - * - * @param pcb Protocol control block for the TCP connection. - * @param flags TCP header flags to set in the outgoing segment. - */ -err_t -tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) -{ - struct pbuf *p; - struct tcp_seg *seg; - u8_t optflags = 0; - u8_t optlen = 0; - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); - - LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)", - (flags & (TCP_SYN | TCP_FIN)) != 0); - - /* check for configured max queuelen and possible overflow (FIN flag should always come through!) */ - if (((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) && - ((flags & TCP_FIN) == 0)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n", - pcb->snd_queuelen, (u16_t)TCP_SND_QUEUELEN)); - TCP_STATS_INC(tcp.memerr); - pcb->flags |= TF_NAGLEMEMERR; - return ERR_MEM; - } - - if (flags & TCP_SYN) { - optflags = TF_SEG_OPTS_MSS; -#if LWIP_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_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; - } -#endif /* LWIP_TCP_TIMESTAMPS */ - optlen = LWIP_TCP_OPT_LENGTH(optflags); - - /* Allocate pbuf with room for TCP header + options */ - if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { - pcb->flags |= TF_NAGLEMEMERR; - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen", - (p->len >= optlen)); - - /* Allocate memory for tcp_seg, and fill in fields. */ - if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) { - pcb->flags |= TF_NAGLEMEMERR; - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % 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", - ntohl(seg->tcphdr->seqno), - ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), - (u16_t)flags)); - - /* Now append seg to pcb->unsent queue */ - if (pcb->unsent == NULL) { - pcb->unsent = seg; - } else { - struct tcp_seg *useg; - for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); - useg->next = seg; - } -#if TCP_OVERSIZE - /* The new unsent tail has no space */ - pcb->unsent_oversize = 0; -#endif /* TCP_OVERSIZE */ - - /* SYN and FIN bump the sequence number */ - if ((flags & TCP_SYN) || (flags & TCP_FIN)) { - pcb->snd_lbb++; - /* optlen does not influence snd_buf */ - } - if (flags & TCP_FIN) { - pcb->flags |= TF_FIN; - } - - /* update number of segments on the queues */ - pcb->snd_queuelen += pbuf_clen(seg->p); - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_enqueue_flags: invalid queue length", - pcb->unacked != NULL || pcb->unsent != NULL); - } - - return ERR_OK; -} - -#if LWIP_TCP_TIMESTAMPS -/* Build a timestamp option (12 bytes long) at the specified options pointer) - * - * @param pcb tcp_pcb - * @param opts option pointer where to store the timestamp option - */ -static void -tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts) -{ - /* Pad with two NOP options to make everything nicely aligned */ - opts[0] = PP_HTONL(0x0101080A); - opts[1] = htonl(sys_now()); - opts[2] = htonl(pcb->ts_recent); -} -#endif - -#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) -{ - /* Pad with one NOP option to make everything nicely aligned */ - opts[0] = PP_HTONL(0x01030300 | TCP_RCV_SCALE); -} -#endif - -/** Send an ACK without data. - * - * @param pcb Protocol control block for the TCP connection to send the ACK - */ -err_t -tcp_send_empty_ack(struct tcp_pcb *pcb) -{ - err_t err; - struct pbuf *p; - u8_t optlen = 0; - struct netif *netif; -#if LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP - struct tcp_hdr *tcphdr; -#endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */ - -#if LWIP_TCP_TIMESTAMPS - if (pcb->flags & TF_TIMESTAMP) { - optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); - } -#endif - - p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt)); - if (p == NULL) { - /* let tcp_fasttmr retry sending this ACK */ - pcb->flags |= (TF_ACK_DELAY | TF_ACK_NOW); - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); - return ERR_BUF; - } -#if LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP - tcphdr = (struct tcp_hdr *)p->payload; -#endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */ - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, - ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); - - /* NB. MSS and window scale options are only sent on SYNs, so ignore them here */ -#if LWIP_TCP_TIMESTAMPS - pcb->ts_lastacksent = pcb->rcv_nxt; - - if (pcb->flags & TF_TIMESTAMP) { - tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1)); - } -#endif - - netif = ip_route(&pcb->local_ip, &pcb->remote_ip); - if (netif == NULL) { - err = ERR_RTE; - } else { -#if CHECKSUM_GEN_TCP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - &pcb->local_ip, &pcb->remote_ip); - } -#endif - NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); - err = ip_output_if(p, &pcb->local_ip, &pcb->remote_ip, - pcb->ttl, pcb->tos, IP_PROTO_TCP, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - } - pbuf_free(p); - - if (err != ERR_OK) { - /* let tcp_fasttmr retry sending this ACK */ - pcb->flags |= (TF_ACK_DELAY | TF_ACK_NOW); - } else { - /* remove ACK flags from the PCB, as we sent an empty ACK now */ - pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - } - - return err; -} - -/** - * 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 */ - - /* 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 the TF_ACK_NOW flag is set and no data will be sent (either - * because the ->unsent queue is empty or because the window does - * not allow it), construct an empty ACK segment and send it. - * - * If data is to be sent, we will just piggyback the ACK (see below). - */ - if (pcb->flags & TF_ACK_NOW && - (seg == NULL || - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { - return tcp_send_empty_ack(pcb); - } - - /* useg should point to last segment on unacked queue */ - useg = pcb->unacked; - if (useg != NULL) { - for (; useg->next != NULL; useg = useg->next); - } - - netif = ip_route(&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); - } - -#if TCP_OUTPUT_DEBUG - if (seg == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", - (void*)pcb->unsent)); - } -#endif /* TCP_OUTPUT_DEBUG */ -#if TCP_CWND_DEBUG - if (seg == NULL) { - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F - ", cwnd %"TCPWNDSIZE_F", wnd %"U32_F - ", seg == NULL, ack %"U32_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); - } else { - LWIP_DEBUGF(TCP_CWND_DEBUG, - ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F - ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, - ntohl(seg->tcphdr->seqno), pcb->lastack)); - } -#endif /* TCP_CWND_DEBUG */ - /* data available and window allows it to be sent? */ - while (seg != NULL && - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { - LWIP_ASSERT("RST not expected here!", - (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); - /* Stop sending if the nagle algorithm would prevent it - * Don't stop: - * - if tcp_write had a memory error before (prevent delayed ACK timeout) or - * - if FIN was already enqueued for this PCB (SYN is always alone in a segment - - * either seg->next != NULL or pcb->unacked == NULL; - * RST is no sent using tcp_write/tcp_output. - */ - if ((tcp_do_output_nagle(pcb) == 0) && - ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) { - break; - } -#if TCP_CWND_DEBUG - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"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, - ntohl(seg->tcphdr->seqno) + seg->len - - pcb->lastack, - ntohl(seg->tcphdr->seqno), pcb->lastack, i)); - ++i; -#endif /* TCP_CWND_DEBUG */ - - if (pcb->state != SYN_SENT) { - TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); - } - -#if TCP_OVERSIZE_DBGCHECK - seg->oversize_left = 0; -#endif /* TCP_OVERSIZE_DBGCHECK */ - err = tcp_output_segment(seg, pcb, netif); - if (err != ERR_OK) { - /* segment could not be sent, for whatever reason */ - pcb->flags |= TF_NAGLEMEMERR; - return err; - } - pcb->unsent = seg->next; - if (pcb->state != SYN_SENT) { - pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - } - snd_nxt = 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(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) { - /* add segment to before tail of unacked list, keeping the list sorted */ - struct tcp_seg **cur_seg = &(pcb->unacked); - while (*cur_seg && - TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { - cur_seg = &((*cur_seg)->next ); - } - seg->next = (*cur_seg); - (*cur_seg) = seg; - } else { - /* add segment to tail of unacked list */ - useg->next = seg; - useg = useg->next; - } - } - /* do not queue empty segments on the unacked list */ - } else { - 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 */ - - pcb->flags &= ~TF_NAGLEMEMERR; - return ERR_OK; -} - -/** - * Called by tcp_output() to actually send a TCP segment over IP. - * - * @param seg the tcp_seg to send - * @param pcb the tcp_pcb for the TCP connection used to send the segment - * @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 (seg->p->ref != 1) { - /* This can happen if the pbuf of this segment is still referenced by the - netif driver due to deferred transmission. Since this function modifies - p->len, we must not continue in this case. */ - return ERR_OK; - } - - /* The TCP header has already been constructed, but the ackno and - wnd fields remain. */ - seg->tcphdr->ackno = htonl(pcb->rcv_nxt); - - /* advertise our receive window size in this TCP segment */ -#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 = htons(TCPWND_MIN16(pcb->rcv_ann_wnd)); - } else -#endif /* LWIP_WND_SCALE */ - { - seg->tcphdr->wnd = 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(TCP_MSS, &pcb->local_ip, &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 - - /* 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 = ntohl(seg->tcphdr->seqno); - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq)); - } - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n", - htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) + - seg->len)); - - len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); - 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; -#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(seg->tcphdr) * 4)); - } - - /* 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(seg->tcphdr) * 4, &pcb->local_ip, &pcb->remote_ip); - /* add payload checksum */ - if (seg->chksum_swapped) { - seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); - seg->chksum_swapped = 0; - } - acc += (u16_t)~(seg->chksum); - seg->tcphdr->chksum = FOLD_U32T(acc); -#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK - if (chksum_slow != seg->tcphdr->chksum) { - 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_HWADDRHINT(netif, &(pcb->addr_hint)); - err = ip_output_if(seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, - pcb->tos, IP_PROTO_TCP, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - 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 seqno the sequence number to use for the outgoing segment - * @param ackno the acknowledge number to use for the outgoing segment - * @param local_ip the local IP address to send the segment from - * @param remote_ip the remote IP address to send the segment to - * @param local_port the local TCP port to send the segment from - * @param remote_port the remote TCP port to send the segment to - */ -void -tcp_rst(u32_t seqno, u32_t ackno, - const ip_addr_t *local_ip, const ip_addr_t *remote_ip, - u16_t local_port, u16_t remote_port) -{ - struct pbuf *p; - struct tcp_hdr *tcphdr; - struct netif *netif; - p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); - if (p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); - return; - } - LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", - (p->len >= sizeof(struct tcp_hdr))); - - tcphdr = (struct tcp_hdr *)p->payload; - tcphdr->src = htons(local_port); - tcphdr->dest = htons(remote_port); - tcphdr->seqno = htonl(seqno); - tcphdr->ackno = htonl(ackno); - TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK); -#if LWIP_WND_SCALE - tcphdr->wnd = PP_HTONS(((TCP_WND >> TCP_RCV_SCALE) & 0xFFFF)); -#else - tcphdr->wnd = PP_HTONS(TCP_WND); -#endif - tcphdr->chksum = 0; - tcphdr->urgp = 0; - - TCP_STATS_INC(tcp.xmit); - MIB2_STATS_INC(mib2.tcpoutrsts); - - netif = ip_route(local_ip, remote_ip); - if (netif != NULL) { -#if CHECKSUM_GEN_TCP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - local_ip, remote_ip); - } -#endif - /* Send output with hardcoded TTL/HL since we have no access to the pcb */ - ip_output_if(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP, netif); - } - pbuf_free(p); - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); -} - -/** - * Requeue all unacked segments for retransmission - * - * Called by tcp_slowtmr() for slow retransmission. - * - * @param pcb the tcp_pcb for which to re-enqueue all unacked segments - */ -void -tcp_rexmit_rto(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg; - - if (pcb->unacked == NULL) { - return; - } - - /* Move all unacked segments to the head of the unsent queue */ - for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); - /* concatenate unsent queue after unacked queue */ - seg->next = pcb->unsent; -#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; - - /* increment number of retransmissions */ - ++pcb->nrtx; - - /* Don't take any RTT measurements after retransmitting. */ - pcb->rttest = 0; - - /* Do the actual retransmission */ - tcp_output(pcb); -} - -/** - * Requeue the first unacked segment for retransmission - * - * Called by tcp_receive() for fast retramsmit. - * - * @param pcb the tcp_pcb for which to retransmit the first unacked segment - */ -void -tcp_rexmit(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg; - struct tcp_seg **cur_seg; - - if (pcb->unacked == NULL) { - return; - } - - /* Move the first unacked segment to the unsent queue */ - /* Keep the unsent queue sorted. */ - seg = pcb->unacked; - pcb->unacked = seg->next; - - cur_seg = &(pcb->unsent); - while (*cur_seg && - TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { - cur_seg = &((*cur_seg)->next ); - } - seg->next = *cur_seg; - *cur_seg = seg; -#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 */ - - ++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. */ -} - - -/** - * Handle retransmission after three dupacks received - * - * @param pcb the tcp_pcb for which to retransmit the first unacked segment - */ -void -tcp_rexmit_fast(struct tcp_pcb *pcb) -{ - if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) { - /* This is fast retransmit. Retransmit the first unacked segment. */ - LWIP_DEBUGF(TCP_FR_DEBUG, - ("tcp_receive: dupacks %"U16_F" (%"U32_F - "), fast retransmit %"U32_F"\n", - (u16_t)pcb->dupacks, pcb->lastack, - ntohl(pcb->unacked->tcphdr->seqno))); - tcp_rexmit(pcb); - - /* Set ssthresh to half of the minimum of the current - * cwnd and the advertised window */ - if (pcb->cwnd > pcb->snd_wnd) { - pcb->ssthresh = pcb->snd_wnd / 2; - } else { - pcb->ssthresh = pcb->cwnd / 2; - } - - /* The minimum value for ssthresh should be 2 MSS */ - if (pcb->ssthresh < (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; - pcb->flags |= TF_INFR; - - /* Reset the retransmission timer to prevent immediate rto retransmissions */ - pcb->rtime = 0; - } -} - - -/** - * 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; - struct netif *netif; - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to ")); - ip_addr_debug_print(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, 0, 0, htonl(pcb->snd_nxt - 1)); - if (p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, - ("tcp_keepalive: could not allocate memory for pbuf\n")); - return ERR_MEM; - } - netif = ip_route(&pcb->local_ip, &pcb->remote_ip); - if (netif == NULL) { - err = ERR_RTE; - } else { -#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, - &pcb->local_ip, &pcb->remote_ip); - } -#endif /* CHECKSUM_GEN_TCP */ - TCP_STATS_INC(tcp.xmit); - - /* Send output to IP */ - NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); - err = ip_output_if(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - } - pbuf_free(p); - - 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; - struct netif *netif; - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to ")); - ip_addr_debug_print(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)); - - seg = pcb->unacked; - - if (seg == NULL) { - seg = pcb->unsent; - } - if (seg == NULL) { - /* nothing to send, zero window probe not needed */ - return ERR_OK; - } - - is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0); - /* we want to send one seqno: either FIN or data (no options) */ - len = is_fin ? 0 : 1; - - p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno); - if (p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); - return 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); - } - - netif = ip_route(&pcb->local_ip, &pcb->remote_ip); - if (netif == NULL) { - err = ERR_RTE; - } else { -#if CHECKSUM_GEN_TCP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - &pcb->local_ip, &pcb->remote_ip); - } -#endif - TCP_STATS_INC(tcp.xmit); - - /* Send output to IP */ - NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); - err = ip_output_if(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, - 0, IP_PROTO_TCP, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - } - - pbuf_free(p); - - 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/ext/lwip/src/core/timeouts.c b/ext/lwip/src/core/timeouts.c deleted file mode 100644 index fcba0a1..0000000 --- a/ext/lwip/src/core/timeouts.c +++ /dev/null @@ -1,435 +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/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 */ - -/** 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 */ -#endif /* LWIP_IPV6 */ -}; - -#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM - -/** The one and only timeout list */ -static struct sys_timeo *next_timeout; -static u32_t timeouts_last_time; - -#if LWIP_TCP -/** global variable that shows if the tcp timer is currently scheduled or not */ -static int tcpip_tcp_timer_active; - -/** - * Timer callback function that calls tcp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -tcpip_tcp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - - /* call TCP timer handler */ - tcp_tmr(); - /* timer still needed? */ - if (tcp_active_pcbs || tcp_tw_pcbs) { - /* restart timer */ - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); - } else { - /* disable timer */ - tcpip_tcp_timer_active = 0; - } -} - -/** - * Called from TCP_REG when registering a new PCB: - * the reason is to have the TCP timer only running when - * there are active (or time-wait) PCBs. - */ -void -tcp_timer_needed(void) -{ - /* timer is off but needed again? */ - if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { - /* enable and start timer */ - tcpip_tcp_timer_active = 1; - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); - } -} -#endif /* LWIP_TCP */ - -/** - * Timer callback function that calls mld6_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -cyclic_timer(void *arg) -{ - 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(); - sys_timeout(cyclic->interval_ms, cyclic_timer, arg); -} - -/** Initialize this module */ -void sys_timeouts_init(void) -{ - size_t i; - /* tcp_tmr() at index 0 is started on demand */ - for (i = 1; 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, cyclic_timer, (void*)(size_t)&lwip_cyclic_timers[i]); - } - - /* Initialise timestamp for sys_check_timeouts */ - timeouts_last_time = sys_now(); -} - -/** - * Create a one-shot timer (aka timeout). Timeouts are processed in the - * following cases: - * - while waiting for a message using sys_timeouts_mbox_fetch() - * - by calling sys_check_timeouts() (NO_SYS==1 only) - * - * @param msecs time in milliseconds after that the timer should expire - * @param handler callback function to call when msecs have elapsed - * @param arg argument to pass to the callback function - */ -#if LWIP_DEBUG_TIMERNAMES -void -sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) -#else /* LWIP_DEBUG_TIMERNAMES */ -void -sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) -#endif /* LWIP_DEBUG_TIMERNAMES */ -{ - struct sys_timeo *timeout, *t; - u32_t now, diff; - - 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; - } - - now = sys_now(); - if (next_timeout == NULL) { - diff = 0; - timeouts_last_time = now; - } else { - diff = now - timeouts_last_time; - } - - timeout->next = NULL; - timeout->h = handler; - timeout->arg = arg; - timeout->time = msecs + diff; -#if LWIP_DEBUG_TIMERNAMES - timeout->handler_name = handler_name; - LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", - (void *)timeout, msecs, handler_name, (void *)arg)); -#endif /* LWIP_DEBUG_TIMERNAMES */ - - if (next_timeout == NULL) { - next_timeout = timeout; - return; - } - - if (next_timeout->time > msecs) { - next_timeout->time -= msecs; - timeout->next = next_timeout; - next_timeout = timeout; - } else { - for (t = next_timeout; t != NULL; t = t->next) { - timeout->time -= t->time; - if (t->next == NULL || t->next->time > timeout->time) { - if (t->next != NULL) { - t->next->time -= timeout->time; - } else if (timeout->time > msecs) { - /* If this is the case, 'timeouts_last_time' and 'now' differs too much. - This can be due to sys_check_timeouts() not being called at the right - times, but also when stopping in a breakpoint. Anyway, let's assume - this is not wanted, so add the first timer's time instead of 'diff' */ - timeout->time = msecs + next_timeout->time; - } - timeout->next = t->next; - t->next = timeout; - break; - } - } - } -} - -/** - * 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; - - if (next_timeout == NULL) { - return; - } - - for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { - if ((t->h == handler) && (t->arg == arg)) { - /* We have a match */ - /* Unlink from previous in list */ - if (prev_t == NULL) { - next_timeout = t->next; - } else { - prev_t->next = t->next; - } - /* If not the last one, add time of this one back to next */ - if (t->next != NULL) { - t->next->time += t->time; - } - memp_free(MEMP_SYS_TIMEOUT, t); - return; - } - } - return; -} - -/** - * @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. - */ -#if !NO_SYS && !defined __DOXYGEN__ -static -#endif /* !NO_SYS */ -void -sys_check_timeouts(void) -{ - if (next_timeout) { - struct sys_timeo *tmptimeout; - u32_t diff; - sys_timeout_handler handler; - void *arg; - u8_t had_one; - u32_t now; - - now = sys_now(); - /* this cares for wraparounds */ - diff = now - timeouts_last_time; - do { - PBUF_CHECK_FREE_OOSEQ(); - had_one = 0; - tmptimeout = next_timeout; - if (tmptimeout && (tmptimeout->time <= diff)) { - /* timeout has expired */ - had_one = 1; - timeouts_last_time += tmptimeout->time; - diff -= tmptimeout->time; - next_timeout = tmptimeout->next; - handler = tmptimeout->h; - arg = tmptimeout->arg; -#if LWIP_DEBUG_TIMERNAMES - if (handler != NULL) { - LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n", - tmptimeout->handler_name, arg)); - } -#endif /* LWIP_DEBUG_TIMERNAMES */ - memp_free(MEMP_SYS_TIMEOUT, tmptimeout); - if (handler != NULL) { -#if !NO_SYS - /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the - timeout handler function. */ - LOCK_TCPIP_CORE(); -#endif /* !NO_SYS */ - handler(arg); -#if !NO_SYS - UNLOCK_TCPIP_CORE(); -#endif /* !NO_SYS */ - } - LWIP_TCPIP_THREAD_ALIVE(); - } - /* repeat until all expired timers have been called */ - } while (had_one); - } -} - -#if NO_SYS -/** Set back the timestamp of the last call to sys_check_timeouts() - * This is necessary if sys_check_timeouts() hasn't been called for a long - * time (e.g. while saving energy) to prevent all timer functions of that - * period being called. - */ -void -sys_restart_timeouts(void) -{ - timeouts_last_time = sys_now(); -} -#endif /* NO_SYS */ - -/** Return the time left before the next timeout is due. If no timeouts are - * enqueued, returns 0xffffffff - */ -#if !NO_SYS -static -#endif /* !NO_SYS */ -u32_t -sys_timeouts_sleeptime(void) -{ - u32_t diff; - if (next_timeout == NULL) { - return 0xffffffff; - } - diff = sys_now() - timeouts_last_time; - if (diff > next_timeout->time) { - return 0; - } else { - return next_timeout->time - diff; - } -} - -#if !NO_SYS - -/** - * Wait (forever) for a message to arrive in an mbox. - * While waiting, timeouts are processed. - * - * @param mbox the mbox to fetch the message from - * @param msg the place to store the message - */ -void -sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) -{ - u32_t sleeptime; - -again: - if (!next_timeout) { - sys_arch_mbox_fetch(mbox, msg, 0); - return; - } - - sleeptime = sys_timeouts_sleeptime(); - if (sleeptime == 0 || sys_arch_mbox_fetch(mbox, msg, sleeptime) == SYS_ARCH_TIMEOUT) { - /* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred - before a message could be fetched. */ - sys_check_timeouts(); - /* We try again to fetch a message from the mbox. */ - goto again; - } -} - -#endif /* NO_SYS */ - -#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/ext/lwip/src/core/udp.c b/ext/lwip/src/core/udp.c deleted file mode 100644 index 14130ab..0000000 --- a/ext/lwip/src/core/udp.c +++ /dev/null @@ -1,1223 +0,0 @@ -/** - * @file - * User Datagram Protocol module\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 - * - */ - -/** - * @defgroup udp_raw UDP - * @ingroup raw_api - * User Datagram Protocol module\n - * @see @ref raw_api and @ref netconn - */ - -/* udp.c - * - * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828). - * - */ - -/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'! - */ - -#include "lwip/opt.h" - -#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/udp.h" -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/inet_chksum.h" -#include "lwip/ip_addr.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/inet_chksum.h" -#include "lwip/netif.h" -#include "lwip/icmp.h" -#include "lwip/icmp6.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "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) & ~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) -{ -#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) - udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); -#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(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; -#if 0 - struct udp_pcb *ipcb = udp_pcbs; - while ((ipcb != NULL) && (udp_port != UDP_LOCAL_PORT_RANGE_END)) { - if (ipcb->local_port == udp_port) { - /* port is already used by another udp_pcb */ - udp_port++; - /* restart scanning all udp pcbs */ - ipcb = udp_pcbs; - } else { - /* go on with next udp pcb */ - ipcb = ipcb->next; - } - } - if (ipcb != NULL) { - return 0; - } - return udp_port; -#endif -} - -/** 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 */ - - /* 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, multicast or exact match */ - if (ip_addr_isany(&pcb->local_ip) || -#if LWIP_IPV6_MLD - (ip_current_is_v6() && ip6_addr_ismulticast(ip6_current_dest_addr())) || -#endif /* LWIP_IPV6_MLD */ -#if LWIP_IGMP - (!ip_current_is_v6() && ip4_addr_ismulticast(ip4_current_dest_addr())) || -#endif /* LWIP_IGMP */ - 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); - - 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 = ntohs(udphdr->src); - dest = ntohs(udphdr->dest); - - udp_debug_print(udphdr); - - /* print the UDP source and destination */ - LWIP_DEBUGF(UDP_DEBUG, ("udp (")); - ip_addr_debug_print(UDP_DEBUG, ip_current_dest_addr()); - LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest))); - ip_addr_debug_print(UDP_DEBUG, ip_current_src_addr()); - LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", 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) { - /* print the PCB local and remote address */ - LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); - ip_addr_debug_print(UDP_DEBUG, &pcb->local_ip); - LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); - ip_addr_debug_print(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) && - ((uncon_pcb == NULL) -#if SO_REUSE - /* prefer specific IPs over cath-all */ - || !ip_addr_isany(&pcb->local_ip) -#endif /* SO_REUSE */ - )) { - /* the first unconnected matching PCB */ - uncon_pcb = pcb; - } - - /* 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, CHECKSUM_CHECK_UDP) { -#if LWIP_UDPLITE - if (ip_current_header_proto() == IP_PROTO_UDPLITE) { - /* Do the UDP Lite checksum */ - u16_t chklen = ntohs(udphdr->len); - if (chklen < sizeof(struct udp_hdr)) { - if (chklen == 0) { - /* 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_header(p, -UDP_HLEN)) { - /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_header failed\n", 0); - UDP_STATS_INC(udp.drop); - 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; - u8_t p_header_changed = 0; - s16_t hdrs_len = (s16_t)(ip_current_header_tot_len() + UDP_HLEN); - for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { - if (mpcb != pcb) { - /* compare PCB local addr+port to UDP destination addr+port */ - if ((mpcb->local_port == dest) && - (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; - /* for that, move payload to IP header again */ - if (p_header_changed == 0) { - pbuf_header_force(p, hdrs_len); - p_header_changed = 1; - } - q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if (q != NULL) { - err_t err = pbuf_copy(q, p); - if (err == ERR_OK) { - /* move payload to UDP data */ - pbuf_header(q, -hdrs_len); - mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); - } - } - } - } - } - } - if (p_header_changed) { - /* and move payload to UDP data again */ - pbuf_header(p, -hdrs_len); - } - } -#endif /* SO_REUSE && SO_REUSE_RXTOALL */ - /* callback */ - if (pcb->recv != NULL) { - /* now the recv function is responsible for freeing p */ - pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); - } else { - /* no recv function registered? then we have to free the pbuf! */ - pbuf_free(p); - goto end; - } - } else { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); - -#if LWIP_ICMP || 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, 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 - * Send data using UDP. - * - * @param pcb UDP PCB used to send the data. - * @param p chain of pbuf's to be sent. - * - * The datagram will be sent to the current remote_ip & remote_port - * stored in pcb. If the pcb is not bound to a port, it will - * automatically be bound to a random port. - * - * @return lwIP error code. - * - ERR_OK. Successful. No error 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) -{ - if ((pcb == NULL) || IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) { - return ERR_VAL; - } - - /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); -} - -#if LWIP_CHECKSUM_ON_COPY && 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) -{ - if ((pcb == NULL) || IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) { - return ERR_VAL; - } - - /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, - have_chksum, chksum); -} -#endif /* LWIP_CHECKSUM_ON_COPY && 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() - */ -err_t -udp_sendto(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port) -{ -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP - 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 /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - struct netif *netif; - const ip_addr_t *dst_ip_route = dst_ip; - - if ((pcb == NULL) || (dst_ip == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { - return ERR_VAL; - } - - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); - -#if LWIP_IPV6 || (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) - if (ip_addr_ismulticast(dst_ip_route)) { -#if LWIP_IPV6 - if (IP_IS_V6(dst_ip)) { - /* For multicast, find a netif based on source address. */ - dst_ip_route = &pcb->local_ip; - } else -#endif /* LWIP_IPV6 */ - { -#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS - /* 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->multicast_ip that is used for routing. */ - if (!ip_addr_isany_val(pcb->multicast_ip) && - !ip4_addr_cmp(ip_2_ip4(&pcb->multicast_ip), IP4_ADDR_BROADCAST)) { - dst_ip_route = &pcb->multicast_ip; - } -#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS */ - } - } -#endif /* LWIP_IPV6 || (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) */ - - /* find the outgoing network interface for this packet */ - netif = ip_route(&pcb->local_ip, dst_ip_route); - - /* 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 - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); -#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); -#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() - */ -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) -{ -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP - 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 /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - const ip_addr_t *src_ip; - - if ((pcb == NULL) || (dst_ip == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { - return ERR_VAL; - } - - /* PCB local address is IP_ANY_ADDR? */ -#if LWIP_IPV6 - if (IP_IS_V6(dst_ip)) { - if (ip6_addr_isany(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_VAL; - } - /* use UDP PCB local IP address as source address */ - src_ip = &pcb->local_ip; - } -#endif /* LWIP_IPV4 */ -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP - return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum, src_ip); -#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - return udp_sendto_if_src(pcb, p, dst_ip, dst_port, netif, src_ip); -#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ -} - -/** @ingroup udp_raw - * Same as @ref udp_sendto_if, but with source address */ -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) -{ -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP - 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 /* 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; - - if ((pcb == NULL) || (dst_ip == NULL) || !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; - } - } - - /* not enough space to add an UDP header to first pbuf in given p chain? */ - if (pbuf_header(p, UDP_HLEN)) { - /* allocate header in a separate new pbuf */ - q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); - /* new header pbuf could not be allocated? */ - if (q == NULL) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); - return ERR_MEM; - } - if (p->tot_len != 0) { - /* chain header q in front of given pbuf p (only if p contains data) */ - pbuf_chain(q, p); - } - /* first pbuf q points to header pbuf */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); - } else { - /* adding space for header within p succeeded */ - /* first pbuf q equals given pbuf */ - q = p; - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); - } - LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", - (q->len >= sizeof(struct udp_hdr))); - /* q now represents the packet to be sent */ - udphdr = (struct udp_hdr *)q->payload; - udphdr->src = htons(pcb->local_port); - udphdr->dest = htons(dst_port); - /* in UDP, 0 checksum means 'no checksum' */ - udphdr->chksum = 0x0000; - - /* Multicast Loop? */ -#if (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) || (LWIP_IPV6 && LWIP_IPV6_MLD) - if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) && ip_addr_ismulticast(dst_ip)) { - q->flags |= PBUF_FLAG_MCASTLOOP; - } -#endif /* (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ - - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); - -#if LWIP_UDPLITE - /* UDP Lite protocol? */ - if (pcb->flags & UDP_FLAGS_UDPLITE) { - u16_t chklen, chklen_hdr; - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); - /* set UDP message length in UDP header */ - chklen_hdr = chklen = pcb->chksum_len_tx; - if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { - if (chklen != 0) { - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); - } - /* For UDP-Lite, checksum length of 0 means checksum - over the complete packet. (See RFC 3828 chap. 3.1) - At least the UDP-Lite header must be covered by the - checksum, therefore, if chksum_len has an illegal - value, we generate the checksum over the complete - packet to be safe. */ - chklen_hdr = 0; - chklen = q->tot_len; - } - udphdr->len = htons(chklen_hdr); - /* calculate checksum */ -#if CHECKSUM_GEN_UDP - 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 = 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) ? pcb->mcast_ttl : 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_HWADDRHINT(netif, &(pcb->addr_hint)); - err = ip_output_if_src(q, src_ip, dst_ip, ttl, pcb->tos, ip_proto, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - - /* @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_ADDR_ANY to - * bind to all local interfaces. - * @param port local UDP port to bind with. Use 0 to automatically bind - * to a random port between UDP_LOCAL_PORT_RANGE_START and - * UDP_LOCAL_PORT_RANGE_END. - * - * ipaddr & port are expected to be in the same byte order as in the pcb. - * - * @return lwIP error code. - * - ERR_OK. Successful. No error 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_IPV4 - /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ - if (ipaddr == NULL) { - ipaddr = IP_ADDR_ANY; - } -#endif /* LWIP_IPV4 */ - - /* still need to check for ipaddr == NULL in IPv6 only case */ - if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) { - return ERR_VAL; - } - - 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; - } - } - - /* 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? */ - ip_addr_cmp(&ipcb->local_ip, ipaddr)) { - /* other PCB already binds to this local IP and port */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); - return ERR_USE; - } - } - } - } - } - - ip_addr_set_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(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 - * Connect an UDP PCB. - * - * This will associate the UDP PCB with the remote address. - * - * @param pcb UDP PCB to be connected with remote address ipaddr and port. - * @param ipaddr remote IP address to connect with. - * @param port remote UDP port to connect with. - * - * @return lwIP error code - * - * ipaddr & port are expected to be in the same byte order as in the pcb. - * - * The udp pcb is bound to a random local port if not already bound. - * - * @see udp_disconnect() - */ -err_t -udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) -{ - struct udp_pcb *ipcb; - - if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) { - return ERR_VAL; - } - - 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); - 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(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 - * Disconnect a UDP PCB - * - * @param pcb the udp pcb to disconnect. - */ -void -udp_disconnect(struct udp_pcb *pcb) -{ - /* 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; - /* mark PCB as unconnected */ - pcb->flags &= ~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) -{ - /* remember recv() callback and user data */ - pcb->recv = recv; - pcb->recv_arg = recv_arg; -} - -/** - * @ingroup udp_raw - * Remove an UDP PCB. - * - * @param pcb UDP PCB to be removed. The PCB is removed from the list of - * UDP PCB's and the data structure is freed from memory. - * - * @see udp_new() - */ -void -udp_remove(struct udp_pcb *pcb) -{ - struct udp_pcb *pcb2; - - 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 - * Create a UDP PCB. - * - * @return The UDP PCB which was created. NULL if the PCB data structure - * could not be allocated. - * - * @see udp_remove() - */ -struct udp_pcb * -udp_new(void) -{ - struct udp_pcb *pcb; - pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); - /* could allocate UDP PCB? */ - if (pcb != NULL) { - /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0 - * which means checksum is generated over the whole datagram per default - * (recommended as default by RFC 3828). */ - /* initialize PCB to all zeroes */ - memset(pcb, 0, sizeof(struct udp_pcb)); - pcb->ttl = UDP_TTL; -#if LWIP_MULTICAST_TX_OPTIONS - pcb->mcast_ttl = UDP_TTL; -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - } - return pcb; -} - -/** - * @ingroup udp_raw - * Create a UDP PCB for specific IP type. - * - * @param type IP address type, see IPADDR_TYPE_XX definitions. - * @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; - 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; -} - -#if LWIP_IPV4 -/** This function is called from netif.c when address is changed - * - * @param old_addr IPv4 address of the netif before change - * @param new_addr IPv4 address of the netif after change - */ -void udp_netif_ipv4_addr_changed(const ip4_addr_t* old_addr, const ip4_addr_t* new_addr) -{ - struct udp_pcb* upcb; - - if (!ip4_addr_isany(new_addr)) { - for (upcb = udp_pcbs; upcb != NULL; upcb = upcb->next) { - /* Is this an IPv4 pcb? */ - if (IP_IS_V4_VAL(upcb->local_ip)) { - /* PCB bound to current local interface address? */ - if (!ip4_addr_isany(ip_2_ip4(&upcb->local_ip)) && - ip4_addr_cmp(ip_2_ip4(&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_from_ip4(upcb->local_ip, *new_addr); - } - } - } - } -} -#endif /* LWIP_IPV4 */ - -#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", - ntohs(udphdr->src), ntohs(udphdr->dest))); - LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", - ntohs(udphdr->len), ntohs(udphdr->chksum))); - LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); -} -#endif /* UDP_DEBUG */ - -#endif /* LWIP_UDP */ diff --git a/ext/lwip/src/include/arch/cc.h b/ext/lwip/src/include/arch/cc.h deleted file mode 100644 index 462124d..0000000 --- a/ext/lwip/src/include/arch/cc.h +++ /dev/null @@ -1,90 +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 __ARCH_CC_H__ -#define __ARCH_CC_H__ - -/* Include some files for defining library routines */ -#include -#include -#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) - -#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ - x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) - -#define LWIP_RAND() ((u32_t)rand()) - -#endif /* __ARCH_CC_H__ */ diff --git a/ext/lwip/src/include/arch/perf.h b/ext/lwip/src/include/arch/perf.h deleted file mode 100644 index 9fbcf60..0000000 --- a/ext/lwip/src/include/arch/perf.h +++ /dev/null @@ -1,63 +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 __ARCH_PERF_H__ -#define __ARCH_PERF_H__ - -#include - -#ifdef PERF -#define PERF_START { \ - unsigned long __c1l, __c1h, __c2l, __c2h; \ - __asm__(".byte 0x0f, 0x31" : "=a" (__c1l), "=d" (__c1h)) -#define PERF_STOP(x) __asm__(".byte 0x0f, 0x31" : "=a" (__c2l), "=d" (__c2h)); \ - perf_print(__c1l, __c1h, __c2l, __c2h, x);} - -/*#define PERF_START do { \ - struct tms __perf_start, __perf_end; \ - times(&__perf_start) -#define PERF_STOP(x) times(&__perf_end); \ - perf_print_times(&__perf_start, &__perf_end, x);\ - } while(0)*/ -#else /* PERF */ -#define PERF_START /* null definition */ -#define PERF_STOP(x) /* null definition */ -#endif /* PERF */ - -void perf_print(unsigned long c1l, unsigned long c1h, - unsigned long c2l, unsigned long c2h, - char *key); - -void perf_print_times(struct tms *start, struct tms *end, char *key); - -void perf_init(char *fname); - -#endif /* __ARCH_PERF_H__ */ diff --git a/ext/lwip/src/include/arch/sys_arch.h b/ext/lwip/src/include/arch/sys_arch.h deleted file mode 100644 index 56d20af..0000000 --- a/ext/lwip/src/include/arch/sys_arch.h +++ /dev/null @@ -1,59 +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 __ARCH_SYS_ARCH_H__ -#define __ARCH_SYS_ARCH_H__ - -#include - -#define SYS_MBOX_NULL NULL -#define SYS_SEM_NULL NULL - -typedef u32_t sys_prot_t; - -struct sys_sem; -typedef struct sys_sem * sys_sem_t; -#define sys_sem_valid(sem) (((sem) != NULL) && (*(sem) != NULL)) -#define sys_sem_set_invalid(sem) do { if((sem) != NULL) { *(sem) = NULL; }}while(0) - -/* let sys.h use binary semaphores for mutexes */ -#define LWIP_COMPAT_MUTEX 1 - -struct sys_mbox; -typedef struct sys_mbox *sys_mbox_t; -#define sys_mbox_valid(mbox) (((mbox) != NULL) && (*(mbox) != NULL)) -#define sys_mbox_set_invalid(mbox) do { if((mbox) != NULL) { *(mbox) = NULL; }}while(0) - -struct sys_thread; -typedef struct sys_thread * sys_thread_t; - -#endif /* __ARCH_SYS_ARCH_H__ */ - diff --git a/ext/lwip/src/include/lwip/api.h b/ext/lwip/src/include/lwip/api.h deleted file mode 100644 index 8bd8bf1..0000000 --- a/ext/lwip/src/include/lwip/api.h +++ /dev/null @@ -1,375 +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 /* for size_t */ - -#include "lwip/netbuf.h" -#include "lwip/sys.h" -#include "lwip/ip_addr.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Throughout this file, IP addresses and port numbers are expected to be in - * the same byte order as in the corresponding pcb. - */ - -/* Flags for netconn_write (u8_t) */ -#define NETCONN_NOFLAG 0x00 -#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ -#define NETCONN_COPY 0x01 -#define NETCONN_MORE 0x02 -#define NETCONN_DONTBLOCK 0x04 - -/* Flags for struct netconn.flags (u8_t) */ -/** 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 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 */ - - -/* 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_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 -}; - -/** Use to inform the callback function about changes */ -enum netconn_evt { - NETCONN_EVT_RCVPLUS, - NETCONN_EVT_RCVMINUS, - NETCONN_EVT_SENDPLUS, - NETCONN_EVT_SENDMINUS, - NETCONN_EVT_ERROR -}; - -#if LWIP_IGMP || (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 error this netconn had */ - err_t last_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 */ - /** 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) */ - int recv_timeout; -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF - /** maximum amount of bytes queued in recvmbox - not used for TCP: adjust TCP_WND instead! */ - int recv_bufsize; - /** number of bytes currently in recvmbox to be received, - tested against recv_bufsize to limit bytes on recvmbox - for UDP and RAW, used for FIONREAD */ - 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 how much is already sent. */ - size_t write_offset; - /** TCP: when data passed to netconn_write doesn't fit into the send buffer, - this temporarily stores the message. - Also used during connect and close. */ - struct api_msg *current_msg; -#endif /* LWIP_TCP */ - /** A callback function that is informed about events for this netconn */ - netconn_callback callback; -}; - -/** Register an Network connection event */ -#define API_EVENT(c,e,l) if (c->callback) { \ - (*c->callback)(c, e, l); \ - } - -/** Set conn->last_err to err but don't overwrite fatal errors */ -#define NETCONN_SET_SAFE_ERR(conn, err) do { if ((conn) != NULL) { \ - SYS_ARCH_DECL_PROTECT(netconn_set_safe_err_lev); \ - SYS_ARCH_PROTECT(netconn_set_safe_err_lev); \ - if (!ERR_IS_FATAL((conn)->last_err)) { \ - (conn)->last_err = err; \ - } \ - SYS_ARCH_UNPROTECT(netconn_set_safe_err_lev); \ -}} while(0); - -/* 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_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_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_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); -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); -/** @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); -#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 */ - -#define netconn_err(conn) ((conn)->last_err) -#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) - -/** Set the blocking status of netconn calls (@todo: write/send is missing) */ -#define netconn_set_nonblocking(conn, val) do { if(val) { \ - (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \ -} else { \ - (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0) -/** Get the blocking status of netconn calls (@todo: write/send is missing) */ -#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) - -#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) { \ - (conn)->flags |= NETCONN_FLAG_IPV6_V6ONLY; \ -} else { \ - (conn)->flags &= ~ 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/ext/lwip/src/include/lwip/apps/FILES b/ext/lwip/src/include/lwip/apps/FILES deleted file mode 100644 index adfc0f3..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/lwip/apps/fs.h b/ext/lwip/src/include/lwip/apps/fs.h deleted file mode 100644 index bb176fa..0000000 --- a/ext/lwip/src/include/lwip/apps/fs.h +++ /dev/null @@ -1,103 +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 - -struct fs_file { - const char *data; - int len; - int index; - void *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 */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_FS_H */ diff --git a/ext/lwip/src/include/lwip/apps/httpd.h b/ext/lwip/src/include/lwip/apps/httpd.h deleted file mode 100644 index 40f1811..0000000 --- a/ext/lwip/src/include/lwip/apps/httpd.h +++ /dev/null @@ -1,236 +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 - -/* - * 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_handler. The iIndex parameter provides the index of the - * CGI within the ppcURLs array passed to http_set_cgi_handler. 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[]); - -/* - * 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 -/** Define this generic CGI handler in your application. - * It is called once for every URI with parameters. - * The parameters can be stored to - */ -extern void httpd_cgi_handler(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 - -/* - * 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 a .shtml, .ssi or .shtm file where "name" appears as - * one of the tags supplied to http_set_ssi_handler in the ppcTags 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 ppcTags 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 a negative number to indicate a failure (tag not - * recognized, for example). - * - * 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. To work around this, any SSI tag which needs to - * output JavaScript code must do so in an encapsulated way, sending the whole - * HTML section as a single include. - */ -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 */ - -/** 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); - -/** 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); - -/** 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); - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HTTPD_H */ diff --git a/ext/lwip/src/include/lwip/apps/httpd_opts.h b/ext/lwip/src/include/lwip/apps/httpd_opts.h deleted file mode 100644 index 5fa8402..0000000 --- a/ext/lwip/src/include/lwip/apps/httpd_opts.h +++ /dev/null @@ -1,345 +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" - -/** - * @defgroup httpd_opts Options - * @ingroup httpd - * @{ - */ - -/** Set this to 1 to support CGI (old style) */ -#if !defined LWIP_HTTPD_CGI || defined __DOXYGEN__ -#define LWIP_HTTPD_CGI 0 -#endif - -/** Set this to 1 to support CGI (new style) */ -#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) */ -#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 !defined LWIP_HTTPD_SSI_RAW || defined __DOXYGEN__ -#define LWIP_HTTPD_SSI_RAW 0 -#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 tag name */ -#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 !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 !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 80 -#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 1 on platforms where strnstr is not available */ -#if !defined LWIP_HTTPD_STRNSTR_PRIVATE || defined __DOXYGEN__ -#define LWIP_HTTPD_STRNSTR_PRIVATE 1 -#endif - -/** Set this to 1 on platforms where stricmp is not available */ -#if !defined LWIP_HTTPD_STRICMP_PRIVATE || defined __DOXYGEN__ -#define LWIP_HTTPD_STRICMP_PRIVATE 0 -#endif - -/** Define this to a smaller function if you have itoa() at hand... */ -#if !defined LWIP_HTTPD_ITOA || defined __DOXYGEN__ -#if !defined LWIP_HTTPD_ITOA_PRIVATE || defined __DOXYGEN__ -#define LWIP_HTTPD_ITOA_PRIVATE 1 -#endif -#if LWIP_HTTPD_ITOA_PRIVATE -#define LWIP_HTTPD_ITOA(buffer, bufsize, number) httpd_itoa(number, buffer) -#else -#define LWIP_HTTPD_ITOA(buffer, bufsize, number) snprintf(buffer, bufsize, "%d", number) -#endif -#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 tcp_pcb* pcb); */ -#if !defined HTTPD_MAX_WRITE_LEN || defined __DOXYGEN__ -#if HTTPD_LIMIT_SENDING_TO_2MSS -#define HTTPD_MAX_WRITE_LEN(pcb) (2 * tcp_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 - -/** Set this to 1 to include "fsdata_custom.c" instead of "fsdata.c" for the - * file system (to prevent changing the file included in CVS) */ -#if !defined HTTPD_USE_CUSTOM_FSDATA || defined __DOXYGEN__ -#define HTTPD_USE_CUSTOM_FSDATA 0 -#endif - -/** - * @} - */ - -#endif /* LWIP_HDR_APPS_HTTPD_OPTS_H */ diff --git a/ext/lwip/src/include/lwip/apps/lwiperf.h b/ext/lwip/src/include/lwip/apps/lwiperf.h deleted file mode 100644 index 7dbebb0..0000000 --- a/ext/lwip/src/include/lwip/apps/lwiperf.h +++ /dev/null @@ -1,84 +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 -}; - -/** 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_abort(void* lwiperf_session); - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_LWIPERF_H */ diff --git a/ext/lwip/src/include/lwip/apps/netbiosns.h b/ext/lwip/src/include/lwip/apps/netbiosns.h deleted file mode 100644 index c9f68d8..0000000 --- a/ext/lwip/src/include/lwip/apps/netbiosns.h +++ /dev/null @@ -1,43 +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" - -void netbiosns_init(void); -#ifndef NETBIOS_LWIP_NAME -void netbiosns_set_name(const char* hostname); -#endif -void netbiosns_stop(void); - -#endif /* LWIP_HDR_APPS_NETBIOS_H */ diff --git a/ext/lwip/src/include/lwip/apps/netbiosns_opts.h b/ext/lwip/src/include/lwip/apps/netbiosns_opts.h deleted file mode 100644 index 870b9fd..0000000 --- a/ext/lwip/src/include/lwip/apps/netbiosns_opts.h +++ /dev/null @@ -1,69 +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 - * @{ - */ - -/** Since there's no standard function for case-insensitive string comparision, - * we need another define here: - * define this to stricmp() for windows or strcasecmp() for linux. - * If not defined, comparision is case sensitive and the provided hostname must be - * uppercase. - */ -#if !defined NETBIOS_STRCMP || defined __DOXYGEN__ -#define NETBIOS_STRCMP(str1, str2) strcmp(str1, str2) -#endif - -/** 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 - -/** - * @} - */ - -#endif /* LWIP_HDR_APPS_NETBIOS_OPTS_H */ diff --git a/ext/lwip/src/include/lwip/apps/snmp.h b/ext/lwip/src/include/lwip/apps/snmp.h deleted file mode 100644 index 60ce9c9..0000000 --- a/ext/lwip/src/include/lwip/apps/snmp.h +++ /dev/null @@ -1,127 +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); - -#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); - -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/ext/lwip/src/include/lwip/apps/snmp_core.h b/ext/lwip/src/include/lwip/apps/snmp_core.h deleted file mode 100644 index 938be50..0000000 --- a/ext/lwip/src/include/lwip/apps/snmp_core.h +++ /dev/null @@ -1,364 +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) -#define SNMP_ASN1_TYPE_COUNTER64 (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER64) - -#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; -}; - - -/** -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 0x8000 - -/** 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, const u8_t oid_len); -u8_t snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const 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; -}; - -extern struct snmp_statistics snmp_stats; - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SNMP */ - -#endif /* LWIP_HDR_APPS_SNMP_CORE_H */ diff --git a/ext/lwip/src/include/lwip/apps/snmp_mib2.h b/ext/lwip/src/include/lwip/apps/snmp_mib2.h deleted file mode 100644 index 2f4a689..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/lwip/apps/snmp_opts.h b/ext/lwip/src/include/lwip/apps/snmp_opts.h deleted file mode 100644 index bf6f009..0000000 --- a/ext/lwip/src/include/lwip/apps/snmp_opts.h +++ /dev/null @@ -1,289 +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 maximum 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 minimum 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_CRYPTO -#define LWIP_SNMP_V3_CRYPTO LWIP_SNMP_V3 -#endif - -#endif /* LWIP_HDR_SNMP_OPTS_H */ diff --git a/ext/lwip/src/include/lwip/apps/snmp_scalar.h b/ext/lwip/src/include/lwip/apps/snmp_scalar.h deleted file mode 100644 index 40a060c..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/lwip/apps/snmp_table.h b/ext/lwip/src/include/lwip/apps/snmp_table.h deleted file mode 100644 index c08f1aa..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/lwip/apps/snmp_threadsync.h b/ext/lwip/src/include/lwip/apps/snmp_threadsync.h deleted file mode 100644 index a25dbf2..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/lwip/apps/snmpv3.h b/ext/lwip/src/include/lwip/apps/snmpv3.h deleted file mode 100644 index c99fed4..0000000 --- a/ext/lwip/src/include/lwip/apps/snmpv3.h +++ /dev/null @@ -1,90 +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" - -#if LWIP_SNMP && LWIP_SNMP_V3 - -#define SNMP_V3_AUTH_ALGO_INVAL 0 -#define SNMP_V3_AUTH_ALGO_MD5 1 -#define SNMP_V3_AUTH_ALGO_SHA 2 - -#define SNMP_V3_PRIV_ALGO_INVAL 0 -#define SNMP_V3_PRIV_ALGO_DES 1 -#define SNMP_V3_PRIV_ALGO_AES 2 - -#define SNMP_V3_PRIV_MODE_DECRYPT 0 -#define SNMP_V3_PRIV_MODE_ENCRYPT 1 - -/* - * 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, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key); - -/* The following functions are provided by the SNMPv3 agent */ - -void snmpv3_engine_id_changed(void); - -void snmpv3_password_to_key_md5( - const u8_t *password, /* IN */ - u8_t passwordlen, /* IN */ - const u8_t *engineID, /* IN - pointer to snmpEngineID */ - u8_t engineLength, /* IN - length of snmpEngineID */ - u8_t *key); /* OUT - pointer to caller 16-octet buffer */ - -void snmpv3_password_to_key_sha( - const u8_t *password, /* IN */ - u8_t passwordlen, /* IN */ - const u8_t *engineID, /* IN - pointer to snmpEngineID */ - u8_t engineLength, /* IN - length of snmpEngineID */ - u8_t *key); /* OUT - pointer to caller 20-octet buffer */ - -#endif - -#endif /* LWIP_HDR_APPS_SNMP_V3_H */ diff --git a/ext/lwip/src/include/lwip/apps/sntp.h b/ext/lwip/src/include/lwip/apps/sntp.h deleted file mode 100644 index 40df9cc..0000000 --- a/ext/lwip/src/include/lwip/apps/sntp.h +++ /dev/null @@ -1,76 +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_SERVER_DNS -void sntp_setservername(u8_t idx, char *server); -char *sntp_getservername(u8_t idx); -#endif /* SNTP_SERVER_DNS */ - -#if SNTP_GET_SERVERS_FROM_DHCP -void sntp_servermode_dhcp(int set_servers_from_dhcp); -#else /* SNTP_GET_SERVERS_FROM_DHCP */ -#define sntp_servermode_dhcp(x) -#endif /* SNTP_GET_SERVERS_FROM_DHCP */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_SNTP_H */ diff --git a/ext/lwip/src/include/lwip/apps/sntp_opts.h b/ext/lwip/src/include/lwip/apps/sntp_opts.h deleted file mode 100644 index f3651f9..0000000 --- a/ext/lwip/src/include/lwip/apps/sntp_opts.h +++ /dev/null @@ -1,173 +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" - -/** - * @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. - */ -#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 123 -#endif - -/** Set this to 1 to allow config of SNTP server(s) by DNS name */ -#if !defined SNTP_SERVER_DNS || defined __DOXYGEN__ -#define SNTP_SERVER_DNS 0 -#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 LI, Stratum, or Transmit Timestamp - * fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast). - * - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each - * greater than or equal to 0 and less than infinity, where infinity is - * currently a cozy number like one second. This check avoids using a - * server whose synchronization source has expired for a very long time. - */ -#if !defined SNTP_CHECK_RESPONSE || defined __DOXYGEN__ -#define SNTP_CHECK_RESPONSE 0 -#endif - -/** According to the RFC, this shall be a random delay - * between 1 and 5 minutes (in milliseconds) to prevent load peaks. - * This can be defined to a random generation function, - * which must return the delay in milliseconds as u32_t. - * Turned off by default. - */ -#if !defined SNTP_STARTUP_DELAY || defined __DOXYGEN__ -#define SNTP_STARTUP_DELAY 0 -#endif - -/** If you want the startup delay to be a function, define this - * to a function (including the brackets) and define SNTP_STARTUP_DELAY to 1. - */ -#if !defined SNTP_STARTUP_DELAY_FUNC || defined __DOXYGEN__ -#define SNTP_STARTUP_DELAY_FUNC SNTP_STARTUP_DELAY -#endif - -/** SNTP receive timeout - in milliseconds - * Also used as retry timeout - this shouldn't be too low. - * Default is 3 seconds. - */ -#if !defined SNTP_RECV_TIMEOUT || defined __DOXYGEN__ -#define SNTP_RECV_TIMEOUT 3000 -#endif - -/** SNTP update delay - in milliseconds - * Default is 1 hour. Must not be beolw 15 seconds by specification (i.e. 15000) - */ -#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. - */ -#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 - -/** - * @} - */ - -#endif /* LWIP_HDR_APPS_SNTP_OPTS_H */ diff --git a/ext/lwip/src/include/lwip/arch.h b/ext/lwip/src/include/lwip/arch.h deleted file mode 100644 index 598fb83..0000000 --- a/ext/lwip/src/include/lwip/arch.h +++ /dev/null @@ -1,332 +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" - -/** Define this to 1 in arch/cc.h of your port if your compiler does not provide - * the stdint.h header. This cannot be \#defined in lwipopts.h since - * this is not an option of lwIP itself, but an option of the lwIP port - * to your system. - * Additionally, this header is meant to be \#included in lwipopts.h - * (you may need to declare function prototypes in there). - */ -#ifndef LWIP_NO_STDINT_H -#define LWIP_NO_STDINT_H 0 -#endif - -/* Define generic types used in lwIP */ -#if !LWIP_NO_STDINT_H -#include -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 defined(__ANDROID__) - typedef unsigned long mem_ptr_t; - #else - typedef uintptr_t mem_ptr_t; - #endif -#endif - -/** Define this to 1 in arch/cc.h of your port if your compiler does not provide - * the inttypes.h header. This cannot be \#defined in lwipopts.h since - * this is not an option of lwIP itself, but an option of the lwIP port - * to your system. - * Additionally, this header is meant to be \#included in lwipopts.h - * (you may need to declare function prototypes in there). - */ -#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 - -/** 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. - * e.g. if you use gcc and need 32 bit alignment: - * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] __attribute__((aligned(4))) - * or more portable: - * \#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 - -#ifndef PACK_STRUCT_BEGIN -#define PACK_STRUCT_BEGIN -#endif /* PACK_STRUCT_BEGIN */ - -#ifndef PACK_STRUCT_END -#define PACK_STRUCT_END -#endif /* PACK_STRUCT_END */ - -#ifndef PACK_STRUCT_STRUCT -#define PACK_STRUCT_STRUCT -#endif /* PACK_STRUCT_STRUCT */ - -#ifndef PACK_STRUCT_FIELD -#define PACK_STRUCT_FIELD(x) x -#endif /* PACK_STRUCT_FIELD */ - -/* Used for struct fields of u8_t, - * where some compilers warn that packing is not necessary */ -#ifndef PACK_STRUCT_FLD_8 -#define PACK_STRUCT_FLD_8(x) PACK_STRUCT_FIELD(x) -#endif /* PACK_STRUCT_FLD_8 */ - -/* Used for struct fields of that are packed structs themself, - * where some compilers warn that packing is not necessary */ -#ifndef PACK_STRUCT_FLD_S -#define PACK_STRUCT_FLD_S(x) PACK_STRUCT_FIELD(x) -#endif /* PACK_STRUCT_FLD_S */ - - -#ifndef LWIP_UNUSED_ARG -#define LWIP_UNUSED_ARG(x) (void)x -#endif /* LWIP_UNUSED_ARG */ - - -#ifdef LWIP_PROVIDE_ERRNO - -#define EPERM 1 /* Operation not permitted */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Arg list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ -#define EAGAIN 11 /* Try again */ -#define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Device or resource busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ -#define EDEADLK 35 /* Resource deadlock would occur */ -#define ENAMETOOLONG 36 /* File name too long */ -#define ENOLCK 37 /* No record locks available */ -#define ENOSYS 38 /* Function not implemented */ -#define ENOTEMPTY 39 /* Directory not empty */ -#define ELOOP 40 /* Too many symbolic links encountered */ -#define EWOULDBLOCK EAGAIN /* Operation would block */ -#define ENOMSG 42 /* No message of desired type */ -#define EIDRM 43 /* Identifier removed */ -#define ECHRNG 44 /* Channel number out of range */ -#define EL2NSYNC 45 /* Level 2 not synchronized */ -#define EL3HLT 46 /* Level 3 halted */ -#define EL3RST 47 /* Level 3 reset */ -#define ELNRNG 48 /* Link number out of range */ -#define EUNATCH 49 /* Protocol driver not attached */ -#define ENOCSI 50 /* No CSI structure available */ -#define EL2HLT 51 /* Level 2 halted */ -#define EBADE 52 /* Invalid exchange */ -#define EBADR 53 /* Invalid request descriptor */ -#define EXFULL 54 /* Exchange full */ -#define ENOANO 55 /* No anode */ -#define EBADRQC 56 /* Invalid request code */ -#define EBADSLT 57 /* Invalid slot */ - -#define EDEADLOCK EDEADLK - -#define EBFONT 59 /* Bad font file format */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data available */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* Object is remote */ -#define ENOLINK 67 /* Link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EMULTIHOP 72 /* Multihop attempted */ -#define EDOTDOT 73 /* RFS specific error */ -#define EBADMSG 74 /* Not a data message */ -#define EOVERFLOW 75 /* Value too large for defined data type */ -#define ENOTUNIQ 76 /* Name not unique on network */ -#define EBADFD 77 /* File descriptor in bad state */ -#define EREMCHG 78 /* Remote address changed */ -#define ELIBACC 79 /* Can not access a needed shared library */ -#define ELIBBAD 80 /* Accessing a corrupted shared library */ -#define ELIBSCN 81 /* .lib section in a.out corrupted */ -#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ -#define ELIBEXEC 83 /* Cannot exec a shared library directly */ -#define EILSEQ 84 /* Illegal byte sequence */ -#define ERESTART 85 /* Interrupted system call should be restarted */ -#define ESTRPIPE 86 /* Streams pipe error */ -#define EUSERS 87 /* Too many users */ -#define ENOTSOCK 88 /* Socket operation on non-socket */ -#define EDESTADDRREQ 89 /* Destination address required */ -#define EMSGSIZE 90 /* Message too long */ -#define EPROTOTYPE 91 /* Protocol wrong type for socket */ -#define ENOPROTOOPT 92 /* Protocol not available */ -#define EPROTONOSUPPORT 93 /* Protocol not supported */ -#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ -#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ -#define EPFNOSUPPORT 96 /* Protocol family not supported */ -#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ -#define EADDRINUSE 98 /* Address already in use */ -#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ -#define ENETDOWN 100 /* Network is down */ -#define ENETUNREACH 101 /* Network is unreachable */ -#define ENETRESET 102 /* Network dropped connection because of reset */ -#define ECONNABORTED 103 /* Software caused connection abort */ -#define ECONNRESET 104 /* Connection reset by peer */ -#define ENOBUFS 105 /* No buffer space available */ -#define EISCONN 106 /* Transport endpoint is already connected */ -#define ENOTCONN 107 /* Transport endpoint is not connected */ -#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ -#define ETOOMANYREFS 109 /* Too many references: cannot splice */ -#define ETIMEDOUT 110 /* Connection timed out */ -#define ECONNREFUSED 111 /* Connection refused */ -#define EHOSTDOWN 112 /* Host is down */ -#define EHOSTUNREACH 113 /* No route to host */ -#define EALREADY 114 /* Operation already in progress */ -#define EINPROGRESS 115 /* Operation now in progress */ -#define ESTALE 116 /* Stale NFS file handle */ -#define EUCLEAN 117 /* Structure needs cleaning */ -#define ENOTNAM 118 /* Not a XENIX named type file */ -#define ENAVAIL 119 /* No XENIX semaphores available */ -#define EISNAM 120 /* Is a named type file */ -#define EREMOTEIO 121 /* Remote I/O error */ -#define EDQUOT 122 /* Quota exceeded */ - -#define ENOMEDIUM 123 /* No medium found */ -#define EMEDIUMTYPE 124 /* Wrong medium type */ - -#ifndef errno -extern int errno; -#endif - -#endif /* LWIP_PROVIDE_ERRNO */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_ARCH_H */ diff --git a/ext/lwip/src/include/lwip/autoip.h b/ext/lwip/src/include/lwip/autoip.h deleted file mode 100644 index 81d8993..0000000 --- a/ext/lwip/src/include/lwip/autoip.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * @file - * - * AutoIP Automatic LinkLocal IP Configuration - */ - -/* - * - * Copyright (c) 2007 Dominik Spies - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dominik Spies - * - * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform - * with RFC 3927. - * - * - * Please coordinate changes and requests with Dominik Spies - * - */ - -#ifndef LWIP_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; -}; - - -#define autoip_init() /* Compatibility define, no init needed. */ -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); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV4 && LWIP_AUTOIP */ - -#endif /* LWIP_HDR_AUTOIP_H */ diff --git a/ext/lwip/src/include/lwip/debug.h b/ext/lwip/src/include/lwip/debug.h deleted file mode 100644 index dd7afa8..0000000 --- a/ext/lwip/src/include/lwip/debug.h +++ /dev/null @@ -1,112 +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" - -/** lower two bits indicate debug level - * - 0 all - * - 1 warning - * - 2 serious - * - 3 severe - */ -#define LWIP_DBG_LEVEL_ALL 0x00 -#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */ -#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */ -#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */ -#define LWIP_DBG_LEVEL_SEVERE 0x03 -#define LWIP_DBG_MASK_LEVEL 0x03 - -/** flag for LWIP_DEBUGF to enable that debug message */ -#define LWIP_DBG_ON 0x80U -/** flag for LWIP_DEBUGF to disable that debug message */ -#define LWIP_DBG_OFF 0x00U - -/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ -#define LWIP_DBG_TRACE 0x40U -/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ -#define LWIP_DBG_STATE 0x20U -/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ -#define LWIP_DBG_FRESH 0x10U -/** flag for LWIP_DEBUGF to halt after printing this debug message */ -#define LWIP_DBG_HALT 0x08U - -/** - * LWIP_NOASSERT: Disable LWIP_ASSERT checks. - * -- To disable assertions define LWIP_NOASSERT in arch/cc.h. - */ -#ifndef LWIP_NOASSERT -#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \ - LWIP_PLATFORM_ASSERT(message); } while(0) -#ifndef LWIP_PLATFORM_ASSERT -#error "If you want to use LWIP_ASSERT, LWIP_PLATFORM_ASSERT(message) needs to be defined in your arch/cc.h" -#endif -#else /* LWIP_NOASSERT */ -#define LWIP_ASSERT(message, assertion) -#endif /* LWIP_NOASSERT */ - -/** if "expression" isn't true, then print "message" and execute "handler" expression */ -#ifndef LWIP_ERROR -#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 - -#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ - LWIP_PLATFORM_ERROR(message); handler;}} while(0) -#endif /* LWIP_ERROR */ - -#ifdef LWIP_DEBUG -#ifndef LWIP_PLATFORM_DIAG -#error "If you want to use LWIP_DEBUG, LWIP_PLATFORM_DIAG(message) needs to be defined in your arch/cc.h" -#endif -/** print debug message only if debug message type is enabled... - * AND is of correct type AND is at least LWIP_DBG_LEVEL - */ -#define LWIP_DEBUGF(debug, message) LWIP_PLATFORM_DIAG(message); - -#else /* LWIP_DEBUG */ -#define LWIP_DEBUGF(debug, message) -#endif /* LWIP_DEBUG */ - -#endif /* LWIP_HDR_DEBUG_H */ - diff --git a/ext/lwip/src/include/lwip/def.h b/ext/lwip/src/include/lwip/def.h deleted file mode 100644 index 39d720c..0000000 --- a/ext/lwip/src/include/lwip/def.h +++ /dev/null @@ -1,141 +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 - * - */ -#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])) - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -/* Endianess-optimized shifting of two u8_t to create one u16_t */ -#if BYTE_ORDER == LITTLE_ENDIAN -#define LWIP_MAKE_U16(a, b) ((a << 8) | b) -#else -#define LWIP_MAKE_U16(a, b) ((b << 8) | a) -#endif - -#ifndef LWIP_PLATFORM_BYTESWAP -#define LWIP_PLATFORM_BYTESWAP 0 -#endif - -#ifndef LWIP_PREFIX_BYTEORDER_FUNCS -/* workaround for naming collisions on some platforms */ - -#ifdef htons -#undef htons -#endif /* htons */ -#ifdef htonl -#undef htonl -#endif /* htonl */ -#ifdef ntohs -#undef ntohs -#endif /* ntohs */ -#ifdef ntohl -#undef ntohl -#endif /* ntohl */ - -#define htons(x) lwip_htons(x) -#define ntohs(x) lwip_ntohs(x) -#define htonl(x) lwip_htonl(x) -#define ntohl(x) lwip_ntohl(x) -#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */ - -#if BYTE_ORDER == BIG_ENDIAN -#define lwip_htons(x) (x) -#define lwip_ntohs(x) (x) -#define lwip_htonl(x) (x) -#define lwip_ntohl(x) (x) -#define PP_HTONS(x) (x) -#define PP_NTOHS(x) (x) -#define PP_HTONL(x) (x) -#define PP_NTOHL(x) (x) -#else /* BYTE_ORDER != BIG_ENDIAN */ -#if LWIP_PLATFORM_BYTESWAP -#define lwip_htons(x) LWIP_PLATFORM_HTONS(x) -#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x) -#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x) -#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x) -#else /* LWIP_PLATFORM_BYTESWAP */ -u16_t lwip_htons(u16_t x); -u16_t lwip_ntohs(u16_t x); -u32_t lwip_htonl(u32_t x); -u32_t lwip_ntohl(u32_t x); -#endif /* LWIP_PLATFORM_BYTESWAP */ - -/* These macros should be calculated by the preprocessor and are used - with compile-time constants only (so that there is no little-endian - overhead at runtime). */ -#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) -#define PP_NTOHS(x) PP_HTONS(x) -#define PP_HTONL(x) ((((x) & 0xff) << 24) | \ - (((x) & 0xff00) << 8) | \ - (((x) & 0xff0000UL) >> 8) | \ - (((x) & 0xff000000UL) >> 24)) -#define PP_NTOHL(x) PP_HTONL(x) - -#endif /* BYTE_ORDER == BIG_ENDIAN */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_DEF_H */ - diff --git a/ext/lwip/src/include/lwip/dhcp.h b/ext/lwip/src/include/lwip/dhcp.h deleted file mode 100644 index ca19a2a..0000000 --- a/ext/lwip/src/include/lwip/dhcp.h +++ /dev/null @@ -1,289 +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_CHADDR_LEN 16U -#define DHCP_SNAME_LEN 64U -#define DHCP_FILE_LEN 128U - -struct dhcp -{ - /** transaction identifier of last sent request */ - u32_t xid; - /** incoming msg */ - struct dhcp_msg *msg_in; - /** 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; - - struct pbuf *p_out; /* pbuf of outcoming msg */ - struct dhcp_msg *msg_out; /* outgoing msg */ - u16_t options_out_len; /* outgoing msg options length */ - u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ - u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ - u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ - 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 - ip_addr_t offered_si_addr; - char boot_file_name[DHCP_FILE_LEN]; -#endif /* LWIP_DHCP_BOOTPFILE */ -}; - -/* MUST be compiled with "pack structs" or equivalent! */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** minimum set of fields of any DHCP message */ -struct dhcp_msg -{ - PACK_STRUCT_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 - -void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp); -/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */ -#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0) -void dhcp_cleanup(struct netif *netif); -/** start DHCP configuration */ -err_t dhcp_start(struct netif *netif); -/** enforce early lease renewal (not needed normally)*/ -err_t dhcp_renew(struct netif *netif); -/** release the DHCP lease, usually called before dhcp_stop()*/ -err_t dhcp_release(struct netif *netif); -/** stop DHCP configuration */ -void dhcp_stop(struct netif *netif); -/** inform server of our manual IP address */ -void dhcp_inform(struct netif *netif); -/** Handle a possible change in the network configuration */ -void dhcp_network_changed(struct netif *netif); - -/** if enabled, check whether the offered IP address is not in use, using ARP */ -#if DHCP_DOES_ARP_CHECK -void dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr); -#endif - -/** check if DHCP supplied netif->ip_addr */ -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); - -/** DHCP message item offsets and length */ -#define DHCP_OP_OFS 0 -#define DHCP_HTYPE_OFS 1 -#define DHCP_HLEN_OFS 2 -#define DHCP_HOPS_OFS 3 -#define DHCP_XID_OFS 4 -#define DHCP_SECS_OFS 8 -#define DHCP_FLAGS_OFS 10 -#define DHCP_CIADDR_OFS 12 -#define DHCP_YIADDR_OFS 16 -#define DHCP_SIADDR_OFS 20 -#define DHCP_GIADDR_OFS 24 -#define DHCP_CHADDR_OFS 28 -#define DHCP_SNAME_OFS 44 -#define DHCP_FILE_OFS 108 -#define DHCP_MSG_LEN 236 - -#define DHCP_COOKIE_OFS DHCP_MSG_LEN -#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4) - -#define DHCP_CLIENT_PORT 68 -#define DHCP_SERVER_PORT 67 - -/** DHCP client states */ -#define DHCP_STATE_OFF 0 -#define DHCP_STATE_REQUESTING 1 -#define DHCP_STATE_INIT 2 -#define DHCP_STATE_REBOOTING 3 -#define DHCP_STATE_REBINDING 4 -#define DHCP_STATE_RENEWING 5 -#define DHCP_STATE_SELECTING 6 -#define DHCP_STATE_INFORMING 7 -#define DHCP_STATE_CHECKING 8 -/** not yet implemented \#define DHCP_STATE_PERMANENT 9 */ -#define DHCP_STATE_BOUND 10 -/** not yet implemented \#define DHCP_STATE_RELEASING 11 */ -#define DHCP_STATE_BACKING_OFF 12 - -/** AUTOIP cooperation flags */ -#define DHCP_AUTOIP_COOP_STATE_OFF 0 -#define DHCP_AUTOIP_COOP_STATE_ON 1 - -#define DHCP_BOOTREQUEST 1 -#define DHCP_BOOTREPLY 2 - -/** DHCP message types */ -#define DHCP_DISCOVER 1 -#define DHCP_OFFER 2 -#define DHCP_REQUEST 3 -#define DHCP_DECLINE 4 -#define DHCP_ACK 5 -#define DHCP_NAK 6 -#define DHCP_RELEASE 7 -#define DHCP_INFORM 8 - -/** DHCP hardware type, currently only ethernet is supported */ -#define DHCP_HTYPE_ETH 1 - -#define DHCP_MAGIC_COOKIE 0x63825363UL - -/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ - -/** BootP options */ -#define DHCP_OPTION_PAD 0 -#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ -#define DHCP_OPTION_ROUTER 3 -#define DHCP_OPTION_DNS_SERVER 6 -#define DHCP_OPTION_HOSTNAME 12 -#define DHCP_OPTION_IP_TTL 23 -#define DHCP_OPTION_MTU 26 -#define DHCP_OPTION_BROADCAST 28 -#define DHCP_OPTION_TCP_TTL 37 -#define DHCP_OPTION_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 - -#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 */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_DHCP */ - -#endif /*LWIP_HDR_DHCP_H*/ diff --git a/ext/lwip/src/include/lwip/dhcp6.h b/ext/lwip/src/include/lwip/dhcp6.h deleted file mode 100644 index 455336d..0000000 --- a/ext/lwip/src/include/lwip/dhcp6.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file - * - * IPv6 address autoconfiguration as per RFC 4862. - */ - -/* - * 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 - * - * IPv6 address autoconfiguration as per RFC 4862. - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#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 */ - - -struct dhcp6 -{ - /*@todo: implement DHCP6*/ -}; - -#endif /* LWIP_IPV6_DHCP6 */ - -#endif /* LWIP_HDR_IP6_DHCP6_H */ diff --git a/ext/lwip/src/include/lwip/dns.h b/ext/lwip/src/include/lwip/dns.h deleted file mode 100644 index 00d5a78..0000000 --- a/ext/lwip/src/include/lwip/dns.h +++ /dev/null @@ -1,118 +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" - -#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 defined(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; -}; -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC -#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN -#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH -#endif -#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1)) -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ -#endif /* DNS_LOCAL_HOSTLIST */ - -/** Callback which is invoked when a hostname is found. - * A function of this type must be implemented by the application using the DNS resolver. - * @param name pointer to the name that was looked up. - * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, - * or NULL if the name could not be found (or on any other error). - * @param callback_arg a user-specified callback argument passed to dns_gethostbyname -*/ -typedef void (*dns_found_callback)(const char *name, 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 && DNS_LOCAL_HOSTLIST_IS_DYNAMIC -int dns_local_removehost(const char *hostname, const ip_addr_t *addr); -err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr); -#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_DNS */ - -#endif /* LWIP_HDR_DNS_H */ diff --git a/ext/lwip/src/include/lwip/err.h b/ext/lwip/src/include/lwip/err.h deleted file mode 100644 index 81a049d..0000000 --- a/ext/lwip/src/include/lwip/err.h +++ /dev/null @@ -1,113 +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 - * @{ - */ - -/** Define LWIP_ERR_T in cc.h if you want to use - * a different type for your platform (must be signed). */ -#ifdef LWIP_ERR_T -typedef LWIP_ERR_T err_t; -#else /* LWIP_ERR_T */ -typedef s8_t err_t; -#endif /* LWIP_ERR_T*/ - -/* Definitions for error constants. */ - -/** No error, everything OK. */ -#define ERR_OK 0 -/** Out of memory error. */ -#define ERR_MEM -1 -/** Buffer error. */ -#define ERR_BUF -2 -/** Timeout. */ -#define ERR_TIMEOUT -3 -/** Routing problem. */ -#define ERR_RTE -4 -/** Operation in progress */ -#define ERR_INPROGRESS -5 -/** Illegal value. */ -#define ERR_VAL -6 -/** Operation would block. */ -#define ERR_WOULDBLOCK -7 -/** Address in use. */ -#define ERR_USE -8 -/** Already connecting. */ -#define ERR_ALREADY -9 -/** Conn already established.*/ -#define ERR_ISCONN -10 -/** Not connected. */ -#define ERR_CONN -11 -/** Low-level netif error */ -#define ERR_IF -12 - -#define ERR_IS_FATAL(e) ((e) <= ERR_ABRT) -/** Connection aborted. */ -#define ERR_ABRT -13 -/** Connection reset. */ -#define ERR_RST -14 -/** Connection closed. */ -#define ERR_CLSD -15 -/** Illegal argument. */ -#define ERR_ARG -16 - -/** - * @} - */ - -#ifdef LWIP_DEBUG -extern const char *lwip_strerr(err_t err); -#else -#define lwip_strerr(x) "" -#endif /* LWIP_DEBUG */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_ERR_H */ diff --git a/ext/lwip/src/include/lwip/etharp.h b/ext/lwip/src/include/lwip/etharp.h deleted file mode 100644 index d23b6c2..0000000 --- a/ext/lwip/src/include/lwip/etharp.h +++ /dev/null @@ -1,151 +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 "netif/ethernet.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ - -#ifndef ETHARP_HWADDR_LEN -#define ETHARP_HWADDR_LEN ETH_HWADDR_LEN -#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_addr2 sipaddr); - PACK_STRUCT_FLD_S(struct eth_addr dhwaddr); - PACK_STRUCT_FLD_S(struct ip4_addr2 dipaddr); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define SIZEOF_ETHARP_HDR 28 - -#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR) -#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) -#define SIZEOF_ETHARP_PACKET_TX (SIZEOF_ETHARP_PACKET + SIZEOF_VLAN_HDR) -#else /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ -#define SIZEOF_ETHARP_PACKET_TX SIZEOF_ETHARP_PACKET -#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ - -/** 1 seconds period */ -#define ARP_TMR_INTERVAL 1000 - -/** ARP message types (opcodes) */ -#define ARP_REQUEST 1 -#define ARP_REPLY 2 - -#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); -s8_t etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr, - struct eth_addr **eth_ret, const ip4_addr_t **ip_ret); -u8_t etharp_get_entry(u8_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); -void etharp_ip_input(struct netif *netif, struct pbuf *p); - -#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 */ - -#if LWIP_AUTOIP -err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, - const struct eth_addr *ethdst_addr, - const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr, - const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr, - const u16_t opcode); -#endif /* LWIP_AUTOIP */ - -#endif /* LWIP_IPV4 && LWIP_ARP */ - -void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_ARP || LWIP_ETHERNET */ - -#endif /* LWIP_HDR_NETIF_ETHARP_H */ diff --git a/ext/lwip/src/include/lwip/ethip6.h b/ext/lwip/src/include/lwip/ethip6.h deleted file mode 100644 index 9018d1d..0000000 --- a/ext/lwip/src/include/lwip/ethip6.h +++ /dev/null @@ -1,66 +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" - - -#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_HDR_ETHIP6_H */ diff --git a/ext/lwip/src/include/lwip/icmp.h b/ext/lwip/src/include/lwip/icmp.h deleted file mode 100644 index 0d3652b..0000000 --- a/ext/lwip/src/include/lwip/icmp.h +++ /dev/null @@ -1,152 +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" - -#if LWIP_IPV6 && LWIP_ICMP6 -#include "lwip/icmp6.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define ICMP_ER 0 /* echo reply */ -#define ICMP_DUR 3 /* destination unreachable */ -#define ICMP_SQ 4 /* source quench */ -#define ICMP_RD 5 /* redirect */ -#define ICMP_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 */ - -/** 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 -}; - -#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 - -#define ICMPH_TYPE(hdr) ((hdr)->type) -#define ICMPH_CODE(hdr) ((hdr)->code) - -/** Combines type and code to an u16_t */ -#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) -#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) - - -#if LWIP_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/ext/lwip/src/include/lwip/icmp6.h b/ext/lwip/src/include/lwip/icmp6.h deleted file mode 100644 index cfa99c2..0000000 --- a/ext/lwip/src/include/lwip/icmp6.h +++ /dev/null @@ -1,191 +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" - - -#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 - - -#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -void icmp6_input(struct pbuf *p, struct netif *inp); -void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c); -void icmp6_packet_too_big(struct pbuf *p, u32_t mtu); -void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c); -void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer); - -#endif /* LWIP_ICMP6 && LWIP_IPV6 */ - - -#ifdef __cplusplus -} -#endif - - -#endif /* LWIP_HDR_ICMP6_H */ diff --git a/ext/lwip/src/include/lwip/igmp.h b/ext/lwip/src/include/lwip/igmp.h deleted file mode 100644 index 292e5c3..0000000 --- a/ext/lwip/src/include/lwip/igmp.h +++ /dev/null @@ -1,113 +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) - -/* MAC Filter Actions, these are passed to a netif's - * igmp_mac_filter callback function. */ -#define IGMP_DEL_MAC_FILTER 0 -#define IGMP_ADD_MAC_FILTER 1 - - -/** - * igmp group structure - there is - * a list of groups for each interface - * these should really be linked from the interface, but - * if we keep them separate we will not affect the lwip original code - * too much - * - * There will be a group for the all systems group address but this - * will not run the state machine as it is used to kick off reports - * from all the other groups - */ -struct igmp_group { - /** next link */ - struct igmp_group *next; - /** interface on which the group is active */ - struct netif *netif; - /** multicast address */ - 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); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV4 && LWIP_IGMP */ - -#endif /* LWIP_HDR_IGMP_H */ diff --git a/ext/lwip/src/include/lwip/inet.h b/ext/lwip/src/include/lwip/inet.h deleted file mode 100644 index 036cd98..0000000 --- a/ext/lwip/src/include/lwip/inet.h +++ /dev/null @@ -1,172 +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_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) -#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) -/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */ -#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr)) - -/* directly map this to the lwip internal functions */ -#define inet_addr(cp) ipaddr_addr(cp) -#define inet_aton(cp, addr) 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];} -/* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */ -#define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr) ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr)) - -/* directly map this to the lwip internal functions */ -#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr) -#define inet6_ntoa(addr) ip6addr_ntoa((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/ext/lwip/src/include/lwip/inet_chksum.h b/ext/lwip/src/include/lwip/inet_chksum.h deleted file mode 100644 index 52d76d3..0000000 --- a/ext/lwip/src/include/lwip/inet_chksum.h +++ /dev/null @@ -1,111 +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 htons() for little-endian */ -#ifndef SWAP_BYTES_IN_WORD -#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) -/* little endian and PLATFORM_BYTESWAP defined */ -#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) -#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */ -/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ -#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) -#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/ -#endif /* SWAP_BYTES_IN_WORD */ - -/** Split an u32_t in two u16_ts and add them up */ -#ifndef FOLD_U32T -#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL)) -#endif - -#if LWIP_CHECKSUM_ON_COPY -/** Function-like macro: same as MEMCPY but returns the checksum of copied data - as u16_t */ -# ifndef LWIP_CHKSUM_COPY -# define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len) -# ifndef LWIP_CHKSUM_COPY_ALGORITHM -# define LWIP_CHKSUM_COPY_ALGORITHM 1 -# endif /* LWIP_CHKSUM_COPY_ALGORITHM */ -# 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/ext/lwip/src/include/lwip/init.h b/ext/lwip/src/include/lwip/init.h deleted file mode 100644 index b88c8b1..0000000 --- a/ext/lwip/src/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 0 -/** x.x.X: Revision of the stack */ -#define LWIP_VERSION_REVISION 0 -/** 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 2 - -/** 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 (((u32_t)LWIP_VERSION_MAJOR) << 24 | ((u32_t)LWIP_VERSION_MINOR) << 16 | \ - ((u32_t)LWIP_VERSION_REVISION) << 8 | ((u32_t)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/ext/lwip/src/include/lwip/ip.h b/ext/lwip/src/include/lwip/ip.h deleted file mode 100644 index 772a4c0..0000000 --- a/ext/lwip/src/include/lwip/ip.h +++ /dev/null @@ -1,315 +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" - -#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) - -/* This is passed as the destination address to ip_output_if (not - to ip_output), meaning that an IP header already is constructed - in the pbuf. This is used when TCP retransmits. */ -#ifdef IP_HDRINCL -#undef IP_HDRINCL -#endif /* IP_HDRINCL */ -#define IP_HDRINCL NULL - -/** 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_HWADDRHINT -#define IP_PCB_ADDRHINT ;u8_t addr_hint -#else -#define IP_PCB_ADDRHINT -#endif /* LWIP_NETIF_HWADDRHINT */ - -/** This is the common part of all PCB types. It needs to be at the - beginning of a PCB type definition. It is located here so that - changes to this common part are made in one location instead of - having to change all PCB structs. */ -#define IP_PCB \ - /* ip addresses in network byte order */ \ - ip_addr_t local_ip; \ - ip_addr_t remote_ip; \ - /* Socket options */ \ - u8_t so_options; \ - /* Type Of Service */ \ - u8_t tos; \ - /* Time To Live */ \ - u8_t ttl \ - /* link layer address resolution hint */ \ - IP_PCB_ADDRHINT - -struct ip_pcb { -/* Common members of all PCB types */ - IP_PCB; -}; - -/* - * Option flags per-socket. These are the same like SO_XXX 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. */ - 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() ((const struct ip_hdr*)(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() ((const struct ip_hdr*)(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())) -/** 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 |= (opt)) -/** Resets an IP pcb option (SOF_* flags) */ -#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt)) - -#if LWIP_IPV4 && LWIP_IPV6 -/** 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)) -/** 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)) -/** 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 with addr_hint */ -#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ - (IP_IS_V6(dest) ? \ - ip6_output_hinted(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, addr_hint) : \ - ip4_output_hinted(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, addr_hint)) -/** 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(dest), ip_2_ip4(src))) -/** 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, addr_hint) \ - ip4_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) -#define ip_route(src, dest) \ - ip4_route_src(dest, src) -#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, addr_hint) \ - ip6_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) -#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/ext/lwip/src/include/lwip/ip4.h b/ext/lwip/src/include/lwip/ip4.h deleted file mode 100644 index c78c119..0000000 --- a/ext/lwip/src/include/lwip/ip4.h +++ /dev/null @@ -1,166 +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" - -#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_HLEN 20 - - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -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 - -#define IPH_V(hdr) ((hdr)->_v_hl >> 4) -#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) -#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_TTL(hdr) ((hdr)->_ttl) -#define IPH_PROTO(hdr) ((hdr)->_proto) -#define IPH_CHKSUM(hdr) ((hdr)->_chksum) - -#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) - -#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 *dest, const ip4_addr_t *src); -#else /* LWIP_IPV4_SRC_ROUTING */ -#define ip4_route_src(dest, src) 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_HWADDRHINT -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, u8_t *addr_hint); -#endif /* LWIP_NETIF_HWADDRHINT */ -#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/ext/lwip/src/include/lwip/ip4_addr.h b/ext/lwip/src/include/lwip/ip4_addr.h deleted file mode 100644 index 2db8bd5..0000000 --- a/ext/lwip/src/include/lwip/ip4_addr.h +++ /dev/null @@ -1,257 +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; -}; - -/** 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 - -/** 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; -typedef struct ip4_addr_packed ip4_addr_p_t; - -/** - * struct ipaddr2 is used in the definition of the ARP packet format in - * order to support compilers that don't have structure packing. - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip4_addr2 { - PACK_STRUCT_FIELD(u16_t addrw[2]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/* Forward declaration to not include netif.h */ -struct netif; - -/** 255.255.255.255 */ -#define IPADDR_NONE ((u32_t)0xffffffffUL) -/** 127.0.0.1 */ -#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) -/** 0.0.0.0 */ -#define IPADDR_ANY ((u32_t)0x00000000UL) -/** 255.255.255.255 */ -#define IPADDR_BROADCAST ((u32_t)0xffffffffUL) - -/* Definitions of the bits in an Internet address integer. - - On subnets, host and network parts are found according to - the subnet mask, not these masks. */ -#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) -#define IP_CLASSA_NET 0xff000000 -#define IP_CLASSA_NSHIFT 24 -#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET) -#define IP_CLASSA_MAX 128 - -#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) -#define IP_CLASSB_NET 0xffff0000 -#define IP_CLASSB_NSHIFT 16 -#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET) -#define IP_CLASSB_MAX 65536 - -#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) -#define IP_CLASSC_NET 0xffffff00 -#define IP_CLASSC_NSHIFT 8 -#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET) - -#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) -#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */ -#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */ -#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */ -#define IP_MULTICAST(a) IP_CLASSD(a) - -#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) -#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) - -#define IP_LOOPBACKNET 127 /* official! */ - - -#if BYTE_ORDER == BIG_ENDIAN -/** Set an IP address given by the four byte-parts */ -#define IP4_ADDR(ipaddr, a,b,c,d) \ - (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \ - ((u32_t)((b) & 0xff) << 16) | \ - ((u32_t)((c) & 0xff) << 8) | \ - (u32_t)((d) & 0xff) -#else -/** Set an IP address given by the four byte-parts. - Little-endian version that prevents the use of htonl. */ -#define IP4_ADDR(ipaddr, a,b,c,d) \ - (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \ - ((u32_t)((c) & 0xff) << 16) | \ - ((u32_t)((b) & 0xff) << 8) | \ - (u32_t)((a) & 0xff) -#endif - -/** MEMCPY-like copying of IP addresses where addresses are known to be - * 16-bit-aligned if the port is correctly configured (so a port could define - * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ -#ifndef IPADDR2_COPY -#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip4_addr_t)) -#endif - -/** 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 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:\ - 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(&(ipaddr)), \ - ip4_addr2_16(&(ipaddr)), \ - ip4_addr3_16(&(ipaddr)), \ - ip4_addr4_16(&(ipaddr))) - -/* Get one byte from the 4-byte address */ -#define ip4_addr1(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[0]) -#define ip4_addr2(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[1]) -#define ip4_addr3(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[2]) -#define ip4_addr4(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[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 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/ext/lwip/src/include/lwip/ip4_frag.h b/ext/lwip/src/include/lwip/ip4_frag.h deleted file mode 100644 index 89b9e31..0000000 --- a/ext/lwip/src/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 !IP_FRAG_USES_STATIC_BUF && !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 /* !IP_FRAG_USES_STATIC_BUF && !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/ext/lwip/src/include/lwip/ip6.h b/ext/lwip/src/include/lwip/ip6.h deleted file mode 100644 index 7b3fe87..0000000 --- a/ext/lwip/src/include/lwip/ip6.h +++ /dev/null @@ -1,197 +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/def.h" -#include "lwip/pbuf.h" -#include "lwip/netif.h" - -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define IP6_HLEN 40 - -#define IP6_NEXTH_HOPBYHOP 0 -#define IP6_NEXTH_TCP 6 -#define IP6_NEXTH_UDP 17 -#define IP6_NEXTH_ENCAPS 41 -#define IP6_NEXTH_ROUTING 43 -#define IP6_NEXTH_FRAGMENT 44 -#define IP6_NEXTH_ICMP6 58 -#define IP6_NEXTH_NONE 59 -#define IP6_NEXTH_DESTOPTS 60 -#define IP6_NEXTH_UDPLITE 136 - - -/** The IPv6 header. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_hdr { - /** version / traffic class / flow label */ - PACK_STRUCT_FIELD(u32_t _v_tc_fl); - /** payload length */ - PACK_STRUCT_FIELD(u16_t _plen); - /** next header */ - PACK_STRUCT_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 - -/* Hop-by-hop router alert option. */ -#define IP6_HBH_HLEN 8 -#define IP6_PAD1_OPTION 0 -#define IP6_PADN_ALERT_OPTION 1 -#define IP6_ROUTER_ALERT_OPTION 5 -#define IP6_ROUTER_ALERT_VALUE_MLD 0 -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_hbh_hdr { - /* next header */ - PACK_STRUCT_FLD_8(u8_t _nexth); - /* header length */ - PACK_STRUCT_FLD_8(u8_t _hlen); - /* router alert option type */ - PACK_STRUCT_FLD_8(u8_t _ra_opt_type); - /* router alert option data len */ - PACK_STRUCT_FLD_8(u8_t _ra_opt_dlen); - /* router alert option data */ - PACK_STRUCT_FIELD(u16_t _ra_opt_data); - /* PadN option type */ - PACK_STRUCT_FLD_8(u8_t _padn_opt_type); - /* PadN option data len */ - PACK_STRUCT_FLD_8(u8_t _padn_opt_dlen); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/* Fragment header. */ -#define IP6_FRAG_HLEN 8 -#define IP6_FRAG_OFFSET_MASK 0xfff8 -#define IP6_FRAG_MORE_FLAG 0x0001 -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_frag_hdr { - /* next header */ - PACK_STRUCT_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 IP6H_V(hdr) ((ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f) -#define IP6H_TC(hdr) ((ntohl((hdr)->_v_tc_fl) >> 20) & 0xff) -#define IP6H_FL(hdr) (ntohl((hdr)->_v_tc_fl) & 0x000fffff) -#define IP6H_PLEN(hdr) (ntohs((hdr)->_plen)) -#define IP6H_NEXTH(hdr) ((hdr)->_nexth) -#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6) -#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim) - -#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (htonl((((u32_t)(v)) << 28) | (((u32_t)(tc)) << 20) | (fl))) -#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = htons(plen) -#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth) -#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) - - -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_HWADDRHINT -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, u8_t *addr_hint); -#endif /* LWIP_NETIF_HWADDRHINT */ -#if LWIP_IPV6_MLD -err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value); -#endif /* LWIP_IPV6_MLD */ - -#define ip6_netif_get_local_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/ext/lwip/src/include/lwip/ip6_addr.h b/ext/lwip/src/include/lwip/ip6_addr.h deleted file mode 100644 index 665e75f..0000000 --- a/ext/lwip/src/include/lwip/ip6_addr.h +++ /dev/null @@ -1,311 +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" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - - -#ifdef __cplusplus -extern "C" { -#endif - - -/** This is the aligned version of ip6_addr_t, - used as local variable, on the stack, etc. */ -struct ip6_addr { - u32_t addr[4]; -}; - -/** This is the packed version of ip6_addr_t, - used in network headers that are itself packed */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_addr_packed { - PACK_STRUCT_FIELD(u32_t addr[4]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** IPv6 address */ -typedef struct ip6_addr ip6_addr_t; -typedef struct ip6_addr_packed ip6_addr_p_t; - - -#if BYTE_ORDER == BIG_ENDIAN -/** Set an IPv6 partial address given by byte-parts. */ -#define IP6_ADDR_PART(ip6addr, index, a,b,c,d) \ - (ip6addr)->addr[index] = ((u32_t)((a) & 0xff) << 24) | \ - ((u32_t)((b) & 0xff) << 16) | \ - ((u32_t)((c) & 0xff) << 8) | \ - (u32_t)((d) & 0xff) -#else -/** Set an IPv6 partial address given by byte-parts. -Little-endian version, stored in network order (no htonl). */ -#define IP6_ADDR_PART(ip6addr, index, a,b,c,d) \ - (ip6addr)->addr[index] = ((u32_t)((d) & 0xff) << 24) | \ - ((u32_t)((c) & 0xff) << 16) | \ - ((u32_t)((b) & 0xff) << 8) | \ - (u32_t)((a) & 0xff) -#endif - -/** 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; } while(0) - -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK1(ip6addr) ((u16_t)((htonl((ip6addr)->addr[0]) >> 16) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK2(ip6addr) ((u16_t)((htonl((ip6addr)->addr[0])) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK3(ip6addr) ((u16_t)((htonl((ip6addr)->addr[1]) >> 16) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK4(ip6addr) ((u16_t)((htonl((ip6addr)->addr[1])) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK5(ip6addr) ((u16_t)((htonl((ip6addr)->addr[2]) >> 16) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK6(ip6addr) ((u16_t)((htonl((ip6addr)->addr[2])) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK7(ip6addr) ((u16_t)((htonl((ip6addr)->addr[3]) >> 16) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK8(ip6addr) ((u16_t)((htonl((ip6addr)->addr[3])) & 0xffff)) - -/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */ -#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ - (dest).addr[1] = (src).addr[1]; \ - (dest).addr[2] = (src).addr[2]; \ - (dest).addr[3] = (src).addr[3];}while(0) -/** Safely copy one IPv6 address to another (src may be NULL) */ -#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \ - (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \ - (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \ - (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];}while(0) - -/** Set complete address to zero */ -#define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = 0;}while(0) - -/** Set address to ipv6 'any' (no need for htonl()) */ -#define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr) -/** Set address to ipv6 loopback address */ -#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) -/** Safely copy one IPv6 address to another and change byte order - * from host- to network-order. */ -#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : htonl((src)->addr[0]); \ - (dest)->addr[1] = (src) == NULL ? 0 : htonl((src)->addr[1]); \ - (dest)->addr[2] = (src) == NULL ? 0 : htonl((src)->addr[2]); \ - (dest)->addr[3] = (src) == NULL ? 0 : htonl((src)->addr[3]);}while(0) - - -/** - * Determine if two IPv6 address are on the same network. - * - * @arg addr1 IPv6 address 1 - * @arg addr2 IPv6 address 2 - * @return !0 if the network identifiers of both address match - */ -#define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ - ((addr1)->addr[1] == (addr2)->addr[1])) - -#define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ - ((addr1)->addr[1] == (addr2)->addr[1]) && \ - ((addr1)->addr[2] == (addr2)->addr[2]) && \ - ((addr1)->addr[3] == (addr2)->addr[3])) - -#define ip6_get_subnet_id(ip6addr) (htonl((ip6addr)->addr[2]) & 0x0000ffffUL) - -#define ip6_addr_isany_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_isipv6mappedipv4(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) ((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)) - -/* @todo define get/set for well-know multicast addresses, e.g. ff02::1 */ -#define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \ - ((ip6addr)->addr[1] == 0UL) && \ - ((ip6addr)->addr[2] == 0UL) && \ - ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) - -#define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ - ((ip6addr)->addr[1] == 0UL) && \ - ((ip6addr)->addr[2] == 0UL) && \ - ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) -#define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) - -#define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ - ((ip6addr)->addr[1] == 0UL) && \ - ((ip6addr)->addr[2] == 0UL) && \ - ((ip6addr)->addr[3] == PP_HTONL(0x00000002UL))) -#define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = PP_HTONL(0x00000002UL);}while(0) - -#define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ - ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ - (((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) ) - -#define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \ - (ip6addr)->addr[3] = (PP_HTONL(0xff000000UL) | (if_id));}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 -#define IP6_ADDR_PREFERRED 0x30 -#define IP6_ADDR_DEPRECATED 0x50 - -#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID) -#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE) -#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */ -#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED) -#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED) - -#define ip6_addr_debug_print_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/ext/lwip/src/include/lwip/ip6_frag.h b/ext/lwip/src/include/lwip/ip6_frag.h deleted file mode 100644 index d625e4e..0000000 --- a/ext/lwip/src/include/lwip/ip6_frag.h +++ /dev/null @@ -1,120 +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 */ - -/** IP6_FRAG_COPYHEADER==1: for platforms where sizeof(void*) > 4, this needs to - * be enabled (to not overwrite part of the data). When enabled, the IPv6 header - * is copied instead of referencing it, which gives more room for struct ip6_reass_helper */ -#ifndef IPV6_FRAG_COPYHEADER -#define IPV6_FRAG_COPYHEADER 0 -#endif - -/** The IPv6 reassembly timer interval in milliseconds. */ -#define IP6_REASS_TMR_INTERVAL 1000 - -/* Copy the complete header of the first fragment to struct ip6_reassdata - or just point to its original location in the first pbuf? */ -#if IPV6_FRAG_COPYHEADER -#define IPV6_FRAG_HDRPTR -#define IPV6_FRAG_HDRREF(hdr) (&(hdr)) -#else /* IPV6_FRAG_COPYHEADER */ -#define IPV6_FRAG_HDRPTR * -#define IPV6_FRAG_HDRREF(hdr) (hdr) -#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 IPV6_FRAG_HDRPTR iphdr; - u32_t identification; - u16_t datagram_len; - u8_t nexth; - u8_t timer; -}; - -#define ip6_reass_init() /* Compatibility define */ -void ip6_reass_tmr(void); -struct pbuf * ip6_reass(struct pbuf *p); - -#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ - -#if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ - -#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/ext/lwip/src/include/lwip/ip_addr.h b/ext/lwip/src/include/lwip/ip_addr.h deleted file mode 100644 index d2690e8..0000000 --- a/ext/lwip/src/include/lwip/ip_addr.h +++ /dev/null @@ -1,360 +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 - -/** These are the values for ip_addr_t.type */ -#define IPADDR_TYPE_V4 0U -#define IPADDR_TYPE_V6 6U -#define 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; - 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 } } }, IPADDR_TYPE_V4 } -/** @ingroup ip6addr */ -#define IPADDR6_INIT(a, b, c, d) { { { { a, b, c, d } } }, 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 } } }, 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_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 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))); }}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 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); }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); }}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)); }}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); }}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); }}while(0) -/** @ingroup ipaddr */ -#define ip_addr_set_hton(dest, src) do{if(IP_IS_V6(src)){ \ - ip6_addr_set_hton(ip_2_ip6(ipaddr), (src)); IP_SET_TYPE(dest, IPADDR_TYPE_V6); }else{ \ - ip4_addr_set_hton(ip_2_ip4(ipaddr), (src)); IP_SET_TYPE(dest, IPADDR_TYPE_V4); }}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_isany(ipaddr) ((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) -/** @ingroup ipaddr */ -#define ipaddr_ntoa(addr) (((addr) == NULL) ? "NULL" : \ - ((IP_IS_V6(addr)) ? ip6addr_ntoa(ip_2_ip6(addr)) : ip4addr_ntoa(ip_2_ip4(addr)))) -/** @ingroup ipaddr */ -#define ipaddr_ntoa_r(addr, buf, buflen) (((addr) == NULL) ? "NULL" : \ - ((IP_IS_V6(addr)) ? ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen) : ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen))) -int ipaddr_aton(const char *cp, ip_addr_t *addr); - -/** @ingroup ipaddr */ -#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX - -#else /* LWIP_IPV4 && LWIP_IPV6 */ - -#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1 -#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) 1 - -#if LWIP_IPV4 - -typedef ip4_addr_t ip_addr_t; -#define IPADDR4_INIT(u32val) { u32val } -#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_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_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 - -#else /* LWIP_IPV4 */ - -typedef ip6_addr_t ip_addr_t; -#define IPADDR6_INIT(a, b, c, d) { { a, b, c, d } } -#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_2_ip6(ipaddr) (ipaddr) -#define IP_ADDR6(ipaddr,i0,i1,i2,i3) IP6_ADDR(ipaddr,i0,i1,i2,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_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_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 - -#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 ipaddr - * IP_ADDR_ can be used as a fixed/const ip_addr_t - * for the IPv4 wildcard and the broadcast address - */ -#define IP_ADDR_ANY (&ip_addr_any) -/** @ingroup ipaddr */ -#define IP_ADDR_BROADCAST (&ip_addr_broadcast) -/** - * @ingroup ip4addr - * IP4_ADDR_ can be used as a fixed/const ip4_addr_t - * for the wildcard and the broadcast address - */ -#define IP4_ADDR_ANY (ip_2_ip4(&ip_addr_any)) -/** @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 -/** Just a little upgrade-helper for 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/ext/lwip/src/include/lwip/mem.h b/ext/lwip/src/include/lwip/mem.h deleted file mode 100644 index e4f6a64..0000000 --- a/ext/lwip/src/include/lwip/mem.h +++ /dev/null @@ -1,81 +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 /* for size_t */ -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/ext/lwip/src/include/lwip/memp.h b/ext/lwip/src/include/lwip/memp.h deleted file mode 100644 index 8a555c8..0000000 --- a/ext/lwip/src/include/lwip/memp.h +++ /dev/null @@ -1,153 +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 - -#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]; - -#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 prototype for private memory pool if it is used in multiple files - */ -#define LWIP_MEMPOOL_PROTOTYPE(name) extern const struct memp_desc memp_ ## name - -/** - * @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[]; - */ -#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/ext/lwip/src/include/lwip/mld6.h b/ext/lwip/src/include/lwip/mld6.h deleted file mode 100644 index 6fcd110..0000000 --- a/ext/lwip/src/include/lwip/mld6.h +++ /dev/null @@ -1,120 +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; - /** interface on which the group is active */ - struct netif *netif; - /** multicast address */ - ip6_addr_t group_address; - /** signifies we were the last person to report */ - u8_t last_reporter_flag; - /** current state of the group */ - u8_t group_state; - /** timer for reporting */ - u16_t timer; - /** counter of simultaneous uses */ - u8_t use; -}; - -/** Multicast listener report/query/done message header. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct mld_header { - PACK_STRUCT_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 - -#define MLD6_TMR_INTERVAL 100 /* Milliseconds */ - -/* MAC Filter Actions, these are passed to a netif's - * mld_mac_filter callback function. */ -#define MLD6_DEL_MAC_FILTER 0 -#define MLD6_ADD_MAC_FILTER 1 - - -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); - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */ - -#endif /* LWIP_HDR_MLD6_H */ diff --git a/ext/lwip/src/include/lwip/nd6.h b/ext/lwip/src/include/lwip/nd6.h deleted file mode 100644 index 5e09651..0000000 --- a/ext/lwip/src/include/lwip/nd6.h +++ /dev/null @@ -1,362 +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/pbuf.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/netif.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -/** Struct for tables. */ -struct nd6_neighbor_cache_entry { - ip6_addr_t next_hop_address; - struct netif * netif; - u8_t lladdr[NETIF_MAX_HWADDR_LEN]; - /*u32_t pmtu;*/ -#if LWIP_ND6_QUEUEING - /** Pointer to queue of pending outgoing packets on this entry. */ - struct nd6_q_entry *q; -#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; - u32_t delay_time; - u32_t probes_sent; - u32_t stale_time; - } counter; -}; - -struct nd6_destination_cache_entry { - ip6_addr_t destination_addr; - ip6_addr_t next_hop_addr; - u16_t pmtu; - u32_t age; -}; - -struct nd6_prefix_list_entry { - ip6_addr_t prefix; - struct netif * netif; - u32_t invalidation_timer; -#if LWIP_IPV6_AUTOCONFIG - u8_t flags; -#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01 -#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02 -#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04 -#endif /* LWIP_IPV6_AUTOCONFIG */ -}; - -struct nd6_router_list_entry { - struct nd6_neighbor_cache_entry * neighbor_entry; - u32_t invalidation_timer; - u8_t flags; -}; - - -enum nd6_neighbor_cache_entry_state { - ND6_NO_ENTRY = 0, - ND6_INCOMPLETE, - ND6_REACHABLE, - ND6_STALE, - ND6_DELAY, - ND6_PROBE -}; - -#if LWIP_ND6_QUEUEING -/** struct for queueing outgoing packets for unknown address - * defined here to be accessed by memp.h - */ -struct nd6_q_entry { - struct nd6_q_entry *next; - struct pbuf *p; -}; -#endif /* LWIP_ND6_QUEUEING */ - -/** Neighbor solicitation message header. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ns_header { - PACK_STRUCT_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 - -/** 1 second period */ -#define ND6_TMR_INTERVAL 1000 - -/* Router tables. */ -/* @todo make these static? and entries accessible through API? */ -extern struct nd6_neighbor_cache_entry neighbor_cache[]; -extern struct nd6_destination_cache_entry destination_cache[]; -extern struct nd6_prefix_list_entry prefix_list[]; -extern struct nd6_router_list_entry default_router_list[]; - -/* Default values, can be updated by a RA message. */ -extern u32_t reachable_time; -extern u32_t retrans_timer; - -void nd6_tmr(void); -void nd6_input(struct pbuf *p, struct netif *inp); -s8_t nd6_get_next_hop_entry(const ip6_addr_t * ip6addr, struct netif * netif); -s8_t nd6_select_router(const ip6_addr_t * ip6addr, struct netif * netif); -u16_t nd6_get_destination_mtu(const ip6_addr_t * ip6addr, struct netif * netif); -err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p); -#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); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 */ - -#endif /* LWIP_HDR_ND6_H */ diff --git a/ext/lwip/src/include/lwip/netbuf.h b/ext/lwip/src/include/lwip/netbuf.h deleted file mode 100644 index e6865f8..0000000 --- a/ext/lwip/src/include/lwip/netbuf.h +++ /dev/null @@ -1,118 +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 -#if LWIP_CHECKSUM_ON_COPY - u8_t flags; -#endif /* LWIP_CHECKSUM_ON_COPY */ - u16_t toport_chksum; -#if LWIP_NETBUF_RECVINFO - ip_addr_t toaddr; -#endif /* LWIP_NETBUF_RECVINFO */ -#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ -}; - -/* Network buffer functions: */ -struct netbuf * netbuf_new (void); -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/ext/lwip/src/include/lwip/netdb.h b/ext/lwip/src/include/lwip/netdb.h deleted file mode 100644 index 21688c6..0000000 --- a/ext/lwip/src/include/lwip/netdb.h +++ /dev/null @@ -1,151 +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 /* for size_t */ - -#include "lwip/inet.h" -#include "lwip/sockets.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* some rarely used options */ -#ifndef LWIP_DNS_API_DECLARE_H_ERRNO -#define LWIP_DNS_API_DECLARE_H_ERRNO 1 -#endif - -#ifndef LWIP_DNS_API_DEFINE_ERRORS -#define LWIP_DNS_API_DEFINE_ERRORS 1 -#endif - -#ifndef LWIP_DNS_API_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/ext/lwip/src/include/lwip/netif.h b/ext/lwip/src/include/lwip/netif.h deleted file mode 100644 index 8903a56..0000000 --- a/ext/lwip/src/include/lwip/netif.h +++ /dev/null @@ -1,442 +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" - -#if LWIP_DHCP -struct dhcp; -#endif -#if LWIP_AUTOIP -struct autoip; -#endif -#if LWIP_IPV6_DHCP6 -struct dhcp6; -#endif /* LWIP_IPV6_DHCP6 */ - -#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 - -/** - * @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 - -/** - * @} - */ - -#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; - -/** Function prototype for netif init functions. Set up flags and output/linkoutput - * callback functions in this function. - * - * @param netif The netif to initialize - */ -typedef err_t (*netif_init_fn)(struct netif *netif); -/** Function prototype for netif->input functions. This function is saved as 'input' - * callback function in the netif struct. Call it when a packet has been received. - * - * @param p The received packet, copied into a pbuf - * @param inp The netif which received the packet - */ -typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); - -#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, u8_t 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, u8_t action); -#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - -/** Generic data structure used for all lwIP network interfaces. - * The following fields should be filled in by the initialization - * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ -struct netif { - /** pointer to next in linked list */ - struct netif *next; - -#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]; -#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. */ - netif_output_fn output; -#endif /* LWIP_IPV4 */ - /** This function is called by the ARP module when it wants - * to send a packet on the interface. This function outputs - * the pbuf as-is on the link medium. */ - netif_linkoutput_fn linkoutput; -#if LWIP_IPV6 - /** This function is called by the IPv6 module when it wants - * to send a packet on the interface. This function typically - * first resolves the hardware address, then sends the packet. */ - netif_output_ip6_fn output_ip6; -#endif /* LWIP_IPV6 */ -#if LWIP_NETIF_STATUS_CALLBACK - /** This function is called when the netif state is set to up or down - */ - 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; -#if LWIP_DHCP - /** the DHCP client state information for this netif */ - struct dhcp *dhcp; -#endif /* LWIP_DHCP */ -#if LWIP_AUTOIP - /** the AutoIP client state information for this netif */ - struct autoip *autoip; -#endif -#if LWIP_IPV6_AUTOCONFIG - /** is this netif enabled for IPv6 autoconfiguration */ - u8_t ip6_autoconfig_enabled; -#endif /* LWIP_IPV6_AUTOCONFIG */ -#if LWIP_IPV6_SEND_ROUTER_SOLICIT - /** Number of Router Solicitation messages that remain to be sent. */ - u8_t rs_count; -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -#if LWIP_IPV6_DHCP6 - /** the DHCPv6 client state information for this netif */ - struct dhcp6 *dhcp6; -#endif /* LWIP_IPV6_DHCP6 */ -#if LWIP_NETIF_HOSTNAME - /* the hostname for this netif, NULL is a valid value */ - 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; - /** number of bytes used in hwaddr */ - u8_t hwaddr_len; - /** link level hardware address of this interface */ - u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; - /** flags (@see @ref netif_flags) */ - u8_t flags; - /** descriptive abbreviation */ - char name[2]; - /** number of this interface */ - u8_t num; -#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_HWADDRHINT - u8_t *addr_hint; -#endif /* LWIP_NETIF_HWADDRHINT */ -#if ENABLE_LOOPBACK - /* List of packets to be queued for ourselves. */ - struct pbuf *loop_first; - struct pbuf *loop_last; -#if LWIP_LOOPBACK_MAX_PBUFS - u16_t loop_cnt_current; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ -#endif /* ENABLE_LOOPBACK */ -}; - -#if LWIP_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 */ - -/** The list of network interfaces. */ -extern struct netif *netif_list; -/** The default network interface. */ -extern struct netif *netif_default; - -void netif_init(void); - -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_IPV4 -void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, - const ip4_addr_t *gw); -#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); -#define netif_ip4_addr(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->ip_addr))) -#define netif_ip4_netmask(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->netmask))) -#define netif_ip4_gw(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->gw))) -#define netif_ip_addr4(netif) ((const ip_addr_t*)&((netif)->ip_addr)) -#define netif_ip_netmask4(netif) ((const ip_addr_t*)&((netif)->netmask)) -#define netif_ip_gw4(netif) ((const ip_addr_t*)&((netif)->gw)) -#endif /* LWIP_IPV4 */ - -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 -#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) -#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) -#endif /* LWIP_NETIF_HOSTNAME */ - -#if LWIP_IGMP -#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) -#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) -#endif /* LWIP_IGMP */ - -#if LWIP_IPV6 && LWIP_IPV6_MLD -#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 */ -#define netif_ip_addr6(netif, i) ((const ip_addr_t*)(&((netif)->ip6_addr[i]))) -/** @ingroup netif */ -#define netif_ip6_addr(netif, i) ((const ip6_addr_t*)ip_2_ip6(&((netif)->ip6_addr[i]))) -#define netif_ip6_addr_set(netif, i, addr6) do { ip6_addr_set(ip_2_ip6(&((netif)->ip6_addr[i])), addr6); IP_SET_TYPE_VAL((netif)->ip6_addr[i], IPADDR_TYPE_V6); } while(0) -#define netif_ip6_addr_state(netif, i) ((netif)->ip6_addr_state[i]) -#define netif_ip6_addr_set_state(netif, i, state) ((netif)->ip6_addr_state[i] = (state)) -s8_t netif_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) -#endif /* LWIP_IPV6 */ - -#if LWIP_NETIF_HWADDRHINT -#define NETIF_SET_HWADDRHINT(netif, hint) ((netif)->addr_hint = (hint)) -#else /* LWIP_NETIF_HWADDRHINT */ -#define NETIF_SET_HWADDRHINT(netif, hint) -#endif /* LWIP_NETIF_HWADDRHINT */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_NETIF_H */ diff --git a/ext/lwip/src/include/lwip/netifapi.h b/ext/lwip/src/include/lwip/netifapi.h deleted file mode 100644 index 20f8bca..0000000 --- a/ext/lwip/src/include/lwip/netifapi.h +++ /dev/null @@ -1,136 +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" - -#ifdef __cplusplus -extern "C" { -#endif - -#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; - } msg; -}; - - -/* API for application */ -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 */ -#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) -/** @ingroup netifapi_netif */ -#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) -/** @ingroup netifapi_netif */ -#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) -/** @ingroup netifapi_netif */ -#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) - -/** - * @defgroup netifapi_dhcp4 DHCPv4 - * @ingroup netifapi - * To be called from non-TCPIP threads - */ -/** @ingroup netifapi_dhcp4 */ -#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start) -/** @ingroup netifapi_dhcp4 */ -#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL) -/** @ingroup netifapi_dhcp4 */ -#define netifapi_dhcp_inform(n) netifapi_netif_common(n, dhcp_inform, NULL) -/** @ingroup netifapi_dhcp4 */ -#define netifapi_dhcp_renew(n) netifapi_netif_common(n, NULL, dhcp_renew) -/** @ingroup netifapi_dhcp4 */ -#define netifapi_dhcp_release(n) netifapi_netif_common(n, NULL, dhcp_release) - -/** - * @defgroup netifapi_autoip AUTOIP - * @ingroup netifapi - * To be called from non-TCPIP threads - */ -/** @ingroup netifapi_autoip */ -#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start) -/** @ingroup netifapi_autoip */ -#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/ext/lwip/src/include/lwip/opt.h b/ext/lwip/src/include/lwip/opt.h deleted file mode 100644 index b37124c..0000000 --- a/ext/lwip/src/include/lwip/opt.h +++ /dev/null @@ -1,2797 +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 -/** - * @} - */ - -/* - ------------------------------------ - ----------- 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 -/** - * @} - */ - -/* - ------------------------------------ - ---------- 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 - -/** - * 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_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_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 IP_FRAG_USES_STATIC_BUF==0 and - * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs - * where the packet is not yet sent when netif->output returns. - */ -#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 - -/** - * 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_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)) -#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_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_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be - * updated with the source MAC and IP addresses supplied in the packet. - * You may want to disable this if you do not trust LAN peers to have the - * correct addresses, or as a limited approach to attempt to handle - * spoofing. If disabled, lwIP will need to make a new ARP request if - * the peer is not already in the ARP table, adding a little latency. - * The peer *is* in the ARP table if it requested our address before. - * Also notice that this slows down input processing of every IP packet! - */ -#if !defined ETHARP_TRUST_IP_MAC || defined __DOXYGEN__ -#define ETHARP_TRUST_IP_MAC 0 -#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 0 -#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 3 -#endif - -/** - * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. - * Since the received pbufs are enqueued, be sure to configure - * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive - * packets even if the maximum amount of fragments is enqueued for reassembly! - */ -#if !defined IP_REASS_MAX_PBUFS || defined __DOXYGEN__ -#define IP_REASS_MAX_PBUFS 10 -#endif - -/** - * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP - * fragmentation. Otherwise pbufs are allocated and reference the original - * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, - * new PBUF_RAM pbufs are used for fragments). - * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! - */ -#if !defined IP_FRAG_USES_STATIC_BUF || defined __DOXYGEN__ -#define IP_FRAG_USES_STATIC_BUF 0 -#endif - -/** - * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer - * (requires IP_FRAG_USES_STATIC_BUF==1) - */ -#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) || defined __DOXYGEN__ -#define IP_FRAG_MAX_MTU 1500 -#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 - -/** - * LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first - * local TCP/UDP pcb (default==0). This can prevent creating predictable port - * numbers after booting a device. - */ -#if !defined LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS || defined __DOXYGEN__ -#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 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_CHECK_LINK_UP==1: dhcp_start() only really starts if the netif has - * NETIF_FLAG_LINK_UP set in its flags. As this is only an optimization and - * netif drivers might not set this flag, the default is off. If enabled, - * netif_set_link_up() must be called to continue dhcp starting. - */ -#if !defined LWIP_DHCP_CHECK_LINK_UP -#define LWIP_DHCP_CHECK_LINK_UP 0 -#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 -/** - * @} - */ - -/* - ------------------------------------ - ---------- 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/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 - -/** - * LWIP_MULTICAST_TX_OPTIONS==1: Enable multicast TX support like the socket options - * IP_MULTICAST_TTL/IP_MULTICAST_IF/IP_MULTICAST_LOOP - */ -#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ -#define LWIP_MULTICAST_TX_OPTIONS LWIP_IGMP -#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 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 - * \#define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} - * (an array of structs name/address, where address is an u32_t in network - * byte order). - * - * Instead, you can also use an external function: - * \#define DNS_LOOKUP_LOCAL_EXTERN(x) extern 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 */ -/** - * @} - */ - -/* - --------------------------------- - ---------- 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 - */ -#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 - -/** - * 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 maximum number of bytes queued on ooseq per pcb. - * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0. - */ -#if !defined TCP_OOSEQ_MAX_BYTES || defined __DOXYGEN__ -#define TCP_OOSEQ_MAX_BYTES 0 -#endif - -/** - * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb. - * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0. - */ -#if !defined TCP_OOSEQ_MAX_PBUFS || defined __DOXYGEN__ -#define TCP_OOSEQ_MAX_PBUFS 0 -#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 -#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 -/** - * @} - */ - -/* - ---------------------------------- - ---------- 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 -/** - * @} - */ - -/* - ------------------------------------------------ - ---------- Network Interfaces options ---------- - ------------------------------------------------ -*/ -/** - * @defgroup lwip_opts_netif NETIF - * @ingroup lwip_opts - * @{ - */ -/** - * 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_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! - * - * @todo: TCP and IP-frag do not work with this, yet: - */ -#if !defined LWIP_NETIF_TX_SINGLE_PBUF || defined __DOXYGEN__ -#define LWIP_NETIF_TX_SINGLE_PBUF 0 -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ -/** - * @} - */ - -/* - ------------------------------------ - ---------- 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 -#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_SOCKET_SET_ERRNO==1: Set errno when socket functions cannot complete - * successfully, as required by POSIX. Default is POSIX-compliant. - */ -#if !defined LWIP_SOCKET_SET_ERRNO || defined __DOXYGEN__ -#define LWIP_SOCKET_SET_ERRNO 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 -/** - * @} - */ - -/* - ---------------------------------------- - ---------- 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 - -/** - * 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 0 -#endif - -/** - * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented - */ -#if !defined LWIP_IPV6_REASS || defined __DOXYGEN__ || 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_DUP_DETECT_ATTEMPTS: 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 !defined LWIP_IPV6_MLD || defined __DOXYGEN__ -#define LWIP_IPV6_MLD (LWIP_IPV6) -#endif - -/** - * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast that can be joined. - */ -#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__s -#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__ || defined __DOXYGEN__ -#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 -#endif -/** - * @} - */ - -/** - * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration. - */ -#if !defined LWIP_IPV6_DHCP6 || defined __DOXYGEN__ -#define LWIP_IPV6_DHCP6 0 -#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_IP4_INPUT(pbuf, input_netif): - * - called from ip_input() (IPv4) - * - 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) - * - dest: destination IPv4 address - * Returns the destination netif or 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(dest, src): - * - source-based routing for IPv4 (see LWIP_HOOK_IP4_ROUTE(), src may be NULL) - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_IP4_ROUTE_SRC(dest, src) -#endif - -/** - * LWIP_HOOK_ETHARP_GET_GW(netif, dest): - * - called from etharp_output() (IPv4) - * - netif: the netif used for sending - * - dest: the destination IPv4 address - * Returns the IPv4 address of the gateway to handle the specified destination - * IPv4 address. If NULL is returned, the netif's default gateway is used. - * The returned address MUST be 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) - * - 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 ip6_route() (IPv6) - * - src: sourc IPv6 address - * - dest: destination IPv6 address - * Returns the destination netif or 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_VLAN_CHECK(netif, eth_hdr, vlan_hdr): - * - called from ethernet_input() if VLAN support is enabled - * - 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(netif, eth_hdr, vlan_hdr): - * - called from etharp_raw() and etharp_send_ip() if VLAN support is enabled - * - netif: struct netif that the packet will be sent through - * - eth_hdr: struct eth_hdr of the packet - * - vlan_hdr: struct eth_vlan_hdr of the packet - * Return values: - * - 0: Packet shall not contain VLAN header. - * - != 0: Packet shall contain VLAN header. - * Hook can be used to set prio_vid field of vlan_hdr. - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_VLAN_SET(netif, eth_hdr, vlan_hdr) -#endif - -/** - * LWIP_HOOK_MEMP_AVAILABLE(memp_t_type): - * - called from memp_free() when a memp pool was empty and an item is now available - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_MEMP_AVAILABLE(memp_t_type) -#endif -/** - * @} - */ - -/* - --------------------------------------- - ---------- Debugging options ---------- - --------------------------------------- -*/ -/** - * @defgroup lwip_opts_debugmsg Debugging - * @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. - */ -#if !defined LWIP_DBG_MIN_LEVEL || defined __DOXYGEN__ || 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. - */ -#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 -/** - * @} - */ - -/* - -------------------------------------------------- - ---------- 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/ext/lwip/src/include/lwip/pbuf.h b/ext/lwip/src/include/lwip/pbuf.h deleted file mode 100644 index a3a761f..0000000 --- a/ext/lwip/src/include/lwip/pbuf.h +++ /dev/null @@ -1,238 +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 && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG)) -#endif - -/* @todo: We need a mechanism to prevent wasting memory in every pbuf - (TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */ - -#define PBUF_TRANSPORT_HLEN 20 -#if LWIP_IPV6 -#define PBUF_IP_HLEN 40 -#else -#define PBUF_IP_HLEN 20 -#endif - -typedef enum { - PBUF_TRANSPORT, - PBUF_IP, - PBUF_LINK, - PBUF_RAW_TX, - PBUF_RAW -} pbuf_layer; - -/** - * @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) */ - PBUF_RAM, - /** 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 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 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) */ - 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; - - /** pbuf_type as u8_t instead of enum to save space */ - u8_t /*pbuf_type*/ type; - - /** misc flags */ - u8_t flags; - - /** - * the reference count always equals the number of pointers - * that refer to this pbuf. This can be pointers from an application, - * the stack itself, or pbuf->next pointers from a chain. - */ - u16_t ref; -}; - - -/** 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); -#if LWIP_SUPPORT_CUSTOM_PBUF -struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, - struct pbuf_custom *p, void *payload_mem, - u16_t payload_mem_len); -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ -void pbuf_realloc(struct pbuf *p, u16_t size); -u8_t pbuf_header(struct pbuf *p, s16_t header_size); -u8_t pbuf_header_force(struct pbuf *p, s16_t header_size); -void pbuf_ref(struct pbuf *p); -u8_t pbuf_free(struct pbuf *p); -u8_t pbuf_clen(struct pbuf *p); -void pbuf_cat(struct pbuf *head, struct pbuf *tail); -void pbuf_chain(struct pbuf *head, struct pbuf *tail); -struct pbuf *pbuf_dechain(struct pbuf *p); -err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from); -u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset); -err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); -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); -#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(struct pbuf* p, u16_t offset); -void pbuf_put_at(struct pbuf* p, u16_t offset, u8_t data); -u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n); -u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset); -u16_t pbuf_strstr(struct pbuf* p, const char* substr); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PBUF_H */ diff --git a/ext/lwip/src/include/lwip/priv/api_msg.h b/ext/lwip/src/include/lwip/priv/api_msg.h deleted file mode 100644 index ad38345..0000000 --- a/ext/lwip/src/include/lwip/priv/api_msg.h +++ /dev/null @@ -1,217 +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" - -#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 /* for size_t */ - -#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_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; - } 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 { - const void *dataptr; - size_t len; - u8_t apiflags; -#if LWIP_SO_SNDTIMEO - u32_t time_started; -#endif /* LWIP_SO_SNDTIMEO */ - } w; - /** used for lwip_netconn_do_recv */ - struct { - u32_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); - 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_TCP -extern u8_t netconn_aborted; -#endif /* LWIP_TCP */ - -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_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); -#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); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_NETCONN || LWIP_SOCKET */ - -#endif /* LWIP_HDR_API_MSG_H */ diff --git a/ext/lwip/src/include/lwip/priv/memp_priv.h b/ext/lwip/src/include/lwip/priv/memp_priv.h deleted file mode 100644 index f246061..0000000 --- a/ext/lwip/src/include/lwip/priv/memp_priv.h +++ /dev/null @@ -1,183 +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" - -#if MEMP_OVERFLOW_CHECK -/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning - * and at the end of each element, initialize them as 0xcd and check - * them later. */ -/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free, - * every single element in each pool is checked! - * This is VERY SLOW but also very helpful. */ -/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in - * lwipopts.h to change the amount reserved for checking. */ -#ifndef MEMP_SANITY_REGION_BEFORE -#define MEMP_SANITY_REGION_BEFORE 16 -#endif /* MEMP_SANITY_REGION_BEFORE*/ -#if MEMP_SANITY_REGION_BEFORE > 0 -#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE) -#else -#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0 -#endif /* MEMP_SANITY_REGION_BEFORE*/ -#ifndef MEMP_SANITY_REGION_AFTER -#define MEMP_SANITY_REGION_AFTER 16 -#endif /* MEMP_SANITY_REGION_AFTER*/ -#if MEMP_SANITY_REGION_AFTER > 0 -#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER) -#else -#define MEMP_SANITY_REGION_AFTER_ALIGNED 0 -#endif /* MEMP_SANITY_REGION_AFTER*/ - -/* MEMP_SIZE: save space for struct memp and for sanity check */ -#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED) -#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED) - -#else /* MEMP_OVERFLOW_CHECK */ - -/* No sanity checks - * We don't need to preserve the struct memp while not allocated, so we - * can save a little space and set MEMP_SIZE to 0. - */ -#define MEMP_SIZE 0 -#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) - -#endif /* MEMP_OVERFLOW_CHECK */ - -#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/ext/lwip/src/include/lwip/priv/memp_std.h b/ext/lwip/src/include/lwip/priv/memp_std.h deleted file mode 100644 index ee3e253..0000000 --- a/ext/lwip/src/include/lwip/priv/memp_std.h +++ /dev/null @@ -1,146 +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, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_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_IPV4 && IP_REASSEMBLY -LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA") -#endif /* LWIP_IPV4 && IP_REASSEMBLY */ -#if (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !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 && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ - -#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_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_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "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/ext/lwip/src/include/lwip/priv/tcp_priv.h b/ext/lwip/src/include/lwip/priv/tcp_priv.h deleted file mode 100644 index 957408d..0000000 --- a/ext/lwip/src/include/lwip/priv/tcp_priv.h +++ /dev/null @@ -1,550 +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_IMPL_H -#define LWIP_HDR_TCP_IMPL_H - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/tcp.h" -#include "lwip/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 - -/* 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_abandon (struct tcp_pcb *pcb, int reset); -err_t tcp_send_empty_ack(struct tcp_pcb *pcb); -void tcp_rexmit (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)) -#define TCP_FIN 0x01U -#define TCP_SYN 0x02U -#define TCP_RST 0x04U -#define TCP_PSH 0x08U -#define TCP_ACK 0x10U -#define TCP_URG 0x20U -#define TCP_ECE 0x40U -#define TCP_CWR 0x80U - -#define TCP_FLAGS 0x3fU - -/* Length of the TCP header, excluding options. */ -#define TCP_HLEN 20 - -#ifndef TCP_TMR_INTERVAL -#define TCP_TMR_INTERVAL 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 */ - -/* Fields are (of course) in network byte order. - * Some fields are converted to host byte order in tcp_input(). - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct tcp_hdr { - PACK_STRUCT_FIELD(u16_t src); - PACK_STRUCT_FIELD(u16_t dest); - PACK_STRUCT_FIELD(u32_t seqno); - PACK_STRUCT_FIELD(u32_t ackno); - PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); - PACK_STRUCT_FIELD(u16_t wnd); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u16_t urgp); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define TCPH_HDRLEN(phdr) ((u16_t)(ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)) -#define TCPH_FLAGS(phdr) ((u16_t)(ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)) - -#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) -#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS(~TCP_FLAGS)) | htons(flags)) -#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags)) - -#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags)) -#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags & ~htons(flags)) - -#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) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_POLL, NULL, 0, ERR_OK) -#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \ - LWIP_EVENT_ERR, NULL, 0, (err)) - -#else /* LWIP_EVENT_API */ - -#define TCP_EVENT_ACCEPT(lpcb,pcb,arg,err,ret) \ - do { \ - if((lpcb != NULL) && ((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(errf,arg,err) \ - do { \ - if((errf) != NULL) \ - (errf)((arg),(err)); \ - } while (0) - -#endif /* LWIP_EVENT_API */ - -/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */ -#if TCP_OVERSIZE && defined(LWIP_DEBUG) -#define TCP_OVERSIZE_DBGCHECK 1 -#else -#define TCP_OVERSIZE_DBGCHECK 0 -#endif - -/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */ -#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP) - -/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */ -struct tcp_seg { - struct tcp_seg *next; /* used when putting 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_oversized only) */ -#endif /* TCP_OVERSIZE_DBGCHECK */ -#if TCP_CHECKSUM_ON_COPY - u16_t chksum; - u8_t chksum_swapped; -#endif /* TCP_CHECKSUM_ON_COPY */ - u8_t flags; -#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ -#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ -#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is - checksummed into 'chksum' */ -#define TF_SEG_OPTS_WND_SCALE (u8_t)0x08U /* Include WND SCALE option */ - 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_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 - -#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) - -/** This returns a TCP header option for MSS in an u32_t */ -#define TCP_BUILD_MSS_OPTION(mss) 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 %d\n", (npcb), (npcb)->local_port)); \ - for (tcp_tmp_pcb = *(pcbs); \ - tcp_tmp_pcb != NULL; \ - tcp_tmp_pcb = tcp_tmp_pcb->next) { \ - LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ - } \ - LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ - (npcb)->next = *(pcbs); \ - LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ - *(pcbs) = (npcb); \ - LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ - tcp_timer_needed(); \ - } while(0) -#define TCP_RMV(pcbs, npcb) do { \ - 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", (npcb), *(pcbs))); \ - if(*(pcbs) == (npcb)) { \ - *(pcbs) = (*pcbs)->next; \ - } else for (tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ - if(tcp_tmp_pcb->next == (npcb)) { \ - tcp_tmp_pcb->next = (npcb)->next; \ - break; \ - } \ - } \ - (npcb)->next = NULL; \ - LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ - } while(0) - -#else /* LWIP_DEBUG */ - -#define TCP_REG(pcbs, npcb) \ - do { \ - (npcb)->next = *pcbs; \ - *(pcbs) = (npcb); \ - tcp_timer_needed(); \ - } while (0) - -#define TCP_RMV(pcbs, npcb) \ - do { \ - if(*(pcbs) == (npcb)) { \ - (*(pcbs)) = (*pcbs)->next; \ - } \ - else { \ - 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) { \ - (pcb)->flags &= ~TF_ACK_DELAY; \ - (pcb)->flags |= TF_ACK_NOW; \ - } \ - else { \ - (pcb)->flags |= TF_ACK_DELAY; \ - } \ - } while (0) - -#define tcp_ack_now(pcb) \ - do { \ - (pcb)->flags |= TF_ACK_NOW; \ - } while (0) - -err_t tcp_send_fin(struct tcp_pcb *pcb); -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(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(void); - -err_t tcp_keepalive(struct tcp_pcb *pcb); -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_impl(u16_t sendmss, const ip_addr_t *dest -#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING - , const ip_addr_t *src -#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ - ); -#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING -#define tcp_eff_send_mss(sendmss, src, dest) tcp_eff_send_mss_impl(sendmss, dest, src) -#else /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ -#define tcp_eff_send_mss(sendmss, src, dest) tcp_eff_send_mss_impl(sendmss, dest) -#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ -#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); - -#if LWIP_IPV4 -void tcp_netif_ipv4_addr_changed(const ip4_addr_t* old_addr, const ip4_addr_t* new_addr); -#endif /* LWIP_IPV4 */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_TCP */ - -#endif /* LWIP_HDR_TCP_H */ diff --git a/ext/lwip/src/include/lwip/priv/tcpip_priv.h b/ext/lwip/src/include/lwip/priv/tcpip_priv.h deleted file mode 100644 index d9fe37a..0000000 --- a/ext/lwip/src/include/lwip/priv/tcpip_priv.h +++ /dev/null @@ -1,160 +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(type, pool, name, errorval) do { \ - name = (type *)memp_malloc(pool); \ - if (name == NULL) { \ - return errorval; \ - } \ - } while(0) -#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(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 { - TCPIP_MSG_API, - TCPIP_MSG_API_CALL, - TCPIP_MSG_INPKT, -#if LWIP_TCPIP_TIMEOUT - TCPIP_MSG_TIMEOUT, - TCPIP_MSG_UNTIMEOUT, -#endif /* LWIP_TCPIP_TIMEOUT */ - TCPIP_MSG_CALLBACK, - TCPIP_MSG_CALLBACK_STATIC -}; - -struct tcpip_msg { - enum tcpip_msg_type type; - union { - 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; - struct { - struct pbuf *p; - struct netif *netif; - netif_input_fn input_fn; - } inp; - struct { - tcpip_callback_fn function; - void *ctx; - } cb; -#if LWIP_TCPIP_TIMEOUT - struct { - u32_t msecs; - sys_timeout_handler h; - void *arg; - } tmo; -#endif /* LWIP_TCPIP_TIMEOUT */ - } msg; -}; - -#ifdef __cplusplus -} -#endif - -#endif /* !NO_SYS */ - -#endif /* LWIP_HDR_TCPIP_PRIV_H */ diff --git a/ext/lwip/src/include/lwip/raw.h b/ext/lwip/src/include/lwip/raw.h deleted file mode 100644 index f92c8ee..0000000 --- a/ext/lwip/src/include/lwip/raw.h +++ /dev/null @@ -1,116 +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 - -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; - - /** 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); -err_t raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr); - -err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr); -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); - -/* The following functions are the lower layer interface to RAW. */ -u8_t raw_input (struct pbuf *p, struct netif *inp); -#define raw_init() /* Compatibility define, no init needed. */ - -/* for compatibility with older implementation */ -#define raw_new_ip6(proto) raw_new_ip_type(IPADDR_TYPE_V6, proto) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_RAW */ - -#endif /* LWIP_HDR_RAW_H */ diff --git a/ext/lwip/src/include/lwip/sio.h b/ext/lwip/src/include/lwip/sio.h deleted file mode 100644 index 7643e19..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/lwip/snmp.h b/ext/lwip/src/include/lwip/snmp.h deleted file mode 100644 index 8704d0b..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/lwip/sockets.h b/ext/lwip/src/include/lwip/sockets.h deleted file mode 100644 index 20ba629..0000000 --- a/ext/lwip/src/include/lwip/sockets.h +++ /dev/null @@ -1,592 +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 /* for size_t */ - -#include "lwip/ip_addr.h" -#include "lwip/err.h" -#include "lwip/inet.h" - -#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 - -struct lwip_sock; - -#if !LWIP_TCPIP_CORE_LOCKING -/** Maximum optlen used by setsockopt/getsockopt */ -#define LWIP_SETGETSOCKOPT_MAXOPTLEN 16 - -/** 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 */ - err_t err; - /** semaphore to wake up the calling task */ - void* completed_sem; -}; -#endif /* !LWIP_TCPIP_CORE_LOCKING */ - -#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; -}; - -/* 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 */ - - -/* - * 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 */ - - -/* - * Options for level IPPROTO_IP - */ -#define IP_TOS 1 -#define IP_TTL 2 - -#if LWIP_TCP -/* - * Options for level IPPROTO_TCP - */ -#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ -#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ -#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ -#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ -#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ -#endif /* LWIP_TCP */ - -#if LWIP_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 */ - -/* - * The Type of Service provides an indication of the abstract - * parameters of the quality of service desired. These parameters are - * to be used to guide the selection of the actual service parameters - * when transmitting a datagram through a particular network. Several - * networks offer service precedence, which somehow treats high - * precedence traffic as more important than other traffic (generally - * by accepting only traffic above a certain precedence at time of high - * load). The major choice is a three way tradeoff between low-delay, - * high-reliability, and high-throughput. - * The use of the Delay, Throughput, and Reliability indications may - * increase the cost (in some sense) of the service. In many networks - * better performance for one of these parameters is coupled with worse - * performance on another. Except for very unusual cases at most two - * of these three indications should be set. - */ -#define IPTOS_TOS_MASK 0x1E -#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) -#define IPTOS_LOWDELAY 0x10 -#define IPTOS_THROUGHPUT 0x08 -#define IPTOS_RELIABILITY 0x04 -#define IPTOS_LOWCOST 0x02 -#define IPTOS_MINCOST IPTOS_LOWCOST - -/* - * The Network Control precedence designation is intended to be used - * within a network only. The actual use and control of that - * designation is up to each network. The Internetwork Control - * designation is intended for use by gateway control originators only. - * If the actual use of these precedence designations is of concern to - * a particular network, it is the responsibility of that network to - * control the access to, and use of, those precedence designations. - */ -#define IPTOS_PREC_MASK 0xe0 -#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) -#define IPTOS_PREC_NETCONTROL 0xe0 -#define IPTOS_PREC_INTERNETCONTROL 0xc0 -#define IPTOS_PREC_CRITIC_ECP 0xa0 -#define IPTOS_PREC_FLASHOVERRIDE 0x80 -#define IPTOS_PREC_FLASH 0x60 -#define IPTOS_PREC_IMMEDIATE 0x40 -#define IPTOS_PREC_PRIORITY 0x20 -#define IPTOS_PREC_ROUTINE 0x00 - - -/* - * Commands for ioctlsocket(), taken from the BSD file fcntl.h. - * lwip_ioctl only supports FIONREAD and FIONBIO, for now - * - * Ioctl's have the command encoded in the lower word, - * and the size of any in or out parameters in the upper - * word. The high 2 bits of the upper word are used - * to encode the in/out status of the parameter; for now - * we restrict parameters to at most 128 bytes. - */ -#if !defined(FIONREAD) || !defined(FIONBIO) -#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ -#define IOC_VOID 0x20000000UL /* no parameters */ -#define IOC_OUT 0x40000000UL /* copy out parameters */ -#define IOC_IN 0x80000000UL /* copy in parameters */ -#define IOC_INOUT (IOC_IN|IOC_OUT) - /* 0x20000000 distinguishes new & - old ioctl's */ -#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) - -#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) - -#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) -#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ - -#ifndef FIONREAD -#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ -#endif -#ifndef FIONBIO -#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ -#endif - -/* Socket I/O Controls: unimplemented */ -#ifndef SIOCSHIWAT -#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ -#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ -#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ -#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ -#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ -#endif - -/* commands for fnctl */ -#ifndef F_GETFL -#define F_GETFL 3 -#endif -#ifndef F_SETFL -#define F_SETFL 4 -#endif - -/* File status flags and file access modes for fnctl, - these are bits in an int. */ -#ifndef O_NONBLOCK -#define O_NONBLOCK 1 /* nonblocking I/O */ -#endif -#ifndef O_NDELAY -#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ -#endif - -#ifndef SHUT_RD - #define SHUT_RD 0 - #define SHUT_WR 1 - #define SHUT_RDWR 2 -#endif - -/* FD_SET used for lwip_select */ -#ifndef FD_SET -#undef FD_SETSIZE -/* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ -#define FD_SETSIZE MEMP_NUM_NETCONN -#define 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] |= (1 << (((n)-LWIP_SOCKET_OFFSET) & 7))) -#define FD_CLR(n, p) FDSETSAFESET(n, (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 LWIP_SOCKET_OFFSET -#error LWIP_SOCKET_OFFSET does not work with external FD_SET! -#endif /* FD_SET */ - -/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided - * by your system, set this to 0 and include in cc.h */ -#ifndef LWIP_TIMEVAL_PRIVATE -#define LWIP_TIMEVAL_PRIVATE 1 -#endif - -#if LWIP_TIMEVAL_PRIVATE -struct timeval { - long tv_sec; /* seconds */ - long tv_usec; /* and microseconds */ -}; -#endif /* LWIP_TIMEVAL_PRIVATE */ - -#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_recvfrom recvfrom -#define lwip_send send -#define lwip_sendmsg sendmsg -#define lwip_sendto sendto -#define lwip_socket socket -#define lwip_select select -#define lwip_ioctlsocket ioctl - -#if LWIP_POSIX_SOCKETS_IO_NAMES -#define lwip_read read -#define lwip_write write -#define lwip_writev writev -#undef lwip_close -#define lwip_close close -#define closesocket(s) close(s) -#define lwip_fcntl fcntl -#define lwip_ioctl 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); -int lwip_recv(int s, void *mem, size_t len, int flags); -int lwip_read(int s, void *mem, size_t len); -int lwip_recvfrom(int s, void *mem, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen); -int lwip_send(int s, const void *dataptr, size_t size, int flags); -int lwip_sendmsg(int s, const struct msghdr *message, int flags); -int lwip_sendto(int s, const void *dataptr, size_t size, int flags, - const struct sockaddr *to, socklen_t tolen); -int lwip_socket(int domain, int type, int protocol); -int lwip_write(int s, const void *dataptr, size_t size); -int lwip_writev(int s, const struct iovec *iov, int iovcnt); -int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, - struct timeval *timeout); -int lwip_ioctl(int s, long cmd, void *argp); -int lwip_fcntl(int s, int cmd, int val); - -#if LWIP_COMPAT_SOCKETS -#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 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) -/** @ingroup socket */ -#define select(maxfdp1,readset,writeset,exceptset,timeout) lwip_select(maxfdp1,readset,writeset,exceptset,timeout) -/** @ingroup socket */ -#define ioctlsocket(s,cmd,argp) lwip_ioctl(s,cmd,argp) - -#if LWIP_POSIX_SOCKETS_IO_NAMES -/** @ingroup socket */ -#define read(s,mem,len) lwip_read(s,mem,len) -/** @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 */ - -#if LWIP_IPV4 && LWIP_IPV6 -/** @ingroup socket */ -#define inet_ntop(af,src,dst,size) \ - (((af) == AF_INET6) ? ip6addr_ntoa_r((const ip6_addr_t*)(src),(dst),(size)) \ - : (((af) == AF_INET) ? ip4addr_ntoa_r((const ip4_addr_t*)(src),(dst),(size)) : NULL)) -/** @ingroup socket */ -#define inet_pton(af,src,dst) \ - (((af) == AF_INET6) ? ip6addr_aton((src),(ip6_addr_t*)(dst)) \ - : (((af) == AF_INET) ? ip4addr_aton((src),(ip4_addr_t*)(dst)) : 0)) -#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ -#define inet_ntop(af,src,dst,size) \ - (((af) == AF_INET) ? ip4addr_ntoa_r((const ip4_addr_t*)(src),(dst),(size)) : NULL) -#define inet_pton(af,src,dst) \ - (((af) == AF_INET) ? ip4addr_aton((src),(ip4_addr_t*)(dst)) : 0) -#else /* LWIP_IPV4 && LWIP_IPV6 */ -#define inet_ntop(af,src,dst,size) \ - (((af) == AF_INET6) ? ip6addr_ntoa_r((const ip6_addr_t*)(src),(dst),(size)) : NULL) -#define inet_pton(af,src,dst) \ - (((af) == AF_INET6) ? ip6addr_aton((src),(ip6_addr_t*)(dst)) : 0) -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - -#endif /* LWIP_COMPAT_SOCKETS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SOCKET */ - -#endif /* LWIP_HDR_SOCKETS_H */ diff --git a/ext/lwip/src/include/lwip/stats.h b/ext/lwip/src/include/lwip/stats.h deleted file mode 100644 index 99f49cc..0000000 --- a/ext/lwip/src/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) do { lwip_stats.x.used += y; \ - if (lwip_stats.x.max < lwip_stats.x.used) { \ - lwip_stats.x.max = lwip_stats.x.used; \ - } \ - } while(0) -#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) -#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) -#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y -#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") -#else -#define MEM_STATS_AVAIL(x, y) -#define MEM_STATS_INC(x) -#define MEM_STATS_INC_USED(x, y) -#define MEM_STATS_DEC_USED(x, y) -#define MEM_STATS_DISPLAY() -#endif - - #if MEMP_STATS -#define MEMP_STATS_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) -#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/ext/lwip/src/include/lwip/sys.h b/ext/lwip/src/include/lwip/sys.h deleted file mode 100644 index c05af04..0000000 --- a/ext/lwip/src/include/lwip/sys.h +++ /dev/null @@ -1,491 +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 - */ - -/** - * @defgroup sys_layer System abstraction layer - * @ingroup infrastructure - * @verbinclude "sys_arch.txt" - * - * @defgroup sys_os OS abstraction layer - * @ingroup sys_layer - * No need to implement functions in this section in NO_SYS mode. - * - * @defgroup sys_sem Semaphores - * @ingroup sys_os - * - * @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 - * - * @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 - */ - -#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 - * @param mutex pointer to the mutex to create - * @return a new mutex - */ -err_t sys_mutex_new(sys_mutex_t *mutex); -/** - * @ingroup sys_mutex - * Lock a mutex - * @param mutex the mutex to lock - */ -void sys_mutex_lock(sys_mutex_t *mutex); -/** - * @ingroup sys_mutex - * Unlock a mutex - * @param mutex the mutex to unlock - */ -void sys_mutex_unlock(sys_mutex_t *mutex); -/** - * @ingroup sys_mutex - * Delete a semaphore - * @param mutex the mutex to delete - */ -void sys_mutex_free(sys_mutex_t *mutex); -#ifndef sys_mutex_valid -/** - * @ingroup sys_mutex - * Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid - */ -int sys_mutex_valid(sys_mutex_t *mutex); -#endif -#ifndef sys_mutex_set_invalid -/** - * @ingroup sys_mutex - * Set a mutex invalid so that sys_mutex_valid returns 0 - */ -void sys_mutex_set_invalid(sys_mutex_t *mutex); -#endif -#endif /* LWIP_COMPAT_MUTEX */ - -/* Semaphore functions: */ - -/** - * @ingroup sys_sem - * Create a new semaphore - * @param sem pointer to the semaphore to create - * @param count initial count of the semaphore - * @return ERR_OK if successful, another err_t otherwise - */ -err_t sys_sem_new(sys_sem_t *sem, u8_t count); -/** - * @ingroup sys_sem - * Signals a semaphore - * @param sem the semaphore to signal - */ -void sys_sem_signal(sys_sem_t *sem); -/** - * @ingroup sys_sem - * Wait for a semaphore for the specified timeout - * @param sem the semaphore to wait for - * @param timeout timeout in milliseconds to wait (0 = wait forever) - * @return time (in milliseconds) waited for the semaphore - * or SYS_ARCH_TIMEOUT on timeout - */ -u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); -/** - * @ingroup sys_sem - * Delete a semaphore - * @param sem semaphore to delete - */ -void sys_sem_free(sys_sem_t *sem); -/** Wait for a semaphore - forever/no timeout */ -#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) -#ifndef sys_sem_valid -/** - * @ingroup sys_sem - * Check if a semaphore is valid/allocated: return 1 for valid, 0 for invalid - */ -int sys_sem_valid(sys_sem_t *sem); -#endif -#ifndef sys_sem_set_invalid -/** - * @ingroup sys_sem - * Set a semaphore invalid so that sys_sem_valid returns 0 - */ -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 - * Create a new mbox of specified size - * @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 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 or ISR - * @param mbox mbox to posts the message - * @param msg message to post (ATTENTION: can be NULL) - */ -err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); -/** - * @ingroup sys_mbox - * Wait for a new message to arrive in the mbox - * @param mbox mbox to get a message from - * @param msg pointer where the message is stored - * @param timeout maximum time (in milliseconds) to wait for a message (0 = wait forever) - * @return time (in milliseconds) waited for a message, may be 0 if not waited - or SYS_ARCH_TIMEOUT on timeout - * The returned time has to be accurate to prevent timer jitter! - */ -u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); -/* Allow port to override with a macro, e.g. special timeout for sys_arch_mbox_fetch() */ -#ifndef sys_arch_mbox_tryfetch -/** - * @ingroup sys_mbox - * Wait for a new message to arrive in the mbox - * @param mbox mbox to get a message from - * @param msg pointer where the message is stored - * @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 - * Delete an mbox - * @param mbox mbox to delete - */ -void sys_mbox_free(sys_mbox_t *mbox); -#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) -#ifndef sys_mbox_valid -/** - * @ingroup sys_mbox - * Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid - */ -int sys_mbox_valid(sys_mbox_t *mbox); -#endif -#ifndef sys_mbox_set_invalid -/** - * @ingroup sys_mbox - * Set an mbox invalid so that sys_mbox_valid returns 0 - */ -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: - * Creates a new thread - * 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 */ - -/* sys_init() must be called before anything else. */ -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. - */ -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 */ - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_SYS_H */ diff --git a/ext/lwip/src/include/lwip/tcp.h b/ext/lwip/src/include/lwip/tcp.h deleted file mode 100644 index 0ae49a0..0000000 --- a/ext/lwip/src/include/lwip/tcp.h +++ /dev/null @@ -1,423 +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/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; - -/** 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))) -typedef u32_t tcpwnd_size_t; -#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 -typedef u16_t tcpwnd_size_t; -#endif - -#if LWIP_WND_SCALE || TCP_LISTEN_BACKLOG -typedef u16_t tcpflags_t; -#else -typedef u8_t tcpflags_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 -}; - -/** - * 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; \ - 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_TIMESTAMP 0x08U /* Timestamp option enabled */ -#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 - - /* 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 */ - - /* Retransmission timer. */ - s16_t rtime; - - u16_t mss; /* maximum segment size */ - - /* RTT (round trip time) estimation variables */ - u32_t rttest; /* RTT estimate in 500ms ticks */ - u32_t rtseq; /* sequence number being timed */ - s16_t sa, sv; /* @todo document this */ - - s16_t rto; /* retransmission time-out */ - u8_t nrtx; /* number of retransmissions */ - - /* fast retransmit/recovery */ - u8_t dupacks; - u32_t lastack; /* Highest acknowledged seqno. */ - - /* congestion avoidance/control variables */ - tcpwnd_size_t cwnd; - tcpwnd_size_t ssthresh; - - /* 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 */ - - /* 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; - - /* 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); -void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); -void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv); -void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent); -void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); -void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err); - -#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) -#define tcp_sndbuf(pcb) (TCPWND16((pcb)->snd_buf)) -#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) -/** @ingroup tcp_raw */ -#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY) -/** @ingroup tcp_raw */ -#define tcp_nagle_enable(pcb) ((pcb)->flags = (tcpflags_t)((pcb)->flags & ~TF_NODELAY)) -/** @ingroup tcp_raw */ -#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0) - -#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) /* 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); -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(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); - -/* Flags for "apiflags" parameter in tcp_write */ -#define TCP_WRITE_FLAG_COPY 0x01 -#define TCP_WRITE_FLAG_MORE 0x02 - -err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, - u8_t apiflags); - -void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); - -#define TCP_PRIO_MIN 1 -#define TCP_PRIO_NORMAL 64 -#define TCP_PRIO_MAX 127 - -err_t tcp_output (struct tcp_pcb *pcb); - - -const char* tcp_debug_state_str(enum tcp_state s); - -/* for compatibility with older implementation */ -#define tcp_new_ip6() tcp_new_ip_type(IPADDR_TYPE_V6) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_TCP */ - -#endif /* LWIP_HDR_TCP_H */ diff --git a/ext/lwip/src/include/lwip/tcpip.h b/ext/lwip/src/include/lwip/tcpip.h deleted file mode 100644 index 796f34a..0000000 --- a/ext/lwip/src/include/lwip/tcpip.h +++ /dev/null @@ -1,104 +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; -#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) -#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&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_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block); -/** - * @ingroup lwip_os - * @see tcpip_callback_with_block - */ -#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1) - -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_trycallback(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 -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 */ - -#ifdef __cplusplus -} -#endif - -#endif /* !NO_SYS */ - -#endif /* LWIP_HDR_TCPIP_H */ diff --git a/ext/lwip/src/include/lwip/timeouts.h b/ext/lwip/src/include/lwip/timeouts.h deleted file mode 100644 index 4988b15..0000000 --- a/ext/lwip/src/include/lwip/timeouts.h +++ /dev/null @@ -1,121 +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 - -/** 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_ARRAYSIZE() */ -extern const struct lwip_cyclic_timer lwip_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); -#if NO_SYS -void sys_check_timeouts(void); -void sys_restart_timeouts(void); -u32_t sys_timeouts_sleeptime(void); -#else /* NO_SYS */ -void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); -#endif /* NO_SYS */ - - -#endif /* LWIP_TIMERS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_TIMEOUTS_H */ diff --git a/ext/lwip/src/include/lwip/udp.h b/ext/lwip/src/include/lwip/udp.h deleted file mode 100644 index a0381dd..0000000 --- a/ext/lwip/src/include/lwip/udp.h +++ /dev/null @@ -1,201 +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" - -#ifdef __cplusplus -extern "C" { -#endif - -#define UDP_HLEN 8 - -/* Fields are (of course) in network byte order. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct udp_hdr { - PACK_STRUCT_FIELD(u16_t src); - PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ - PACK_STRUCT_FIELD(u16_t len); - PACK_STRUCT_FIELD(u16_t chksum); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define UDP_FLAGS_NOCHKSUM 0x01U -#define UDP_FLAGS_UDPLITE 0x02U -#define UDP_FLAGS_CONNECTED 0x04U -#define UDP_FLAGS_MULTICAST_LOOP 0x08U - -struct udp_pcb; - -/** Function prototype for udp pcb receive callback functions - * addr and port are in same byte order as in the pcb - * The callback is responsible for freeing the pbuf - * if it's not used any more. - * - * ATTENTION: Be aware that 'addr' 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 - */ -typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *addr, u16_t port); - -/** 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 - /** outgoing network interface for multicast packets */ - ip_addr_t multicast_ip; - /** 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); -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); -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); -err_t udp_send (struct udp_pcb *pcb, struct pbuf *p); - -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP -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); -err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, - u8_t have_chksum, u16_t chksum); -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 /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - -#define udp_flags(pcb) ((pcb)->flags) -#define udp_setflags(pcb, f) ((pcb)->flags = (f)) - -/* The following functions are the lower layer interface to UDP. */ -void udp_input (struct pbuf *p, struct netif *inp); - -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 -#define udp_set_multicast_netif_addr(pcb, ip4addr) ip_addr_copy_from_ip4((pcb)->multicast_ip, *(ip4addr)) -#define udp_get_multicast_netif_addr(pcb) ip_2_ip4(&(pcb)->multicast_ip) -#define udp_set_multicast_ttl(pcb, value) do { (pcb)->mcast_ttl = value; } while(0) -#define udp_get_multicast_ttl(pcb) ((pcb)->mcast_ttl) -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - -#if UDP_DEBUG -void udp_debug_print(struct udp_hdr *udphdr); -#else -#define udp_debug_print(udphdr) -#endif - -#if LWIP_IPV4 -void udp_netif_ipv4_addr_changed(const ip4_addr_t* old_addr, const ip4_addr_t* new_addr); -#endif /* LWIP_IPV4 */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_UDP */ - -#endif /* LWIP_HDR_UDP_H */ diff --git a/ext/lwip/src/include/netif/etharp.h b/ext/lwip/src/include/netif/etharp.h deleted file mode 100644 index df63a70..0000000 --- a/ext/lwip/src/include/netif/etharp.h +++ /dev/null @@ -1,2 +0,0 @@ -/* ARP has been moved to core/ipv4, provide this #include for compatibility only */ -#include "lwip/etharp.h" diff --git a/ext/lwip/src/include/netif/ethernet.h b/ext/lwip/src/include/netif/ethernet.h deleted file mode 100644 index 03bfe7f..0000000 --- a/ext/lwip/src/include/netif/ethernet.h +++ /dev/null @@ -1,177 +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" - -#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 -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 - -#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) - -#if ETHARP_SUPPORT_VLAN - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** VLAN header inserted between ethernet header and payload - * if 'type' in ethernet header is ETHTYPE_VLAN. - * See IEEE802.Q */ -struct eth_vlan_hdr { - PACK_STRUCT_FIELD(u16_t 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) (htons((vlan_hdr)->prio_vid) & 0xFFF) - -#endif /* ETHARP_SUPPORT_VLAN */ - -/* A list of often ethtypes (although lwIP does not use all of them): */ -#define ETHTYPE_IP 0x0800U /* Internet protocol v4 */ -#define ETHTYPE_ARP 0x0806U /* Address resolution protocol */ -#define ETHTYPE_WOL 0x0842U /* Wake on lan */ -#define ETHTYPE_VLAN 0x8100U /* Virtual local area network */ -#define ETHTYPE_IPV6 0x86DDU /* Internet protocol v6 */ -#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */ -#define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */ -#define ETHTYPE_JUMBO 0x8870U /* Jumbo Frames */ -#define ETHTYPE_PROFINET 0x8892U /* Process field network */ -#define ETHTYPE_ETHERCAT 0x88A4U /* Ethernet for control automation technology */ -#define ETHTYPE_LLDP 0x88CCU /* Link layer discovery protocol */ -#define ETHTYPE_SERCOS 0x88CDU /* Serial real-time communication system */ -#define ETHTYPE_PTP 0x88F7U /* Precision time protocol */ -#define ETHTYPE_QINQ 0x9100U /* Q-in-Q, 802.1ad */ - -/** 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 - -/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables - * or known to be 32-bit aligned within the protocol header. */ -#ifndef ETHADDR32_COPY -#define ETHADDR32_COPY(dst, src) SMEMCPY(dst, src, ETH_HWADDR_LEN) -#endif - -/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local - * variables and known to be 16-bit aligned within the protocol header. */ -#ifndef ETHADDR16_COPY -#define ETHADDR16_COPY(dst, src) SMEMCPY(dst, src, ETH_HWADDR_LEN) -#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); - -#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETH_HWADDR_LEN) == 0) - -extern const struct eth_addr ethbroadcast, ethzero; - -#endif /* LWIP_ARP || LWIP_ETHERNET */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_NETIF_ETHERNET_H */ diff --git a/ext/lwip/src/include/netif/lowpan6.h b/ext/lwip/src/include/netif/lowpan6.h deleted file mode 100644 index 4174644..0000000 --- a/ext/lwip/src/include/netif/lowpan6.h +++ /dev/null @@ -1,86 +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 && LWIP_6LOWPAN /* don't build if not configured for use in lwipopts.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 */ -#define LOWPAN6_TMR_INTERVAL 1000 - -void lowpan6_tmr(void); - -err_t lowpan6_set_context(u8_t index, 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); - -#if !NO_SYS -err_t tcpip_6lowpan_input(struct pbuf *p, struct netif *inp); -#endif /* !NO_SYS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 && LWIP_6LOWPAN */ - -#endif /* LWIP_HDR_LOWPAN6_H */ diff --git a/ext/lwip/src/include/netif/lowpan6_opts.h b/ext/lwip/src/include/netif/lowpan6_opts.h deleted file mode 100644 index fb93ea0..0000000 --- a/ext/lwip/src/include/netif/lowpan6_opts.h +++ /dev/null @@ -1,70 +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" - -#ifndef LWIP_6LOWPAN -#define LWIP_6LOWPAN 0 -#endif - -#ifndef LWIP_6LOWPAN_NUM_CONTEXTS -#define LWIP_6LOWPAN_NUM_CONTEXTS 10 -#endif - -#ifndef LWIP_6LOWPAN_INFER_SHORT_ADDRESS -#define LWIP_6LOWPAN_INFER_SHORT_ADDRESS 1 -#endif - -#ifndef LWIP_6LOWPAN_IPHC -#define LWIP_6LOWPAN_IPHC 1 -#endif - -#ifndef LWIP_6LOWPAN_HW_CRC -#define LWIP_6LOWPAN_HW_CRC 1 -#endif - -#ifndef LOWPAN6_DEBUG -#define LOWPAN6_DEBUG LWIP_DBG_OFF -#endif - -#endif /* LWIP_HDR_LOWPAN6_OPTS_H */ diff --git a/ext/lwip/src/include/netif/ppp/ccp.h b/ext/lwip/src/include/netif/ppp/ccp.h deleted file mode 100644 index 14dd659..0000000 --- a/ext/lwip/src/include/netif/ppp/ccp.h +++ /dev/null @@ -1,156 +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 - -/* - * 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. */ - -#endif /* CCP_H */ -#endif /* PPP_SUPPORT && CCP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/chap-md5.h b/ext/lwip/src/include/netif/ppp/chap-md5.h deleted file mode 100644 index eb0269f..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/netif/ppp/chap-new.h b/ext/lwip/src/include/netif/ppp/chap-new.h deleted file mode 100644 index 64eae32..0000000 --- a/ext/lwip/src/include/netif/ppp/chap-new.h +++ /dev/null @@ -1,192 +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" - -/* - * 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; - -#endif /* CHAP_H */ -#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/chap_ms.h b/ext/lwip/src/include/netif/ppp/chap_ms.h deleted file mode 100644 index 0795291..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/netif/ppp/eap.h b/ext/lwip/src/include/netif/ppp/eap.h deleted file mode 100644 index 3ee9aaf..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/netif/ppp/ecp.h b/ext/lwip/src/include/netif/ppp/ecp.h deleted file mode 100644 index 5cdce29..0000000 --- a/ext/lwip/src/include/netif/ppp/ecp.h +++ /dev/null @@ -1,50 +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 */ - -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; - -#endif /* PPP_SUPPORT && ECP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/eui64.h b/ext/lwip/src/include/netif/ppp/eui64.h deleted file mode 100644 index 1b5147f..0000000 --- a/ext/lwip/src/include/netif/ppp/eui64.h +++ /dev/null @@ -1,94 +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 - -/* - * @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] = htonl(l); \ - } while (0) -#define eui64_setlo32(e, l) eui64_set32(e, l) - -char *eui64_ntoa(eui64_t); /* Returns ascii representation of id */ - -#endif /* EUI64_H */ -#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/fsm.h b/ext/lwip/src/include/netif/ppp/fsm.h deleted file mode 100644 index b6915d3..0000000 --- a/ext/lwip/src/include/netif/ppp/fsm.h +++ /dev/null @@ -1,175 +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" - -/* - * 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); - - -#endif /* FSM_H */ -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/ipcp.h b/ext/lwip/src/include/netif/ppp/ipcp.h deleted file mode 100644 index 45f46b3..0000000 --- a/ext/lwip/src/include/netif/ppp/ipcp.h +++ /dev/null @@ -1,126 +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 - -/* - * 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; - -#endif /* IPCP_H */ -#endif /* PPP_SUPPORT && PPP_IPV4_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/ipv6cp.h b/ext/lwip/src/include/netif/ppp/ipv6cp.h deleted file mode 100644 index 07d1ae3..0000000 --- a/ext/lwip/src/include/netif/ppp/ipv6cp.h +++ /dev/null @@ -1,183 +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" - -/* - * 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; - -#endif /* IPV6CP_H */ -#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/lcp.h b/ext/lwip/src/include/netif/ppp/lcp.h deleted file mode 100644 index 12e2a05..0000000 --- a/ext/lwip/src/include/netif/ppp/lcp.h +++ /dev/null @@ -1,171 +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" - -/* - * 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 */ - -#endif /* LCP_H */ -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/magic.h b/ext/lwip/src/include/netif/ppp/magic.h deleted file mode 100644 index a2a9b53..0000000 --- a/ext/lwip/src/include/netif/ppp/magic.h +++ /dev/null @@ -1,122 +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 - -/*********************** -*** 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); - -#endif /* MAGIC_H */ - -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/mppe.h b/ext/lwip/src/include/netif/ppp/mppe.h deleted file mode 100644 index 551a47e..0000000 --- a/ext/lwip/src/include/netif/ppp/mppe.h +++ /dev/null @@ -1,173 +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" - -#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 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); - -#endif /* MPPE_H */ -#endif /* PPP_SUPPORT && MPPE_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/polarssl/arc4.h b/ext/lwip/src/include/netif/ppp/polarssl/arc4.h deleted file mode 100644 index 4af724c..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/netif/ppp/polarssl/des.h b/ext/lwip/src/include/netif/ppp/polarssl/des.h deleted file mode 100644 index e893890..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/netif/ppp/polarssl/md4.h b/ext/lwip/src/include/netif/ppp/polarssl/md4.h deleted file mode 100644 index 5704456..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/netif/ppp/polarssl/md5.h b/ext/lwip/src/include/netif/ppp/polarssl/md5.h deleted file mode 100644 index 1244011..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/netif/ppp/polarssl/sha1.h b/ext/lwip/src/include/netif/ppp/polarssl/sha1.h deleted file mode 100644 index a4c53e0..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/netif/ppp/ppp.h b/ext/lwip/src/include/netif/ppp/ppp.h deleted file mode 100644 index 016d6ba..0000000 --- a/ext/lwip/src/include/netif/ppp/ppp.h +++ /dev/null @@ -1,688 +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 */ - -/* 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_INITIALIZE 1 -#define PPP_PHASE_SERIALCONN 2 -#define PPP_PHASE_DORMANT 3 -#define PPP_PHASE_ESTABLISH 4 -#define PPP_PHASE_AUTHENTICATE 5 -#define PPP_PHASE_CALLBACK 6 -#define PPP_PHASE_NETWORK 7 -#define PPP_PHASE_RUNNING 8 -#define PPP_PHASE_TERMINATE 9 -#define PPP_PHASE_DISCONNECT 10 -#define PPP_PHASE_HOLDOFF 11 -#define PPP_PHASE_MASTER 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 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) (ppp->ipcp_wantoptions.ouraddr = ip4_addr_get_u32(addr)) -#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); - -#endif /* PPP_H */ - -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/ppp_impl.h b/ext/lwip/src/include/netif/ppp/ppp_impl.h deleted file mode 100644 index 1b27415..0000000 --- a/ext/lwip/src/include/netif/ppp/ppp_impl.h +++ /dev/null @@ -1,632 +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" - -/* - * 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) */ - err_t (*connect) (ppp_pcb *pcb, void *ctx); -#if PPP_SERVER - /* Listen for an incoming connection (Passive mode) */ - err_t (*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); - -/* Called when link is starting */ -void ppp_link_start(ppp_pcb *pcb); - -/* 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); - -/* helper function, merge a pbuf chain into one pbuf */ -struct pbuf *ppp_singlebuf(struct pbuf *p); - - -/* - * 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(const char *tag, unsigned char *p, int len); - /* dump packet to debug log if interesting */ -#endif /* PRINTPKT_SUPPORT */ - - -#endif /* PPP_SUPPORT */ -#endif /* LWIP_HDR_PPP_IMPL_H */ diff --git a/ext/lwip/src/include/netif/ppp/ppp_opts.h b/ext/lwip/src/include/netif/ppp/ppp_opts.h deleted file mode 100644 index 75541f4..0000000 --- a/ext/lwip/src/include/netif/ppp/ppp_opts.h +++ /dev/null @@ -1,593 +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 - -/** - * 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 - -#if PPP_SUPPORT - -/** - * 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 IPv4 over PPPoS. */ -#if !PPPOS_SUPPORT || !PPP_IPV4_SUPPORT -#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 */ - -#endif /* LWIP_PPP_OPTS_H */ diff --git a/ext/lwip/src/include/netif/ppp/pppapi.h b/ext/lwip/src/include/netif/ppp/pppapi.h deleted file mode 100644 index 913d93f..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/netif/ppp/pppcrypt.h b/ext/lwip/src/include/netif/ppp/pppcrypt.h deleted file mode 100644 index a7b2099..0000000 --- a/ext/lwip/src/include/netif/ppp/pppcrypt.h +++ /dev/null @@ -1,136 +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" - -/* - * 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); - -#endif /* PPPCRYPT_H */ - -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/pppdebug.h b/ext/lwip/src/include/netif/ppp/pppdebug.h deleted file mode 100644 index 7ead045..0000000 --- a/ext/lwip/src/include/netif/ppp/pppdebug.h +++ /dev/null @@ -1,80 +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 - -/* 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 */ - -#endif /* PPPDEBUG_H */ - -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/pppoe.h b/ext/lwip/src/include/netif/ppp/pppoe.h deleted file mode 100644 index 9f8f289..0000000 --- a/ext/lwip/src/include/netif/ppp/pppoe.h +++ /dev/null @@ -1,179 +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 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); - -#endif /* PPP_OE_H */ - -#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/pppol2tp.h b/ext/lwip/src/include/netif/ppp/pppol2tp.h deleted file mode 100644 index 9384255..0000000 --- a/ext/lwip/src/include/netif/ppp/pppol2tp.h +++ /dev/null @@ -1,201 +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" - -/* 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; /* 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); - -#endif /* PPPOL2TP_H_ */ -#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/pppos.h b/ext/lwip/src/include/netif/ppp/pppos.h deleted file mode 100644 index d924a9f..0000000 --- a/ext/lwip/src/include/netif/ppp/pppos.h +++ /dev/null @@ -1,118 +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" - -/* 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 */ - -#endif /* PPPOS_H */ -#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/upap.h b/ext/lwip/src/include/netif/ppp/upap.h deleted file mode 100644 index 7da792e..0000000 --- a/ext/lwip/src/include/netif/ppp/upap.h +++ /dev/null @@ -1,123 +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" - -/* - * 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; - -#endif /* UPAP_H */ -#endif /* PPP_SUPPORT && PAP_SUPPORT */ diff --git a/ext/lwip/src/include/netif/ppp/vj.h b/ext/lwip/src/include/netif/ppp/vj.h deleted file mode 100644 index 7f389c8..0000000 --- a/ext/lwip/src/include/netif/ppp/vj.h +++ /dev/null @@ -1,161 +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" - -#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); - -#endif /* VJ_H */ - -#endif /* PPP_SUPPORT && VJ_SUPPORT */ diff --git a/ext/lwip/src/include/netif/slipif.h b/ext/lwip/src/include/netif/slipif.h deleted file mode 100644 index 65ba31f..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/posix/netdb.h b/ext/lwip/src/include/posix/netdb.h deleted file mode 100644 index 12d4c7f..0000000 --- a/ext/lwip/src/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/ext/lwip/src/include/posix/sys/socket.h b/ext/lwip/src/include/posix/sys/socket.h deleted file mode 100644 index 0ed9baf..0000000 --- a/ext/lwip/src/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/ext/lwip/src/netif/FILES b/ext/lwip/src/netif/FILES deleted file mode 100644 index 501edac..0000000 --- a/ext/lwip/src/netif/FILES +++ /dev/null @@ -1,31 +0,0 @@ -This directory contains generic network interface device drivers that -do not contain any hardware or architecture specific code. The files -are: - -etharp.c - Implements the ARP (Address Resolution Protocol) over - Ethernet. The code in this file should be used together with - Ethernet device drivers. Note that this module has been - largely made Ethernet independent so you should be able to - adapt this for other link layers (such as Firewire). - -ethernetif.c - An example of how an Ethernet device driver could look. This - file can be used as a "skeleton" for developing new Ethernet - network device drivers. It uses the etharp.c ARP code. - -loopif.c - A "loopback" network interface driver. It requires configuration - through the define LWIP_LOOPIF_MULTITHREADING (see opt.h). - -slipif.c - A generic implementation of the SLIP (Serial Line IP) - protocol. It requires a sio (serial I/O) module to work. - -lowpan6.c - 6LoWPAN implementation - -ppp/ Point-to-Point Protocol stack - The lwIP PPP support is based from pppd (http://ppp.samba.org) with - huge changes to match code size and memory requirements for embedded - devices. Please read ppp/PPPD_FOLLOWUP for a detailed explanation. diff --git a/ext/lwip/src/netif/ethernet.c b/ext/lwip/src/netif/ethernet.c deleted file mode 100644 index 77bbfbd..0000000 --- a/ext/lwip/src/netif/ethernet.c +++ /dev/null @@ -1,228 +0,0 @@ -/** - * @file - * Ethernet common functions - */ - -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * Copyright (c) 2003-2004 Leon Woestenberg - * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - */ - -#include "lwip/opt.h" - -#if LWIP_ARP || LWIP_ETHERNET - -#include "netif/ethernet.h" -#include "lwip/def.h" -#include "lwip/stats.h" -#include "lwip/etharp.h" -#include "lwip/ip.h" -#include "lwip/snmp.h" - -#include - -#include "netif/ppp/ppp_opts.h" -#if PPPOE_SUPPORT -#include "netif/ppp/pppoe.h" -#endif /* PPPOE_SUPPORT */ - -const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; -const struct eth_addr ethzero = {{0,0,0,0,0,0}}; - -/** - * @ingroup lwip_nosys - * Process received ethernet frames. Using this function instead of directly - * calling ip_input and passing ARP frames through etharp in ethernetif_input, - * the ARP cache is protected from concurrent access.\n - * Don't call directly, pass to netif_add() and call netif->input(). - * - * @param p the received packet, p->payload pointing to the ethernet header - * @param netif the network interface on which the packet was received - */ -err_t -ethernet_input(struct pbuf *p, struct netif *netif) -{ - LWIP_DEBUGF(IP6_DEBUG, ("ethernet_input: netif = %p\n", (void*)netif)); - struct eth_hdr* ethhdr; - u16_t type; -#if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6 - s16_t ip_hdr_offset = SIZEOF_ETH_HDR; -#endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */ - - if (p->len <= SIZEOF_ETH_HDR) { - /* a packet with only an ethernet header (or less) is not valid for us */ - ETHARP_STATS_INC(etharp.proterr); - ETHARP_STATS_INC(etharp.drop); - MIB2_STATS_NETIF_INC(netif, ifinerrors); - goto free_and_return; - } - - /* points to packet payload, which starts with an Ethernet header */ - ethhdr = (struct eth_hdr *)p->payload; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, - ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n", - (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], - (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], - (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], - (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], - htons(ethhdr->type))); - - type = ethhdr->type; -#if ETHARP_SUPPORT_VLAN - if (type == PP_HTONS(ETHTYPE_VLAN)) { - struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); - if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { - /* a packet with only an ethernet/vlan header (or less) is not valid for us */ - ETHARP_STATS_INC(etharp.proterr); - ETHARP_STATS_INC(etharp.drop); - MIB2_STATS_NETIF_INC(netif, ifinerrors); - goto free_and_return; - } -#if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ -#ifdef LWIP_HOOK_VLAN_CHECK - if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) { -#elif defined(ETHARP_VLAN_CHECK_FN) - if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { -#elif defined(ETHARP_VLAN_CHECK) - if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { -#endif - /* silently ignore this packet: not for our VLAN */ - pbuf_free(p); - return ERR_OK; - } -#endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ - type = vlan->tpid; - ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; - } -#endif /* ETHARP_SUPPORT_VLAN */ - -#if LWIP_ARP_FILTER_NETIF - netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type)); -#endif /* LWIP_ARP_FILTER_NETIF*/ - - if (ethhdr->dest.addr[0] & 1) { - /* this might be a multicast or broadcast packet */ - if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) { -#if LWIP_IPV4 - if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) && - (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) { - /* mark the pbuf as link-layer multicast */ - p->flags |= PBUF_FLAG_LLMCAST; - } -#endif /* LWIP_IPV4 */ - } -#if LWIP_IPV6 - else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) && - (ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) { - /* mark the pbuf as link-layer multicast */ - p->flags |= PBUF_FLAG_LLMCAST; - } -#endif /* LWIP_IPV6 */ - else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { - /* mark the pbuf as link-layer broadcast */ - p->flags |= PBUF_FLAG_LLBCAST; - } - } - - switch (type) { -#if LWIP_IPV4 && LWIP_ARP - /* IP packet? */ - case PP_HTONS(ETHTYPE_IP): - if (!(netif->flags & NETIF_FLAG_ETHARP)) { - goto free_and_return; - } -#if ETHARP_TRUST_IP_MAC - /* update ARP table */ - etharp_ip_input(netif, p); -#endif /* ETHARP_TRUST_IP_MAC */ - /* skip Ethernet header */ - if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("ethernet_input: IPv4 packet dropped, too short (%"S16_F"/%"S16_F")\n", - p->tot_len, ip_hdr_offset)); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); - goto free_and_return; - } else { - /* pass to IP layer */ - ip4_input(p, netif); - } - break; - - case PP_HTONS(ETHTYPE_ARP): - if (!(netif->flags & NETIF_FLAG_ETHARP)) { - goto free_and_return; - } - /* pass p to ARP module */ - etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); - break; -#endif /* LWIP_IPV4 && LWIP_ARP */ -#if PPPOE_SUPPORT - case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ - pppoe_disc_input(netif, p); - break; - - case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ - pppoe_data_input(netif, p); - break; -#endif /* PPPOE_SUPPORT */ - -#if LWIP_IPV6 - case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */ - /* skip Ethernet header */ - if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("ethernet_input: IPv6 packet dropped, too short (%"S16_F"/%"S16_F")\n", - p->tot_len, ip_hdr_offset)); - goto free_and_return; - } else { - /* pass to IPv6 layer */ - - LWIP_DEBUGF(IP6_DEBUG, ("calling ip6_input()")); - ip6_input(p, netif); - } - break; -#endif /* LWIP_IPV6 */ - - default: - ETHARP_STATS_INC(etharp.proterr); - ETHARP_STATS_INC(etharp.drop); - MIB2_STATS_NETIF_INC(netif, ifinunknownprotos); - goto free_and_return; - } - - /* This means the pbuf is freed or consumed, - so the caller doesn't have to free it again */ - return ERR_OK; - -free_and_return: - pbuf_free(p); - return ERR_OK; -} -#endif /* LWIP_ARP || LWIP_ETHERNET */ diff --git a/ext/lwip/src/netif/ethernetif.c b/ext/lwip/src/netif/ethernetif.c deleted file mode 100644 index 973b3e1..0000000 --- a/ext/lwip/src/netif/ethernetif.c +++ /dev/null @@ -1,335 +0,0 @@ -/** - * @file - * Ethernet Interface Skeleton - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -/* - * This file is a skeleton for developing Ethernet network interface - * drivers for lwIP. Add code to the low_level functions and do a - * search-and-replace for the word "ethernetif" to replace it with - * something that better describes your network interface. - */ - -#include "lwip/opt.h" - -#if 0 /* don't build, this is only a skeleton, see previous comment */ - -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/pbuf.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "lwip/ethip6.h" -#include "lwip/etharp.h" -#include "netif/ppp/pppoe.h" - -/* Define those to better describe your network interface. */ -#define IFNAME0 'e' -#define IFNAME1 'n' - -/** - * Helper struct to hold private data used to operate your ethernet interface. - * Keeping the ethernet address of the MAC in this struct is not necessary - * as it is already kept in the struct netif. - * But this is only an example, anyway... - */ -struct ethernetif { - struct eth_addr *ethaddr; - /* Add whatever per-interface state that is needed here. */ -}; - -/* Forward declarations. */ -static void ethernetif_input(struct netif *netif); - -/** - * In this function, the hardware should be initialized. - * Called from ethernetif_init(). - * - * @param netif the already initialized lwip network interface structure - * for this ethernetif - */ -static void -low_level_init(struct netif *netif) -{ - struct ethernetif *ethernetif = netif->state; - - /* set MAC hardware address length */ - netif->hwaddr_len = ETHARP_HWADDR_LEN; - - /* set MAC hardware address */ - netif->hwaddr[0] = ; - ... - netif->hwaddr[5] = ; - - /* maximum transfer unit */ - netif->mtu = 1500; - - /* device capabilities */ - /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; - -#if LWIP_IPV6 && LWIP_IPV6_MLD - /* - * For hardware/netifs that implement MAC filtering. - * All-nodes link-local is handled by default, so we must let the hardware know - * to allow multicast packets in. - * Should set mld_mac_filter previously. */ - if (netif->mld_mac_filter != NULL) { - ip6_addr_t ip6_allnodes_ll; - ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); - netif->mld_mac_filter(netif, &ip6_allnodes_ll, MLD6_ADD_MAC_FILTER); - } -#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - - /* Do whatever else is needed to initialize interface. */ -} - -/** - * This function should do the actual transmission of the packet. The packet is - * contained in the pbuf that is passed to the function. This pbuf - * might be chained. - * - * @param netif the lwip network interface structure for this ethernetif - * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) - * @return ERR_OK if the packet could be sent - * an err_t value if the packet couldn't be sent - * - * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to - * strange results. You might consider waiting for space in the DMA queue - * to become available since the stack doesn't retry to send a packet - * dropped because of memory failure (except for the TCP timers). - */ - -static err_t -low_level_output(struct netif *netif, struct pbuf *p) -{ - struct ethernetif *ethernetif = netif->state; - struct pbuf *q; - - initiate transfer(); - -#if ETH_PAD_SIZE - pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ -#endif - - for (q = p; q != NULL; q = q->next) { - /* Send the data from the pbuf to the interface, one pbuf at a - time. The size of the data in each pbuf is kept in the ->len - variable. */ - send data from(q->payload, q->len); - } - - signal that packet should be sent(); - - MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); - if (((u8_t*)p->payload)[0] & 1) { - /* broadcast or multicast packet*/ - MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); - } else { - /* unicast packet */ - MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); - } - /* increase ifoutdiscards or ifouterrors on error */ - -#if ETH_PAD_SIZE - pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ -#endif - - LINK_STATS_INC(link.xmit); - - return ERR_OK; -} - -/** - * Should allocate a pbuf and transfer the bytes of the incoming - * packet from the interface into the pbuf. - * - * @param netif the lwip network interface structure for this ethernetif - * @return a pbuf filled with the received packet (including MAC header) - * NULL on memory error - */ -static struct pbuf * -low_level_input(struct netif *netif) -{ - struct ethernetif *ethernetif = netif->state; - struct pbuf *p, *q; - u16_t len; - - /* Obtain the size of the packet and put it into the "len" - variable. */ - len = ; - -#if ETH_PAD_SIZE - len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ -#endif - - /* We allocate a pbuf chain of pbufs from the pool. */ - p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); - - if (p != NULL) { - -#if ETH_PAD_SIZE - pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ -#endif - - /* We iterate over the pbuf chain until we have read the entire - * packet into the pbuf. */ - for (q = p; q != NULL; q = q->next) { - /* Read enough bytes to fill this pbuf in the chain. The - * available data in the pbuf is given by the q->len - * variable. - * This does not necessarily have to be a memcpy, you can also preallocate - * pbufs for a DMA-enabled MAC and after receiving truncate it to the - * actually received size. In this case, ensure the tot_len member of the - * pbuf is the sum of the chained pbuf len members. - */ - read data into(q->payload, q->len); - } - acknowledge that packet has been read(); - - MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); - if (((u8_t*)p->payload)[0] & 1) { - /* broadcast or multicast packet*/ - MIB2_STATS_NETIF_INC(netif, ifinnucastpkts); - } else { - /* unicast packet*/ - MIB2_STATS_NETIF_INC(netif, ifinucastpkts); - } -#if ETH_PAD_SIZE - pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ -#endif - - LINK_STATS_INC(link.recv); - } else { - drop packet(); - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(netif, ifindiscards); - } - - return p; -} - -/** - * This function should be called when a packet is ready to be read - * from the interface. It uses the function low_level_input() that - * should handle the actual reception of bytes from the network - * interface. Then the type of the received packet is determined and - * the appropriate input function is called. - * - * @param netif the lwip network interface structure for this ethernetif - */ -static void -ethernetif_input(struct netif *netif) -{ - struct ethernetif *ethernetif; - struct eth_hdr *ethhdr; - struct pbuf *p; - - ethernetif = netif->state; - - /* move received packet into a new pbuf */ - p = low_level_input(netif); - /* if no packet could be read, silently ignore this */ - if (p != NULL) { - /* pass all packets to ethernet_input, which decides what packets it supports */ - if (netif->input(p, netif) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); - pbuf_free(p); - p = NULL; - } - } -} - -/** - * Should be called at the beginning of the program to set up the - * network interface. It calls the function low_level_init() to do the - * actual setup of the hardware. - * - * This function should be passed as a parameter to netif_add(). - * - * @param netif the lwip network interface structure for this ethernetif - * @return ERR_OK if the loopif is initialized - * ERR_MEM if private data couldn't be allocated - * any other err_t on error - */ -err_t -ethernetif_init(struct netif *netif) -{ - struct ethernetif *ethernetif; - - LWIP_ASSERT("netif != NULL", (netif != NULL)); - - ethernetif = mem_malloc(sizeof(struct ethernetif)); - if (ethernetif == NULL) { - LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); - return ERR_MEM; - } - -#if LWIP_NETIF_HOSTNAME - /* Initialize interface hostname */ - netif->hostname = "lwip"; -#endif /* LWIP_NETIF_HOSTNAME */ - - /* - * Initialize the snmp variables and counters inside the struct netif. - * The last argument should be replaced with your link speed, in units - * of bits per second. - */ - MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); - - netif->state = ethernetif; - netif->name[0] = IFNAME0; - netif->name[1] = IFNAME1; - /* We directly use etharp_output() here to save a function call. - * You can instead declare your own function an call etharp_output() - * from it if you have to do some checks before sending (e.g. if link - * is available...) */ - netif->output = etharp_output; -#if LWIP_IPV6 - netif->output_ip6 = ethip6_output; -#endif /* LWIP_IPV6 */ - netif->linkoutput = low_level_output; - - ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); - - /* initialize the hardware */ - low_level_init(netif); - - return ERR_OK; -} - -#endif /* 0 */ diff --git a/ext/lwip/src/netif/lowpan6.c b/ext/lwip/src/netif/lowpan6.c deleted file mode 100644 index 407848c..0000000 --- a/ext/lwip/src/netif/lowpan6.c +++ /dev/null @@ -1,1204 +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 - * - */ - -/** - * @defgroup sixlowpan 6LowPAN netif - * @ingroup addons - * 6LowPAN netif implementation - */ - -#include "netif/lowpan6.h" - -#if LWIP_IPV6 && LWIP_6LOWPAN - -#include "lwip/ip.h" -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/nd6.h" -#include "lwip/mem.h" -#include "lwip/udp.h" -#include "lwip/tcpip.h" -#include "lwip/snmp.h" - -#include - -struct ieee_802154_addr { - u8_t addr_len; - u8_t addr[8]; -}; - -/** This is a helper struct. - */ -struct lowpan6_reass_helper { - struct pbuf *pbuf; - struct lowpan6_reass_helper *next_packet; - u8_t timer; - struct ieee_802154_addr sender_addr; - u16_t datagram_size; - u16_t datagram_tag; -}; - -static struct lowpan6_reass_helper * reass_list; - -#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 -static ip6_addr_t lowpan6_context[LWIP_6LOWPAN_NUM_CONTEXTS]; -#endif - -static u16_t ieee_802154_pan_id; - -static const struct ieee_802154_addr ieee_802154_broadcast = {2, {0xff, 0xff}}; - -#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS -static struct ieee_802154_addr short_mac_addr = {2, {0,0}}; -#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ - -static err_t dequeue_datagram(struct lowpan6_reass_helper *lrh); - -/** - * Periodic timer for 6LowPAN functions: - * - * - Remove incomplete/old packets - */ -void -lowpan6_tmr(void) -{ - struct lowpan6_reass_helper *lrh, *lrh_temp; - - lrh = reass_list; - while (lrh != NULL) { - lrh_temp = lrh->next_packet; - if ((--lrh->timer) == 0) { - dequeue_datagram(lrh); - pbuf_free(lrh->pbuf); - mem_free(lrh); - } - lrh = lrh_temp; - } -} - -/** - * Removes a datagram from the reassembly queue. - **/ -static err_t -dequeue_datagram(struct lowpan6_reass_helper *lrh) -{ - struct lowpan6_reass_helper *lrh_temp; - - if (reass_list == lrh) { - reass_list = reass_list->next_packet; - } else { - lrh_temp = reass_list; - while (lrh_temp != NULL) { - if (lrh_temp->next_packet == lrh) { - lrh_temp->next_packet = lrh->next_packet; - break; - } - lrh_temp = lrh_temp->next_packet; - } - } - - return ERR_OK; -} - -static s8_t -lowpan6_context_lookup(const ip6_addr_t *ip6addr) -{ - s8_t i; - - for (i = 0; i < LWIP_6LOWPAN_NUM_CONTEXTS; i++) { - if (ip6_addr_netcmp(&lowpan6_context[i], ip6addr)) { - return i; - } - } - - return -1; -} - -/* Determine compression mode for unicast address. */ -static s8_t -lowpan6_get_address_mode(const ip6_addr_t *ip6addr, const struct ieee_802154_addr *mac_addr) -{ - if (mac_addr->addr_len == 2) { - if ((ip6addr->addr[2] == (u32_t)PP_HTONL(0x000000ff)) && - ((ip6addr->addr[3] & PP_HTONL(0xffff0000)) == PP_NTOHL(0xfe000000))) { - if ((ip6addr->addr[3] & PP_HTONL(0x0000ffff)) == ntohl((mac_addr->addr[0] << 8) | mac_addr->addr[1])) { - return 3; - } - } - } else if (mac_addr->addr_len == 8) { - if ((ip6addr->addr[2] == ntohl(((mac_addr->addr[0] ^ 2) << 24) | (mac_addr->addr[1] << 16) | mac_addr->addr[2] << 8 | mac_addr->addr[3])) && - (ip6addr->addr[3] == ntohl((mac_addr->addr[4] << 24) | (mac_addr->addr[5] << 16) | mac_addr->addr[6] << 8 | mac_addr->addr[7]))) { - return 3; - } - } - - if ((ip6addr->addr[2] == PP_HTONL(0x000000ffUL)) && - ((ip6addr->addr[3] & PP_HTONL(0xffff0000)) == PP_NTOHL(0xfe000000UL))) { - return 2; - } - - return 1; -} - -/* Determine compression mode for multicast address. */ -static s8_t -lowpan6_get_address_mode_mc(const ip6_addr_t *ip6addr) -{ - if ((ip6addr->addr[0] == PP_HTONL(0xff020000)) && - (ip6addr->addr[1] == 0) && - (ip6addr->addr[2] == 0) && - ((ip6addr->addr[3] & PP_HTONL(0xffffff00)) == 0)) { - return 3; - } else if (((ip6addr->addr[0] & PP_HTONL(0xff00ffff)) == PP_HTONL(0xff000000)) && - (ip6addr->addr[1] == 0)) { - if ((ip6addr->addr[2] == 0) && - ((ip6addr->addr[3] & PP_HTONL(0xff000000)) == 0)) { - return 2; - } else if ((ip6addr->addr[2] & PP_HTONL(0xffffff00)) == 0) { - return 1; - } - } - - return 0; -} - -/* - * Encapsulates data into IEEE 802.15.4 frames. - * Fragments an IPv6 datagram into 6LowPAN units, which fit into IEEE 802.15.4 frames. - * If configured, will compress IPv6 and or UDP headers. - * */ -static err_t -lowpan6_frag(struct netif *netif, struct pbuf *p, const struct ieee_802154_addr *src, const struct ieee_802154_addr *dst) -{ - struct pbuf * p_frag; - u16_t frag_len, remaining_len; - u8_t * buffer; - u8_t ieee_header_len; - u8_t lowpan6_header_len; - s8_t i; - static u8_t frame_seq_num; - static u16_t datagram_tag; - u16_t datagram_offset; - err_t err = ERR_IF; - - /* We'll use a dedicated pbuf for building 6LowPAN fragments. */ - p_frag = pbuf_alloc(PBUF_RAW, 127, PBUF_RAM); - if (p_frag == NULL) { - MIB2_STATS_NETIF_INC(netif, ifoutdiscards); - return ERR_MEM; - } - - /* Write IEEE 802.15.4 header. */ - buffer = (u8_t*)p_frag->payload; - ieee_header_len = 0; - if (dst == &ieee_802154_broadcast) { - buffer[ieee_header_len++] = 0x01; /* data packet, no ack required. */ - } else { - buffer[ieee_header_len++] = 0x21; /* data packet, ack required. */ - } - buffer[ieee_header_len] = (0x00 << 4); /* 2003 frame version */ - buffer[ieee_header_len] |= (dst->addr_len == 2) ? (0x02 << 2) : (0x03 << 2); /* destination addressing mode */ - buffer[ieee_header_len] |= (src->addr_len == 2) ? (0x02 << 6) : (0x03 << 6); /* source addressing mode */ - ieee_header_len++; - buffer[ieee_header_len++] = frame_seq_num++; - - buffer[ieee_header_len++] = ieee_802154_pan_id & 0xff; /* pan id */ - buffer[ieee_header_len++] = (ieee_802154_pan_id >> 8) & 0xff; /* pan id */ - i = dst->addr_len; - while (i-- > 0) { - buffer[ieee_header_len++] = dst->addr[i]; - } - - buffer[ieee_header_len++] = ieee_802154_pan_id & 0xff; /* pan id */ - buffer[ieee_header_len++] = (ieee_802154_pan_id >> 8) & 0xff; /* pan id */ - i = src->addr_len; - while (i-- > 0) { - buffer[ieee_header_len++] = src->addr[i]; - } - -#if LWIP_6LOWPAN_IPHC - /* Perform 6LowPAN IPv6 header compression according to RFC 6282 */ - { - struct ip6_hdr *ip6hdr; - - /* Point to ip6 header and align copies of src/dest addresses. */ - ip6hdr = (struct ip6_hdr *)p->payload; - ip_addr_copy_from_ip6(ip_data.current_iphdr_dest, ip6hdr->dest); - ip_addr_copy_from_ip6(ip_data.current_iphdr_src, ip6hdr->src); - - /* Basic length of 6LowPAN header, set dispatch and clear fields. */ - lowpan6_header_len = 2; - buffer[ieee_header_len] = 0x60; - buffer[ieee_header_len + 1] = 0; - - /* Determine whether there will be a Context Identifier Extension byte or not. - * If so, set it already. */ -#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 - buffer[ieee_header_len + 2] = 0; - - i = lowpan6_context_lookup(ip_2_ip6(&ip_data.current_iphdr_src)); - if (i >= 0) { - /* Stateful source address compression. */ - buffer[ieee_header_len + 1] |= 0x40; - buffer[ieee_header_len + 2] |= (i & 0x0f) << 4; - } - - i = lowpan6_context_lookup(ip_2_ip6(&ip_data.current_iphdr_dest)); - if (i >= 0) { - /* Stateful destination address compression. */ - buffer[ieee_header_len + 1] |= 0x04; - buffer[ieee_header_len + 2] |= i & 0x0f; - } - - if (buffer[ieee_header_len + 2] != 0x00) { - /* Context identifier extension byte is appended. */ - buffer[ieee_header_len + 1] |= 0x80; - lowpan6_header_len++; - } -#endif /* LWIP_6LOWPAN_NUM_CONTEXTS > 0 */ - - /* Determine TF field: Traffic Class, Flow Label */ - if (IP6H_FL(ip6hdr) == 0) { - /* Flow label is elided. */ - buffer[ieee_header_len] |= 0x10; - if (IP6H_TC(ip6hdr) == 0) { - /* Traffic class (ECN+DSCP) elided too. */ - buffer[ieee_header_len] |= 0x08; - } else { - /* Traffic class (ECN+DSCP) appended. */ - buffer[ieee_header_len + lowpan6_header_len++] = IP6H_TC(ip6hdr); - } - } else { - if (((IP6H_TC(ip6hdr) & 0x3f) == 0)) { - /* DSCP portion of Traffic Class is elided, ECN and FL are appended (3 bytes) */ - buffer[ieee_header_len] |= 0x08; - - buffer[ieee_header_len + lowpan6_header_len] = IP6H_TC(ip6hdr) & 0xc0; - buffer[ieee_header_len + lowpan6_header_len++] |= (IP6H_FL(ip6hdr) >> 16) & 0x0f; - buffer[ieee_header_len + lowpan6_header_len++] = (IP6H_FL(ip6hdr) >> 8) & 0xff; - buffer[ieee_header_len + lowpan6_header_len++] = IP6H_FL(ip6hdr) & 0xff; - } else { - /* Traffic class and flow label are appended (4 bytes) */ - buffer[ieee_header_len + lowpan6_header_len++] = IP6H_TC(ip6hdr); - buffer[ieee_header_len + lowpan6_header_len++] = (IP6H_FL(ip6hdr) >> 16) & 0x0f; - buffer[ieee_header_len + lowpan6_header_len++] = (IP6H_FL(ip6hdr) >> 8) & 0xff; - buffer[ieee_header_len + lowpan6_header_len++] = IP6H_FL(ip6hdr) & 0xff; - } - } - - /* Compress NH? - * Only if UDP for now. @todo support other NH compression. */ - if (IP6H_NEXTH(ip6hdr) == IP6_NEXTH_UDP) { - buffer[ieee_header_len] |= 0x04; - } else { - /* append nexth. */ - buffer[ieee_header_len + lowpan6_header_len++] = IP6H_NEXTH(ip6hdr); - } - - /* Compress hop limit? */ - if (IP6H_HOPLIM(ip6hdr) == 255) { - buffer[ieee_header_len] |= 0x03; - } else if (IP6H_HOPLIM(ip6hdr) == 64) { - buffer[ieee_header_len] |= 0x02; - } else if (IP6H_HOPLIM(ip6hdr) == 1) { - buffer[ieee_header_len] |= 0x01; - } else { - /* append hop limit */ - buffer[ieee_header_len + lowpan6_header_len++] = IP6H_HOPLIM(ip6hdr); - } - - /* Compress source address */ - if (((buffer[ieee_header_len + 1] & 0x40) != 0) || - (ip6_addr_islinklocal(ip_2_ip6(&ip_data.current_iphdr_src)))) { - /* Context-based or link-local source address compression. */ - i = lowpan6_get_address_mode(ip_2_ip6(&ip_data.current_iphdr_src), src); - buffer[ieee_header_len + 1] |= (i & 0x03) << 4; - if (i == 1) { - MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 16, 8); - lowpan6_header_len += 8; - } else if (i == 2) { - MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 22, 2); - lowpan6_header_len += 2; - } - } else if (ip6_addr_isany(ip_2_ip6(&ip_data.current_iphdr_src))) { - /* Special case: mark SAC and leave SAM=0 */ - buffer[ieee_header_len + 1] |= 0x40; - } else { - /* Append full address. */ - MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 8, 16); - lowpan6_header_len += 16; - } - - /* Compress destination address */ - if (ip6_addr_ismulticast(ip_2_ip6(&ip_data.current_iphdr_dest))) { - /* @todo support stateful multicast address compression */ - - buffer[ieee_header_len + 1] |= 0x08; - - i = lowpan6_get_address_mode_mc(ip_2_ip6(&ip_data.current_iphdr_dest)); - buffer[ieee_header_len + 1] |= i & 0x03; - if (i == 0) { - MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 24, 16); - lowpan6_header_len += 16; - } else if (i == 1) { - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[25]; - MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 35, 5); - lowpan6_header_len += 5; - } else if (i == 2) { - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[25]; - MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 37, 3); - lowpan6_header_len += 3; - } else if (i == 3) { - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[39]; - } - } else if (((buffer[ieee_header_len + 1] & 0x04) != 0) || - (ip6_addr_islinklocal(ip_2_ip6(&ip_data.current_iphdr_dest)))) { - /* Context-based or link-local destination address compression. */ - i = lowpan6_get_address_mode(ip_2_ip6(&ip_data.current_iphdr_dest), dst); - buffer[ieee_header_len + 1] |= i & 0x03; - if (i == 1) { - MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 32, 8); - lowpan6_header_len += 8; - } else if (i == 2) { - MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 38, 2); - lowpan6_header_len += 2; - } - } else { - /* Append full address. */ - MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 24, 16); - lowpan6_header_len += 16; - } - - /* Move to payload. */ - pbuf_header(p, -IP6_HLEN); - - /* Compress UDP header? */ - if (IP6H_NEXTH(ip6hdr) == IP6_NEXTH_UDP) { - /* @todo support optional checksum compression */ - - buffer[ieee_header_len + lowpan6_header_len] = 0xf0; - - /* determine port compression mode. */ - if ((((u8_t *)p->payload)[0] == 0xf0) && ((((u8_t *)p->payload)[1] & 0xf0) == 0xb0) && - (((u8_t *)p->payload)[2] == 0xf0) && ((((u8_t *)p->payload)[3] & 0xf0) == 0xb0)) { - /* Compress source and dest ports. */ - buffer[ieee_header_len + lowpan6_header_len++] |= 0x03; - buffer[ieee_header_len + lowpan6_header_len++] = ((((u8_t *)p->payload)[1] & 0x0f) << 4) | (((u8_t *)p->payload)[3] & 0x0f); - } else if (((u8_t *)p->payload)[0] == 0xf0) { - /* Compress source port. */ - buffer[ieee_header_len + lowpan6_header_len++] |= 0x02; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[1]; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[2]; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[3]; - } else if (((u8_t *)p->payload)[2] == 0xf0) { - /* Compress dest port. */ - buffer[ieee_header_len + lowpan6_header_len++] |= 0x01; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[0]; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[1]; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[3]; - } else { - /* append full ports. */ - lowpan6_header_len++; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[0]; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[1]; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[2]; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[3]; - } - - /* elide length and copy checksum */ - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[6]; - buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[7]; - - pbuf_header(p, -UDP_HLEN); - } - } - -#else /* LWIP_6LOWPAN_HC */ - /* Send uncompressed IPv6 header with appropriate dispatch byte. */ - lowpan6_header_len = 1; - buffer[ieee_header_len] = 0x41; /* IPv6 dispatch */ -#endif /* LWIP_6LOWPAN_HC */ - - /* Calculate remaining packet length */ - remaining_len = p->tot_len; - - if (remaining_len > 0x7FF) { - MIB2_STATS_NETIF_INC(netif, ifoutdiscards); - /* datagram_size must fit into 11 bit */ - pbuf_free(p_frag); - return ERR_VAL; - } - - /* Fragment, or 1 packet? */ - if (remaining_len > (127 - ieee_header_len - lowpan6_header_len - 3)) { /* 127 - header - 1 byte dispatch - 2 bytes CRC */ - /* We must move the 6LowPAN header to make room for the FRAG header. */ - i = lowpan6_header_len; - while (i-- != 0) { - buffer[ieee_header_len + i + 4] = buffer[ieee_header_len + i]; - } - - /* Now we need to fragment the packet. FRAG1 header first */ - buffer[ieee_header_len] = 0xc0 | (((p->tot_len + lowpan6_header_len) >> 8) & 0x7); - buffer[ieee_header_len + 1] = (p->tot_len + lowpan6_header_len) & 0xff; - - datagram_tag++; - buffer[ieee_header_len + 2] = datagram_tag & 0xff; - buffer[ieee_header_len + 3] = (datagram_tag >> 8) & 0xff; - - /* Fragment follows. */ - frag_len = (127 - ieee_header_len - 4 - 2) & 0xf8; - - pbuf_copy_partial(p, buffer + ieee_header_len + lowpan6_header_len + 4, frag_len - lowpan6_header_len, 0); - remaining_len -= frag_len - lowpan6_header_len; - datagram_offset = frag_len; - - /* 2 bytes CRC */ -#if LWIP_6LOWPAN_HW_CRC - /* Leave blank, will be filled by HW. */ -#else /* LWIP_6LOWPAN_HW_CRC */ - /* @todo calculate CRC */ -#endif /* LWIP_6LOWPAN_HW_CRC */ - - /* Calculate frame length */ - p_frag->len = p_frag->tot_len = ieee_header_len + 4 + frag_len + 2; /* add 2 dummy bytes for crc*/ - - /* send the packet */ - MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); - LWIP_DEBUGF(LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); - err = netif->linkoutput(netif, p_frag); - - while ((remaining_len > 0) && (err == ERR_OK)) { - /* new frame, new seq num for ACK */ - buffer[2] = frame_seq_num++; - - buffer[ieee_header_len] |= 0x20; /* Change FRAG1 to FRAGN */ - - buffer[ieee_header_len + 4] = (u8_t)(datagram_offset >> 3); /* datagram offset in FRAGN header (datagram_offset is max. 11 bit) */ - - frag_len = (127 - ieee_header_len - 5 - 2) & 0xf8; - if (frag_len > remaining_len) { - frag_len = remaining_len; - } - - pbuf_copy_partial(p, buffer + ieee_header_len + 5, frag_len, p->tot_len - remaining_len); - remaining_len -= frag_len; - datagram_offset += frag_len; - - /* 2 bytes CRC */ -#if LWIP_6LOWPAN_HW_CRC - /* Leave blank, will be filled by HW. */ -#else /* LWIP_6LOWPAN_HW_CRC */ - /* @todo calculate CRC */ -#endif /* LWIP_6LOWPAN_HW_CRC */ - - /* Calculate frame length */ - p_frag->len = p_frag->tot_len = frag_len + 5 + ieee_header_len + 2; - - /* send the packet */ - MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); - LWIP_DEBUGF(LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); - err = netif->linkoutput(netif, p_frag); - } - } else { - /* It fits in one frame. */ - frag_len = remaining_len; - - /* Copy IPv6 packet */ - pbuf_copy_partial(p, buffer + ieee_header_len + lowpan6_header_len, frag_len, 0); - remaining_len = 0; - - /* 2 bytes CRC */ -#if LWIP_6LOWPAN_HW_CRC - /* Leave blank, will be filled by HW. */ -#else /* LWIP_6LOWPAN_HW_CRC */ - /* @todo calculate CRC */ -#endif /* LWIP_6LOWPAN_HW_CRC */ - - /* Calculate frame length */ - p_frag->len = p_frag->tot_len = frag_len + lowpan6_header_len + ieee_header_len + 2; - - /* send the packet */ - MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); - LWIP_DEBUGF(LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); - err = netif->linkoutput(netif, p_frag); - } - - pbuf_free(p_frag); - - return err; -} - -err_t -lowpan6_set_context(u8_t idx, const ip6_addr_t * context) -{ - if (idx >= LWIP_6LOWPAN_NUM_CONTEXTS) { - return ERR_ARG; - } - - ip6_addr_set(&lowpan6_context[idx], context); - - return ERR_OK; -} - -#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS -err_t -lowpan6_set_short_addr(u8_t addr_high, u8_t addr_low) -{ - short_mac_addr.addr[0] = addr_high; - short_mac_addr.addr[1] = addr_low; - - return ERR_OK; -} -#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ - -#if LWIP_IPV4 -err_t -lowpan4_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) -{ - (void)netif; - (void)q; - (void)ipaddr; - - return ERR_IF; -} -#endif /* LWIP_IPV4 */ - -/** - * Resolve and fill-in IEEE 802.15.4 address header for outgoing IPv6 packet. - * - * Perform Header Compression and fragment if necessary. - * - * @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_t -lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) -{ - s8_t i; - struct ieee_802154_addr src, dest; -#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS - ip6_addr_t ip6_src; - struct ip6_hdr * ip6_hdr; -#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ - -#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS - /* Check if we can compress source address (use aligned copy) */ - ip6_hdr = (struct ip6_hdr *)q->payload; - ip6_addr_set(&ip6_src, &ip6_hdr->src); - if (lowpan6_get_address_mode(&ip6_src, &short_mac_addr) == 3) { - src.addr_len = 2; - src.addr[0] = short_mac_addr.addr[0]; - src.addr[1] = short_mac_addr.addr[1]; - } else -#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ - { - src.addr_len = netif->hwaddr_len; - SMEMCPY(src.addr, netif->hwaddr, netif->hwaddr_len); - } - - /* multicast destination IP address? */ - if (ip6_addr_ismulticast(ip6addr)) { - MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); - /* We need to send to the broadcast address.*/ - return lowpan6_frag(netif, q, &src, &ieee_802154_broadcast); - } - - /* We have a unicast destination IP address */ - /* @todo anycast? */ - -#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS - if (src.addr_len == 2) { - /* If source address was compressable to short_mac_addr, and dest has same subnet and - * is also compressable to 2-bytes, assume we can infer dest as a short address too. */ - dest.addr_len = 2; - dest.addr[0] = ((u8_t *)q->payload)[38]; - dest.addr[1] = ((u8_t *)q->payload)[39]; - if ((src.addr_len == 2) && (ip6_addr_netcmp(&ip6_hdr->src, &ip6_hdr->dest)) && - (lowpan6_get_address_mode(ip6addr, &dest) == 3)) { - MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); - return lowpan6_frag(netif, q, &src, &dest); - } - } -#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ - - - /* Get next hop record. */ - i = nd6_get_next_hop_entry(ip6addr, netif); - if (i < 0) { - MIB2_STATS_NETIF_INC(netif, ifoutdiscards); - /* failed to get a next hop neighbor record. */ - return ERR_MEM; - } - - /* Now that we have a destination record, send or queue the packet. */ - if (neighbor_cache[i].state == ND6_STALE) { - /* Switch to delay state. */ - neighbor_cache[i].state = ND6_DELAY; - neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; - } - /* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */ - if ((neighbor_cache[i].state == ND6_REACHABLE) || - (neighbor_cache[i].state == ND6_DELAY) || - (neighbor_cache[i].state == ND6_PROBE)) { - - /* Send out. */ - dest.addr_len = netif->hwaddr_len; - SMEMCPY(dest.addr, neighbor_cache[i].lladdr, netif->hwaddr_len); - MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); - return lowpan6_frag(netif, q, &src, &dest); - } - - /* We should queue packet on this interface. */ - return nd6_queue_packet(i, q); -} - -static struct pbuf * -lowpan6_decompress(struct pbuf * p, struct ieee_802154_addr * src, struct ieee_802154_addr * dest) -{ - struct pbuf * q; - u8_t * lowpan6_buffer; - s8_t lowpan6_offset; - struct ip6_hdr *ip6hdr; - s8_t i; - s8_t ip6_offset = IP6_HLEN; - - - q = pbuf_alloc(PBUF_IP, p->len + IP6_HLEN + UDP_HLEN, PBUF_POOL); - if (q == NULL) { - pbuf_free(p); - return NULL; - } - - lowpan6_buffer = (u8_t *)p->payload; - ip6hdr = (struct ip6_hdr *)q->payload; - - lowpan6_offset = 2; - if (lowpan6_buffer[1] & 0x80) { - lowpan6_offset++; - } - - /* Set IPv6 version, traffic class and flow label. */ - if ((lowpan6_buffer[0] & 0x18) == 0x00) { - IP6H_VTCFL_SET(ip6hdr, 6, lowpan6_buffer[lowpan6_offset], ((lowpan6_buffer[lowpan6_offset+1] & 0x0f) << 16) | (lowpan6_buffer[lowpan6_offset + 2] << 8) | lowpan6_buffer[lowpan6_offset+3]); - lowpan6_offset += 4; - } else if ((lowpan6_buffer[0] & 0x18) == 0x08) { - IP6H_VTCFL_SET(ip6hdr, 6, lowpan6_buffer[lowpan6_offset] & 0xc0, ((lowpan6_buffer[lowpan6_offset] & 0x0f) << 16) | (lowpan6_buffer[lowpan6_offset + 1] << 8) | lowpan6_buffer[lowpan6_offset+2]); - lowpan6_offset += 3; - } else if ((lowpan6_buffer[0] & 0x18) == 0x10) { - IP6H_VTCFL_SET(ip6hdr, 6, lowpan6_buffer[lowpan6_offset],0); - lowpan6_offset += 1; - } else if ((lowpan6_buffer[0] & 0x18) == 0x18) { - IP6H_VTCFL_SET(ip6hdr, 6, 0, 0); - } - - /* Set Next Header */ - if ((lowpan6_buffer[0] & 0x04) == 0x00) { - IP6H_NEXTH_SET(ip6hdr, lowpan6_buffer[lowpan6_offset++]); - } else { - /* We should fill this later with NHC decoding */ - IP6H_NEXTH_SET(ip6hdr, 0); - } - - /* Set Hop Limit */ - if ((lowpan6_buffer[0] & 0x03) == 0x00) { - IP6H_HOPLIM_SET(ip6hdr, lowpan6_buffer[lowpan6_offset++]); - } else if ((lowpan6_buffer[0] & 0x03) == 0x01) { - IP6H_HOPLIM_SET(ip6hdr, 1); - } else if ((lowpan6_buffer[0] & 0x03) == 0x02) { - IP6H_HOPLIM_SET(ip6hdr, 64); - } else if ((lowpan6_buffer[0] & 0x03) == 0x03) { - IP6H_HOPLIM_SET(ip6hdr, 255); - } - - /* Source address decoding. */ - if ((lowpan6_buffer[1] & 0x40) == 0x00) { - /* Stateless compression */ - if ((lowpan6_buffer[1] & 0x30) == 0x00) { - /* copy full address */ - MEMCPY(&ip6hdr->src.addr[0], lowpan6_buffer + lowpan6_offset, 16); - lowpan6_offset += 16; - } else if ((lowpan6_buffer[1] & 0x30) == 0x10) { - ip6hdr->src.addr[0] = PP_HTONL(0xfe800000UL); - ip6hdr->src.addr[1] = 0; - MEMCPY(&ip6hdr->src.addr[2], lowpan6_buffer + lowpan6_offset, 8); - lowpan6_offset += 8; - } else if ((lowpan6_buffer[1] & 0x30) == 0x20) { - ip6hdr->src.addr[0] = PP_HTONL(0xfe800000UL); - ip6hdr->src.addr[1] = 0; - ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); - ip6hdr->src.addr[3] = htonl(0xfe000000UL | (lowpan6_buffer[lowpan6_offset] << 8) | - lowpan6_buffer[lowpan6_offset+1]); - lowpan6_offset += 2; - } else if ((lowpan6_buffer[1] & 0x30) == 0x30) { - ip6hdr->src.addr[0] = PP_HTONL(0xfe800000UL); - ip6hdr->src.addr[1] = 0; - if (src->addr_len == 2) { - ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); - ip6hdr->src.addr[3] = htonl(0xfe000000UL | (src->addr[0] << 8) | src->addr[1]); - } else { - ip6hdr->src.addr[2] = htonl(((src->addr[0] ^ 2) << 24) | (src->addr[1] << 16) | - (src->addr[2] << 8) | src->addr[3]); - ip6hdr->src.addr[3] = htonl((src->addr[4] << 24) | (src->addr[5] << 16) | - (src->addr[6] << 8) | src->addr[7]); - } - } - } else { - /* Stateful compression */ - if ((lowpan6_buffer[1] & 0x30) == 0x00) { - /* ANY address */ - ip6hdr->src.addr[0] = 0; - ip6hdr->src.addr[1] = 0; - ip6hdr->src.addr[2] = 0; - ip6hdr->src.addr[3] = 0; - } else { - /* Set prefix from context info */ - if (lowpan6_buffer[1] & 0x80) { - i = (lowpan6_buffer[2] >> 4) & 0x0f; - } else { - i = 0; - } - if (i >= LWIP_6LOWPAN_NUM_CONTEXTS) { - /* Error */ - pbuf_free(p); - pbuf_free(q); - return NULL; - } - - ip6hdr->src.addr[0] = lowpan6_context[i].addr[0]; - ip6hdr->src.addr[1] = lowpan6_context[i].addr[1]; - } - - if ((lowpan6_buffer[1] & 0x30) == 0x10) { - MEMCPY(&ip6hdr->src.addr[2], lowpan6_buffer + lowpan6_offset, 8); - lowpan6_offset += 8; - } else if ((lowpan6_buffer[1] & 0x30) == 0x20) { - ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); - ip6hdr->src.addr[3] = htonl(0xfe000000UL | (lowpan6_buffer[lowpan6_offset] << 8) | lowpan6_buffer[lowpan6_offset+1]); - lowpan6_offset += 2; - } else if ((lowpan6_buffer[1] & 0x30) == 0x30) { - if (src->addr_len == 2) { - ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); - ip6hdr->src.addr[3] = htonl(0xfe000000UL | (src->addr[0] << 8) | src->addr[1]); - } else { - ip6hdr->src.addr[2] = htonl(((src->addr[0] ^ 2) << 24) | (src->addr[1] << 16) | (src->addr[2] << 8) | src->addr[3]); - ip6hdr->src.addr[3] = htonl((src->addr[4] << 24) | (src->addr[5] << 16) | (src->addr[6] << 8) | src->addr[7]); - } - } - } - - /* Destination address decoding. */ - if (lowpan6_buffer[1] & 0x08) { - /* Multicast destination */ - if (lowpan6_buffer[1] & 0x04) { - /* @todo support stateful multicast addressing */ - pbuf_free(p); - pbuf_free(q); - return NULL; - } - - if ((lowpan6_buffer[1] & 0x03) == 0x00) { - /* copy full address */ - MEMCPY(&ip6hdr->dest.addr[0], lowpan6_buffer + lowpan6_offset, 16); - lowpan6_offset += 16; - } else if ((lowpan6_buffer[1] & 0x03) == 0x01) { - ip6hdr->dest.addr[0] = htonl(0xff000000UL | (lowpan6_buffer[lowpan6_offset++] << 16)); - ip6hdr->dest.addr[1] = 0; - ip6hdr->dest.addr[2] = htonl(lowpan6_buffer[lowpan6_offset++]); - ip6hdr->dest.addr[3] = htonl((lowpan6_buffer[lowpan6_offset] << 24) | (lowpan6_buffer[lowpan6_offset + 1] << 16) | (lowpan6_buffer[lowpan6_offset + 2] << 8) | lowpan6_buffer[lowpan6_offset + 3]); - lowpan6_offset += 4; - } else if ((lowpan6_buffer[1] & 0x03) == 0x02) { - ip6hdr->dest.addr[0] = htonl(0xff000000UL | lowpan6_buffer[lowpan6_offset++]); - ip6hdr->dest.addr[1] = 0; - ip6hdr->dest.addr[2] = 0; - ip6hdr->dest.addr[3] = htonl((lowpan6_buffer[lowpan6_offset] << 16) | (lowpan6_buffer[lowpan6_offset + 1] << 8) | lowpan6_buffer[lowpan6_offset + 2]); - lowpan6_offset += 3; - } else if ((lowpan6_buffer[1] & 0x03) == 0x03) { - ip6hdr->dest.addr[0] = PP_HTONL(0xff020000UL); - ip6hdr->dest.addr[1] = 0; - ip6hdr->dest.addr[2] = 0; - ip6hdr->dest.addr[3] = htonl(lowpan6_buffer[lowpan6_offset++]); - } - - } else { - if (lowpan6_buffer[1] & 0x04) { - /* Stateful destination compression */ - /* Set prefix from context info */ - if (lowpan6_buffer[1] & 0x80) { - i = lowpan6_buffer[2] & 0x0f; - } else { - i = 0; - } - if (i >= LWIP_6LOWPAN_NUM_CONTEXTS) { - /* Error */ - pbuf_free(p); - pbuf_free(q); - return NULL; - } - - ip6hdr->dest.addr[0] = lowpan6_context[i].addr[0]; - ip6hdr->dest.addr[1] = lowpan6_context[i].addr[1]; - } else { - /* Link local address compression */ - ip6hdr->dest.addr[0] = PP_HTONL(0xfe800000UL); - ip6hdr->dest.addr[1] = 0; - } - - if ((lowpan6_buffer[1] & 0x03) == 0x00) { - /* copy full address */ - MEMCPY(&ip6hdr->dest.addr[0], lowpan6_buffer + lowpan6_offset, 16); - lowpan6_offset += 16; - } else if ((lowpan6_buffer[1] & 0x03) == 0x01) { - MEMCPY(&ip6hdr->dest.addr[2], lowpan6_buffer + lowpan6_offset, 8); - lowpan6_offset += 8; - } else if ((lowpan6_buffer[1] & 0x03) == 0x02) { - ip6hdr->dest.addr[2] = PP_HTONL(0x000000ffUL); - ip6hdr->dest.addr[3] = htonl(0xfe000000UL | (lowpan6_buffer[lowpan6_offset] << 8) | lowpan6_buffer[lowpan6_offset + 1]); - lowpan6_offset += 2; - } else if ((lowpan6_buffer[1] & 0x03) == 0x03) { - if (dest->addr_len == 2) { - ip6hdr->dest.addr[2] = PP_HTONL(0x000000ffUL); - ip6hdr->dest.addr[3] = htonl(0xfe000000UL | (dest->addr[0] << 8) | dest->addr[1]); - } else { - ip6hdr->dest.addr[2] = htonl(((dest->addr[0] ^ 2) << 24) | (dest->addr[1] << 16) | dest->addr[2] << 8 | dest->addr[3]); - ip6hdr->dest.addr[3] = htonl((dest->addr[4] << 24) | (dest->addr[5] << 16) | dest->addr[6] << 8 | dest->addr[7]); - } - } - } - - - /* Next Header Compression (NHC) decoding? */ - if (lowpan6_buffer[0] & 0x04) { - if ((lowpan6_buffer[lowpan6_offset] & 0xf8) == 0xf0) { - struct udp_hdr *udphdr; - - /* UDP compression */ - IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_UDP); - udphdr = (struct udp_hdr *)((u8_t *)q->payload + ip6_offset); - - if (lowpan6_buffer[lowpan6_offset] & 0x04) { - /* @todo support checksum decompress */ - pbuf_free(p); - pbuf_free(q); - return NULL; - } - - /* Decompress ports */ - i = lowpan6_buffer[lowpan6_offset++] & 0x03; - if (i == 0) { - udphdr->src = htons(lowpan6_buffer[lowpan6_offset] << 8 | lowpan6_buffer[lowpan6_offset + 1]); - udphdr->dest = htons(lowpan6_buffer[lowpan6_offset + 2] << 8 | lowpan6_buffer[lowpan6_offset + 3]); - lowpan6_offset += 4; - } else if (i == 0x01) { - udphdr->src = htons(lowpan6_buffer[lowpan6_offset] << 8 | lowpan6_buffer[lowpan6_offset + 1]); - udphdr->dest = htons(0xf000 | lowpan6_buffer[lowpan6_offset + 2]); - lowpan6_offset += 3; - } else if (i == 0x02) { - udphdr->src = htons(0xf000 | lowpan6_buffer[lowpan6_offset]); - udphdr->dest = htons(lowpan6_buffer[lowpan6_offset + 1] << 8 | lowpan6_buffer[lowpan6_offset + 2]); - lowpan6_offset += 3; - } else if (i == 0x03) { - udphdr->src = htons(0xf0b0 | ((lowpan6_buffer[lowpan6_offset] >> 4) & 0x0f)); - udphdr->dest = htons(0xf0b0 | (lowpan6_buffer[lowpan6_offset] & 0x0f)); - lowpan6_offset += 1; - } - - udphdr->chksum = htons(lowpan6_buffer[lowpan6_offset] << 8 | lowpan6_buffer[lowpan6_offset + 1]); - lowpan6_offset += 2; - udphdr->len = htons(p->tot_len - lowpan6_offset + UDP_HLEN); - - ip6_offset += UDP_HLEN; - } else { - /* @todo support NHC other than UDP */ - pbuf_free(p); - pbuf_free(q); - return NULL; - } - } - - /* Now we copy leftover contents from p to q, so we have all L2 and L3 headers (and L4?) in a single PBUF. - * Replace p with q, and free p */ - pbuf_header(p, -lowpan6_offset); - MEMCPY((u8_t*)q->payload + ip6_offset, p->payload, p->len); - q->len = q->tot_len = ip6_offset + p->len; - if (p->next != NULL) { - pbuf_cat(q, p->next); - } - p->next = NULL; - pbuf_free(p); - - /* Infer IPv6 payload length for header */ - IP6H_PLEN_SET(ip6hdr, q->tot_len - IP6_HLEN); - - /* all done */ - return q; -} - -err_t -lowpan6_input(struct pbuf * p, struct netif *netif) -{ - u8_t * puc; - s8_t i; - struct ieee_802154_addr src, dest; - u16_t datagram_size, datagram_offset, datagram_tag; - struct lowpan6_reass_helper *lrh, *lrh_temp; - - MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); - - /* Analyze header. @todo validate. */ - puc = (u8_t*)p->payload; - datagram_offset = 5; - if ((puc[1] & 0x0c) == 0x0c) { - dest.addr_len = 8; - for (i = 0; i < 8; i++) { - dest.addr[i] = puc[datagram_offset + 7 - i]; - } - datagram_offset += 8; - } else { - dest.addr_len = 2; - dest.addr[0] = puc[datagram_offset + 1]; - dest.addr[1] = puc[datagram_offset]; - datagram_offset += 2; - } - - datagram_offset += 2; /* skip PAN ID. */ - - if ((puc[1] & 0xc0) == 0xc0) { - src.addr_len = 8; - for (i = 0; i < 8; i++) { - src.addr[i] = puc[datagram_offset + 7 - i]; - } - datagram_offset += 8; - } else { - src.addr_len = 2; - src.addr[0] = puc[datagram_offset + 1]; - src.addr[1] = puc[datagram_offset]; - datagram_offset += 2; - } - - pbuf_header(p, -datagram_offset); /* hide IEEE802.15.4 header. */ - - /* Check dispatch. */ - puc = (u8_t*)p->payload; - - if ((*puc & 0xf8) == 0xc0) { - /* FRAG1 dispatch. add this packet to reassembly list. */ - datagram_size = ((u16_t)(puc[0] & 0x07) << 8) | (u16_t)puc[1]; - datagram_tag = ((u16_t)puc[2] << 8) | (u16_t)puc[3]; - - /* check for duplicate */ - lrh = reass_list; - while (lrh != NULL) { - if ((lrh->sender_addr.addr_len == src.addr_len) && - (memcmp(lrh->sender_addr.addr, src.addr, src.addr_len) == 0)) { - /* address match with packet in reassembly. */ - if ((datagram_tag == lrh->datagram_tag) && (datagram_size == lrh->datagram_size)) { - MIB2_STATS_NETIF_INC(netif, ifindiscards); - /* duplicate fragment. */ - pbuf_free(p); - return ERR_OK; - } else { - /* We are receiving the start of a new datagram. Discard old one (incomplete). */ - lrh_temp = lrh->next_packet; - dequeue_datagram(lrh); - pbuf_free(lrh->pbuf); - mem_free(lrh); - - /* Check next datagram in queue. */ - lrh = lrh_temp; - } - } else { - /* Check next datagram in queue. */ - lrh = lrh->next_packet; - } - } - - pbuf_header(p, -4); /* hide frag1 dispatch */ - - lrh = (struct lowpan6_reass_helper *) mem_malloc(sizeof(struct lowpan6_reass_helper)); - if (lrh == NULL) { - MIB2_STATS_NETIF_INC(netif, ifindiscards); - pbuf_free(p); - return ERR_MEM; - } - - lrh->sender_addr.addr_len = src.addr_len; - for (i = 0; i < src.addr_len; i++) { - lrh->sender_addr.addr[i] = src.addr[i]; - } - lrh->datagram_size = datagram_size; - lrh->datagram_tag = datagram_tag; - lrh->pbuf = p; - lrh->next_packet = reass_list; - lrh->timer = 2; - reass_list = lrh; - - return ERR_OK; - } else if ((*puc & 0xf8) == 0xe0) { - /* FRAGN dispatch, find packet being reassembled. */ - datagram_size = ((u16_t)(puc[0] & 0x07) << 8) | (u16_t)puc[1]; - datagram_tag = ((u16_t)puc[2] << 8) | (u16_t)puc[3]; - datagram_offset = (u16_t)puc[4] << 3; - pbuf_header(p, -5); /* hide frag1 dispatch */ - - for (lrh = reass_list; lrh != NULL; lrh = lrh->next_packet) { - if ((lrh->sender_addr.addr_len == src.addr_len) && - (memcmp(lrh->sender_addr.addr, src.addr, src.addr_len) == 0) && - (datagram_tag == lrh->datagram_tag) && - (datagram_size == lrh->datagram_size)) { - break; - } - } - if (lrh == NULL) { - /* rogue fragment */ - MIB2_STATS_NETIF_INC(netif, ifindiscards); - pbuf_free(p); - return ERR_OK; - } - - if (lrh->pbuf->tot_len < datagram_offset) { - /* duplicate, ignore. */ - pbuf_free(p); - return ERR_OK; - } else if (lrh->pbuf->tot_len > datagram_offset) { - MIB2_STATS_NETIF_INC(netif, ifindiscards); - /* We have missed a fragment. Delete whole reassembly. */ - dequeue_datagram(lrh); - pbuf_free(lrh->pbuf); - mem_free(lrh); - pbuf_free(p); - return ERR_OK; - } - pbuf_cat(lrh->pbuf, p); - p = NULL; - - /* is packet now complete?*/ - if (lrh->pbuf->tot_len >= lrh->datagram_size) { - /* dequeue from reass list. */ - dequeue_datagram(lrh); - - /* get pbuf */ - p = lrh->pbuf; - - /* release helper */ - mem_free(lrh); - } else { - return ERR_OK; - } - } - - if (p == NULL) { - return ERR_OK; - } - - /* We have a complete packet, check dispatch for headers. */ - puc = (u8_t*)p->payload; - - if (*puc == 0x41) { - /* This is a complete IPv6 packet, just skip dispatch byte. */ - pbuf_header(p, -1); /* hide dispatch byte. */ - } else if ((*puc & 0xe0 )== 0x60) { - /* IPv6 headers are compressed using IPHC. */ - p = lowpan6_decompress(p, &src, &dest); - if (p == NULL) { - MIB2_STATS_NETIF_INC(netif, ifindiscards); - return ERR_OK; - } - } else { - MIB2_STATS_NETIF_INC(netif, ifindiscards); - pbuf_free(p); - return ERR_OK; - } - - /* @todo: distinguish unicast/multicast */ - MIB2_STATS_NETIF_INC(netif, ifinucastpkts); - - return ip6_input(p, netif); -} - -err_t -lowpan6_if_init(struct netif *netif) -{ - netif->name[0] = 'L'; - netif->name[1] = '6'; -#if LWIP_IPV4 - netif->output = lowpan4_output; -#endif /* LWIP_IPV4 */ - netif->output_ip6 = lowpan6_output; - - MIB2_INIT_NETIF(netif, snmp_ifType_other, 0); - - /* maximum transfer unit */ - netif->mtu = 1280; - - /* broadcast capability */ - netif->flags = NETIF_FLAG_BROADCAST /* | NETIF_FLAG_LOWPAN6 */; - - return ERR_OK; -} - -err_t -lowpan6_set_pan_id(u16_t pan_id) -{ - ieee_802154_pan_id = pan_id; - - return ERR_OK; -} - -#if !NO_SYS -/** - * Pass a received packet to tcpip_thread for input processing - * - * @param p the received packet, p->payload pointing to the - * IEEE 802.15.4 header. - * @param inp the network interface on which the packet was received - */ -err_t -tcpip_6lowpan_input(struct pbuf *p, struct netif *inp) -{ - return tcpip_inpkt(p, inp, lowpan6_input); -} -#endif /* !NO_SYS */ - -#endif /* LWIP_IPV6 && LWIP_6LOWPAN */ diff --git a/ext/lwip/src/netif/ppp/PPPD_FOLLOWUP b/ext/lwip/src/netif/ppp/PPPD_FOLLOWUP deleted file mode 100644 index c231982..0000000 --- a/ext/lwip/src/netif/ppp/PPPD_FOLLOWUP +++ /dev/null @@ -1,473 +0,0 @@ -The lwIP PPP support is based from pppd 2.4.5 (http://ppp.samba.org) with -huge changes to match code size and memory requirements for embedded devices. - -Anyway, pppd has a mature codebase for years and the average commit count -is getting low on their Git repository, meaning that we can follow what -is happening on their side and merge what is relevant for lwIP. - -So, here is the pppd follow up, so that we don't get away too far from pppd. - - -== Patch fetched from from pppd Debian packages == - -This has nothing to do with pppd, but we merged some good patch from -Debian and this is a good place to be. - -- LCP adaptive echo, so that we don't send LCP echo request if we - are receiving data from peer, can be enabled by setting PPP_LCP_ADAPTIVE - to true. - -- IPCP no/replace default route option, were added in the early stage of - the ppp port, but it wasn't really helpful and was disabled when adding - the new API ppp_set_default() call, which gives the lwIP user control over - which one is the default interface, it was actually a requirement if you - are doing PPP over PPP (i.e. PPPoL2TP, VPN link, over PPPoE, ADSL link). - -- using rp-pppoe pppd exits with EXIT_OK after receiving a timeout waiting - for PADO due to no modem attached, bug reported to pppd bug tracker, fixed - in Debian but not in the latest (at the time when the port were started) - pppd release. - - -== Commits on pppd == - -2010-03-06 - Document +ipv6 and ipv6cp-accept-local - e7537958aee79b3f653c601e903cb31d78fb7dcc - -Don't care. - - -2010-03-06 - Install pppol2tp plugins with sane permissions - 406215672cfadc03017341fe03802d1c7294b903 - -Don't care. - - -2010-03-07 - pppd: Terminate correctly if lcp_lowerup delayed calling - fsm_lowerup - 3eb9e810cfa515543655659b72dde30c54fea0a5 - -Merged 2012-05-17. - - -2010-03-07 - rp_pppoe: Copy acName and pppd_pppoe_service after option parsing - cab58617fd9d328029fffabc788020264b4fa91f - -Don't care, is a patch for pppd/plugins/rp-pppoe/plugin.c which is not part -of the port. - - -2010-08-23 - set and reset options to control environment variables - for scripts. - 2b6310fd24dba8e0fca8999916a162f0a1842a84 - -We can't fork processes in embedded, therefore all the pppd process run -feature is disabled in the port, so we don't care about the new -"environment variables" pppd feature. - - -2010-08-23 - Nit: use _exit when exec fails and restrict values to 0-255 - per POSIX. - 2b4ea140432eeba5a007c0d4e6236bd0e0c12ba4 - -Again, we are not running as a heavy process, so all exit() or _exit() calls -were removed. - - -2010-08-23 - Fix quote handling in configuration files to be more like shell - quoting. - 3089132cdf5b58dbdfc2daf08ec5c08eb47f8aca - -We are not parsing config file, all the filesystem I/O stuff were disabled -in our port. - - -2010-08-24 - rp-pppoe: allow MTU to be increased up to 1500 - fd1dcdf758418f040da3ed801ab001b5e46854e7 - -Only concern changes on RP-PPPoE plugin, which we don't use. - - -2010-09-11 - chat: Allow TIMEOUT value to come from environment variable - ae80bf833e48a6202f44a935a68083ae52ad3824 - -See 2b6310fd24dba8e0fca8999916a162f0a1842a84. - - -2011-03-05 - pppdump: Fix printfs with insufficient arguments - 7b8db569642c83ba3283745034f2e2c95e459423 - -pppdump is a ppp tool outside pppd source tree. - - -2012-05-06 - pppd: Don't unconditionally disable VJ compression under Linux - d8a66adf98a0e525cf38031b42098d539da6eeb6 - -Patch for sys-linux.c, which we don't use. - - -2012-05-20 - Remove old version of Linux if_pppol2tp.h - c41092dd4c49267f232f6cba3d31c6c68bfdf68d - -Not in the port. - - -2012-05-20 - pppd: Make MSCHAP-v2 cope better with packet loss - 08ef47ca532294eb428238c831616748940e24a2 - -This is an interesting patch. However it consumes much more memory for -MSCHAP and I am not sure if the benefit worth it. The PPP client can -always start the authentication again if it failed for whatever reason. - - -2012-05-20 - scripts: Make poff ignore extra arguments to pppd - 18f515f32c9f5723a9c2c912601e04335106534b - -Again, we are not running scripts. - - -2012-05-20 - rp-pppoe plugin: Print leading zeros in MAC address - f5dda0cfc220c4b52e26144096d729e27b30f0f7 - -Again, we are not using the RP-PPPoE plugin. - - -2012-05-20 - pppd: Notify IPv6 up/down as we do for IPv4 - 845cda8fa18939cf56e60b073f63a7efa65336fc - -This is just a patch that adds plugins hooks for IPv6, the plugin interface -was disabled because we don't have .so plugins in embedded. - - -2012-05-20 - pppd: Enable IPV6 by default and fix some warnings - 0b6118239615e98959f7e0b4e746bdd197533248 - -Change on Makefile for IPv6, warnings were already cleared during port. - - -2012-05-20 - contrib: Fix pppgetpass.gtk compilation - 80a8e2ce257ca12cce723519a0f20ea1d663b14a - -Change on Makefile, don't care. - - -2012-05-20 - pppd: Don't crash if crypt() returns NULL - 04c4348108d847e034dd91066cc6843f60d71731 - -We are using the PolarSSL DES implementation that does not return NULL. - - -2012-05-20 - pppd: Eliminate some warnings - c44ae5e6a7338c96eb463881fe709b2dfaffe568 - -Again, we are handling compilation warnings on our own. - - -2012-05-20 - rp-pppoe plugin: Import some fixes from rp-pppoe-3.10 - 1817d83e51a411044e730ba89ebdb0480e1c8cd4 - -Once more, we are not using the RP-PPPoE plugin. - - -2013-01-23 - pppd: Clarify circumstances where DNS1/DNS2 environment variables are set - cf2f5c9538b9400ade23446a194729b0a4113b3a - -Documentation only. - - -2013-02-03 - ppp: ignore unrecognised radiusclient configuration directives - 7f736dde0da3c19855997d9e67370e351e15e923 - -Radius plugin, not in the port. - - -2013-02-03 - pppd: Take out unused %r conversion completely - 356d8d558d844412119aa18c8e5a113bc6459c7b - -Merged 2014-04-15. - - -2013-02-03 - pppd: Arrange to use logwtmp from libutil on Linux - 9617a7eb137f4fee62799a677a9ecf8d834db3f5 - -Patch for sys-linux.c, which we don't use. - - -2013-02-03 - pppdump: Eliminate some compiler warnings - 3e3acf1ba2b3046c072a42c19164788a9e419bd1 - -pppdump is a ppp tool outside pppd source tree. - - -2013-02-03 - chat: Correct spelling errors in the man page - 8dea1b969d266ccbf6f3a8c5474eb6dcd8838e3b - -Documentation only. - - -2013-02-03 - pppd: Fix spelling errors in man page - 9e05a25d76b3f83096c661678010320df673df6b - -Documentation only. - - -2013-02-03 - plugins/passprompt: Fix potential out-of-bounds array reference - 8edb889b753056a691a3e4b217a110a35f9fdedb - -Plugin patch, we do not have plugins. - - -2013-02-03 - chat: Fix *roff errors in the man page - a7c3489eeaf44e83ce592143c7c8a5b5c29f4c48 - -Documentation only. - - -2013-03-02 - pppd: Fix man page description of case when remote IP address isn't known - 224841f4799f4f1e2e71bc490c54448d66740f4f - -Documentation only. - - -2013-03-02 - pppd: Add master_detach option - 398ed2585640d198c53e736ee5bbd67f7ce8168e - -Option for multilink support, we do not support multilink and this option -is about detaching from the terminal, which is out of the embedded scope. - - -2013-03-11 - pppd: Default exit status to EXIT_CONNECT_FAILED during connection phase - 225361d64ae737afdc8cb57579a2f33525461bc9 - -Commented out in our port, and already fixed by a previously applied Debian patch. - - -2013-03-11 - pppstats: Fix undefined macro in man page - d16a3985eade5280b8e171f5dd0670a91cba0d39 - -Documentation only. - - -2013-05-11 - plugins/radius: Handle bindaddr keyword in radiusclient.conf - d883b2dbafeed3ebd9d7a56ab1469373bd001a3b - -Radius plugin, not in the port. - - -2013-06-09 - pppoatm: Remove explicit loading of pppoatm kernel module - 52cd43a84bea524033b918b603698104f221bbb7 - -PPPoATM plugin, not in the port. - - -2013-06-09 - pppd: Fix segfault in update_db_entry() - 37476164f15a45015310b9d4b197c2d7db1f7f8f - -We do not use the samba db. - - -2013-06-09 - chat: Fix some text that was intended to be literal - cd9683676618adcee8add2c3cfa3382341b5a1f6 - -Documentation only. - - -2013-06-09 - README.pppoe: Minor semantic fix - b5b8898af6fd3d44e873cfc66810ace5f1f47e17 - -Documentation only. - - -2013-06-10 - radius: Handle additional attributes - 2f581cd986a56f2ec4a95abad4f8297a1b10d7e2 - -Radius plugin, not in the port. - - -2013-06-10 - chat, pppd: Use \e instead of \\ in man pages - 8d6942415d22f6ca4377340ca26e345c3f5fa5db - -Documentation only. - - -2014-01-02 - pppd: Don't crash if NULL pointer passed to vslprintf for %q or %v - 906814431bddeb2061825fa1ebad1a967b6d87a9 - -Merged 2014-04-15. - - -2014-01-02 - pppd: Accept IPCP ConfAck packets containing MS-WINS options - a243f217f1c6ac1aa7793806bc88590d077f490a - -Merged 2014-04-15. - - -2014-01-02 - config: Update Solaris compiler options and enable CHAPMS and IPV6 - 99c46caaed01b7edba87962aa52b77fad61bfd7b - -Solaris port, don't care. - - -2014-01-02 - Update README and patchlevel for 2.4.6 release - 4043750fca36e7e0eb90d702e048ad1da4929418 - -Just release stuff. - - -2014-02-18 - pppd: Add option "stop-bits" to set number of serial port stop bits. - ad993a20ee485f0d0e2ac4105221641b200da6e2 - -Low level serial port, not in the port. - - -2014-03-09 - pppd: Separate IPv6 handling for sifup/sifdown - b04d2dc6df5c6b5650fea44250d58757ee3dac4a - -Reimplemented. - - -2014-03-09 - pppol2tp: Connect up/down events to notifiers and add IPv6 ones - fafbe50251efc7d6b4a8be652d085316e112b34f - -Not in the port. - - -2014-03-09 - pppd: Add declarations to eliminate compile warnings - 50967962addebe15c7a7e63116ff46a0441dc464 - -We are handling compilation warnings on our own - - -2014-03-09 - pppd: Eliminate some unnecessary ifdefs - de8da14d845ee6db9236ccfddabf1d8ebf045ddb - -We mostly did that previously. Anyway, merged 2014-12-24. - - -2014-08-01 - radius: Fix realms-config-file option - 880a81be7c8e0fe8567227bc17a1bff3ea035943 - -Radius plugin, not in the port. - - -2014-08-01 - pppd: Eliminate potential integer overflow in option parsing - 7658e8257183f062dc01f87969c140707c7e52cb - -pppd config file parser, not in the port. - - -2014-08-01 - pppd: Eliminate memory leak with multiple instances of a string option - b94b7fbbaa0589aa6ec5fdc733aeb9ff294d2656 - -pppd config file parser, not in the port. - - -2014-08-01 - pppd: Fix a stack variable overflow in MSCHAP-v2 - 36733a891fb56594fcee580f667b33a64b990981 - -This fixes a bug introduced in 08ef47ca ("pppd: Make MSCHAP-v2 cope better with packet loss"). - -We didn't merge 08ef47ca ;-) - - -2014-08-01 - winbind plugin: Add -DMPPE=1 to eliminate compiler warnings - 2b05e22c62095e97dd0a97e4b5588402c2185071 - -Linux plugin, not in the port. - - -2014-08-09 - Update README and patchlevel for 2.4.7 release - 6e8eaa7a78b31cdab2edf140a9c8afdb02ffaca5 - -Just release stuff. - - -2014-08-10 - abort on errors in subdir builds - 5e90783d11a59268e05f4cfb29ce2343b13e8ab2 - -Linux Makefile, not in the port. - - -2014-06-03 - pppd: add support for defaultroute-metric option - 35e5a569c988b1ff865b02a24d9a727a00db4da9 - -Only necessary for Linux, lwIP does not support route metrics. - - -2014-12-13 - scripts: Avoid killing wrong pppd - 67811a647d399db5d188a242827760615a0f86b5 - -pppd helper script, not in the port. - - -2014-12-20 - pppd: Fix sign-extension when displaying bytes in octal - 5e8c3cb256a7e86e3572a82a75d51c6850efdbdc - -Merged 2016-07-02. - - -2015-03-01 - Suppress false error message on PPPoE disconnect - 219aac3b53d0827549377f1bfe22853ee52d4405 - -PPPoE plugin, not in the port. - - -2015-03-01 - Send PADT on PPPoE disconnect - cd2c14f998c57bbe6a01dc5854f2763c0d7f31fb - -PPPoE plugin, not in the port. And our PPPoE implementation already does -that: pppoe_disconnect() calls pppoe_send_padt(). - - -2015-08-14 - pppd: ipxcp: Prevent buffer overrun on remote router name - fe149de624f96629a7f46732055d8f718c74b856 - -We never ported IPX support. lwIP does not support IPX. - - -2015-03-25 - pppd: Fix ccp_options.mppe type - 234edab99a6bb250cc9ecd384cca27b0c8b475ce - -We found that while working on MPPE support in lwIP, that's our patch ;-) - - -2015-03-24 - pppd: Fix ccp_cilen calculated size if both deflate_correct and deflate_draft are enabled - 094cb8ae4c61db225e67fedadb4964f846dd0c27 - -We found that while working on MPPE support in lwIP, that's our patch ;-) - - -2015-08-14 - Merge branch 'master' of https://github.com/ncopa/ppp - 3a5c9a8fbc8970375cd881151d44e4b6fe249c6a - -Merge commit, we don't care. - - -2015-08-14 - Merge branch 'master' of git://github.com/vapier/ppp - 912e4fc6665aca188dced7ea7fdc663ce5a2dd24 - -Merge commit, we don't care. - - -2015-08-14 - Merge branch 'bug_fix' of git://github.com/radaiming/ppp - dfd33d7f526ecd7b39dd1bba8101260d02af5ebb - -Merge commit, we don't care. - - -2015-08-14 - Merge branch 'master' of git://github.com/pprindeville/ppp - aa4a985f6114d08cf4e47634fb6325da71016473 - -Merge commit, we don't care. - - -2015-08-14 - Merge branch 'no-error-on-already-closed' of git://github.com/farnz/ppp - 6edf252483b30dbcdcc5059f01831455365d5b6e - -Merge commit, we don't care. - - -2015-08-14 - Merge branch 'send-padt-on-disconnect' of git://github.com/farnz/ppp - 84684243d651f55f6df69d2a6707b52fbbe62bb9 - -Merge commit, we don't care. diff --git a/ext/lwip/src/netif/ppp/auth.c b/ext/lwip/src/netif/ppp/auth.c deleted file mode 100644 index 6e80352..0000000 --- a/ext/lwip/src/netif/ppp/auth.c +++ /dev/null @@ -1,2503 +0,0 @@ -/* - * auth.c - PPP authentication and phase control. - * - * Copyright (c) 1993-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. - * - * Derived from main.c, which is: - * - * 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#if 0 /* UNUSED */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(_PATH_LASTLOG) && defined(__linux__) -#include -#endif - -#include -#include -#include - -#ifdef HAS_SHADOW -#include -#ifndef PW_PPP -#define PW_PPP PW_LOGIN -#endif -#endif - -#include -#endif /* UNUSED */ - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/fsm.h" -#include "netif/ppp/lcp.h" -#if CCP_SUPPORT -#include "netif/ppp/ccp.h" -#endif /* CCP_SUPPORT */ -#if ECP_SUPPORT -#include "netif/ppp/ecp.h" -#endif /* ECP_SUPPORT */ -#include "netif/ppp/ipcp.h" -#if PAP_SUPPORT -#include "netif/ppp/upap.h" -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT -#include "netif/ppp/chap-new.h" -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT -#include "netif/ppp/eap.h" -#endif /* EAP_SUPPORT */ -#if CBCP_SUPPORT -#include "netif/ppp/cbcp.h" -#endif - -#if 0 /* UNUSED */ -#include "session.h" -#endif /* UNUSED */ - -#if 0 /* UNUSED */ -/* Bits in scan_authfile return value */ -#define NONWILD_SERVER 1 -#define NONWILD_CLIENT 2 - -#define ISWILD(word) (word[0] == '*' && word[1] == 0) -#endif /* UNUSED */ - -#if 0 /* UNUSED */ -/* List of addresses which the peer may use. */ -static struct permitted_ip *addresses[NUM_PPP]; - -/* Wordlist giving addresses which the peer may use - without authenticating itself. */ -static struct wordlist *noauth_addrs; - -/* Remote telephone number, if available */ -char remote_number[MAXNAMELEN]; - -/* Wordlist giving remote telephone numbers which may connect. */ -static struct wordlist *permitted_numbers; - -/* Extra options to apply, from the secrets file entry for the peer. */ -static struct wordlist *extra_options; -#endif /* UNUSED */ - -#if 0 /* UNUSED */ -/* Set if we require authentication only because we have a default route. */ -static bool default_auth; - -/* Hook to enable a plugin to control the idle time limit */ -int (*idle_time_hook) (struct ppp_idle *) = NULL; - -/* Hook for a plugin to say whether we can possibly authenticate any peer */ -int (*pap_check_hook) (void) = NULL; - -/* Hook for a plugin to check the PAP user and password */ -int (*pap_auth_hook) (char *user, char *passwd, char **msgp, - struct wordlist **paddrs, - struct wordlist **popts) = NULL; - -/* Hook for a plugin to know about the PAP user logout */ -void (*pap_logout_hook) (void) = NULL; - -/* Hook for a plugin to get the PAP password for authenticating us */ -int (*pap_passwd_hook) (char *user, char *passwd) = NULL; - -/* Hook for a plugin to say if we can possibly authenticate a peer using CHAP */ -int (*chap_check_hook) (void) = NULL; - -/* Hook for a plugin to get the CHAP password for authenticating us */ -int (*chap_passwd_hook) (char *user, char *passwd) = NULL; - -/* Hook for a plugin to say whether it is OK if the peer - refuses to authenticate. */ -int (*null_auth_hook) (struct wordlist **paddrs, - struct wordlist **popts) = NULL; - -int (*allowed_address_hook) (u32_t addr) = NULL; -#endif /* UNUSED */ - -#ifdef HAVE_MULTILINK -/* Hook for plugin to hear when an interface joins a multilink bundle */ -void (*multilink_join_hook) (void) = NULL; -#endif - -#if PPP_NOTIFY -/* A notifier for when the peer has authenticated itself, - and we are proceeding to the network phase. */ -struct notifier *auth_up_notifier = NULL; - -/* A notifier for when the link goes down. */ -struct notifier *link_down_notifier = NULL; -#endif /* PPP_NOTIFY */ - -/* - * Option variables. - */ -#if 0 /* MOVED TO ppp_settings */ -bool uselogin = 0; /* Use /etc/passwd for checking PAP */ -bool session_mgmt = 0; /* Do session management (login records) */ -bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */ -bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */ -bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */ -bool refuse_eap = 0; /* Don't wanna auth. ourselves with EAP */ -#if MSCHAP_SUPPORT -bool refuse_mschap = 0; /* Don't wanna auth. ourselves with MS-CHAP */ -bool refuse_mschap_v2 = 0; /* Don't wanna auth. ourselves with MS-CHAPv2 */ -#else /* MSCHAP_SUPPORT */ -bool refuse_mschap = 1; /* Don't wanna auth. ourselves with MS-CHAP */ -bool refuse_mschap_v2 = 1; /* Don't wanna auth. ourselves with MS-CHAPv2 */ -#endif /* MSCHAP_SUPPORT */ -bool usehostname = 0; /* Use hostname for our_name */ -bool auth_required = 0; /* Always require authentication from peer */ -bool allow_any_ip = 0; /* Allow peer to use any IP address */ -bool explicit_remote = 0; /* User specified explicit remote name */ -bool explicit_user = 0; /* Set if "user" option supplied */ -bool explicit_passwd = 0; /* Set if "password" option supplied */ -char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ -static char *uafname; /* name of most recent +ua file */ - -extern char *crypt (const char *, const char *); -#endif /* UNUSED */ -/* Prototypes for procedures local to this file. */ - -static void network_phase(ppp_pcb *pcb); -#if PPP_IDLETIMELIMIT -static void check_idle(void *arg); -#endif /* PPP_IDLETIMELIMIT */ -#if PPP_MAXCONNECT -static void connect_time_expired(void *arg); -#endif /* PPP_MAXCONNECT */ -#if 0 /* UNUSED */ -static int null_login (int); -/* static int get_pap_passwd (char *); */ -static int have_pap_secret (int *); -static int have_chap_secret (char *, char *, int, int *); -static int have_srp_secret (char *client, char *server, int need_ip, - int *lacks_ipp); -static int ip_addr_check (u32_t, struct permitted_ip *); -static int scan_authfile (FILE *, char *, char *, char *, - struct wordlist **, struct wordlist **, - char *, int); -static void free_wordlist (struct wordlist *); -static void set_allowed_addrs (int, struct wordlist *, struct wordlist *); -static int some_ip_ok (struct wordlist *); -static int setupapfile (char **); -static int privgroup (char **); -static int set_noauth_addr (char **); -static int set_permitted_number (char **); -static void check_access (FILE *, char *); -static int wordlist_count (struct wordlist *); -#endif /* UNUSED */ - -#ifdef MAXOCTETS -static void check_maxoctets (void *); -#endif - -#if PPP_OPTIONS -/* - * Authentication-related options. - */ -option_t auth_options[] = { - { "auth", o_bool, &auth_required, - "Require authentication from peer", OPT_PRIO | 1 }, - { "noauth", o_bool, &auth_required, - "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV, - &allow_any_ip }, - { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap, - "Require PAP authentication from peer", - OPT_PRIOSUB | 1, &auth_required }, - { "+pap", o_bool, &lcp_wantoptions[0].neg_upap, - "Require PAP authentication from peer", - OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required }, - { "require-chap", o_bool, &auth_required, - "Require CHAP authentication from peer", - OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5, - &lcp_wantoptions[0].chap_mdtype }, - { "+chap", o_bool, &auth_required, - "Require CHAP authentication from peer", - OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5, - &lcp_wantoptions[0].chap_mdtype }, -#if MSCHAP_SUPPORT - { "require-mschap", o_bool, &auth_required, - "Require MS-CHAP authentication from peer", - OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT, - &lcp_wantoptions[0].chap_mdtype }, - { "+mschap", o_bool, &auth_required, - "Require MS-CHAP authentication from peer", - OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT, - &lcp_wantoptions[0].chap_mdtype }, - { "require-mschap-v2", o_bool, &auth_required, - "Require MS-CHAPv2 authentication from peer", - OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2, - &lcp_wantoptions[0].chap_mdtype }, - { "+mschap-v2", o_bool, &auth_required, - "Require MS-CHAPv2 authentication from peer", - OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2, - &lcp_wantoptions[0].chap_mdtype }, -#endif /* MSCHAP_SUPPORT */ -#if 0 - { "refuse-pap", o_bool, &refuse_pap, - "Don't agree to auth to peer with PAP", 1 }, - { "-pap", o_bool, &refuse_pap, - "Don't allow PAP authentication with peer", OPT_ALIAS | 1 }, - { "refuse-chap", o_bool, &refuse_chap, - "Don't agree to auth to peer with CHAP", - OPT_A2CLRB | MDTYPE_MD5, - &lcp_allowoptions[0].chap_mdtype }, - { "-chap", o_bool, &refuse_chap, - "Don't allow CHAP authentication with peer", - OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5, - &lcp_allowoptions[0].chap_mdtype }, -#endif -#if MSCHAP_SUPPORT -#if 0 - { "refuse-mschap", o_bool, &refuse_mschap, - "Don't agree to auth to peer with MS-CHAP", - OPT_A2CLRB | MDTYPE_MICROSOFT, - &lcp_allowoptions[0].chap_mdtype }, - { "-mschap", o_bool, &refuse_mschap, - "Don't allow MS-CHAP authentication with peer", - OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT, - &lcp_allowoptions[0].chap_mdtype }, - { "refuse-mschap-v2", o_bool, &refuse_mschap_v2, - "Don't agree to auth to peer with MS-CHAPv2", - OPT_A2CLRB | MDTYPE_MICROSOFT_V2, - &lcp_allowoptions[0].chap_mdtype }, - { "-mschap-v2", o_bool, &refuse_mschap_v2, - "Don't allow MS-CHAPv2 authentication with peer", - OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT_V2, - &lcp_allowoptions[0].chap_mdtype }, -#endif -#endif /* MSCHAP_SUPPORT*/ -#if EAP_SUPPORT - { "require-eap", o_bool, &lcp_wantoptions[0].neg_eap, - "Require EAP authentication from peer", OPT_PRIOSUB | 1, - &auth_required }, -#if 0 - { "refuse-eap", o_bool, &refuse_eap, - "Don't agree to authenticate to peer with EAP", 1 }, -#endif -#endif /* EAP_SUPPORT */ - { "name", o_string, our_name, - "Set local name for authentication", - OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXNAMELEN }, - - { "+ua", o_special, (void *)setupapfile, - "Get PAP user and password from file", - OPT_PRIO | OPT_A2STRVAL, &uafname }, - -#if 0 - { "user", o_string, user, - "Set name for auth with peer", OPT_PRIO | OPT_STATIC, - &explicit_user, MAXNAMELEN }, - - { "password", o_string, passwd, - "Password for authenticating us to the peer", - OPT_PRIO | OPT_STATIC | OPT_HIDE, - &explicit_passwd, MAXSECRETLEN }, -#endif - - { "usehostname", o_bool, &usehostname, - "Must use hostname for authentication", 1 }, - - { "remotename", o_string, remote_name, - "Set remote name for authentication", OPT_PRIO | OPT_STATIC, - &explicit_remote, MAXNAMELEN }, - - { "login", o_bool, &uselogin, - "Use system password database for PAP", OPT_A2COPY | 1 , - &session_mgmt }, - { "enable-session", o_bool, &session_mgmt, - "Enable session accounting for remote peers", OPT_PRIV | 1 }, - - { "papcrypt", o_bool, &cryptpap, - "PAP passwords are encrypted", 1 }, - - { "privgroup", o_special, (void *)privgroup, - "Allow group members to use privileged options", OPT_PRIV | OPT_A2LIST }, - - { "allow-ip", o_special, (void *)set_noauth_addr, - "Set IP address(es) which can be used without authentication", - OPT_PRIV | OPT_A2LIST }, - - { "remotenumber", o_string, remote_number, - "Set remote telephone number for authentication", OPT_PRIO | OPT_STATIC, - NULL, MAXNAMELEN }, - - { "allow-number", o_special, (void *)set_permitted_number, - "Set telephone number(s) which are allowed to connect", - OPT_PRIV | OPT_A2LIST }, - - { NULL } -}; -#endif /* PPP_OPTIONS */ - -#if 0 /* UNUSED */ -/* - * setupapfile - specifies UPAP info for authenticating with peer. - */ -static int -setupapfile(argv) - char **argv; -{ - FILE *ufile; - int l; - uid_t euid; - char u[MAXNAMELEN], p[MAXSECRETLEN]; - char *fname; - - lcp_allowoptions[0].neg_upap = 1; - - /* open user info file */ - fname = strdup(*argv); - if (fname == NULL) - novm("+ua file name"); - euid = geteuid(); - if (seteuid(getuid()) == -1) { - option_error("unable to reset uid before opening %s: %m", fname); - return 0; - } - ufile = fopen(fname, "r"); - if (seteuid(euid) == -1) - fatal("unable to regain privileges: %m"); - if (ufile == NULL) { - option_error("unable to open user login data file %s", fname); - return 0; - } - check_access(ufile, fname); - uafname = fname; - - /* get username */ - if (fgets(u, MAXNAMELEN - 1, ufile) == NULL - || fgets(p, MAXSECRETLEN - 1, ufile) == NULL) { - fclose(ufile); - option_error("unable to read user login data file %s", fname); - return 0; - } - fclose(ufile); - - /* get rid of newlines */ - l = strlen(u); - if (l > 0 && u[l-1] == '\n') - u[l-1] = 0; - l = strlen(p); - if (l > 0 && p[l-1] == '\n') - p[l-1] = 0; - - if (override_value("user", option_priority, fname)) { - strlcpy(ppp_settings.user, u, sizeof(ppp_settings.user)); - explicit_user = 1; - } - if (override_value("passwd", option_priority, fname)) { - strlcpy(ppp_settings.passwd, p, sizeof(ppp_settings.passwd)); - explicit_passwd = 1; - } - - return (1); -} - -/* - * privgroup - allow members of the group to have privileged access. - */ -static int -privgroup(argv) - char **argv; -{ - struct group *g; - int i; - - g = getgrnam(*argv); - if (g == 0) { - option_error("group %s is unknown", *argv); - return 0; - } - for (i = 0; i < ngroups; ++i) { - if (groups[i] == g->gr_gid) { - privileged = 1; - break; - } - } - return 1; -} - - -/* - * set_noauth_addr - set address(es) that can be used without authentication. - * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets. - */ -static int -set_noauth_addr(argv) - char **argv; -{ - char *addr = *argv; - int l = strlen(addr) + 1; - struct wordlist *wp; - - wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l); - if (wp == NULL) - novm("allow-ip argument"); - wp->word = (char *) (wp + 1); - wp->next = noauth_addrs; - MEMCPY(wp->word, addr, l); - noauth_addrs = wp; - return 1; -} - - -/* - * set_permitted_number - set remote telephone number(s) that may connect. - */ -static int -set_permitted_number(argv) - char **argv; -{ - char *number = *argv; - int l = strlen(number) + 1; - struct wordlist *wp; - - wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l); - if (wp == NULL) - novm("allow-number argument"); - wp->word = (char *) (wp + 1); - wp->next = permitted_numbers; - MEMCPY(wp->word, number, l); - permitted_numbers = wp; - return 1; -} -#endif - -/* - * An Open on LCP has requested a change from Dead to Establish phase. - */ -void link_required(ppp_pcb *pcb) { - LWIP_UNUSED_ARG(pcb); -} - -#if 0 -/* - * Bring the link up to the point of being able to do ppp. - */ -void start_link(unit) - int unit; -{ - ppp_pcb *pcb = &ppp_pcb_list[unit]; - char *msg; - - status = EXIT_NEGOTIATION_FAILED; - new_phase(pcb, PPP_PHASE_SERIALCONN); - - hungup = 0; - devfd = the_channel->connect(); - msg = "Connect script failed"; - if (devfd < 0) - goto fail; - - /* set up the serial device as a ppp interface */ - /* - * N.B. we used to do tdb_writelock/tdb_writeunlock around this - * (from establish_ppp to set_ifunit). However, we won't be - * doing the set_ifunit in multilink mode, which is the only time - * we need the atomicity that the tdb_writelock/tdb_writeunlock - * gives us. Thus we don't need the tdb_writelock/tdb_writeunlock. - */ - fd_ppp = the_channel->establish_ppp(devfd); - msg = "ppp establishment failed"; - if (fd_ppp < 0) { - status = EXIT_FATAL_ERROR; - goto disconnect; - } - - if (!demand && ifunit >= 0) - set_ifunit(1); - - /* - * Start opening the connection and wait for - * incoming events (reply, timeout, etc.). - */ - if (ifunit >= 0) - ppp_notice("Connect: %s <--> %s", ifname, ppp_devnam); - else - ppp_notice("Starting negotiation on %s", ppp_devnam); - add_fd(fd_ppp); - - new_phase(pcb, PPP_PHASE_ESTABLISH); - - lcp_lowerup(pcb); - return; - - disconnect: - new_phase(pcb, PPP_PHASE_DISCONNECT); - if (the_channel->disconnect) - the_channel->disconnect(); - - fail: - new_phase(pcb, PPP_PHASE_DEAD); - if (the_channel->cleanup) - (*the_channel->cleanup)(); -} -#endif - -/* - * LCP has terminated the link; go to the Dead phase and take the - * physical layer down. - */ -void link_terminated(ppp_pcb *pcb) { - if (pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_MASTER) - return; - new_phase(pcb, PPP_PHASE_DISCONNECT); - -#if 0 /* UNUSED */ - if (pap_logout_hook) { - pap_logout_hook(); - } - session_end(devnam); -#endif /* UNUSED */ - - if (!doing_multilink) { - ppp_notice("Connection terminated."); -#if PPP_STATS_SUPPORT - print_link_stats(); -#endif /* PPP_STATS_SUPPORT */ - } else - ppp_notice("Link terminated."); - - lcp_lowerdown(pcb); - - new_phase(pcb, PPP_PHASE_DEAD); - ppp_link_terminated(pcb); -#if 0 - /* - * Delete pid files before disestablishing ppp. Otherwise it - * can happen that another pppd gets the same unit and then - * we delete its pid file. - */ - if (!doing_multilink && !demand) - remove_pidfiles(); - - /* - * If we may want to bring the link up again, transfer - * the ppp unit back to the loopback. Set the - * real serial device back to its normal mode of operation. - */ - if (fd_ppp >= 0) { - remove_fd(fd_ppp); - clean_check(); - the_channel->disestablish_ppp(devfd); - if (doing_multilink) - mp_exit_bundle(); - fd_ppp = -1; - } - if (!hungup) - lcp_lowerdown(pcb); - if (!doing_multilink && !demand) - script_unsetenv("IFNAME"); - - /* - * Run disconnector script, if requested. - * XXX we may not be able to do this if the line has hung up! - */ - if (devfd >= 0 && the_channel->disconnect) { - the_channel->disconnect(); - devfd = -1; - } - if (the_channel->cleanup) - (*the_channel->cleanup)(); - - if (doing_multilink && multilink_master) { - if (!bundle_terminating) - new_phase(pcb, PPP_PHASE_MASTER); - else - mp_bundle_terminated(); - } else - new_phase(pcb, PPP_PHASE_DEAD); -#endif -} - -/* - * LCP has gone down; it will either die or try to re-establish. - */ -void link_down(ppp_pcb *pcb) { -#if PPP_NOTIFY - notify(link_down_notifier, 0); -#endif /* PPP_NOTIFY */ - - if (!doing_multilink) { - upper_layers_down(pcb); - if (pcb->phase != PPP_PHASE_DEAD && pcb->phase != PPP_PHASE_MASTER) - new_phase(pcb, PPP_PHASE_ESTABLISH); - } - /* XXX if doing_multilink, should do something to stop - network-layer traffic on the link */ -} - -void upper_layers_down(ppp_pcb *pcb) { - int i; - const struct protent *protp; - - for (i = 0; (protp = protocols[i]) != NULL; ++i) { - if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) - (*protp->lowerdown)(pcb); - if (protp->protocol < 0xC000 && protp->close != NULL) - (*protp->close)(pcb, "LCP down"); - } - pcb->num_np_open = 0; - pcb->num_np_up = 0; -} - -/* - * The link is established. - * Proceed to the Dead, Authenticate or Network phase as appropriate. - */ -void link_established(ppp_pcb *pcb) { -#if PPP_AUTH_SUPPORT - int auth; -#if PPP_SERVER -#if PAP_SUPPORT - lcp_options *wo = &pcb->lcp_wantoptions; -#endif /* PAP_SUPPORT */ - lcp_options *go = &pcb->lcp_gotoptions; -#endif /* PPP_SERVER */ - lcp_options *ho = &pcb->lcp_hisoptions; -#endif /* PPP_AUTH_SUPPORT */ - int i; - const struct protent *protp; - - /* - * Tell higher-level protocols that LCP is up. - */ - if (!doing_multilink) { - for (i = 0; (protp = protocols[i]) != NULL; ++i) - if (protp->protocol != PPP_LCP - && protp->lowerup != NULL) - (*protp->lowerup)(pcb); - } - -#if PPP_AUTH_SUPPORT -#if PPP_SERVER -#if PPP_ALLOWED_ADDRS - if (!auth_required && noauth_addrs != NULL) - set_allowed_addrs(unit, NULL, NULL); -#endif /* PPP_ALLOWED_ADDRS */ - - if (pcb->settings.auth_required && !(0 -#if PAP_SUPPORT - || go->neg_upap -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - || go->neg_chap -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - || go->neg_eap -#endif /* EAP_SUPPORT */ - )) { - -#if PPP_ALLOWED_ADDRS - /* - * We wanted the peer to authenticate itself, and it refused: - * if we have some address(es) it can use without auth, fine, - * otherwise treat it as though it authenticated with PAP using - * a username of "" and a password of "". If that's not OK, - * boot it out. - */ - if (noauth_addrs != NULL) { - set_allowed_addrs(unit, NULL, NULL); - } else -#endif /* PPP_ALLOWED_ADDRS */ - if (!pcb->settings.null_login -#if PAP_SUPPORT - || !wo->neg_upap -#endif /* PAP_SUPPORT */ - ) { - ppp_warn("peer refused to authenticate: terminating link"); -#if 0 /* UNUSED */ - status = EXIT_PEER_AUTH_FAILED; -#endif /* UNUSED */ - pcb->err_code = PPPERR_AUTHFAIL; - lcp_close(pcb, "peer refused to authenticate"); - return; - } - } -#endif /* PPP_SERVER */ - - new_phase(pcb, PPP_PHASE_AUTHENTICATE); - auth = 0; -#if PPP_SERVER -#if EAP_SUPPORT - if (go->neg_eap) { - eap_authpeer(pcb, PPP_OUR_NAME); - auth |= EAP_PEER; - } else -#endif /* EAP_SUPPORT */ -#if CHAP_SUPPORT - if (go->neg_chap) { - chap_auth_peer(pcb, PPP_OUR_NAME, CHAP_DIGEST(go->chap_mdtype)); - auth |= CHAP_PEER; - } else -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - if (go->neg_upap) { - upap_authpeer(pcb); - auth |= PAP_PEER; - } else -#endif /* PAP_SUPPORT */ - {} -#endif /* PPP_SERVER */ - -#if EAP_SUPPORT - if (ho->neg_eap) { - eap_authwithpeer(pcb, pcb->settings.user); - auth |= EAP_WITHPEER; - } else -#endif /* EAP_SUPPORT */ -#if CHAP_SUPPORT - if (ho->neg_chap) { - chap_auth_with_peer(pcb, pcb->settings.user, CHAP_DIGEST(ho->chap_mdtype)); - auth |= CHAP_WITHPEER; - } else -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - if (ho->neg_upap) { - upap_authwithpeer(pcb, pcb->settings.user, pcb->settings.passwd); - auth |= PAP_WITHPEER; - } else -#endif /* PAP_SUPPORT */ - {} - - pcb->auth_pending = auth; - pcb->auth_done = 0; - - if (!auth) -#endif /* PPP_AUTH_SUPPORT */ - network_phase(pcb); -} - -/* - * Proceed to the network phase. - */ -static void network_phase(ppp_pcb *pcb) { -#if CBCP_SUPPORT - ppp_pcb *pcb = &ppp_pcb_list[unit]; -#endif -#if 0 /* UNUSED */ - lcp_options *go = &lcp_gotoptions[unit]; -#endif /* UNUSED */ - -#if 0 /* UNUSED */ - /* Log calling number. */ - if (*remote_number) - ppp_notice("peer from calling number %q authorized", remote_number); -#endif /* UNUSED */ - -#if PPP_NOTIFY - /* - * If the peer had to authenticate, notify it now. - */ - if (0 -#if CHAP_SUPPORT - || go->neg_chap -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - || go->neg_upap -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - || go->neg_eap -#endif /* EAP_SUPPORT */ - ) { - notify(auth_up_notifier, 0); - } -#endif /* PPP_NOTIFY */ - -#if CBCP_SUPPORT - /* - * If we negotiated callback, do it now. - */ - if (go->neg_cbcp) { - new_phase(pcb, PPP_PHASE_CALLBACK); - (*cbcp_protent.open)(pcb); - return; - } -#endif - -#if PPP_OPTIONS - /* - * Process extra options from the secrets file - */ - if (extra_options) { - options_from_list(extra_options, 1); - free_wordlist(extra_options); - extra_options = 0; - } -#endif /* PPP_OPTIONS */ - start_networks(pcb); -} - -void start_networks(ppp_pcb *pcb) { -#if CCP_SUPPORT || ECP_SUPPORT - int i; - const struct protent *protp; -#endif /* CCP_SUPPORT || ECP_SUPPORT */ - - new_phase(pcb, PPP_PHASE_NETWORK); - -#ifdef HAVE_MULTILINK - if (multilink) { - if (mp_join_bundle()) { - if (multilink_join_hook) - (*multilink_join_hook)(); - if (updetach && !nodetach) - detach(); - return; - } - } -#endif /* HAVE_MULTILINK */ - -#ifdef PPP_FILTER - if (!demand) - set_filters(&pass_filter, &active_filter); -#endif -#if CCP_SUPPORT || ECP_SUPPORT - /* Start CCP and ECP */ - for (i = 0; (protp = protocols[i]) != NULL; ++i) - if ( - (0 -#if ECP_SUPPORT - || protp->protocol == PPP_ECP -#endif /* ECP_SUPPORT */ -#if CCP_SUPPORT - || protp->protocol == PPP_CCP -#endif /* CCP_SUPPORT */ - ) - && protp->open != NULL) - (*protp->open)(pcb); -#endif /* CCP_SUPPORT || ECP_SUPPORT */ - - /* - * Bring up other network protocols iff encryption is not required. - */ - if (1 -#if ECP_SUPPORT - && !ecp_gotoptions[unit].required -#endif /* ECP_SUPPORT */ -#if MPPE_SUPPORT - && !pcb->ccp_gotoptions.mppe -#endif /* MPPE_SUPPORT */ - ) - continue_networks(pcb); -} - -void continue_networks(ppp_pcb *pcb) { - int i; - const struct protent *protp; - - /* - * Start the "real" network protocols. - */ - for (i = 0; (protp = protocols[i]) != NULL; ++i) - if (protp->protocol < 0xC000 -#if CCP_SUPPORT - && protp->protocol != PPP_CCP -#endif /* CCP_SUPPORT */ -#if ECP_SUPPORT - && protp->protocol != PPP_ECP -#endif /* ECP_SUPPORT */ - && protp->open != NULL) { - (*protp->open)(pcb); - ++pcb->num_np_open; - } - - if (pcb->num_np_open == 0) - /* nothing to do */ - lcp_close(pcb, "No network protocols running"); -} - -#if PPP_AUTH_SUPPORT -#if PPP_SERVER -/* - * auth_check_passwd - Check the user name and passwd against configuration. - * - * returns: - * 0: Authentication failed. - * 1: Authentication succeeded. - * In either case, msg points to an appropriate message and msglen to the message len. - */ -int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen) { - int secretuserlen; - int secretpasswdlen; - - if (pcb->settings.user && pcb->settings.passwd) { - secretuserlen = (int)strlen(pcb->settings.user); - secretpasswdlen = (int)strlen(pcb->settings.passwd); - if (secretuserlen == userlen - && secretpasswdlen == passwdlen - && !memcmp(auser, pcb->settings.user, userlen) - && !memcmp(apasswd, pcb->settings.passwd, passwdlen) ) { - *msg = "Login ok"; - *msglen = sizeof("Login ok")-1; - return 1; - } - } - - *msg = "Login incorrect"; - *msglen = sizeof("Login incorrect")-1; - return 0; -} - -/* - * The peer has failed to authenticate himself using `protocol'. - */ -void auth_peer_fail(ppp_pcb *pcb, int protocol) { - LWIP_UNUSED_ARG(protocol); - /* - * Authentication failure: take the link down - */ -#if 0 /* UNUSED */ - status = EXIT_PEER_AUTH_FAILED; -#endif /* UNUSED */ - pcb->err_code = PPPERR_AUTHFAIL; - lcp_close(pcb, "Authentication failed"); -} - -/* - * The peer has been successfully authenticated using `protocol'. - */ -void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, const char *name, int namelen) { - int bit; -#ifndef HAVE_MULTILINK - LWIP_UNUSED_ARG(name); - LWIP_UNUSED_ARG(namelen); -#endif /* HAVE_MULTILINK */ - - switch (protocol) { -#if CHAP_SUPPORT - case PPP_CHAP: - bit = CHAP_PEER; - switch (prot_flavor) { - case CHAP_MD5: - bit |= CHAP_MD5_PEER; - break; -#if MSCHAP_SUPPORT - case CHAP_MICROSOFT: - bit |= CHAP_MS_PEER; - break; - case CHAP_MICROSOFT_V2: - bit |= CHAP_MS2_PEER; - break; -#endif /* MSCHAP_SUPPORT */ - default: - break; - } - break; -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - case PPP_PAP: - bit = PAP_PEER; - break; -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - case PPP_EAP: - bit = EAP_PEER; - break; -#endif /* EAP_SUPPORT */ - default: - ppp_warn("auth_peer_success: unknown protocol %x", protocol); - return; - } - -#ifdef HAVE_MULTILINK - /* - * Save the authenticated name of the peer for later. - */ - if (namelen > (int)sizeof(pcb->peer_authname) - 1) - namelen = (int)sizeof(pcb->peer_authname) - 1; - MEMCPY(pcb->peer_authname, name, namelen); - pcb->peer_authname[namelen] = 0; -#endif /* HAVE_MULTILINK */ -#if 0 /* UNUSED */ - script_setenv("PEERNAME", , 0); -#endif /* UNUSED */ - - /* Save the authentication method for later. */ - pcb->auth_done |= bit; - - /* - * If there is no more authentication still to be done, - * proceed to the network (or callback) phase. - */ - if ((pcb->auth_pending &= ~bit) == 0) - network_phase(pcb); -} -#endif /* PPP_SERVER */ - -/* - * We have failed to authenticate ourselves to the peer using `protocol'. - */ -void auth_withpeer_fail(ppp_pcb *pcb, int protocol) { - LWIP_UNUSED_ARG(protocol); - /* - * We've failed to authenticate ourselves to our peer. - * - * Some servers keep sending CHAP challenges, but there - * is no point in persisting without any way to get updated - * authentication secrets. - * - * He'll probably take the link down, and there's not much - * we can do except wait for that. - */ - pcb->err_code = PPPERR_AUTHFAIL; - lcp_close(pcb, "Failed to authenticate ourselves to peer"); -} - -/* - * We have successfully authenticated ourselves with the peer using `protocol'. - */ -void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor) { - int bit; - const char *prot = ""; - - switch (protocol) { -#if CHAP_SUPPORT - case PPP_CHAP: - bit = CHAP_WITHPEER; - prot = "CHAP"; - switch (prot_flavor) { - case CHAP_MD5: - bit |= CHAP_MD5_WITHPEER; - break; -#if MSCHAP_SUPPORT - case CHAP_MICROSOFT: - bit |= CHAP_MS_WITHPEER; - break; - case CHAP_MICROSOFT_V2: - bit |= CHAP_MS2_WITHPEER; - break; -#endif /* MSCHAP_SUPPORT */ - default: - break; - } - break; -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - case PPP_PAP: - bit = PAP_WITHPEER; - prot = "PAP"; - break; -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - case PPP_EAP: - bit = EAP_WITHPEER; - prot = "EAP"; - break; -#endif /* EAP_SUPPORT */ - default: - ppp_warn("auth_withpeer_success: unknown protocol %x", protocol); - bit = 0; - /* no break */ - } - - ppp_notice("%s authentication succeeded", prot); - - /* Save the authentication method for later. */ - pcb->auth_done |= bit; - - /* - * If there is no more authentication still being done, - * proceed to the network (or callback) phase. - */ - if ((pcb->auth_pending &= ~bit) == 0) - network_phase(pcb); -} -#endif /* PPP_AUTH_SUPPORT */ - - -/* - * np_up - a network protocol has come up. - */ -void np_up(ppp_pcb *pcb, int proto) { -#if PPP_IDLETIMELIMIT - int tlim; -#endif /* PPP_IDLETIMELIMIT */ - LWIP_UNUSED_ARG(proto); - - if (pcb->num_np_up == 0) { - /* - * At this point we consider that the link has come up successfully. - */ - new_phase(pcb, PPP_PHASE_RUNNING); - -#if PPP_IDLETIMELIMIT -#if 0 /* UNUSED */ - if (idle_time_hook != 0) - tlim = (*idle_time_hook)(NULL); - else -#endif /* UNUSED */ - tlim = pcb->settings.idle_time_limit; - if (tlim > 0) - TIMEOUT(check_idle, (void*)pcb, tlim); -#endif /* PPP_IDLETIMELIMIT */ - -#if PPP_MAXCONNECT - /* - * Set a timeout to close the connection once the maximum - * connect time has expired. - */ - if (pcb->settings.maxconnect > 0) - TIMEOUT(connect_time_expired, (void*)pcb, pcb->settings.maxconnect); -#endif /* PPP_MAXCONNECT */ - -#ifdef MAXOCTETS - if (maxoctets > 0) - TIMEOUT(check_maxoctets, NULL, maxoctets_timeout); -#endif - -#if 0 /* Unused */ - /* - * Detach now, if the updetach option was given. - */ - if (updetach && !nodetach) - detach(); -#endif /* Unused */ - } - ++pcb->num_np_up; -} - -/* - * np_down - a network protocol has gone down. - */ -void np_down(ppp_pcb *pcb, int proto) { - LWIP_UNUSED_ARG(proto); - if (--pcb->num_np_up == 0) { -#if PPP_IDLETIMELIMIT - UNTIMEOUT(check_idle, (void*)pcb); -#endif /* PPP_IDLETIMELIMIT */ -#if PPP_MAXCONNECT - UNTIMEOUT(connect_time_expired, NULL); -#endif /* PPP_MAXCONNECT */ -#ifdef MAXOCTETS - UNTIMEOUT(check_maxoctets, NULL); -#endif - new_phase(pcb, PPP_PHASE_NETWORK); - } -} - -/* - * np_finished - a network protocol has finished using the link. - */ -void np_finished(ppp_pcb *pcb, int proto) { - LWIP_UNUSED_ARG(proto); - if (--pcb->num_np_open <= 0) { - /* no further use for the link: shut up shop. */ - lcp_close(pcb, "No network protocols running"); - } -} - -#ifdef MAXOCTETS -static void -check_maxoctets(arg) - void *arg; -{ -#if PPP_STATS_SUPPORT - unsigned int used; - - update_link_stats(ifunit); - link_stats_valid=0; - - switch(maxoctets_dir) { - case PPP_OCTETS_DIRECTION_IN: - used = link_stats.bytes_in; - break; - case PPP_OCTETS_DIRECTION_OUT: - used = link_stats.bytes_out; - break; - case PPP_OCTETS_DIRECTION_MAXOVERAL: - case PPP_OCTETS_DIRECTION_MAXSESSION: - used = (link_stats.bytes_in > link_stats.bytes_out) ? link_stats.bytes_in : link_stats.bytes_out; - break; - default: - used = link_stats.bytes_in+link_stats.bytes_out; - break; - } - if (used > maxoctets) { - ppp_notice("Traffic limit reached. Limit: %u Used: %u", maxoctets, used); - status = EXIT_TRAFFIC_LIMIT; - lcp_close(pcb, "Traffic limit"); -#if 0 /* UNUSED */ - need_holdoff = 0; -#endif /* UNUSED */ - } else { - TIMEOUT(check_maxoctets, NULL, maxoctets_timeout); - } -#endif /* PPP_STATS_SUPPORT */ -} -#endif /* MAXOCTETS */ - -#if PPP_IDLETIMELIMIT -/* - * check_idle - check whether the link has been idle for long - * enough that we can shut it down. - */ -static void check_idle(void *arg) { - ppp_pcb *pcb = (ppp_pcb*)arg; - struct ppp_idle idle; - time_t itime; - int tlim; - - if (!get_idle_time(pcb, &idle)) - return; -#if 0 /* UNUSED */ - if (idle_time_hook != 0) { - tlim = idle_time_hook(&idle); - } else { -#endif /* UNUSED */ - itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle); - tlim = pcb->settings.idle_time_limit - itime; -#if 0 /* UNUSED */ - } -#endif /* UNUSED */ - if (tlim <= 0) { - /* link is idle: shut it down. */ - ppp_notice("Terminating connection due to lack of activity."); - pcb->err_code = PPPERR_IDLETIMEOUT; - lcp_close(pcb, "Link inactive"); -#if 0 /* UNUSED */ - need_holdoff = 0; -#endif /* UNUSED */ - } else { - TIMEOUT(check_idle, (void*)pcb, tlim); - } -} -#endif /* PPP_IDLETIMELIMIT */ - -#if PPP_MAXCONNECT -/* - * connect_time_expired - log a message and close the connection. - */ -static void connect_time_expired(void *arg) { - ppp_pcb *pcb = (ppp_pcb*)arg; - ppp_info("Connect time expired"); - pcb->err_code = PPPERR_CONNECTTIME; - lcp_close(pcb, "Connect time expired"); /* Close connection */ -} -#endif /* PPP_MAXCONNECT */ - -#if PPP_OPTIONS -/* - * auth_check_options - called to check authentication options. - */ -void -auth_check_options() -{ - lcp_options *wo = &lcp_wantoptions[0]; - int can_auth; - int lacks_ip; - - /* Default our_name to hostname, and user to our_name */ - if (our_name[0] == 0 || usehostname) - strlcpy(our_name, hostname, sizeof(our_name)); - /* If a blank username was explicitly given as an option, trust - the user and don't use our_name */ - if (ppp_settings.user[0] == 0 && !explicit_user) - strlcpy(ppp_settings.user, our_name, sizeof(ppp_settings.user)); - - /* - * If we have a default route, require the peer to authenticate - * unless the noauth option was given or the real user is root. - */ - if (!auth_required && !allow_any_ip && have_route_to(0) && !privileged) { - auth_required = 1; - default_auth = 1; - } - -#if CHAP_SUPPORT - /* If we selected any CHAP flavors, we should probably negotiate it. :-) */ - if (wo->chap_mdtype) - wo->neg_chap = 1; -#endif /* CHAP_SUPPORT */ - - /* If authentication is required, ask peer for CHAP, PAP, or EAP. */ - if (auth_required) { - allow_any_ip = 0; - if (1 -#if CHAP_SUPPORT - && !wo->neg_chap -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - && !wo->neg_upap -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - && !wo->neg_eap -#endif /* EAP_SUPPORT */ - ) { -#if CHAP_SUPPORT - wo->neg_chap = CHAP_MDTYPE_SUPPORTED != MDTYPE_NONE; - wo->chap_mdtype = CHAP_MDTYPE_SUPPORTED; -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - wo->neg_upap = 1; -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - wo->neg_eap = 1; -#endif /* EAP_SUPPORT */ - } - } else { -#if CHAP_SUPPORT - wo->neg_chap = 0; - wo->chap_mdtype = MDTYPE_NONE; -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - wo->neg_upap = 0; -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - wo->neg_eap = 0; -#endif /* EAP_SUPPORT */ - } - - /* - * Check whether we have appropriate secrets to use - * to authenticate the peer. Note that EAP can authenticate by way - * of a CHAP-like exchanges as well as SRP. - */ - lacks_ip = 0; -#if PAP_SUPPORT - can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip)); -#else - can_auth = 0; -#endif /* PAP_SUPPORT */ - if (!can_auth && (0 -#if CHAP_SUPPORT - || wo->neg_chap -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - || wo->neg_eap -#endif /* EAP_SUPPORT */ - )) { -#if CHAP_SUPPORT - can_auth = have_chap_secret((explicit_remote? remote_name: NULL), - our_name, 1, &lacks_ip); -#else - can_auth = 0; -#endif - } - if (!can_auth -#if EAP_SUPPORT - && wo->neg_eap -#endif /* EAP_SUPPORT */ - ) { - can_auth = have_srp_secret((explicit_remote? remote_name: NULL), - our_name, 1, &lacks_ip); - } - - if (auth_required && !can_auth && noauth_addrs == NULL) { - if (default_auth) { - option_error( -"By default the remote system is required to authenticate itself"); - option_error( -"(because this system has a default route to the internet)"); - } else if (explicit_remote) - option_error( -"The remote system (%s) is required to authenticate itself", - remote_name); - else - option_error( -"The remote system is required to authenticate itself"); - option_error( -"but I couldn't find any suitable secret (password) for it to use to do so."); - if (lacks_ip) - option_error( -"(None of the available passwords would let it use an IP address.)"); - - exit(1); - } - - /* - * Early check for remote number authorization. - */ - if (!auth_number()) { - ppp_warn("calling number %q is not authorized", remote_number); - exit(EXIT_CNID_AUTH_FAILED); - } -} -#endif /* PPP_OPTIONS */ - -#if 0 /* UNUSED */ -/* - * auth_reset - called when LCP is starting negotiations to recheck - * authentication options, i.e. whether we have appropriate secrets - * to use for authenticating ourselves and/or the peer. - */ -void -auth_reset(unit) - int unit; -{ - lcp_options *go = &lcp_gotoptions[unit]; - lcp_options *ao = &lcp_allowoptions[unit]; - int hadchap; - - hadchap = -1; - ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL)); - ao->neg_chap = (!refuse_chap || !refuse_mschap || !refuse_mschap_v2) - && (passwd[0] != 0 || - (hadchap = have_chap_secret(user, (explicit_remote? remote_name: - NULL), 0, NULL))); - ao->neg_eap = !refuse_eap && ( - passwd[0] != 0 || - (hadchap == 1 || (hadchap == -1 && have_chap_secret(user, - (explicit_remote? remote_name: NULL), 0, NULL))) || - have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL)); - - hadchap = -1; - if (go->neg_upap && !uselogin && !have_pap_secret(NULL)) - go->neg_upap = 0; - if (go->neg_chap) { - if (!(hadchap = have_chap_secret((explicit_remote? remote_name: NULL), - our_name, 1, NULL))) - go->neg_chap = 0; - } - if (go->neg_eap && - (hadchap == 0 || (hadchap == -1 && - !have_chap_secret((explicit_remote? remote_name: NULL), our_name, - 1, NULL))) && - !have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1, - NULL)) - go->neg_eap = 0; -} - -/* - * check_passwd - Check the user name and passwd against the PAP secrets - * file. If requested, also check against the system password database, - * and login the user if OK. - * - * returns: - * UPAP_AUTHNAK: Authentication failed. - * UPAP_AUTHACK: Authentication succeeded. - * In either case, msg points to an appropriate message. - */ -int -check_passwd(unit, auser, userlen, apasswd, passwdlen, msg) - int unit; - char *auser; - int userlen; - char *apasswd; - int passwdlen; - char **msg; -{ - return UPAP_AUTHNAK; - int ret; - char *filename; - FILE *f; - struct wordlist *addrs = NULL, *opts = NULL; - char passwd[256], user[256]; - char secret[MAXWORDLEN]; - static int attempts = 0; - - /* - * Make copies of apasswd and auser, then null-terminate them. - * If there are unprintable characters in the password, make - * them visible. - */ - slprintf(ppp_settings.passwd, sizeof(ppp_settings.passwd), "%.*v", passwdlen, apasswd); - slprintf(ppp_settings.user, sizeof(ppp_settings.user), "%.*v", userlen, auser); - *msg = ""; - - /* - * Check if a plugin wants to handle this. - */ - if (pap_auth_hook) { - ret = (*pap_auth_hook)(ppp_settings.user, ppp_settings.passwd, msg, &addrs, &opts); - if (ret >= 0) { - /* note: set_allowed_addrs() saves opts (but not addrs): - don't free it! */ - if (ret) - set_allowed_addrs(unit, addrs, opts); - else if (opts != 0) - free_wordlist(opts); - if (addrs != 0) - free_wordlist(addrs); - BZERO(ppp_settings.passwd, sizeof(ppp_settings.passwd)); - return ret? UPAP_AUTHACK: UPAP_AUTHNAK; - } - } - - /* - * Open the file of pap secrets and scan for a suitable secret - * for authenticating this user. - */ - filename = _PATH_UPAPFILE; - addrs = opts = NULL; - ret = UPAP_AUTHNAK; - f = fopen(filename, "r"); - if (f == NULL) { - ppp_error("Can't open PAP password file %s: %m", filename); - - } else { - check_access(f, filename); - if (scan_authfile(f, ppp_settings.user, our_name, secret, &addrs, &opts, filename, 0) < 0) { - ppp_warn("no PAP secret found for %s", user); - } else { - /* - * If the secret is "@login", it means to check - * the password against the login database. - */ - int login_secret = strcmp(secret, "@login") == 0; - ret = UPAP_AUTHACK; - if (uselogin || login_secret) { - /* login option or secret is @login */ - if (session_full(ppp_settings.user, ppp_settings.passwd, devnam, msg) == 0) { - ret = UPAP_AUTHNAK; - } - } else if (session_mgmt) { - if (session_check(ppp_settings.user, NULL, devnam, NULL) == 0) { - ppp_warn("Peer %q failed PAP Session verification", user); - ret = UPAP_AUTHNAK; - } - } - if (secret[0] != 0 && !login_secret) { - /* password given in pap-secrets - must match */ - if ((cryptpap || strcmp(ppp_settings.passwd, secret) != 0) - && strcmp(crypt(ppp_settings.passwd, secret), secret) != 0) - ret = UPAP_AUTHNAK; - } - } - fclose(f); - } - - if (ret == UPAP_AUTHNAK) { - if (**msg == 0) - *msg = "Login incorrect"; - /* - * XXX can we ever get here more than once?? - * Frustrate passwd stealer programs. - * Allow 10 tries, but start backing off after 3 (stolen from login). - * On 10'th, drop the connection. - */ - if (attempts++ >= 10) { - ppp_warn("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user); - lcp_close(pcb, "login failed"); - } - if (attempts > 3) - sleep((u_int) (attempts - 3) * 5); - if (opts != NULL) - free_wordlist(opts); - - } else { - attempts = 0; /* Reset count */ - if (**msg == 0) - *msg = "Login ok"; - set_allowed_addrs(unit, addrs, opts); - } - - if (addrs != NULL) - free_wordlist(addrs); - BZERO(ppp_settings.passwd, sizeof(ppp_settings.passwd)); - BZERO(secret, sizeof(secret)); - - return ret; -} - -/* - * null_login - Check if a username of "" and a password of "" are - * acceptable, and iff so, set the list of acceptable IP addresses - * and return 1. - */ -static int -null_login(unit) - int unit; -{ - char *filename; - FILE *f; - int i, ret; - struct wordlist *addrs, *opts; - char secret[MAXWORDLEN]; - - /* - * Check if a plugin wants to handle this. - */ - ret = -1; - if (null_auth_hook) - ret = (*null_auth_hook)(&addrs, &opts); - - /* - * Open the file of pap secrets and scan for a suitable secret. - */ - if (ret <= 0) { - filename = _PATH_UPAPFILE; - addrs = NULL; - f = fopen(filename, "r"); - if (f == NULL) - return 0; - check_access(f, filename); - - i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename, 0); - ret = i >= 0 && secret[0] == 0; - BZERO(secret, sizeof(secret)); - fclose(f); - } - - if (ret) - set_allowed_addrs(unit, addrs, opts); - else if (opts != 0) - free_wordlist(opts); - if (addrs != 0) - free_wordlist(addrs); - - return ret; -} - -/* - * get_pap_passwd - get a password for authenticating ourselves with - * our peer using PAP. Returns 1 on success, 0 if no suitable password - * could be found. - * Assumes passwd points to MAXSECRETLEN bytes of space (if non-null). - */ -static int -get_pap_passwd(passwd) - char *passwd; -{ - char *filename; - FILE *f; - int ret; - char secret[MAXWORDLEN]; - - /* - * Check whether a plugin wants to supply this. - */ - if (pap_passwd_hook) { - ret = (*pap_passwd_hook)(ppp_settings,user, ppp_settings.passwd); - if (ret >= 0) - return ret; - } - - filename = _PATH_UPAPFILE; - f = fopen(filename, "r"); - if (f == NULL) - return 0; - check_access(f, filename); - ret = scan_authfile(f, user, - (remote_name[0]? remote_name: NULL), - secret, NULL, NULL, filename, 0); - fclose(f); - if (ret < 0) - return 0; - if (passwd != NULL) - strlcpy(passwd, secret, MAXSECRETLEN); - BZERO(secret, sizeof(secret)); - return 1; -} - -/* - * have_pap_secret - check whether we have a PAP file with any - * secrets that we could possibly use for authenticating the peer. - */ -static int -have_pap_secret(lacks_ipp) - int *lacks_ipp; -{ - FILE *f; - int ret; - char *filename; - struct wordlist *addrs; - - /* let the plugin decide, if there is one */ - if (pap_check_hook) { - ret = (*pap_check_hook)(); - if (ret >= 0) - return ret; - } - - filename = _PATH_UPAPFILE; - f = fopen(filename, "r"); - if (f == NULL) - return 0; - - ret = scan_authfile(f, (explicit_remote? remote_name: NULL), our_name, - NULL, &addrs, NULL, filename, 0); - fclose(f); - if (ret >= 0 && !some_ip_ok(addrs)) { - if (lacks_ipp != 0) - *lacks_ipp = 1; - ret = -1; - } - if (addrs != 0) - free_wordlist(addrs); - - return ret >= 0; -} - -/* - * have_chap_secret - check whether we have a CHAP file with a - * secret that we could possibly use for authenticating `client' - * on `server'. Either can be the null string, meaning we don't - * know the identity yet. - */ -static int -have_chap_secret(client, server, need_ip, lacks_ipp) - char *client; - char *server; - int need_ip; - int *lacks_ipp; -{ - FILE *f; - int ret; - char *filename; - struct wordlist *addrs; - - if (chap_check_hook) { - ret = (*chap_check_hook)(); - if (ret >= 0) { - return ret; - } - } - - filename = _PATH_CHAPFILE; - f = fopen(filename, "r"); - if (f == NULL) - return 0; - - if (client != NULL && client[0] == 0) - client = NULL; - else if (server != NULL && server[0] == 0) - server = NULL; - - ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0); - fclose(f); - if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { - if (lacks_ipp != 0) - *lacks_ipp = 1; - ret = -1; - } - if (addrs != 0) - free_wordlist(addrs); - - return ret >= 0; -} - -/* - * have_srp_secret - check whether we have a SRP file with a - * secret that we could possibly use for authenticating `client' - * on `server'. Either can be the null string, meaning we don't - * know the identity yet. - */ -static int -have_srp_secret(client, server, need_ip, lacks_ipp) - char *client; - char *server; - int need_ip; - int *lacks_ipp; -{ - FILE *f; - int ret; - char *filename; - struct wordlist *addrs; - - filename = _PATH_SRPFILE; - f = fopen(filename, "r"); - if (f == NULL) - return 0; - - if (client != NULL && client[0] == 0) - client = NULL; - else if (server != NULL && server[0] == 0) - server = NULL; - - ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0); - fclose(f); - if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { - if (lacks_ipp != 0) - *lacks_ipp = 1; - ret = -1; - } - if (addrs != 0) - free_wordlist(addrs); - - return ret >= 0; -} -#endif /* UNUSED */ - -#if PPP_AUTH_SUPPORT -/* - * get_secret - open the CHAP secret file and return the secret - * for authenticating the given client on the given server. - * (We could be either client or server). - */ -int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secret, int *secret_len, int am_server) { - int len; - LWIP_UNUSED_ARG(server); - LWIP_UNUSED_ARG(am_server); - - if (!client || !client[0] || !pcb->settings.user || !pcb->settings.passwd || strcmp(client, pcb->settings.user)) { - return 0; - } - - len = (int)strlen(pcb->settings.passwd); - if (len > MAXSECRETLEN) { - ppp_error("Secret for %s on %s is too long", client, server); - len = MAXSECRETLEN; - } - - MEMCPY(secret, pcb->settings.passwd, len); - *secret_len = len; - return 1; - -#if 0 /* UNUSED */ - FILE *f; - int ret, len; - char *filename; - struct wordlist *addrs, *opts; - char secbuf[MAXWORDLEN]; - struct wordlist *addrs; - addrs = NULL; - - if (!am_server && ppp_settings.passwd[0] != 0) { - strlcpy(secbuf, ppp_settings.passwd, sizeof(secbuf)); - } else if (!am_server && chap_passwd_hook) { - if ( (*chap_passwd_hook)(client, secbuf) < 0) { - ppp_error("Unable to obtain CHAP password for %s on %s from plugin", - client, server); - return 0; - } - } else { - filename = _PATH_CHAPFILE; - addrs = NULL; - secbuf[0] = 0; - - f = fopen(filename, "r"); - if (f == NULL) { - ppp_error("Can't open chap secret file %s: %m", filename); - return 0; - } - check_access(f, filename); - - ret = scan_authfile(f, client, server, secbuf, &addrs, &opts, filename, 0); - fclose(f); - if (ret < 0) - return 0; - - if (am_server) - set_allowed_addrs(unit, addrs, opts); - else if (opts != 0) - free_wordlist(opts); - if (addrs != 0) - free_wordlist(addrs); - } - - len = strlen(secbuf); - if (len > MAXSECRETLEN) { - ppp_error("Secret for %s on %s is too long", client, server); - len = MAXSECRETLEN; - } - MEMCPY(secret, secbuf, len); - BZERO(secbuf, sizeof(secbuf)); - *secret_len = len; - - return 1; -#endif /* UNUSED */ -} -#endif /* PPP_AUTH_SUPPORT */ - - -#if 0 /* UNUSED */ -/* - * get_srp_secret - open the SRP secret file and return the secret - * for authenticating the given client on the given server. - * (We could be either client or server). - */ -int -get_srp_secret(unit, client, server, secret, am_server) - int unit; - char *client; - char *server; - char *secret; - int am_server; -{ - FILE *fp; - int ret; - char *filename; - struct wordlist *addrs, *opts; - - if (!am_server && ppp_settings.passwd[0] != '\0') { - strlcpy(secret, ppp_settings.passwd, MAXWORDLEN); - } else { - filename = _PATH_SRPFILE; - addrs = NULL; - - fp = fopen(filename, "r"); - if (fp == NULL) { - ppp_error("Can't open srp secret file %s: %m", filename); - return 0; - } - check_access(fp, filename); - - secret[0] = '\0'; - ret = scan_authfile(fp, client, server, secret, &addrs, &opts, - filename, am_server); - fclose(fp); - if (ret < 0) - return 0; - - if (am_server) - set_allowed_addrs(unit, addrs, opts); - else if (opts != NULL) - free_wordlist(opts); - if (addrs != NULL) - free_wordlist(addrs); - } - - return 1; -} - -/* - * set_allowed_addrs() - set the list of allowed addresses. - * Also looks for `--' indicating options to apply for this peer - * and leaves the following words in extra_options. - */ -static void -set_allowed_addrs(unit, addrs, opts) - int unit; - struct wordlist *addrs; - struct wordlist *opts; -{ - int n; - struct wordlist *ap, **plink; - struct permitted_ip *ip; - char *ptr_word, *ptr_mask; - struct hostent *hp; - struct netent *np; - u32_t a, mask, ah, offset; - struct ipcp_options *wo = &ipcp_wantoptions[unit]; - u32_t suggested_ip = 0; - - if (addresses[unit] != NULL) - free(addresses[unit]); - addresses[unit] = NULL; - if (extra_options != NULL) - free_wordlist(extra_options); - extra_options = opts; - - /* - * Count the number of IP addresses given. - */ - n = wordlist_count(addrs) + wordlist_count(noauth_addrs); - if (n == 0) - return; - ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip)); - if (ip == 0) - return; - - /* temporarily append the noauth_addrs list to addrs */ - for (plink = &addrs; *plink != NULL; plink = &(*plink)->next) - ; - *plink = noauth_addrs; - - n = 0; - for (ap = addrs; ap != NULL; ap = ap->next) { - /* "-" means no addresses authorized, "*" means any address allowed */ - ptr_word = ap->word; - if (strcmp(ptr_word, "-") == 0) - break; - if (strcmp(ptr_word, "*") == 0) { - ip[n].permit = 1; - ip[n].base = ip[n].mask = 0; - ++n; - break; - } - - ip[n].permit = 1; - if (*ptr_word == '!') { - ip[n].permit = 0; - ++ptr_word; - } - - mask = ~ (u32_t) 0; - offset = 0; - ptr_mask = strchr (ptr_word, '/'); - if (ptr_mask != NULL) { - int bit_count; - char *endp; - - bit_count = (int) strtol (ptr_mask+1, &endp, 10); - if (bit_count <= 0 || bit_count > 32) { - ppp_warn("invalid address length %v in auth. address list", - ptr_mask+1); - continue; - } - bit_count = 32 - bit_count; /* # bits in host part */ - if (*endp == '+') { - offset = ifunit + 1; - ++endp; - } - if (*endp != 0) { - ppp_warn("invalid address length syntax: %v", ptr_mask+1); - continue; - } - *ptr_mask = '\0'; - mask <<= bit_count; - } - - hp = gethostbyname(ptr_word); - if (hp != NULL && hp->h_addrtype == AF_INET) { - a = *(u32_t *)hp->h_addr; - } else { - np = getnetbyname (ptr_word); - if (np != NULL && np->n_addrtype == AF_INET) { - a = htonl ((u32_t)np->n_net); - if (ptr_mask == NULL) { - /* calculate appropriate mask for net */ - ah = ntohl(a); - if (IN_CLASSA(ah)) - mask = IN_CLASSA_NET; - else if (IN_CLASSB(ah)) - mask = IN_CLASSB_NET; - else if (IN_CLASSC(ah)) - mask = IN_CLASSC_NET; - } - } else { - a = inet_addr (ptr_word); - } - } - - if (ptr_mask != NULL) - *ptr_mask = '/'; - - if (a == (u32_t)-1L) { - ppp_warn("unknown host %s in auth. address list", ap->word); - continue; - } - if (offset != 0) { - if (offset >= ~mask) { - ppp_warn("interface unit %d too large for subnet %v", - ifunit, ptr_word); - continue; - } - a = htonl((ntohl(a) & mask) + offset); - mask = ~(u32_t)0; - } - ip[n].mask = htonl(mask); - ip[n].base = a & ip[n].mask; - ++n; - if (~mask == 0 && suggested_ip == 0) - suggested_ip = a; - } - *plink = NULL; - - ip[n].permit = 0; /* make the last entry forbid all addresses */ - ip[n].base = 0; /* to terminate the list */ - ip[n].mask = 0; - - addresses[unit] = ip; - - /* - * If the address given for the peer isn't authorized, or if - * the user hasn't given one, AND there is an authorized address - * which is a single host, then use that if we find one. - */ - if (suggested_ip != 0 - && (wo->hisaddr == 0 || !auth_ip_addr(unit, wo->hisaddr))) { - wo->hisaddr = suggested_ip; - /* - * Do we insist on this address? No, if there are other - * addresses authorized than the suggested one. - */ - if (n > 1) - wo->accept_remote = 1; - } -} - -/* - * auth_ip_addr - check whether the peer is authorized to use - * a given IP address. Returns 1 if authorized, 0 otherwise. - */ -int -auth_ip_addr(unit, addr) - int unit; - u32_t addr; -{ - int ok; - - /* don't allow loopback or multicast address */ - if (bad_ip_adrs(addr)) - return 0; - - if (allowed_address_hook) { - ok = allowed_address_hook(addr); - if (ok >= 0) return ok; - } - - if (addresses[unit] != NULL) { - ok = ip_addr_check(addr, addresses[unit]); - if (ok >= 0) - return ok; - } - - if (auth_required) - return 0; /* no addresses authorized */ - return allow_any_ip || privileged || !have_route_to(addr); -} - -static int -ip_addr_check(addr, addrs) - u32_t addr; - struct permitted_ip *addrs; -{ - for (; ; ++addrs) - if ((addr & addrs->mask) == addrs->base) - return addrs->permit; -} - -/* - * bad_ip_adrs - return 1 if the IP address is one we don't want - * to use, such as an address in the loopback net or a multicast address. - * addr is in network byte order. - */ -int -bad_ip_adrs(addr) - u32_t addr; -{ - addr = ntohl(addr); - return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET - || IN_MULTICAST(addr) || IN_BADCLASS(addr); -} - -/* - * some_ip_ok - check a wordlist to see if it authorizes any - * IP address(es). - */ -static int -some_ip_ok(addrs) - struct wordlist *addrs; -{ - for (; addrs != 0; addrs = addrs->next) { - if (addrs->word[0] == '-') - break; - if (addrs->word[0] != '!') - return 1; /* some IP address is allowed */ - } - return 0; -} - -/* - * auth_number - check whether the remote number is allowed to connect. - * Returns 1 if authorized, 0 otherwise. - */ -int -auth_number() -{ - struct wordlist *wp = permitted_numbers; - int l; - - /* Allow all if no authorization list. */ - if (!wp) - return 1; - - /* Allow if we have a match in the authorization list. */ - while (wp) { - /* trailing '*' wildcard */ - l = strlen(wp->word); - if ((wp->word)[l - 1] == '*') - l--; - if (!strncasecmp(wp->word, remote_number, l)) - return 1; - wp = wp->next; - } - - return 0; -} - -/* - * check_access - complain if a secret file has too-liberal permissions. - */ -static void -check_access(f, filename) - FILE *f; - char *filename; -{ - struct stat sbuf; - - if (fstat(fileno(f), &sbuf) < 0) { - ppp_warn("cannot stat secret file %s: %m", filename); - } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { - ppp_warn("Warning - secret file %s has world and/or group access", - filename); - } -} - -/* - * scan_authfile - Scan an authorization file for a secret suitable - * for authenticating `client' on `server'. The return value is -1 - * if no secret is found, otherwise >= 0. The return value has - * NONWILD_CLIENT set if the secret didn't have "*" for the client, and - * NONWILD_SERVER set if the secret didn't have "*" for the server. - * Any following words on the line up to a "--" (i.e. address authorization - * info) are placed in a wordlist and returned in *addrs. Any - * following words (extra options) are placed in a wordlist and - * returned in *opts. - * We assume secret is NULL or points to MAXWORDLEN bytes of space. - * Flags are non-zero if we need two colons in the secret in order to - * match. - */ -static int -scan_authfile(f, client, server, secret, addrs, opts, filename, flags) - FILE *f; - char *client; - char *server; - char *secret; - struct wordlist **addrs; - struct wordlist **opts; - char *filename; - int flags; -{ - int newline, xxx; - int got_flag, best_flag; - FILE *sf; - struct wordlist *ap, *addr_list, *alist, **app; - char word[MAXWORDLEN]; - char atfile[MAXWORDLEN]; - char lsecret[MAXWORDLEN]; - char *cp; - - if (addrs != NULL) - *addrs = NULL; - if (opts != NULL) - *opts = NULL; - addr_list = NULL; - if (!getword(f, word, &newline, filename)) - return -1; /* file is empty??? */ - newline = 1; - best_flag = -1; - for (;;) { - /* - * Skip until we find a word at the start of a line. - */ - while (!newline && getword(f, word, &newline, filename)) - ; - if (!newline) - break; /* got to end of file */ - - /* - * Got a client - check if it's a match or a wildcard. - */ - got_flag = 0; - if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) { - newline = 0; - continue; - } - if (!ISWILD(word)) - got_flag = NONWILD_CLIENT; - - /* - * Now get a server and check if it matches. - */ - if (!getword(f, word, &newline, filename)) - break; - if (newline) - continue; - if (!ISWILD(word)) { - if (server != NULL && strcmp(word, server) != 0) - continue; - got_flag |= NONWILD_SERVER; - } - - /* - * Got some sort of a match - see if it's better than what - * we have already. - */ - if (got_flag <= best_flag) - continue; - - /* - * Get the secret. - */ - if (!getword(f, word, &newline, filename)) - break; - if (newline) - continue; - - /* - * SRP-SHA1 authenticator should never be reading secrets from - * a file. (Authenticatee may, though.) - */ - if (flags && ((cp = strchr(word, ':')) == NULL || - strchr(cp + 1, ':') == NULL)) - continue; - - if (secret != NULL) { - /* - * Special syntax: @/pathname means read secret from file. - */ - if (word[0] == '@' && word[1] == '/') { - strlcpy(atfile, word+1, sizeof(atfile)); - if ((sf = fopen(atfile, "r")) == NULL) { - ppp_warn("can't open indirect secret file %s", atfile); - continue; - } - check_access(sf, atfile); - if (!getword(sf, word, &xxx, atfile)) { - ppp_warn("no secret in indirect secret file %s", atfile); - fclose(sf); - continue; - } - fclose(sf); - } - strlcpy(lsecret, word, sizeof(lsecret)); - } - - /* - * Now read address authorization info and make a wordlist. - */ - app = &alist; - for (;;) { - if (!getword(f, word, &newline, filename) || newline) - break; - ap = (struct wordlist *) - malloc(sizeof(struct wordlist) + strlen(word) + 1); - if (ap == NULL) - novm("authorized addresses"); - ap->word = (char *) (ap + 1); - strcpy(ap->word, word); - *app = ap; - app = &ap->next; - } - *app = NULL; - - /* - * This is the best so far; remember it. - */ - best_flag = got_flag; - if (addr_list) - free_wordlist(addr_list); - addr_list = alist; - if (secret != NULL) - strlcpy(secret, lsecret, MAXWORDLEN); - - if (!newline) - break; - } - - /* scan for a -- word indicating the start of options */ - for (app = &addr_list; (ap = *app) != NULL; app = &ap->next) - if (strcmp(ap->word, "--") == 0) - break; - /* ap = start of options */ - if (ap != NULL) { - ap = ap->next; /* first option */ - free(*app); /* free the "--" word */ - *app = NULL; /* terminate addr list */ - } - if (opts != NULL) - *opts = ap; - else if (ap != NULL) - free_wordlist(ap); - if (addrs != NULL) - *addrs = addr_list; - else if (addr_list != NULL) - free_wordlist(addr_list); - - return best_flag; -} - -/* - * wordlist_count - return the number of items in a wordlist - */ -static int -wordlist_count(wp) - struct wordlist *wp; -{ - int n; - - for (n = 0; wp != NULL; wp = wp->next) - ++n; - return n; -} - -/* - * free_wordlist - release memory allocated for a wordlist. - */ -static void -free_wordlist(wp) - struct wordlist *wp; -{ - struct wordlist *next; - - while (wp != NULL) { - next = wp->next; - free(wp); - wp = next; - } -} -#endif /* UNUSED */ - -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/ccp.c b/ext/lwip/src/netif/ppp/ccp.c deleted file mode 100644 index f8519eb..0000000 --- a/ext/lwip/src/netif/ppp/ccp.c +++ /dev/null @@ -1,1740 +0,0 @@ -/* - * ccp.c - 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && CCP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#include -#include - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/fsm.h" -#include "netif/ppp/ccp.h" - -#if MPPE_SUPPORT -#include "netif/ppp/lcp.h" /* lcp_close(), lcp_fsm */ -#include "netif/ppp/mppe.h" /* mppe_init() */ -#endif /* MPPE_SUPPORT */ - -/* - * Unfortunately there is a bug in zlib which means that using a - * size of 8 (window size = 256) for Deflate compression will cause - * buffer overruns and kernel crashes in the deflate module. - * Until this is fixed we only accept sizes in the range 9 .. 15. - * Thanks to James Carlson for pointing this out. - */ -#define DEFLATE_MIN_WORKS 9 - -/* - * Command-line options. - */ -#if PPP_OPTIONS -static int setbsdcomp (char **); -static int setdeflate (char **); -static char bsd_value[8]; -static char deflate_value[8]; - -/* - * Option variables. - */ -#if MPPE_SUPPORT -bool refuse_mppe_stateful = 1; /* Allow stateful mode? */ -#endif /* MPPE_SUPPORT */ - -static option_t ccp_option_list[] = { - { "noccp", o_bool, &ccp_protent.enabled_flag, - "Disable CCP negotiation" }, - { "-ccp", o_bool, &ccp_protent.enabled_flag, - "Disable CCP negotiation", OPT_ALIAS }, - - { "bsdcomp", o_special, (void *)setbsdcomp, - "Request BSD-Compress packet compression", - OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bsd_value }, - { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, - "don't allow BSD-Compress", OPT_PRIOSUB | OPT_A2CLR, - &ccp_allowoptions[0].bsd_compress }, - { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, - "don't allow BSD-Compress", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, - &ccp_allowoptions[0].bsd_compress }, - - { "deflate", o_special, (void *)setdeflate, - "request Deflate compression", - OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, deflate_value }, - { "nodeflate", o_bool, &ccp_wantoptions[0].deflate, - "don't allow Deflate compression", OPT_PRIOSUB | OPT_A2CLR, - &ccp_allowoptions[0].deflate }, - { "-deflate", o_bool, &ccp_wantoptions[0].deflate, - "don't allow Deflate compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, - &ccp_allowoptions[0].deflate }, - - { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft, - "don't use draft deflate #", OPT_A2COPY, - &ccp_allowoptions[0].deflate_draft }, - - { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1, - "request Predictor-1", OPT_PRIO | 1 }, - { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1, - "don't allow Predictor-1", OPT_PRIOSUB | OPT_A2CLR, - &ccp_allowoptions[0].predictor_1 }, - { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1, - "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, - &ccp_allowoptions[0].predictor_1 }, - -#if MPPE_SUPPORT - /* MPPE options are symmetrical ... we only set wantoptions here */ - { "require-mppe", o_bool, &ccp_wantoptions[0].mppe, - "require MPPE encryption", - OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, - { "+mppe", o_bool, &ccp_wantoptions[0].mppe, - "require MPPE encryption", - OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, - { "nomppe", o_bool, &ccp_wantoptions[0].mppe, - "don't allow MPPE encryption", OPT_PRIO }, - { "-mppe", o_bool, &ccp_wantoptions[0].mppe, - "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO }, - - /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */ - { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe, - "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, - &ccp_wantoptions[0].mppe }, - { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe, - "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, - &ccp_wantoptions[0].mppe }, - { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe, - "don't allow MPPE 40-bit encryption", - OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, - { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe, - "don't allow MPPE 40-bit encryption", - OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, - &ccp_wantoptions[0].mppe }, - - { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe, - "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128, - &ccp_wantoptions[0].mppe }, - { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe, - "require MPPE 128-bit encryption", - OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128, - &ccp_wantoptions[0].mppe }, - { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe, - "don't allow MPPE 128-bit encryption", - OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, - { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe, - "don't allow MPPE 128-bit encryption", - OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, - &ccp_wantoptions[0].mppe }, - - /* strange one; we always request stateless, but will we allow stateful? */ - { "mppe-stateful", o_bool, &refuse_mppe_stateful, - "allow MPPE stateful mode", OPT_PRIO }, - { "nomppe-stateful", o_bool, &refuse_mppe_stateful, - "disallow MPPE stateful mode", OPT_PRIO | 1 }, -#endif /* MPPE_SUPPORT */ - - { NULL } -}; -#endif /* PPP_OPTIONS */ - -/* - * Protocol entry points from main code. - */ -static void ccp_init(ppp_pcb *pcb); -static void ccp_open(ppp_pcb *pcb); -static void ccp_close(ppp_pcb *pcb, const char *reason); -static void ccp_lowerup(ppp_pcb *pcb); -static void ccp_lowerdown(ppp_pcb *pcb); -static void ccp_input(ppp_pcb *pcb, u_char *pkt, int len); -static void ccp_protrej(ppp_pcb *pcb); -#if PRINTPKT_SUPPORT -static int ccp_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg); -#endif /* PRINTPKT_SUPPORT */ -#if PPP_DATAINPUT -static void ccp_datainput(ppp_pcb *pcb, u_char *pkt, int len); -#endif /* PPP_DATAINPUT */ - -const struct protent ccp_protent = { - PPP_CCP, - ccp_init, - ccp_input, - ccp_protrej, - ccp_lowerup, - ccp_lowerdown, - ccp_open, - ccp_close, -#if PRINTPKT_SUPPORT - ccp_printpkt, -#endif /* PRINTPKT_SUPPORT */ -#if PPP_DATAINPUT - ccp_datainput, -#endif /* PPP_DATAINPUT */ -#if PRINTPKT_SUPPORT - "CCP", - "Compressed", -#endif /* PRINTPKT_SUPPORT */ -#if PPP_OPTIONS - ccp_option_list, - NULL, -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT - NULL, - NULL -#endif /* DEMAND_SUPPORT */ -}; - -/* - * Callbacks for fsm code. - */ -static void ccp_resetci (fsm *); -static int ccp_cilen (fsm *); -static void ccp_addci (fsm *, u_char *, int *); -static int ccp_ackci (fsm *, u_char *, int); -static int ccp_nakci (fsm *, u_char *, int, int); -static int ccp_rejci (fsm *, u_char *, int); -static int ccp_reqci (fsm *, u_char *, int *, int); -static void ccp_up (fsm *); -static void ccp_down (fsm *); -static int ccp_extcode (fsm *, int, int, u_char *, int); -static void ccp_rack_timeout (void *); -static const char *method_name (ccp_options *, ccp_options *); - -static const fsm_callbacks ccp_callbacks = { - ccp_resetci, - ccp_cilen, - ccp_addci, - ccp_ackci, - ccp_nakci, - ccp_rejci, - ccp_reqci, - ccp_up, - ccp_down, - NULL, - NULL, - NULL, - NULL, - ccp_extcode, - "CCP" -}; - -/* - * Do we want / did we get any compression? - */ -static int ccp_anycompress(ccp_options *opt) { - return (0 -#if DEFLATE_SUPPORT - || (opt)->deflate -#endif /* DEFLATE_SUPPORT */ -#if BSDCOMPRESS_SUPPORT - || (opt)->bsd_compress -#endif /* BSDCOMPRESS_SUPPORT */ -#if PREDICTOR_SUPPORT - || (opt)->predictor_1 || (opt)->predictor_2 -#endif /* PREDICTOR_SUPPORT */ -#if MPPE_SUPPORT - || (opt)->mppe -#endif /* MPPE_SUPPORT */ - ); -} - -/* - * Local state (mainly for handling reset-reqs and reset-acks). - */ -#define RACK_PENDING 1 /* waiting for reset-ack */ -#define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */ - -#define RACKTIMEOUT 1 /* second */ - -#if PPP_OPTIONS -/* - * Option parsing - */ -static int -setbsdcomp(argv) - char **argv; -{ - int rbits, abits; - char *str, *endp; - - str = *argv; - abits = rbits = strtol(str, &endp, 0); - if (endp != str && *endp == ',') { - str = endp + 1; - abits = strtol(str, &endp, 0); - } - if (*endp != 0 || endp == str) { - option_error("invalid parameter '%s' for bsdcomp option", *argv); - return 0; - } - if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS)) - || (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) { - option_error("bsdcomp option values must be 0 or %d .. %d", - BSD_MIN_BITS, BSD_MAX_BITS); - return 0; - } - if (rbits > 0) { - ccp_wantoptions[0].bsd_compress = 1; - ccp_wantoptions[0].bsd_bits = rbits; - } else - ccp_wantoptions[0].bsd_compress = 0; - if (abits > 0) { - ccp_allowoptions[0].bsd_compress = 1; - ccp_allowoptions[0].bsd_bits = abits; - } else - ccp_allowoptions[0].bsd_compress = 0; - ppp_slprintf(bsd_value, sizeof(bsd_value), - rbits == abits? "%d": "%d,%d", rbits, abits); - - return 1; -} - -static int -setdeflate(argv) - char **argv; -{ - int rbits, abits; - char *str, *endp; - - str = *argv; - abits = rbits = strtol(str, &endp, 0); - if (endp != str && *endp == ',') { - str = endp + 1; - abits = strtol(str, &endp, 0); - } - if (*endp != 0 || endp == str) { - option_error("invalid parameter '%s' for deflate option", *argv); - return 0; - } - if ((rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE)) - || (abits != 0 && (abits < DEFLATE_MIN_SIZE - || abits > DEFLATE_MAX_SIZE))) { - option_error("deflate option values must be 0 or %d .. %d", - DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE); - return 0; - } - if (rbits == DEFLATE_MIN_SIZE || abits == DEFLATE_MIN_SIZE) { - if (rbits == DEFLATE_MIN_SIZE) - rbits = DEFLATE_MIN_WORKS; - if (abits == DEFLATE_MIN_SIZE) - abits = DEFLATE_MIN_WORKS; - warn("deflate option value of %d changed to %d to avoid zlib bug", - DEFLATE_MIN_SIZE, DEFLATE_MIN_WORKS); - } - if (rbits > 0) { - ccp_wantoptions[0].deflate = 1; - ccp_wantoptions[0].deflate_size = rbits; - } else - ccp_wantoptions[0].deflate = 0; - if (abits > 0) { - ccp_allowoptions[0].deflate = 1; - ccp_allowoptions[0].deflate_size = abits; - } else - ccp_allowoptions[0].deflate = 0; - ppp_slprintf(deflate_value, sizeof(deflate_value), - rbits == abits? "%d": "%d,%d", rbits, abits); - - return 1; -} -#endif /* PPP_OPTIONS */ - -/* - * ccp_init - initialize CCP. - */ -static void ccp_init(ppp_pcb *pcb) { - fsm *f = &pcb->ccp_fsm; - - f->pcb = pcb; - f->protocol = PPP_CCP; - f->callbacks = &ccp_callbacks; - fsm_init(f); - -#if 0 /* Not necessary, everything is cleared in ppp_new() */ - memset(wo, 0, sizeof(*wo)); - memset(go, 0, sizeof(*go)); - memset(ao, 0, sizeof(*ao)); - memset(ho, 0, sizeof(*ho)); -#endif /* 0 */ - -#if DEFLATE_SUPPORT - wo->deflate = 1; - wo->deflate_size = DEFLATE_MAX_SIZE; - wo->deflate_correct = 1; - wo->deflate_draft = 1; - ao->deflate = 1; - ao->deflate_size = DEFLATE_MAX_SIZE; - ao->deflate_correct = 1; - ao->deflate_draft = 1; -#endif /* DEFLATE_SUPPORT */ - -#if BSDCOMPRESS_SUPPORT - wo->bsd_compress = 1; - wo->bsd_bits = BSD_MAX_BITS; - ao->bsd_compress = 1; - ao->bsd_bits = BSD_MAX_BITS; -#endif /* BSDCOMPRESS_SUPPORT */ - -#if PREDICTOR_SUPPORT - ao->predictor_1 = 1; -#endif /* PREDICTOR_SUPPORT */ -} - -/* - * ccp_open - CCP is allowed to come up. - */ -static void ccp_open(ppp_pcb *pcb) { - fsm *f = &pcb->ccp_fsm; - ccp_options *go = &pcb->ccp_gotoptions; - - if (f->state != PPP_FSM_OPENED) - ccp_set(pcb, 1, 0, 0, 0); - - /* - * Find out which compressors the kernel supports before - * deciding whether to open in silent mode. - */ - ccp_resetci(f); - if (!ccp_anycompress(go)) - f->flags |= OPT_SILENT; - - fsm_open(f); -} - -/* - * ccp_close - Terminate CCP. - */ -static void ccp_close(ppp_pcb *pcb, const char *reason) { - fsm *f = &pcb->ccp_fsm; - ccp_set(pcb, 0, 0, 0, 0); - fsm_close(f, reason); -} - -/* - * ccp_lowerup - we may now transmit CCP packets. - */ -static void ccp_lowerup(ppp_pcb *pcb) { - fsm *f = &pcb->ccp_fsm; - fsm_lowerup(f); -} - -/* - * ccp_lowerdown - we may not transmit CCP packets. - */ -static void ccp_lowerdown(ppp_pcb *pcb) { - fsm *f = &pcb->ccp_fsm; - fsm_lowerdown(f); -} - -/* - * ccp_input - process a received CCP packet. - */ -static void ccp_input(ppp_pcb *pcb, u_char *p, int len) { - fsm *f = &pcb->ccp_fsm; - ccp_options *go = &pcb->ccp_gotoptions; - int oldstate; - - /* - * Check for a terminate-request so we can print a message. - */ - oldstate = f->state; - fsm_input(f, p, len); - if (oldstate == PPP_FSM_OPENED && p[0] == TERMREQ && f->state != PPP_FSM_OPENED) { - ppp_notice("Compression disabled by peer."); -#if MPPE_SUPPORT - if (go->mppe) { - ppp_error("MPPE disabled, closing LCP"); - lcp_close(pcb, "MPPE disabled by peer"); - } -#endif /* MPPE_SUPPORT */ - } - - /* - * If we get a terminate-ack and we're not asking for compression, - * close CCP. - */ - if (oldstate == PPP_FSM_REQSENT && p[0] == TERMACK - && !ccp_anycompress(go)) - ccp_close(pcb, "No compression negotiated"); -} - -/* - * Handle a CCP-specific code. - */ -static int ccp_extcode(fsm *f, int code, int id, u_char *p, int len) { - ppp_pcb *pcb = f->pcb; - LWIP_UNUSED_ARG(p); - LWIP_UNUSED_ARG(len); - - switch (code) { - case CCP_RESETREQ: - if (f->state != PPP_FSM_OPENED) - break; - ccp_reset_comp(pcb); - /* send a reset-ack, which the transmitter will see and - reset its compression state. */ - fsm_sdata(f, CCP_RESETACK, id, NULL, 0); - break; - - case CCP_RESETACK: - if ((pcb->ccp_localstate & RACK_PENDING) && id == f->reqid) { - pcb->ccp_localstate &= ~(RACK_PENDING | RREQ_REPEAT); - UNTIMEOUT(ccp_rack_timeout, f); - ccp_reset_decomp(pcb); - } - break; - - default: - return 0; - } - - return 1; -} - -/* - * ccp_protrej - peer doesn't talk CCP. - */ -static void ccp_protrej(ppp_pcb *pcb) { - fsm *f = &pcb->ccp_fsm; -#if MPPE_SUPPORT - ccp_options *go = &pcb->ccp_gotoptions; -#endif /* MPPE_SUPPORT */ - - ccp_set(pcb, 0, 0, 0, 0); - fsm_lowerdown(f); - -#if MPPE_SUPPORT - if (go->mppe) { - ppp_error("MPPE required but peer negotiation failed"); - lcp_close(pcb, "MPPE required but peer negotiation failed"); - } -#endif /* MPPE_SUPPORT */ - -} - -/* - * ccp_resetci - initialize at start of negotiation. - */ -static void ccp_resetci(fsm *f) { - ppp_pcb *pcb = f->pcb; - ccp_options *go = &pcb->ccp_gotoptions; - ccp_options *wo = &pcb->ccp_wantoptions; -#if MPPE_SUPPORT - ccp_options *ao = &pcb->ccp_allowoptions; -#endif /* MPPE_SUPPORT */ -#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT - u_char opt_buf[CCP_MAX_OPTION_LENGTH]; -#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT */ -#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT - int res; -#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT */ - -#if MPPE_SUPPORT - if (pcb->settings.require_mppe) { - wo->mppe = ao->mppe = - (pcb->settings.refuse_mppe_40 ? 0 : MPPE_OPT_40) - | (pcb->settings.refuse_mppe_128 ? 0 : MPPE_OPT_128); - } -#endif /* MPPE_SUPPORT */ - - *go = *wo; - pcb->ccp_all_rejected = 0; - -#if MPPE_SUPPORT - if (go->mppe) { - int auth_mschap_bits = pcb->auth_done; - int numbits; - - /* - * Start with a basic sanity check: mschap[v2] auth must be in - * exactly one direction. RFC 3079 says that the keys are - * 'derived from the credentials of the peer that initiated the call', - * however the PPP protocol doesn't have such a concept, and pppd - * cannot get this info externally. Instead we do the best we can. - * NB: If MPPE is required, all other compression opts are invalid. - * So, we return right away if we can't do it. - */ - - /* Leave only the mschap auth bits set */ - auth_mschap_bits &= (CHAP_MS_WITHPEER | CHAP_MS_PEER | - CHAP_MS2_WITHPEER | CHAP_MS2_PEER); - /* Count the mschap auths */ - auth_mschap_bits >>= CHAP_MS_SHIFT; - numbits = 0; - do { - numbits += auth_mschap_bits & 1; - auth_mschap_bits >>= 1; - } while (auth_mschap_bits); - if (numbits > 1) { - ppp_error("MPPE required, but auth done in both directions."); - lcp_close(pcb, "MPPE required but not available"); - return; - } - if (!numbits) { - ppp_error("MPPE required, but MS-CHAP[v2] auth not performed."); - lcp_close(pcb, "MPPE required but not available"); - return; - } - - /* A plugin (eg radius) may not have obtained key material. */ - if (!pcb->mppe_keys_set) { - ppp_error("MPPE required, but keys are not available. " - "Possible plugin problem?"); - lcp_close(pcb, "MPPE required but not available"); - return; - } - - /* LM auth not supported for MPPE */ - if (pcb->auth_done & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) { - /* This might be noise */ - if (go->mppe & MPPE_OPT_40) { - ppp_notice("Disabling 40-bit MPPE; MS-CHAP LM not supported"); - go->mppe &= ~MPPE_OPT_40; - wo->mppe &= ~MPPE_OPT_40; - } - } - - /* Last check: can we actually negotiate something? */ - if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) { - /* Could be misconfig, could be 40-bit disabled above. */ - ppp_error("MPPE required, but both 40-bit and 128-bit disabled."); - lcp_close(pcb, "MPPE required but not available"); - return; - } - - /* sync options */ - ao->mppe = go->mppe; - /* MPPE is not compatible with other compression types */ -#if BSDCOMPRESS_SUPPORT - ao->bsd_compress = go->bsd_compress = 0; -#endif /* BSDCOMPRESS_SUPPORT */ -#if PREDICTOR_SUPPORT - ao->predictor_1 = go->predictor_1 = 0; - ao->predictor_2 = go->predictor_2 = 0; -#endif /* PREDICTOR_SUPPORT */ -#if DEFLATE_SUPPORT - ao->deflate = go->deflate = 0; -#endif /* DEFLATE_SUPPORT */ - } -#endif /* MPPE_SUPPORT */ - - /* - * Check whether the kernel knows about the various - * compression methods we might request. - */ -#if BSDCOMPRESS_SUPPORT - /* FIXME: we don't need to test if BSD compress is available - * if BSDCOMPRESS_SUPPORT is set, it is. - */ - if (go->bsd_compress) { - opt_buf[0] = CI_BSD_COMPRESS; - opt_buf[1] = CILEN_BSD_COMPRESS; - for (;;) { - if (go->bsd_bits < BSD_MIN_BITS) { - go->bsd_compress = 0; - break; - } - opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); - res = ccp_test(pcb, opt_buf, CILEN_BSD_COMPRESS, 0); - if (res > 0) { - break; - } else if (res < 0) { - go->bsd_compress = 0; - break; - } - go->bsd_bits--; - } - } -#endif /* BSDCOMPRESS_SUPPORT */ -#if DEFLATE_SUPPORT - /* FIXME: we don't need to test if deflate is available - * if DEFLATE_SUPPORT is set, it is. - */ - if (go->deflate) { - if (go->deflate_correct) { - opt_buf[0] = CI_DEFLATE; - opt_buf[1] = CILEN_DEFLATE; - opt_buf[3] = DEFLATE_CHK_SEQUENCE; - for (;;) { - if (go->deflate_size < DEFLATE_MIN_WORKS) { - go->deflate_correct = 0; - break; - } - opt_buf[2] = DEFLATE_MAKE_OPT(go->deflate_size); - res = ccp_test(pcb, opt_buf, CILEN_DEFLATE, 0); - if (res > 0) { - break; - } else if (res < 0) { - go->deflate_correct = 0; - break; - } - go->deflate_size--; - } - } - if (go->deflate_draft) { - opt_buf[0] = CI_DEFLATE_DRAFT; - opt_buf[1] = CILEN_DEFLATE; - opt_buf[3] = DEFLATE_CHK_SEQUENCE; - for (;;) { - if (go->deflate_size < DEFLATE_MIN_WORKS) { - go->deflate_draft = 0; - break; - } - opt_buf[2] = DEFLATE_MAKE_OPT(go->deflate_size); - res = ccp_test(pcb, opt_buf, CILEN_DEFLATE, 0); - if (res > 0) { - break; - } else if (res < 0) { - go->deflate_draft = 0; - break; - } - go->deflate_size--; - } - } - if (!go->deflate_correct && !go->deflate_draft) - go->deflate = 0; - } -#endif /* DEFLATE_SUPPORT */ -#if PREDICTOR_SUPPORT - /* FIXME: we don't need to test if predictor is available, - * if PREDICTOR_SUPPORT is set, it is. - */ - if (go->predictor_1) { - opt_buf[0] = CI_PREDICTOR_1; - opt_buf[1] = CILEN_PREDICTOR_1; - if (ccp_test(pcb, opt_buf, CILEN_PREDICTOR_1, 0) <= 0) - go->predictor_1 = 0; - } - if (go->predictor_2) { - opt_buf[0] = CI_PREDICTOR_2; - opt_buf[1] = CILEN_PREDICTOR_2; - if (ccp_test(pcb, opt_buf, CILEN_PREDICTOR_2, 0) <= 0) - go->predictor_2 = 0; - } -#endif /* PREDICTOR_SUPPORT */ -} - -/* - * ccp_cilen - Return total length of our configuration info. - */ -static int ccp_cilen(fsm *f) { - ppp_pcb *pcb = f->pcb; - ccp_options *go = &pcb->ccp_gotoptions; - - return 0 -#if BSDCOMPRESS_SUPPORT - + (go->bsd_compress? CILEN_BSD_COMPRESS: 0) -#endif /* BSDCOMPRESS_SUPPORT */ -#if DEFLATE_SUPPORT - + (go->deflate && go->deflate_correct? CILEN_DEFLATE: 0) - + (go->deflate && go->deflate_draft? CILEN_DEFLATE: 0) -#endif /* DEFLATE_SUPPORT */ -#if PREDICTOR_SUPPORT - + (go->predictor_1? CILEN_PREDICTOR_1: 0) - + (go->predictor_2? CILEN_PREDICTOR_2: 0) -#endif /* PREDICTOR_SUPPORT */ -#if MPPE_SUPPORT - + (go->mppe? CILEN_MPPE: 0) -#endif /* MPPE_SUPPORT */ - ; -} - -/* - * ccp_addci - put our requests in a packet. - */ -static void ccp_addci(fsm *f, u_char *p, int *lenp) { - ppp_pcb *pcb = f->pcb; - ccp_options *go = &pcb->ccp_gotoptions; - u_char *p0 = p; - - /* - * Add the compression types that we can receive, in decreasing - * preference order. - */ -#if MPPE_SUPPORT - if (go->mppe) { - p[0] = CI_MPPE; - p[1] = CILEN_MPPE; - MPPE_OPTS_TO_CI(go->mppe, &p[2]); - mppe_init(pcb, &pcb->mppe_decomp, go->mppe); - p += CILEN_MPPE; - } -#endif /* MPPE_SUPPORT */ -#if DEFLATE_SUPPORT - if (go->deflate) { - if (go->deflate_correct) { - p[0] = CI_DEFLATE; - p[1] = CILEN_DEFLATE; - p[2] = DEFLATE_MAKE_OPT(go->deflate_size); - p[3] = DEFLATE_CHK_SEQUENCE; - p += CILEN_DEFLATE; - } - if (go->deflate_draft) { - p[0] = CI_DEFLATE_DRAFT; - p[1] = CILEN_DEFLATE; - p[2] = p[2 - CILEN_DEFLATE]; - p[3] = DEFLATE_CHK_SEQUENCE; - p += CILEN_DEFLATE; - } - } -#endif /* DEFLATE_SUPPORT */ -#if BSDCOMPRESS_SUPPORT - if (go->bsd_compress) { - p[0] = CI_BSD_COMPRESS; - p[1] = CILEN_BSD_COMPRESS; - p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); - p += CILEN_BSD_COMPRESS; - } -#endif /* BSDCOMPRESS_SUPPORT */ -#if PREDICTOR_SUPPORT - /* XXX Should Predictor 2 be preferable to Predictor 1? */ - if (go->predictor_1) { - p[0] = CI_PREDICTOR_1; - p[1] = CILEN_PREDICTOR_1; - p += CILEN_PREDICTOR_1; - } - if (go->predictor_2) { - p[0] = CI_PREDICTOR_2; - p[1] = CILEN_PREDICTOR_2; - p += CILEN_PREDICTOR_2; - } -#endif /* PREDICTOR_SUPPORT */ - - go->method = (p > p0)? p0[0]: 0; - - *lenp = p - p0; -} - -/* - * ccp_ackci - process a received configure-ack, and return - * 1 iff the packet was OK. - */ -static int ccp_ackci(fsm *f, u_char *p, int len) { - ppp_pcb *pcb = f->pcb; - ccp_options *go = &pcb->ccp_gotoptions; -#if BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT - u_char *p0 = p; -#endif /* BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT */ - -#if MPPE_SUPPORT - if (go->mppe) { - u_char opt_buf[CILEN_MPPE]; - - opt_buf[0] = CI_MPPE; - opt_buf[1] = CILEN_MPPE; - MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]); - if (len < CILEN_MPPE || memcmp(opt_buf, p, CILEN_MPPE)) - return 0; - p += CILEN_MPPE; - len -= CILEN_MPPE; - /* XXX Cope with first/fast ack */ - if (len == 0) - return 1; - } -#endif /* MPPE_SUPPORT */ -#if DEFLATE_SUPPORT - if (go->deflate) { - if (len < CILEN_DEFLATE - || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) - || p[1] != CILEN_DEFLATE - || p[2] != DEFLATE_MAKE_OPT(go->deflate_size) - || p[3] != DEFLATE_CHK_SEQUENCE) - return 0; - p += CILEN_DEFLATE; - len -= CILEN_DEFLATE; - /* XXX Cope with first/fast ack */ - if (len == 0) - return 1; - if (go->deflate_correct && go->deflate_draft) { - if (len < CILEN_DEFLATE - || p[0] != CI_DEFLATE_DRAFT - || p[1] != CILEN_DEFLATE - || p[2] != DEFLATE_MAKE_OPT(go->deflate_size) - || p[3] != DEFLATE_CHK_SEQUENCE) - return 0; - p += CILEN_DEFLATE; - len -= CILEN_DEFLATE; - } - } -#endif /* DEFLATE_SUPPORT */ -#if BSDCOMPRESS_SUPPORT - if (go->bsd_compress) { - if (len < CILEN_BSD_COMPRESS - || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS - || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) - return 0; - p += CILEN_BSD_COMPRESS; - len -= CILEN_BSD_COMPRESS; - /* XXX Cope with first/fast ack */ - if (p == p0 && len == 0) - return 1; - } -#endif /* BSDCOMPRESS_SUPPORT */ -#if PREDICTOR_SUPPORT - if (go->predictor_1) { - if (len < CILEN_PREDICTOR_1 - || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1) - return 0; - p += CILEN_PREDICTOR_1; - len -= CILEN_PREDICTOR_1; - /* XXX Cope with first/fast ack */ - if (p == p0 && len == 0) - return 1; - } - if (go->predictor_2) { - if (len < CILEN_PREDICTOR_2 - || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2) - return 0; - p += CILEN_PREDICTOR_2; - len -= CILEN_PREDICTOR_2; - /* XXX Cope with first/fast ack */ - if (p == p0 && len == 0) - return 1; - } -#endif /* PREDICTOR_SUPPORT */ - - if (len != 0) - return 0; - return 1; -} - -/* - * ccp_nakci - process received configure-nak. - * Returns 1 iff the nak was OK. - */ -static int ccp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { - ppp_pcb *pcb = f->pcb; - ccp_options *go = &pcb->ccp_gotoptions; - ccp_options no; /* options we've seen already */ - ccp_options try_; /* options to ask for next time */ - LWIP_UNUSED_ARG(treat_as_reject); -#if !MPPE_SUPPORT && !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT - LWIP_UNUSED_ARG(p); - LWIP_UNUSED_ARG(len); -#endif /* !MPPE_SUPPORT && !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT */ - - memset(&no, 0, sizeof(no)); - try_ = *go; - -#if MPPE_SUPPORT - if (go->mppe && len >= CILEN_MPPE - && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { - no.mppe = 1; - /* - * Peer wants us to use a different strength or other setting. - * Fail if we aren't willing to use his suggestion. - */ - MPPE_CI_TO_OPTS(&p[2], try_.mppe); - if ((try_.mppe & MPPE_OPT_STATEFUL) && pcb->settings.refuse_mppe_stateful) { - ppp_error("Refusing MPPE stateful mode offered by peer"); - try_.mppe = 0; - } else if (((go->mppe | MPPE_OPT_STATEFUL) & try_.mppe) != try_.mppe) { - /* Peer must have set options we didn't request (suggest) */ - try_.mppe = 0; - } - - if (!try_.mppe) { - ppp_error("MPPE required but peer negotiation failed"); - lcp_close(pcb, "MPPE required but peer negotiation failed"); - } - } -#endif /* MPPE_SUPPORT */ -#if DEFLATE_SUPPORT - if (go->deflate && len >= CILEN_DEFLATE - && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) - && p[1] == CILEN_DEFLATE) { - no.deflate = 1; - /* - * Peer wants us to use a different code size or something. - * Stop asking for Deflate if we don't understand his suggestion. - */ - if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL - || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_WORKS - || p[3] != DEFLATE_CHK_SEQUENCE) - try_.deflate = 0; - else if (DEFLATE_SIZE(p[2]) < go->deflate_size) - try_.deflate_size = DEFLATE_SIZE(p[2]); - p += CILEN_DEFLATE; - len -= CILEN_DEFLATE; - if (go->deflate_correct && go->deflate_draft - && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT - && p[1] == CILEN_DEFLATE) { - p += CILEN_DEFLATE; - len -= CILEN_DEFLATE; - } - } -#endif /* DEFLATE_SUPPORT */ -#if BSDCOMPRESS_SUPPORT - if (go->bsd_compress && len >= CILEN_BSD_COMPRESS - && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { - no.bsd_compress = 1; - /* - * Peer wants us to use a different number of bits - * or a different version. - */ - if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION) - try_.bsd_compress = 0; - else if (BSD_NBITS(p[2]) < go->bsd_bits) - try_.bsd_bits = BSD_NBITS(p[2]); - p += CILEN_BSD_COMPRESS; - len -= CILEN_BSD_COMPRESS; - } -#endif /* BSDCOMPRESS_SUPPORT */ - - /* - * Predictor-1 and 2 have no options, so they can't be Naked. - * - * There may be remaining options but we ignore them. - */ - - if (f->state != PPP_FSM_OPENED) - *go = try_; - return 1; -} - -/* - * ccp_rejci - reject some of our suggested compression methods. - */ -static int ccp_rejci(fsm *f, u_char *p, int len) { - ppp_pcb *pcb = f->pcb; - ccp_options *go = &pcb->ccp_gotoptions; - ccp_options try_; /* options to request next time */ - - try_ = *go; - - /* - * Cope with empty configure-rejects by ceasing to send - * configure-requests. - */ - if (len == 0 && pcb->ccp_all_rejected) - return -1; - -#if MPPE_SUPPORT - if (go->mppe && len >= CILEN_MPPE - && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { - ppp_error("MPPE required but peer refused"); - lcp_close(pcb, "MPPE required but peer refused"); - p += CILEN_MPPE; - len -= CILEN_MPPE; - } -#endif /* MPPE_SUPPORT */ -#if DEFLATE_SUPPORT - if (go->deflate_correct && len >= CILEN_DEFLATE - && p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) { - if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size) - || p[3] != DEFLATE_CHK_SEQUENCE) - return 0; /* Rej is bad */ - try_.deflate_correct = 0; - p += CILEN_DEFLATE; - len -= CILEN_DEFLATE; - } - if (go->deflate_draft && len >= CILEN_DEFLATE - && p[0] == CI_DEFLATE_DRAFT && p[1] == CILEN_DEFLATE) { - if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size) - || p[3] != DEFLATE_CHK_SEQUENCE) - return 0; /* Rej is bad */ - try_.deflate_draft = 0; - p += CILEN_DEFLATE; - len -= CILEN_DEFLATE; - } - if (!try_.deflate_correct && !try_.deflate_draft) - try_.deflate = 0; -#endif /* DEFLATE_SUPPORT */ -#if BSDCOMPRESS_SUPPORT - if (go->bsd_compress && len >= CILEN_BSD_COMPRESS - && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { - if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) - return 0; - try_.bsd_compress = 0; - p += CILEN_BSD_COMPRESS; - len -= CILEN_BSD_COMPRESS; - } -#endif /* BSDCOMPRESS_SUPPORT */ -#if PREDICTOR_SUPPORT - if (go->predictor_1 && len >= CILEN_PREDICTOR_1 - && p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) { - try_.predictor_1 = 0; - p += CILEN_PREDICTOR_1; - len -= CILEN_PREDICTOR_1; - } - if (go->predictor_2 && len >= CILEN_PREDICTOR_2 - && p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) { - try_.predictor_2 = 0; - p += CILEN_PREDICTOR_2; - len -= CILEN_PREDICTOR_2; - } -#endif /* PREDICTOR_SUPPORT */ - - if (len != 0) - return 0; - - if (f->state != PPP_FSM_OPENED) - *go = try_; - - return 1; -} - -/* - * ccp_reqci - processed a received configure-request. - * Returns CONFACK, CONFNAK or CONFREJ and the packet modified - * appropriately. - */ -static int ccp_reqci(fsm *f, u_char *p, int *lenp, int dont_nak) { - ppp_pcb *pcb = f->pcb; - ccp_options *ho = &pcb->ccp_hisoptions; - ccp_options *ao = &pcb->ccp_allowoptions; - int ret, newret; -#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT - int res; - int nb; -#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT */ - u_char *p0, *retp; - int len, clen, type; -#if MPPE_SUPPORT - u8_t rej_for_ci_mppe = 1; /* Are we rejecting based on a bad/missing */ - /* CI_MPPE, or due to other options? */ -#endif /* MPPE_SUPPORT */ - - ret = CONFACK; - retp = p0 = p; - len = *lenp; - - memset(ho, 0, sizeof(ccp_options)); - ho->method = (len > 0)? p[0]: 0; - - while (len > 0) { - newret = CONFACK; - if (len < 2 || p[1] < 2 || p[1] > len) { - /* length is bad */ - clen = len; - newret = CONFREJ; - - } else { - type = p[0]; - clen = p[1]; - - switch (type) { -#if MPPE_SUPPORT - case CI_MPPE: - if (!ao->mppe || clen != CILEN_MPPE) { - newret = CONFREJ; - break; - } - MPPE_CI_TO_OPTS(&p[2], ho->mppe); - - /* Nak if anything unsupported or unknown are set. */ - if (ho->mppe & MPPE_OPT_UNSUPPORTED) { - newret = CONFNAK; - ho->mppe &= ~MPPE_OPT_UNSUPPORTED; - } - if (ho->mppe & MPPE_OPT_UNKNOWN) { - newret = CONFNAK; - ho->mppe &= ~MPPE_OPT_UNKNOWN; - } - - /* Check state opt */ - if (ho->mppe & MPPE_OPT_STATEFUL) { - /* - * We can Nak and request stateless, but it's a - * lot easier to just assume the peer will request - * it if he can do it; stateful mode is bad over - * the Internet -- which is where we expect MPPE. - */ - if (pcb->settings.refuse_mppe_stateful) { - ppp_error("Refusing MPPE stateful mode offered by peer"); - newret = CONFREJ; - break; - } - } - - /* Find out which of {S,L} are set. */ - if ((ho->mppe & MPPE_OPT_128) - && (ho->mppe & MPPE_OPT_40)) { - /* Both are set, negotiate the strongest. */ - newret = CONFNAK; - if (ao->mppe & MPPE_OPT_128) - ho->mppe &= ~MPPE_OPT_40; - else if (ao->mppe & MPPE_OPT_40) - ho->mppe &= ~MPPE_OPT_128; - else { - newret = CONFREJ; - break; - } - } else if (ho->mppe & MPPE_OPT_128) { - if (!(ao->mppe & MPPE_OPT_128)) { - newret = CONFREJ; - break; - } - } else if (ho->mppe & MPPE_OPT_40) { - if (!(ao->mppe & MPPE_OPT_40)) { - newret = CONFREJ; - break; - } - } else { - /* Neither are set. */ - /* We cannot accept this. */ - newret = CONFNAK; - /* Give the peer our idea of what can be used, - so it can choose and confirm */ - ho->mppe = ao->mppe; - } - - /* rebuild the opts */ - MPPE_OPTS_TO_CI(ho->mppe, &p[2]); - if (newret == CONFACK) { - int mtu; - - mppe_init(pcb, &pcb->mppe_comp, ho->mppe); - /* - * We need to decrease the interface MTU by MPPE_PAD - * because MPPE frames **grow**. The kernel [must] - * allocate MPPE_PAD extra bytes in xmit buffers. - */ - mtu = netif_get_mtu(pcb); - if (mtu) - netif_set_mtu(pcb, mtu - MPPE_PAD); - else - newret = CONFREJ; - } - - /* - * We have accepted MPPE or are willing to negotiate - * MPPE parameters. A CONFREJ is due to subsequent - * (non-MPPE) processing. - */ - rej_for_ci_mppe = 0; - break; -#endif /* MPPE_SUPPORT */ -#if DEFLATE_SUPPORT - case CI_DEFLATE: - case CI_DEFLATE_DRAFT: - if (!ao->deflate || clen != CILEN_DEFLATE - || (!ao->deflate_correct && type == CI_DEFLATE) - || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) { - newret = CONFREJ; - break; - } - - ho->deflate = 1; - ho->deflate_size = nb = DEFLATE_SIZE(p[2]); - if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL - || p[3] != DEFLATE_CHK_SEQUENCE - || nb > ao->deflate_size || nb < DEFLATE_MIN_WORKS) { - newret = CONFNAK; - if (!dont_nak) { - p[2] = DEFLATE_MAKE_OPT(ao->deflate_size); - p[3] = DEFLATE_CHK_SEQUENCE; - /* fall through to test this #bits below */ - } else - break; - } - - /* - * Check whether we can do Deflate with the window - * size they want. If the window is too big, reduce - * it until the kernel can cope and nak with that. - * We only check this for the first option. - */ - if (p == p0) { - for (;;) { - res = ccp_test(pcb, p, CILEN_DEFLATE, 1); - if (res > 0) - break; /* it's OK now */ - if (res < 0 || nb == DEFLATE_MIN_WORKS || dont_nak) { - newret = CONFREJ; - p[2] = DEFLATE_MAKE_OPT(ho->deflate_size); - break; - } - newret = CONFNAK; - --nb; - p[2] = DEFLATE_MAKE_OPT(nb); - } - } - break; -#endif /* DEFLATE_SUPPORT */ -#if BSDCOMPRESS_SUPPORT - case CI_BSD_COMPRESS: - if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) { - newret = CONFREJ; - break; - } - - ho->bsd_compress = 1; - ho->bsd_bits = nb = BSD_NBITS(p[2]); - if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION - || nb > ao->bsd_bits || nb < BSD_MIN_BITS) { - newret = CONFNAK; - if (!dont_nak) { - p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits); - /* fall through to test this #bits below */ - } else - break; - } - - /* - * Check whether we can do BSD-Compress with the code - * size they want. If the code size is too big, reduce - * it until the kernel can cope and nak with that. - * We only check this for the first option. - */ - if (p == p0) { - for (;;) { - res = ccp_test(pcb, p, CILEN_BSD_COMPRESS, 1); - if (res > 0) - break; - if (res < 0 || nb == BSD_MIN_BITS || dont_nak) { - newret = CONFREJ; - p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, - ho->bsd_bits); - break; - } - newret = CONFNAK; - --nb; - p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb); - } - } - break; -#endif /* BSDCOMPRESS_SUPPORT */ -#if PREDICTOR_SUPPORT - case CI_PREDICTOR_1: - if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) { - newret = CONFREJ; - break; - } - - ho->predictor_1 = 1; - if (p == p0 - && ccp_test(pcb, p, CILEN_PREDICTOR_1, 1) <= 0) { - newret = CONFREJ; - } - break; - - case CI_PREDICTOR_2: - if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) { - newret = CONFREJ; - break; - } - - ho->predictor_2 = 1; - if (p == p0 - && ccp_test(pcb, p, CILEN_PREDICTOR_2, 1) <= 0) { - newret = CONFREJ; - } - break; -#endif /* PREDICTOR_SUPPORT */ - - default: - newret = CONFREJ; - } - } - - if (newret == CONFNAK && dont_nak) - newret = CONFREJ; - if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) { - /* we're returning this option */ - if (newret == CONFREJ && ret == CONFNAK) - retp = p0; - ret = newret; - if (p != retp) - MEMCPY(retp, p, clen); - retp += clen; - } - - p += clen; - len -= clen; - } - - if (ret != CONFACK) { - if (ret == CONFREJ && *lenp == retp - p0) - pcb->ccp_all_rejected = 1; - else - *lenp = retp - p0; - } -#if MPPE_SUPPORT - if (ret == CONFREJ && ao->mppe && rej_for_ci_mppe) { - ppp_error("MPPE required but peer negotiation failed"); - lcp_close(pcb, "MPPE required but peer negotiation failed"); - } -#endif /* MPPE_SUPPORT */ - return ret; -} - -/* - * Make a string name for a compression method (or 2). - */ -static const char *method_name(ccp_options *opt, ccp_options *opt2) { - static char result[64]; -#if !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT - LWIP_UNUSED_ARG(opt2); -#endif /* !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT */ - - if (!ccp_anycompress(opt)) - return "(none)"; - switch (opt->method) { -#if MPPE_SUPPORT - case CI_MPPE: - { - char *p = result; - char *q = result + sizeof(result); /* 1 past result */ - - ppp_slprintf(p, q - p, "MPPE "); - p += 5; - if (opt->mppe & MPPE_OPT_128) { - ppp_slprintf(p, q - p, "128-bit "); - p += 8; - } - if (opt->mppe & MPPE_OPT_40) { - ppp_slprintf(p, q - p, "40-bit "); - p += 7; - } - if (opt->mppe & MPPE_OPT_STATEFUL) - ppp_slprintf(p, q - p, "stateful"); - else - ppp_slprintf(p, q - p, "stateless"); - - break; - } -#endif /* MPPE_SUPPORT */ -#if DEFLATE_SUPPORT - case CI_DEFLATE: - case CI_DEFLATE_DRAFT: - if (opt2 != NULL && opt2->deflate_size != opt->deflate_size) - ppp_slprintf(result, sizeof(result), "Deflate%s (%d/%d)", - (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""), - opt->deflate_size, opt2->deflate_size); - else - ppp_slprintf(result, sizeof(result), "Deflate%s (%d)", - (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""), - opt->deflate_size); - break; -#endif /* DEFLATE_SUPPORT */ -#if BSDCOMPRESS_SUPPORT - case CI_BSD_COMPRESS: - if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits) - ppp_slprintf(result, sizeof(result), "BSD-Compress (%d/%d)", - opt->bsd_bits, opt2->bsd_bits); - else - ppp_slprintf(result, sizeof(result), "BSD-Compress (%d)", - opt->bsd_bits); - break; -#endif /* BSDCOMPRESS_SUPPORT */ -#if PREDICTOR_SUPPORT - case CI_PREDICTOR_1: - return "Predictor 1"; - case CI_PREDICTOR_2: - return "Predictor 2"; -#endif /* PREDICTOR_SUPPORT */ - default: - ppp_slprintf(result, sizeof(result), "Method %d", opt->method); - } - return result; -} - -/* - * CCP has come up - inform the kernel driver and log a message. - */ -static void ccp_up(fsm *f) { - ppp_pcb *pcb = f->pcb; - ccp_options *go = &pcb->ccp_gotoptions; - ccp_options *ho = &pcb->ccp_hisoptions; - char method1[64]; - - ccp_set(pcb, 1, 1, go->method, ho->method); - if (ccp_anycompress(go)) { - if (ccp_anycompress(ho)) { - if (go->method == ho->method) { - ppp_notice("%s compression enabled", method_name(go, ho)); - } else { - ppp_strlcpy(method1, method_name(go, NULL), sizeof(method1)); - ppp_notice("%s / %s compression enabled", - method1, method_name(ho, NULL)); - } - } else - ppp_notice("%s receive compression enabled", method_name(go, NULL)); - } else if (ccp_anycompress(ho)) - ppp_notice("%s transmit compression enabled", method_name(ho, NULL)); -#if MPPE_SUPPORT - if (go->mppe) { - continue_networks(pcb); /* Bring up IP et al */ - } -#endif /* MPPE_SUPPORT */ -} - -/* - * CCP has gone down - inform the kernel driver. - */ -static void ccp_down(fsm *f) { - ppp_pcb *pcb = f->pcb; -#if MPPE_SUPPORT - ccp_options *go = &pcb->ccp_gotoptions; -#endif /* MPPE_SUPPORT */ - - if (pcb->ccp_localstate & RACK_PENDING) - UNTIMEOUT(ccp_rack_timeout, f); - pcb->ccp_localstate = 0; - ccp_set(pcb, 1, 0, 0, 0); -#if MPPE_SUPPORT - if (go->mppe) { - go->mppe = 0; - if (pcb->lcp_fsm.state == PPP_FSM_OPENED) { - /* If LCP is not already going down, make sure it does. */ - ppp_error("MPPE disabled"); - lcp_close(pcb, "MPPE disabled"); - } - } -#endif /* MPPE_SUPPORT */ -} - -#if PRINTPKT_SUPPORT -/* - * Print the contents of a CCP packet. - */ -static const char* const ccp_codenames[] = { - "ConfReq", "ConfAck", "ConfNak", "ConfRej", - "TermReq", "TermAck", "CodeRej", - NULL, NULL, NULL, NULL, NULL, NULL, - "ResetReq", "ResetAck", -}; - -static int ccp_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg) { - const u_char *p0, *optend; - int code, id, len; - int optlen; - - p0 = p; - if (plen < HEADERLEN) - return 0; - code = p[0]; - id = p[1]; - len = (p[2] << 8) + p[3]; - if (len < HEADERLEN || len > plen) - return 0; - - if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ccp_codenames) && ccp_codenames[code-1] != NULL) - printer(arg, " %s", ccp_codenames[code-1]); - else - printer(arg, " code=0x%x", code); - printer(arg, " id=0x%x", id); - len -= HEADERLEN; - p += HEADERLEN; - - switch (code) { - case CONFREQ: - case CONFACK: - case CONFNAK: - case CONFREJ: - /* print list of possible compression methods */ - while (len >= 2) { - code = p[0]; - optlen = p[1]; - if (optlen < 2 || optlen > len) - break; - printer(arg, " <"); - len -= optlen; - optend = p + optlen; - switch (code) { -#if MPPE_SUPPORT - case CI_MPPE: - if (optlen >= CILEN_MPPE) { - u_char mppe_opts; - - MPPE_CI_TO_OPTS(&p[2], mppe_opts); - printer(arg, "mppe %s %s %s %s %s %s%s", - (p[2] & MPPE_H_BIT)? "+H": "-H", - (p[5] & MPPE_M_BIT)? "+M": "-M", - (p[5] & MPPE_S_BIT)? "+S": "-S", - (p[5] & MPPE_L_BIT)? "+L": "-L", - (p[5] & MPPE_D_BIT)? "+D": "-D", - (p[5] & MPPE_C_BIT)? "+C": "-C", - (mppe_opts & MPPE_OPT_UNKNOWN)? " +U": ""); - if (mppe_opts & MPPE_OPT_UNKNOWN) - printer(arg, " (%.2x %.2x %.2x %.2x)", - p[2], p[3], p[4], p[5]); - p += CILEN_MPPE; - } - break; -#endif /* MPPE_SUPPORT */ -#if DEFLATE_SUPPORT - case CI_DEFLATE: - case CI_DEFLATE_DRAFT: - if (optlen >= CILEN_DEFLATE) { - printer(arg, "deflate%s %d", - (code == CI_DEFLATE_DRAFT? "(old#)": ""), - DEFLATE_SIZE(p[2])); - if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL) - printer(arg, " method %d", DEFLATE_METHOD(p[2])); - if (p[3] != DEFLATE_CHK_SEQUENCE) - printer(arg, " check %d", p[3]); - p += CILEN_DEFLATE; - } - break; -#endif /* DEFLATE_SUPPORT */ -#if BSDCOMPRESS_SUPPORT - case CI_BSD_COMPRESS: - if (optlen >= CILEN_BSD_COMPRESS) { - printer(arg, "bsd v%d %d", BSD_VERSION(p[2]), - BSD_NBITS(p[2])); - p += CILEN_BSD_COMPRESS; - } - break; -#endif /* BSDCOMPRESS_SUPPORT */ -#if PREDICTOR_SUPPORT - case CI_PREDICTOR_1: - if (optlen >= CILEN_PREDICTOR_1) { - printer(arg, "predictor 1"); - p += CILEN_PREDICTOR_1; - } - break; - case CI_PREDICTOR_2: - if (optlen >= CILEN_PREDICTOR_2) { - printer(arg, "predictor 2"); - p += CILEN_PREDICTOR_2; - } - break; -#endif /* PREDICTOR_SUPPORT */ - default: - break; - } - while (p < optend) - printer(arg, " %.2x", *p++); - printer(arg, ">"); - } - break; - - case TERMACK: - case TERMREQ: - if (len > 0 && *p >= ' ' && *p < 0x7f) { - ppp_print_string(p, len, printer, arg); - p += len; - len = 0; - } - break; - default: - break; - } - - /* dump out the rest of the packet in hex */ - while (--len >= 0) - printer(arg, " %.2x", *p++); - - return p - p0; -} -#endif /* PRINTPKT_SUPPORT */ - -#if PPP_DATAINPUT -/* - * We have received a packet that the decompressor failed to - * decompress. Here we would expect to issue a reset-request, but - * Motorola has a patent on resetting the compressor as a result of - * detecting an error in the decompressed data after decompression. - * (See US patent 5,130,993; international patent publication number - * WO 91/10289; Australian patent 73296/91.) - * - * So we ask the kernel whether the error was detected after - * decompression; if it was, we take CCP down, thus disabling - * compression :-(, otherwise we issue the reset-request. - */ -static void ccp_datainput(ppp_pcb *pcb, u_char *pkt, int len) { - fsm *f; -#if MPPE_SUPPORT - ccp_options *go = &pcb->ccp_gotoptions; -#endif /* MPPE_SUPPORT */ - LWIP_UNUSED_ARG(pkt); - LWIP_UNUSED_ARG(len); - - f = &pcb->ccp_fsm; - if (f->state == PPP_FSM_OPENED) { - if (ccp_fatal_error(pcb)) { - /* - * Disable compression by taking CCP down. - */ - ppp_error("Lost compression sync: disabling compression"); - ccp_close(pcb, "Lost compression sync"); -#if MPPE_SUPPORT - /* - * If we were doing MPPE, we must also take the link down. - */ - if (go->mppe) { - ppp_error("Too many MPPE errors, closing LCP"); - lcp_close(pcb, "Too many MPPE errors"); - } -#endif /* MPPE_SUPPORT */ - } else { - /* - * Send a reset-request to reset the peer's compressor. - * We don't do that if we are still waiting for an - * acknowledgement to a previous reset-request. - */ - if (!(pcb->ccp_localstate & RACK_PENDING)) { - fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0); - TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); - pcb->ccp_localstate |= RACK_PENDING; - } else - pcb->ccp_localstate |= RREQ_REPEAT; - } - } -} -#endif /* PPP_DATAINPUT */ - -/* - * We have received a packet that the decompressor failed to - * decompress. Issue a reset-request. - */ -void ccp_resetrequest(ppp_pcb *pcb) { - fsm *f = &pcb->ccp_fsm; - - if (f->state != PPP_FSM_OPENED) - return; - - /* - * Send a reset-request to reset the peer's compressor. - * We don't do that if we are still waiting for an - * acknowledgement to a previous reset-request. - */ - if (!(pcb->ccp_localstate & RACK_PENDING)) { - fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0); - TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); - pcb->ccp_localstate |= RACK_PENDING; - } else - pcb->ccp_localstate |= RREQ_REPEAT; -} - -/* - * Timeout waiting for reset-ack. - */ -static void ccp_rack_timeout(void *arg) { - fsm *f = (fsm*)arg; - ppp_pcb *pcb = f->pcb; - - if (f->state == PPP_FSM_OPENED && (pcb->ccp_localstate & RREQ_REPEAT)) { - fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0); - TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); - pcb->ccp_localstate &= ~RREQ_REPEAT; - } else - pcb->ccp_localstate &= ~RACK_PENDING; -} - -#endif /* PPP_SUPPORT && CCP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/chap-md5.c b/ext/lwip/src/netif/ppp/chap-md5.c deleted file mode 100644 index 88f069f..0000000 --- a/ext/lwip/src/netif/ppp/chap-md5.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * chap-md5.c - 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 */ - -#if 0 /* UNUSED */ -#include -#include -#endif /* UNUSED */ - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/chap-new.h" -#include "netif/ppp/chap-md5.h" -#include "netif/ppp/magic.h" -#include "netif/ppp/pppcrypt.h" - -#define MD5_HASH_SIZE 16 -#define MD5_MIN_CHALLENGE 17 -#define MD5_MAX_CHALLENGE 24 -#define MD5_MIN_MAX_POWER_OF_TWO_CHALLENGE 3 /* 2^3-1 = 7, 17+7 = 24 */ - -#if PPP_SERVER -static void chap_md5_generate_challenge(ppp_pcb *pcb, unsigned char *cp) { - int clen; - LWIP_UNUSED_ARG(pcb); - - clen = MD5_MIN_CHALLENGE + magic_pow(MD5_MIN_MAX_POWER_OF_TWO_CHALLENGE); - *cp++ = clen; - magic_random_bytes(cp, clen); -} - -static int chap_md5_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) { - lwip_md5_context ctx; - unsigned char idbyte = id; - unsigned char hash[MD5_HASH_SIZE]; - int challenge_len, response_len; - LWIP_UNUSED_ARG(name); - LWIP_UNUSED_ARG(pcb); - - challenge_len = *challenge++; - response_len = *response++; - if (response_len == MD5_HASH_SIZE) { - /* Generate hash of ID, secret, challenge */ - lwip_md5_init(&ctx); - lwip_md5_starts(&ctx); - lwip_md5_update(&ctx, &idbyte, 1); - lwip_md5_update(&ctx, secret, secret_len); - lwip_md5_update(&ctx, challenge, challenge_len); - lwip_md5_finish(&ctx, hash); - lwip_md5_free(&ctx); - - /* Test if our hash matches the peer's response */ - if (memcmp(hash, response, MD5_HASH_SIZE) == 0) { - ppp_slprintf(message, message_space, "Access granted"); - return 1; - } - } - ppp_slprintf(message, message_space, "Access denied"); - return 0; -} -#endif /* PPP_SERVER */ - -static void chap_md5_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 *private_) { - lwip_md5_context ctx; - unsigned char idbyte = id; - int challenge_len = *challenge++; - LWIP_UNUSED_ARG(our_name); - LWIP_UNUSED_ARG(private_); - LWIP_UNUSED_ARG(pcb); - - lwip_md5_init(&ctx); - lwip_md5_starts(&ctx); - lwip_md5_update(&ctx, &idbyte, 1); - lwip_md5_update(&ctx, (const u_char *)secret, secret_len); - lwip_md5_update(&ctx, challenge, challenge_len); - lwip_md5_finish(&ctx, &response[1]); - lwip_md5_free(&ctx); - response[0] = MD5_HASH_SIZE; -} - -const struct chap_digest_type md5_digest = { - CHAP_MD5, /* code */ -#if PPP_SERVER - chap_md5_generate_challenge, - chap_md5_verify_response, -#endif /* PPP_SERVER */ - chap_md5_make_response, - NULL, /* check_success */ - NULL, /* handle_failure */ -}; - -#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/chap-new.c b/ext/lwip/src/netif/ppp/chap-new.c deleted file mode 100644 index 485122d..0000000 --- a/ext/lwip/src/netif/ppp/chap-new.c +++ /dev/null @@ -1,677 +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 */ - -#if 0 /* UNUSED */ -#include -#include -#endif /* UNUSED */ - -#include "netif/ppp/ppp_impl.h" - -#if 0 /* UNUSED */ -#include "session.h" -#endif /* UNUSED */ - -#include "netif/ppp/chap-new.h" -#include "netif/ppp/chap-md5.h" -#if MSCHAP_SUPPORT -#include "netif/ppp/chap_ms.h" -#endif -#include "netif/ppp/magic.h" - -#if 0 /* UNUSED */ -/* Hook for a plugin to validate CHAP challenge */ -int (*chap_verify_hook)(const char *name, const char *ourname, int id, - const struct chap_digest_type *digest, - const unsigned char *challenge, const unsigned char *response, - char *message, int message_space) = NULL; -#endif /* UNUSED */ - -#if PPP_OPTIONS -/* - * Command-line options. - */ -static option_t chap_option_list[] = { - { "chap-restart", o_int, &chap_timeout_time, - "Set timeout for CHAP", OPT_PRIO }, - { "chap-max-challenge", o_int, &pcb->settings.chap_max_transmits, - "Set max #xmits for challenge", OPT_PRIO }, - { "chap-interval", o_int, &pcb->settings.chap_rechallenge_time, - "Set interval for rechallenge", OPT_PRIO }, - { NULL } -}; -#endif /* PPP_OPTIONS */ - - -/* Values for flags in chap_client_state and chap_server_state */ -#define LOWERUP 1 -#define AUTH_STARTED 2 -#define AUTH_DONE 4 -#define AUTH_FAILED 8 -#define TIMEOUT_PENDING 0x10 -#define CHALLENGE_VALID 0x20 - -/* - * Prototypes. - */ -static void chap_init(ppp_pcb *pcb); -static void chap_lowerup(ppp_pcb *pcb); -static void chap_lowerdown(ppp_pcb *pcb); -#if PPP_SERVER -static void chap_timeout(void *arg); -static void chap_generate_challenge(ppp_pcb *pcb); -static void chap_handle_response(ppp_pcb *pcb, int code, - unsigned char *pkt, int len); -static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id, - const struct chap_digest_type *digest, - const unsigned char *challenge, const unsigned char *response, - char *message, int message_space); -#endif /* PPP_SERVER */ -static void chap_respond(ppp_pcb *pcb, int id, - unsigned char *pkt, int len); -static void chap_handle_status(ppp_pcb *pcb, int code, int id, - unsigned char *pkt, int len); -static void chap_protrej(ppp_pcb *pcb); -static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen); -#if PRINTPKT_SUPPORT -static int chap_print_pkt(const unsigned char *p, int plen, - void (*printer) (void *, const char *, ...), void *arg); -#endif /* PRINTPKT_SUPPORT */ - -/* List of digest types that we know about */ -static const struct chap_digest_type* const chap_digests[] = { - &md5_digest, -#if MSCHAP_SUPPORT - &chapms_digest, - &chapms2_digest, -#endif /* MSCHAP_SUPPORT */ - NULL -}; - -/* - * chap_init - reset to initial state. - */ -static void chap_init(ppp_pcb *pcb) { - LWIP_UNUSED_ARG(pcb); - -#if 0 /* Not necessary, everything is cleared in ppp_new() */ - memset(&pcb->chap_client, 0, sizeof(chap_client_state)); -#if PPP_SERVER - memset(&pcb->chap_server, 0, sizeof(chap_server_state)); -#endif /* PPP_SERVER */ -#endif /* 0 */ -} - -/* - * chap_lowerup - we can start doing stuff now. - */ -static void chap_lowerup(ppp_pcb *pcb) { - - pcb->chap_client.flags |= LOWERUP; -#if PPP_SERVER - pcb->chap_server.flags |= LOWERUP; - if (pcb->chap_server.flags & AUTH_STARTED) - chap_timeout(pcb); -#endif /* PPP_SERVER */ -} - -static void chap_lowerdown(ppp_pcb *pcb) { - - pcb->chap_client.flags = 0; -#if PPP_SERVER - if (pcb->chap_server.flags & TIMEOUT_PENDING) - UNTIMEOUT(chap_timeout, pcb); - pcb->chap_server.flags = 0; -#endif /* PPP_SERVER */ -} - -#if PPP_SERVER -/* - * chap_auth_peer - Start authenticating the peer. - * If the lower layer is already up, we start sending challenges, - * otherwise we wait for the lower layer to come up. - */ -void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { - const struct chap_digest_type *dp; - int i; - - if (pcb->chap_server.flags & AUTH_STARTED) { - ppp_error("CHAP: peer authentication already started!"); - return; - } - for (i = 0; (dp = chap_digests[i]) != NULL; ++i) - if (dp->code == digest_code) - break; - if (dp == NULL) - ppp_fatal("CHAP digest 0x%x requested but not available", - digest_code); - - pcb->chap_server.digest = dp; - pcb->chap_server.name = our_name; - /* Start with a random ID value */ - pcb->chap_server.id = magic(); - pcb->chap_server.flags |= AUTH_STARTED; - if (pcb->chap_server.flags & LOWERUP) - chap_timeout(pcb); -} -#endif /* PPP_SERVER */ - -/* - * chap_auth_with_peer - Prepare to authenticate ourselves to the peer. - * There isn't much to do until we receive a challenge. - */ -void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { - const struct chap_digest_type *dp; - int i; - - if(NULL == our_name) - return; - - if (pcb->chap_client.flags & AUTH_STARTED) { - ppp_error("CHAP: authentication with peer already started!"); - return; - } - for (i = 0; (dp = chap_digests[i]) != NULL; ++i) - if (dp->code == digest_code) - break; - - if (dp == NULL) - ppp_fatal("CHAP digest 0x%x requested but not available", - digest_code); - - pcb->chap_client.digest = dp; - pcb->chap_client.name = our_name; - pcb->chap_client.flags |= AUTH_STARTED; -} - -#if PPP_SERVER -/* - * chap_timeout - It's time to send another challenge to the peer. - * This could be either a retransmission of a previous challenge, - * or a new challenge to start re-authentication. - */ -static void chap_timeout(void *arg) { - ppp_pcb *pcb = (ppp_pcb*)arg; - struct pbuf *p; - - pcb->chap_server.flags &= ~TIMEOUT_PENDING; - if ((pcb->chap_server.flags & CHALLENGE_VALID) == 0) { - pcb->chap_server.challenge_xmits = 0; - chap_generate_challenge(pcb); - pcb->chap_server.flags |= CHALLENGE_VALID; - } else if (pcb->chap_server.challenge_xmits >= pcb->settings.chap_max_transmits) { - pcb->chap_server.flags &= ~CHALLENGE_VALID; - pcb->chap_server.flags |= AUTH_DONE | AUTH_FAILED; - auth_peer_fail(pcb, PPP_CHAP); - return; - } - - p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - MEMCPY(p->payload, pcb->chap_server.challenge, pcb->chap_server.challenge_pktlen); - ppp_write(pcb, p); - ++pcb->chap_server.challenge_xmits; - pcb->chap_server.flags |= TIMEOUT_PENDING; - TIMEOUT(chap_timeout, arg, pcb->settings.chap_timeout_time); -} - -/* - * chap_generate_challenge - generate a challenge string and format - * the challenge packet in pcb->chap_server.challenge_pkt. - */ -static void chap_generate_challenge(ppp_pcb *pcb) { - int clen = 1, nlen, len; - unsigned char *p; - - p = pcb->chap_server.challenge; - MAKEHEADER(p, PPP_CHAP); - p += CHAP_HDRLEN; - pcb->chap_server.digest->generate_challenge(pcb, p); - clen = *p; - nlen = strlen(pcb->chap_server.name); - memcpy(p + 1 + clen, pcb->chap_server.name, nlen); - - len = CHAP_HDRLEN + 1 + clen + nlen; - pcb->chap_server.challenge_pktlen = PPP_HDRLEN + len; - - p = pcb->chap_server.challenge + PPP_HDRLEN; - p[0] = CHAP_CHALLENGE; - p[1] = ++pcb->chap_server.id; - p[2] = len >> 8; - p[3] = len; -} - -/* - * chap_handle_response - check the response to our challenge. - */ -static void chap_handle_response(ppp_pcb *pcb, int id, - unsigned char *pkt, int len) { - int response_len, ok, mlen; - const unsigned char *response; - unsigned char *outp; - struct pbuf *p; - const char *name = NULL; /* initialized to shut gcc up */ -#if 0 /* UNUSED */ - int (*verifier)(const char *, const char *, int, const struct chap_digest_type *, - const unsigned char *, const unsigned char *, char *, int); -#endif /* UNUSED */ - char rname[MAXNAMELEN+1]; - char message[256]; - - if ((pcb->chap_server.flags & LOWERUP) == 0) - return; - if (id != pcb->chap_server.challenge[PPP_HDRLEN+1] || len < 2) - return; - if (pcb->chap_server.flags & CHALLENGE_VALID) { - response = pkt; - GETCHAR(response_len, pkt); - len -= response_len + 1; /* length of name */ - name = (char *)pkt + response_len; - if (len < 0) - return; - - if (pcb->chap_server.flags & TIMEOUT_PENDING) { - pcb->chap_server.flags &= ~TIMEOUT_PENDING; - UNTIMEOUT(chap_timeout, pcb); - } -#if PPP_REMOTENAME - if (pcb->settings.explicit_remote) { - name = pcb->remote_name; - } else -#endif /* PPP_REMOTENAME */ - { - /* Null terminate and clean remote name. */ - ppp_slprintf(rname, sizeof(rname), "%.*v", len, name); - name = rname; - } - -#if 0 /* UNUSED */ - if (chap_verify_hook) - verifier = chap_verify_hook; - else - verifier = chap_verify_response; - ok = (*verifier)(name, pcb->chap_server.name, id, pcb->chap_server.digest, - pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN, - response, pcb->chap_server.message, sizeof(pcb->chap_server.message)); -#endif /* UNUSED */ - ok = chap_verify_response(pcb, name, pcb->chap_server.name, id, pcb->chap_server.digest, - pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN, - response, message, sizeof(message)); -#if 0 /* UNUSED */ - if (!ok || !auth_number()) { -#endif /* UNUSED */ - if (!ok) { - pcb->chap_server.flags |= AUTH_FAILED; - ppp_warn("Peer %q failed CHAP authentication", name); - } - } else if ((pcb->chap_server.flags & AUTH_DONE) == 0) - return; - - /* send the response */ - mlen = strlen(message); - len = CHAP_HDRLEN + mlen; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = (unsigned char *)p->payload; - MAKEHEADER(outp, PPP_CHAP); - - outp[0] = (pcb->chap_server.flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS; - outp[1] = id; - outp[2] = len >> 8; - outp[3] = len; - if (mlen > 0) - memcpy(outp + CHAP_HDRLEN, message, mlen); - ppp_write(pcb, p); - - if (pcb->chap_server.flags & CHALLENGE_VALID) { - pcb->chap_server.flags &= ~CHALLENGE_VALID; - if (!(pcb->chap_server.flags & AUTH_DONE) && !(pcb->chap_server.flags & AUTH_FAILED)) { - -#if 0 /* UNUSED */ - /* - * Auth is OK, so now we need to check session restrictions - * to ensure everything is OK, but only if we used a - * plugin, and only if we're configured to check. This - * allows us to do PAM checks on PPP servers that - * authenticate against ActiveDirectory, and use AD for - * account info (like when using Winbind integrated with - * PAM). - */ - if (session_mgmt && - session_check(name, NULL, devnam, NULL) == 0) { - pcb->chap_server.flags |= AUTH_FAILED; - ppp_warn("Peer %q failed CHAP Session verification", name); - } -#endif /* UNUSED */ - - } - if (pcb->chap_server.flags & AUTH_FAILED) { - auth_peer_fail(pcb, PPP_CHAP); - } else { - if ((pcb->chap_server.flags & AUTH_DONE) == 0) - auth_peer_success(pcb, PPP_CHAP, - pcb->chap_server.digest->code, - name, strlen(name)); - if (pcb->settings.chap_rechallenge_time) { - pcb->chap_server.flags |= TIMEOUT_PENDING; - TIMEOUT(chap_timeout, pcb, - pcb->settings.chap_rechallenge_time); - } - } - pcb->chap_server.flags |= AUTH_DONE; - } -} - -/* - * chap_verify_response - check whether the peer's response matches - * what we think it should be. Returns 1 if it does (authentication - * succeeded), or 0 if it doesn't. - */ -static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id, - const struct chap_digest_type *digest, - const unsigned char *challenge, const unsigned char *response, - char *message, int message_space) { - int ok; - unsigned char secret[MAXSECRETLEN]; - int secret_len; - - /* Get the secret that the peer is supposed to know */ - if (!get_secret(pcb, name, ourname, (char *)secret, &secret_len, 1)) { - ppp_error("No CHAP secret found for authenticating %q", name); - return 0; - } - ok = digest->verify_response(pcb, id, name, secret, secret_len, challenge, - response, message, message_space); - memset(secret, 0, sizeof(secret)); - - return ok; -} -#endif /* PPP_SERVER */ - -/* - * chap_respond - Generate and send a response to a challenge. - */ -static void chap_respond(ppp_pcb *pcb, int id, - unsigned char *pkt, int len) { - int clen, nlen; - int secret_len; - struct pbuf *p; - u_char *outp; - char rname[MAXNAMELEN+1]; - char secret[MAXSECRETLEN+1]; - - p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - if ((pcb->chap_client.flags & (LOWERUP | AUTH_STARTED)) != (LOWERUP | AUTH_STARTED)) - return; /* not ready */ - if (len < 2 || len < pkt[0] + 1) - return; /* too short */ - clen = pkt[0]; - nlen = len - (clen + 1); - - /* Null terminate and clean remote name. */ - ppp_slprintf(rname, sizeof(rname), "%.*v", nlen, pkt + clen + 1); - -#if PPP_REMOTENAME - /* Microsoft doesn't send their name back in the PPP packet */ - if (pcb->settings.explicit_remote || (pcb->settings.remote_name[0] != 0 && rname[0] == 0)) - strlcpy(rname, pcb->settings.remote_name, sizeof(rname)); -#endif /* PPP_REMOTENAME */ - - /* get secret for authenticating ourselves with the specified host */ - if (!get_secret(pcb, pcb->chap_client.name, rname, secret, &secret_len, 0)) { - secret_len = 0; /* assume null secret if can't find one */ - ppp_warn("No CHAP secret found for authenticating us to %q", rname); - } - - outp = (u_char*)p->payload; - MAKEHEADER(outp, PPP_CHAP); - outp += CHAP_HDRLEN; - - pcb->chap_client.digest->make_response(pcb, outp, id, pcb->chap_client.name, pkt, - secret, secret_len, pcb->chap_client.priv); - memset(secret, 0, secret_len); - - clen = *outp; - nlen = strlen(pcb->chap_client.name); - memcpy(outp + clen + 1, pcb->chap_client.name, nlen); - - outp = (u_char*)p->payload + PPP_HDRLEN; - len = CHAP_HDRLEN + clen + 1 + nlen; - outp[0] = CHAP_RESPONSE; - outp[1] = id; - outp[2] = len >> 8; - outp[3] = len; - - pbuf_realloc(p, PPP_HDRLEN + len); - ppp_write(pcb, p); -} - -static void chap_handle_status(ppp_pcb *pcb, int code, int id, - unsigned char *pkt, int len) { - const char *msg = NULL; - LWIP_UNUSED_ARG(id); - - if ((pcb->chap_client.flags & (AUTH_DONE|AUTH_STARTED|LOWERUP)) - != (AUTH_STARTED|LOWERUP)) - return; - pcb->chap_client.flags |= AUTH_DONE; - - if (code == CHAP_SUCCESS) { - /* used for MS-CHAP v2 mutual auth, yuck */ - if (pcb->chap_client.digest->check_success != NULL) { - if (!(*pcb->chap_client.digest->check_success)(pcb, pkt, len, pcb->chap_client.priv)) - code = CHAP_FAILURE; - } else - msg = "CHAP authentication succeeded"; - } else { - if (pcb->chap_client.digest->handle_failure != NULL) - (*pcb->chap_client.digest->handle_failure)(pcb, pkt, len); - else - msg = "CHAP authentication failed"; - } - if (msg) { - if (len > 0) - ppp_info("%s: %.*v", msg, len, pkt); - else - ppp_info("%s", msg); - } - if (code == CHAP_SUCCESS) - auth_withpeer_success(pcb, PPP_CHAP, pcb->chap_client.digest->code); - else { - pcb->chap_client.flags |= AUTH_FAILED; - ppp_error("CHAP authentication failed"); - auth_withpeer_fail(pcb, PPP_CHAP); - } -} - -static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen) { - unsigned char code, id; - int len; - - if (pktlen < CHAP_HDRLEN) - return; - GETCHAR(code, pkt); - GETCHAR(id, pkt); - GETSHORT(len, pkt); - if (len < CHAP_HDRLEN || len > pktlen) - return; - len -= CHAP_HDRLEN; - - switch (code) { - case CHAP_CHALLENGE: - chap_respond(pcb, id, pkt, len); - break; -#if PPP_SERVER - case CHAP_RESPONSE: - chap_handle_response(pcb, id, pkt, len); - break; -#endif /* PPP_SERVER */ - case CHAP_FAILURE: - case CHAP_SUCCESS: - chap_handle_status(pcb, code, id, pkt, len); - break; - default: - break; - } -} - -static void chap_protrej(ppp_pcb *pcb) { - -#if PPP_SERVER - if (pcb->chap_server.flags & TIMEOUT_PENDING) { - pcb->chap_server.flags &= ~TIMEOUT_PENDING; - UNTIMEOUT(chap_timeout, pcb); - } - if (pcb->chap_server.flags & AUTH_STARTED) { - pcb->chap_server.flags = 0; - auth_peer_fail(pcb, PPP_CHAP); - } -#endif /* PPP_SERVER */ - if ((pcb->chap_client.flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) { - pcb->chap_client.flags &= ~AUTH_STARTED; - ppp_error("CHAP authentication failed due to protocol-reject"); - auth_withpeer_fail(pcb, PPP_CHAP); - } -} - -#if PRINTPKT_SUPPORT -/* - * chap_print_pkt - print the contents of a CHAP packet. - */ -static const char* const chap_code_names[] = { - "Challenge", "Response", "Success", "Failure" -}; - -static int chap_print_pkt(const unsigned char *p, int plen, - void (*printer) (void *, const char *, ...), void *arg) { - int code, id, len; - int clen, nlen; - unsigned char x; - - if (plen < CHAP_HDRLEN) - return 0; - GETCHAR(code, p); - GETCHAR(id, p); - GETSHORT(len, p); - if (len < CHAP_HDRLEN || len > plen) - return 0; - - if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(chap_code_names)) - printer(arg, " %s", chap_code_names[code-1]); - else - printer(arg, " code=0x%x", code); - printer(arg, " id=0x%x", id); - len -= CHAP_HDRLEN; - switch (code) { - case CHAP_CHALLENGE: - case CHAP_RESPONSE: - if (len < 1) - break; - clen = p[0]; - if (len < clen + 1) - break; - ++p; - nlen = len - clen - 1; - printer(arg, " <"); - for (; clen > 0; --clen) { - GETCHAR(x, p); - printer(arg, "%.2x", x); - } - printer(arg, ">, name = "); - ppp_print_string(p, nlen, printer, arg); - break; - case CHAP_FAILURE: - case CHAP_SUCCESS: - printer(arg, " "); - ppp_print_string(p, len, printer, arg); - break; - default: - for (clen = len; clen > 0; --clen) { - GETCHAR(x, p); - printer(arg, " %.2x", x); - } - /* no break */ - } - - return len + CHAP_HDRLEN; -} -#endif /* PRINTPKT_SUPPORT */ - -const struct protent chap_protent = { - PPP_CHAP, - chap_init, - chap_input, - chap_protrej, - chap_lowerup, - chap_lowerdown, - NULL, /* open */ - NULL, /* close */ -#if PRINTPKT_SUPPORT - chap_print_pkt, -#endif /* PRINTPKT_SUPPORT */ -#if PPP_DATAINPUT - NULL, /* datainput */ -#endif /* PPP_DATAINPUT */ -#if PRINTPKT_SUPPORT - "CHAP", /* name */ - NULL, /* data_name */ -#endif /* PRINTPKT_SUPPORT */ -#if PPP_OPTIONS - chap_option_list, - NULL, /* check_options */ -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT - NULL, - NULL -#endif /* DEMAND_SUPPORT */ -}; - -#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/chap_ms.c b/ext/lwip/src/netif/ppp/chap_ms.c deleted file mode 100644 index 5a989c9..0000000 --- a/ext/lwip/src/netif/ppp/chap_ms.c +++ /dev/null @@ -1,962 +0,0 @@ -/* - * chap_ms.c - Microsoft MS-CHAP compatible implementation. - * - * 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. - */ - -/* - * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997 - * - * Implemented LANManager type password response to MS-CHAP challenges. - * Now pppd provides both NT style and LANMan style blocks, and the - * prefered is set by option "ms-lanman". Default is to use NT. - * The hash text (StdText) was taken from Win95 RASAPI32.DLL. - * - * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 - */ - -/* - * Modifications by Frank Cusack, frank@google.com, March 2002. - * - * Implemented MS-CHAPv2 functionality, heavily based on sample - * implementation in RFC 2759. Implemented MPPE functionality, - * heavily based on sample implementation in RFC 3079. - * - * 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. - * - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#if 0 /* UNUSED */ -#include -#include -#include -#include -#include -#include -#include -#endif /* UNUSED */ - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/chap-new.h" -#include "netif/ppp/chap_ms.h" -#include "netif/ppp/pppcrypt.h" -#include "netif/ppp/magic.h" -#if MPPE_SUPPORT -#include "netif/ppp/mppe.h" /* For mppe_sha1_pad*, mppe_set_key() */ -#endif /* MPPE_SUPPORT */ - -#define SHA1_SIGNATURE_SIZE 20 -#define MD4_SIGNATURE_SIZE 16 /* 16 bytes in a MD4 message digest */ -#define MAX_NT_PASSWORD 256 /* Max (Unicode) chars in an NT pass */ - -#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */ -#define MS_CHAP2_RESPONSE_LEN 49 /* Response length for MS-CHAPv2 */ -#define MS_AUTH_RESPONSE_LENGTH 40 /* MS-CHAPv2 authenticator response, */ - /* as ASCII */ - -/* Error codes for MS-CHAP failure messages. */ -#define MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS 646 -#define MS_CHAP_ERROR_ACCT_DISABLED 647 -#define MS_CHAP_ERROR_PASSWD_EXPIRED 648 -#define MS_CHAP_ERROR_NO_DIALIN_PERMISSION 649 -#define MS_CHAP_ERROR_AUTHENTICATION_FAILURE 691 -#define MS_CHAP_ERROR_CHANGING_PASSWORD 709 - -/* - * Offsets within the response field for MS-CHAP - */ -#define MS_CHAP_LANMANRESP 0 -#define MS_CHAP_LANMANRESP_LEN 24 -#define MS_CHAP_NTRESP 24 -#define MS_CHAP_NTRESP_LEN 24 -#define MS_CHAP_USENT 48 - -/* - * Offsets within the response field for MS-CHAP2 - */ -#define MS_CHAP2_PEER_CHALLENGE 0 -#define MS_CHAP2_PEER_CHAL_LEN 16 -#define MS_CHAP2_RESERVED_LEN 8 -#define MS_CHAP2_NTRESP 24 -#define MS_CHAP2_NTRESP_LEN 24 -#define MS_CHAP2_FLAGS 48 - -#if MPPE_SUPPORT -#if 0 /* UNUSED */ -/* These values are the RADIUS attribute values--see RFC 2548. */ -#define MPPE_ENC_POL_ENC_ALLOWED 1 -#define MPPE_ENC_POL_ENC_REQUIRED 2 -#define MPPE_ENC_TYPES_RC4_40 2 -#define MPPE_ENC_TYPES_RC4_128 4 - -/* used by plugins (using above values) */ -extern void set_mppe_enc_types(int, int); -#endif /* UNUSED */ -#endif /* MPPE_SUPPORT */ - -/* Are we the authenticator or authenticatee? For MS-CHAPv2 key derivation. */ -#define MS_CHAP2_AUTHENTICATEE 0 -#define MS_CHAP2_AUTHENTICATOR 1 - -static void ascii2unicode (const char[], int, u_char[]); -static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]); -static void ChallengeResponse (const u_char *, const u_char *, u_char[24]); -static void ChallengeHash (const u_char[16], const u_char *, const char *, u_char[8]); -static void ChapMS_NT (const u_char *, const char *, int, u_char[24]); -static void ChapMS2_NT (const u_char *, const u_char[16], const char *, const char *, int, - u_char[24]); -static void GenerateAuthenticatorResponsePlain - (const char*, int, u_char[24], const u_char[16], const u_char *, - const char *, u_char[41]); -#ifdef MSLANMAN -static void ChapMS_LANMan (u_char *, char *, int, u_char *); -#endif - -static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE], - u_char NTResponse[24], const u_char PeerChallenge[16], - const u_char *rchallenge, const char *username, - u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]); - -#if MPPE_SUPPORT -static void Set_Start_Key (ppp_pcb *pcb, const u_char *, const char *, int); -static void SetMasterKeys (ppp_pcb *pcb, const char *, int, u_char[24], int); -#endif /* MPPE_SUPPORT */ - -static void ChapMS (ppp_pcb *pcb, const u_char *, const char *, int, u_char *); -static void ChapMS2 (ppp_pcb *pcb, const u_char *, const u_char *, const char *, const char *, int, - u_char *, u_char[MS_AUTH_RESPONSE_LENGTH+1], int); - -#ifdef MSLANMAN -bool ms_lanman = 0; /* Use LanMan password instead of NT */ - /* Has meaning only with MS-CHAP challenges */ -#endif - -#if MPPE_SUPPORT -#ifdef DEBUGMPPEKEY -/* For MPPE debug */ -/* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */ -static char *mschap_challenge = NULL; -/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */ -static char *mschap2_peer_challenge = NULL; -#endif - -#include "netif/ppp/fsm.h" /* Need to poke MPPE options */ -#include "netif/ppp/ccp.h" -#endif /* MPPE_SUPPORT */ - -#if PPP_OPTIONS -/* - * Command-line options. - */ -static option_t chapms_option_list[] = { -#ifdef MSLANMAN - { "ms-lanman", o_bool, &ms_lanman, - "Use LanMan passwd when using MS-CHAP", 1 }, -#endif -#ifdef DEBUGMPPEKEY - { "mschap-challenge", o_string, &mschap_challenge, - "specify CHAP challenge" }, - { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge, - "specify CHAP peer challenge" }, -#endif - { NULL } -}; -#endif /* PPP_OPTIONS */ - -#if PPP_SERVER -/* - * chapms_generate_challenge - generate a challenge for MS-CHAP. - * For MS-CHAP the challenge length is fixed at 8 bytes. - * The length goes in challenge[0] and the actual challenge starts - * at challenge[1]. - */ -static void chapms_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) { - LWIP_UNUSED_ARG(pcb); - - *challenge++ = 8; -#ifdef DEBUGMPPEKEY - if (mschap_challenge && strlen(mschap_challenge) == 8) - memcpy(challenge, mschap_challenge, 8); - else -#endif - magic_random_bytes(challenge, 8); -} - -static void chapms2_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) { - LWIP_UNUSED_ARG(pcb); - - *challenge++ = 16; -#ifdef DEBUGMPPEKEY - if (mschap_challenge && strlen(mschap_challenge) == 16) - memcpy(challenge, mschap_challenge, 16); - else -#endif - magic_random_bytes(challenge, 16); -} - -static int chapms_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) { - unsigned char md[MS_CHAP_RESPONSE_LEN]; - int diff; - int challenge_len, response_len; - LWIP_UNUSED_ARG(id); - LWIP_UNUSED_ARG(name); - - challenge_len = *challenge++; /* skip length, is 8 */ - response_len = *response++; - if (response_len != MS_CHAP_RESPONSE_LEN) - goto bad; - -#ifndef MSLANMAN - if (!response[MS_CHAP_USENT]) { - /* Should really propagate this into the error packet. */ - ppp_notice("Peer request for LANMAN auth not supported"); - goto bad; - } -#endif - - /* Generate the expected response. */ - ChapMS(pcb, (const u_char *)challenge, (const char *)secret, secret_len, md); - -#ifdef MSLANMAN - /* Determine which part of response to verify against */ - if (!response[MS_CHAP_USENT]) - diff = memcmp(&response[MS_CHAP_LANMANRESP], - &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN); - else -#endif - diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP], - MS_CHAP_NTRESP_LEN); - - if (diff == 0) { - ppp_slprintf(message, message_space, "Access granted"); - return 1; - } - - bad: - /* See comments below for MS-CHAP V2 */ - ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0", - challenge_len, challenge); - return 0; -} - -static int chapms2_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) { - unsigned char md[MS_CHAP2_RESPONSE_LEN]; - char saresponse[MS_AUTH_RESPONSE_LENGTH+1]; - int challenge_len, response_len; - LWIP_UNUSED_ARG(id); - - challenge_len = *challenge++; /* skip length, is 16 */ - response_len = *response++; - if (response_len != MS_CHAP2_RESPONSE_LEN) - goto bad; /* not even the right length */ - - /* Generate the expected response and our mutual auth. */ - ChapMS2(pcb, (const u_char*)challenge, (const u_char*)&response[MS_CHAP2_PEER_CHALLENGE], name, - (const char *)secret, secret_len, md, - (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR); - - /* compare MDs and send the appropriate status */ - /* - * Per RFC 2759, success message must be formatted as - * "S= M=" - * where - * is the Authenticator Response (mutual auth) - * is a text message - * - * However, some versions of Windows (win98 tested) do not know - * about the M= part (required per RFC 2759) and flag - * it as an error (reported incorrectly as an encryption error - * to the user). Since the RFC requires it, and it can be - * useful information, we supply it if the peer is a conforming - * system. Luckily (?), win98 sets the Flags field to 0x04 - * (contrary to RFC requirements) so we can use that to - * distinguish between conforming and non-conforming systems. - * - * Special thanks to Alex Swiridov for - * help debugging this. - */ - if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP], - MS_CHAP2_NTRESP_LEN) == 0) { - if (response[MS_CHAP2_FLAGS]) - ppp_slprintf(message, message_space, "S=%s", saresponse); - else - ppp_slprintf(message, message_space, "S=%s M=%s", - saresponse, "Access granted"); - return 1; - } - - bad: - /* - * Failure message must be formatted as - * "E=e R=r C=c V=v M=m" - * where - * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE) - * r = retry (we use 1, ok to retry) - * c = challenge to use for next response, we reuse previous - * v = Change Password version supported, we use 0 - * m = text message - * - * The M=m part is only for MS-CHAPv2. Neither win2k nor - * win98 (others untested) display the message to the user anyway. - * They also both ignore the E=e code. - * - * Note that it's safe to reuse the same challenge as we don't - * actually accept another response based on the error message - * (and no clients try to resend a response anyway). - * - * Basically, this whole bit is useless code, even the small - * implementation here is only because of overspecification. - */ - ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s", - challenge_len, challenge, "Access denied"); - return 0; -} -#endif /* PPP_SERVER */ - -static void chapms_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 *private_) { - LWIP_UNUSED_ARG(id); - LWIP_UNUSED_ARG(our_name); - LWIP_UNUSED_ARG(private_); - challenge++; /* skip length, should be 8 */ - *response++ = MS_CHAP_RESPONSE_LEN; - ChapMS(pcb, challenge, secret, secret_len, response); -} - -static void chapms2_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 *private_) { - LWIP_UNUSED_ARG(id); - challenge++; /* skip length, should be 16 */ - *response++ = MS_CHAP2_RESPONSE_LEN; - ChapMS2(pcb, challenge, -#ifdef DEBUGMPPEKEY - mschap2_peer_challenge, -#else - NULL, -#endif - our_name, secret, secret_len, response, private_, - MS_CHAP2_AUTHENTICATEE); -} - -static int chapms2_check_success(ppp_pcb *pcb, unsigned char *msg, int len, unsigned char *private_) { - LWIP_UNUSED_ARG(pcb); - - if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || - strncmp((char *)msg, "S=", 2) != 0) { - /* Packet does not start with "S=" */ - ppp_error("MS-CHAPv2 Success packet is badly formed."); - return 0; - } - msg += 2; - len -= 2; - if (len < MS_AUTH_RESPONSE_LENGTH - || memcmp(msg, private_, MS_AUTH_RESPONSE_LENGTH)) { - /* Authenticator Response did not match expected. */ - ppp_error("MS-CHAPv2 mutual authentication failed."); - return 0; - } - /* Authenticator Response matches. */ - msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */ - len -= MS_AUTH_RESPONSE_LENGTH; - if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) { - msg += 3; /* Eat the delimiter */ - } else if (len) { - /* Packet has extra text which does not begin " M=" */ - ppp_error("MS-CHAPv2 Success packet is badly formed."); - return 0; - } - return 1; -} - -static void chapms_handle_failure(ppp_pcb *pcb, unsigned char *inp, int len) { - int err; - const char *p; - char msg[64]; - LWIP_UNUSED_ARG(pcb); - - /* We want a null-terminated string for strxxx(). */ - len = LWIP_MIN(len, 63); - MEMCPY(msg, inp, len); - msg[len] = 0; - p = msg; - - /* - * Deal with MS-CHAP formatted failure messages; just print the - * M= part (if any). For MS-CHAP we're not really supposed - * to use M=, but it shouldn't hurt. See - * chapms[2]_verify_response. - */ - if (!strncmp(p, "E=", 2)) - err = strtol(p+2, NULL, 10); /* Remember the error code. */ - else - goto print_msg; /* Message is badly formatted. */ - - if (len && ((p = strstr(p, " M=")) != NULL)) { - /* M= field found. */ - p += 3; - } else { - /* No M=; use the error code. */ - switch (err) { - case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS: - p = "E=646 Restricted logon hours"; - break; - - case MS_CHAP_ERROR_ACCT_DISABLED: - p = "E=647 Account disabled"; - break; - - case MS_CHAP_ERROR_PASSWD_EXPIRED: - p = "E=648 Password expired"; - break; - - case MS_CHAP_ERROR_NO_DIALIN_PERMISSION: - p = "E=649 No dialin permission"; - break; - - case MS_CHAP_ERROR_AUTHENTICATION_FAILURE: - p = "E=691 Authentication failure"; - break; - - case MS_CHAP_ERROR_CHANGING_PASSWORD: - /* Should never see this, we don't support Change Password. */ - p = "E=709 Error changing password"; - break; - - default: - ppp_error("Unknown MS-CHAP authentication failure: %.*v", - len, inp); - return; - } - } -print_msg: - if (p != NULL) - ppp_error("MS-CHAP authentication failed: %v", p); -} - -static void ChallengeResponse(const u_char *challenge, - const u_char PasswordHash[MD4_SIGNATURE_SIZE], - u_char response[24]) { - u_char ZPasswordHash[21]; - lwip_des_context des; - u_char des_key[8]; - - BZERO(ZPasswordHash, sizeof(ZPasswordHash)); - MEMCPY(ZPasswordHash, PasswordHash, MD4_SIGNATURE_SIZE); - -#if 0 - dbglog("ChallengeResponse - ZPasswordHash %.*B", - sizeof(ZPasswordHash), ZPasswordHash); -#endif - - pppcrypt_56_to_64_bit_key(ZPasswordHash + 0, des_key); - lwip_des_init(&des); - lwip_des_setkey_enc(&des, des_key); - lwip_des_crypt_ecb(&des, challenge, response +0); - lwip_des_free(&des); - - pppcrypt_56_to_64_bit_key(ZPasswordHash + 7, des_key); - lwip_des_init(&des); - lwip_des_setkey_enc(&des, des_key); - lwip_des_crypt_ecb(&des, challenge, response +8); - lwip_des_free(&des); - - pppcrypt_56_to_64_bit_key(ZPasswordHash + 14, des_key); - lwip_des_init(&des); - lwip_des_setkey_enc(&des, des_key); - lwip_des_crypt_ecb(&des, challenge, response +16); - lwip_des_free(&des); - -#if 0 - dbglog("ChallengeResponse - response %.24B", response); -#endif -} - -static void ChallengeHash(const u_char PeerChallenge[16], const u_char *rchallenge, - const char *username, u_char Challenge[8]) { - lwip_sha1_context sha1Context; - u_char sha1Hash[SHA1_SIGNATURE_SIZE]; - const char *user; - - /* remove domain from "domain\username" */ - if ((user = strrchr(username, '\\')) != NULL) - ++user; - else - user = username; - - lwip_sha1_init(&sha1Context); - lwip_sha1_starts(&sha1Context); - lwip_sha1_update(&sha1Context, PeerChallenge, 16); - lwip_sha1_update(&sha1Context, rchallenge, 16); - lwip_sha1_update(&sha1Context, (const unsigned char*)user, strlen(user)); - lwip_sha1_finish(&sha1Context, sha1Hash); - lwip_sha1_free(&sha1Context); - - MEMCPY(Challenge, sha1Hash, 8); -} - -/* - * Convert the ASCII version of the password to Unicode. - * This implicitly supports 8-bit ISO8859/1 characters. - * This gives us the little-endian representation, which - * is assumed by all M$ CHAP RFCs. (Unicode byte ordering - * is machine-dependent.) - */ -static void ascii2unicode(const char ascii[], int ascii_len, u_char unicode[]) { - int i; - - BZERO(unicode, ascii_len * 2); - for (i = 0; i < ascii_len; i++) - unicode[i * 2] = (u_char) ascii[i]; -} - -static void NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) { - lwip_md4_context md4Context; - - lwip_md4_init(&md4Context); - lwip_md4_starts(&md4Context); - lwip_md4_update(&md4Context, secret, secret_len); - lwip_md4_finish(&md4Context, hash); - lwip_md4_free(&md4Context); -} - -static void ChapMS_NT(const u_char *rchallenge, const char *secret, int secret_len, - u_char NTResponse[24]) { - u_char unicodePassword[MAX_NT_PASSWORD * 2]; - u_char PasswordHash[MD4_SIGNATURE_SIZE]; - - /* Hash the Unicode version of the secret (== password). */ - ascii2unicode(secret, secret_len, unicodePassword); - NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); - - ChallengeResponse(rchallenge, PasswordHash, NTResponse); -} - -static void ChapMS2_NT(const u_char *rchallenge, const u_char PeerChallenge[16], const char *username, - const char *secret, int secret_len, u_char NTResponse[24]) { - u_char unicodePassword[MAX_NT_PASSWORD * 2]; - u_char PasswordHash[MD4_SIGNATURE_SIZE]; - u_char Challenge[8]; - - ChallengeHash(PeerChallenge, rchallenge, username, Challenge); - - /* Hash the Unicode version of the secret (== password). */ - ascii2unicode(secret, secret_len, unicodePassword); - NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); - - ChallengeResponse(Challenge, PasswordHash, NTResponse); -} - -#ifdef MSLANMAN -static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ - -static void ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len, - unsigned char *response) { - int i; - u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ - u_char PasswordHash[MD4_SIGNATURE_SIZE]; - lwip_des_context des; - u_char des_key[8]; - - /* LANMan password is case insensitive */ - BZERO(UcasePassword, sizeof(UcasePassword)); - for (i = 0; i < secret_len; i++) - UcasePassword[i] = (u_char)toupper(secret[i]); - - pppcrypt_56_to_64_bit_key(UcasePassword +0, des_key); - lwip_des_init(&des); - lwip_des_setkey_enc(&des, des_key); - lwip_des_crypt_ecb(&des, StdText, PasswordHash +0); - lwip_des_free(&des); - - pppcrypt_56_to_64_bit_key(UcasePassword +7, des_key); - lwip_des_init(&des); - lwip_des_setkey_enc(&des, des_key); - lwip_des_crypt_ecb(&des, StdText, PasswordHash +8); - lwip_des_free(&des); - - ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]); -} -#endif - - -static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE], - u_char NTResponse[24], const u_char PeerChallenge[16], - const u_char *rchallenge, const char *username, - u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) { - /* - * "Magic" constants used in response generation, from RFC 2759. - */ - static const u_char Magic1[39] = /* "Magic server to client signing constant" */ - { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, - 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, - 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; - static const u_char Magic2[41] = /* "Pad to make it do more than one iteration" */ - { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, - 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, - 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, - 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, - 0x6E }; - - int i; - lwip_sha1_context sha1Context; - u_char Digest[SHA1_SIGNATURE_SIZE]; - u_char Challenge[8]; - - lwip_sha1_init(&sha1Context); - lwip_sha1_starts(&sha1Context); - lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); - lwip_sha1_update(&sha1Context, NTResponse, 24); - lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1)); - lwip_sha1_finish(&sha1Context, Digest); - lwip_sha1_free(&sha1Context); - - ChallengeHash(PeerChallenge, rchallenge, username, Challenge); - - lwip_sha1_init(&sha1Context); - lwip_sha1_starts(&sha1Context); - lwip_sha1_update(&sha1Context, Digest, sizeof(Digest)); - lwip_sha1_update(&sha1Context, Challenge, sizeof(Challenge)); - lwip_sha1_update(&sha1Context, Magic2, sizeof(Magic2)); - lwip_sha1_finish(&sha1Context, Digest); - lwip_sha1_free(&sha1Context); - - /* Convert to ASCII hex string. */ - for (i = 0; i < LWIP_MAX((MS_AUTH_RESPONSE_LENGTH / 2), (int)sizeof(Digest)); i++) - sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]); -} - - -static void GenerateAuthenticatorResponsePlain( - const char *secret, int secret_len, - u_char NTResponse[24], const u_char PeerChallenge[16], - const u_char *rchallenge, const char *username, - u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) { - u_char unicodePassword[MAX_NT_PASSWORD * 2]; - u_char PasswordHash[MD4_SIGNATURE_SIZE]; - u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; - - /* Hash (x2) the Unicode version of the secret (== password). */ - ascii2unicode(secret, secret_len, unicodePassword); - NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); - NTPasswordHash(PasswordHash, sizeof(PasswordHash), - PasswordHashHash); - - GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge, - rchallenge, username, authResponse); -} - - -#if MPPE_SUPPORT -/* - * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) - */ -static void Set_Start_Key(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len) { - u_char unicodePassword[MAX_NT_PASSWORD * 2]; - u_char PasswordHash[MD4_SIGNATURE_SIZE]; - u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; - lwip_sha1_context sha1Context; - u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ - - /* Hash (x2) the Unicode version of the secret (== password). */ - ascii2unicode(secret, secret_len, unicodePassword); - NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); - NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); - - lwip_sha1_init(&sha1Context); - lwip_sha1_starts(&sha1Context); - lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); - lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); - lwip_sha1_update(&sha1Context, rchallenge, 8); - lwip_sha1_finish(&sha1Context, Digest); - lwip_sha1_free(&sha1Context); - - /* Same key in both directions. */ - mppe_set_key(pcb, &pcb->mppe_comp, Digest); - mppe_set_key(pcb, &pcb->mppe_decomp, Digest); - - pcb->mppe_keys_set = 1; -} - -/* - * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) - */ -static void SetMasterKeys(ppp_pcb *pcb, const char *secret, int secret_len, u_char NTResponse[24], int IsServer) { - u_char unicodePassword[MAX_NT_PASSWORD * 2]; - u_char PasswordHash[MD4_SIGNATURE_SIZE]; - u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; - lwip_sha1_context sha1Context; - u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ - u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ - const u_char *s; - - /* "This is the MPPE Master Key" */ - static const u_char Magic1[27] = - { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, - 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; - /* "On the client side, this is the send key; " - "on the server side, it is the receive key." */ - static const u_char Magic2[84] = - { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, - 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, - 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, - 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, - 0x6b, 0x65, 0x79, 0x2e }; - /* "On the client side, this is the receive key; " - "on the server side, it is the send key." */ - static const u_char Magic3[84] = - { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, - 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, - 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, - 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, - 0x6b, 0x65, 0x79, 0x2e }; - - /* Hash (x2) the Unicode version of the secret (== password). */ - ascii2unicode(secret, secret_len, unicodePassword); - NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); - NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); - - lwip_sha1_init(&sha1Context); - lwip_sha1_starts(&sha1Context); - lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); - lwip_sha1_update(&sha1Context, NTResponse, 24); - lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1)); - lwip_sha1_finish(&sha1Context, MasterKey); - lwip_sha1_free(&sha1Context); - - /* - * generate send key - */ - if (IsServer) - s = Magic3; - else - s = Magic2; - lwip_sha1_init(&sha1Context); - lwip_sha1_starts(&sha1Context); - lwip_sha1_update(&sha1Context, MasterKey, 16); - lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE); - lwip_sha1_update(&sha1Context, s, 84); - lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE); - lwip_sha1_finish(&sha1Context, Digest); - lwip_sha1_free(&sha1Context); - - mppe_set_key(pcb, &pcb->mppe_comp, Digest); - - /* - * generate recv key - */ - if (IsServer) - s = Magic2; - else - s = Magic3; - lwip_sha1_init(&sha1Context); - lwip_sha1_starts(&sha1Context); - lwip_sha1_update(&sha1Context, MasterKey, 16); - lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE); - lwip_sha1_update(&sha1Context, s, 84); - lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE); - lwip_sha1_finish(&sha1Context, Digest); - lwip_sha1_free(&sha1Context); - - mppe_set_key(pcb, &pcb->mppe_decomp, Digest); - - pcb->mppe_keys_set = 1; -} - -#endif /* MPPE_SUPPORT */ - - -static void ChapMS(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len, - unsigned char *response) { -#if !MPPE_SUPPORT - LWIP_UNUSED_ARG(pcb); -#endif /* !MPPE_SUPPORT */ - BZERO(response, MS_CHAP_RESPONSE_LEN); - - ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]); - -#ifdef MSLANMAN - ChapMS_LANMan(rchallenge, secret, secret_len, - &response[MS_CHAP_LANMANRESP]); - - /* preferred method is set by option */ - response[MS_CHAP_USENT] = !ms_lanman; -#else - response[MS_CHAP_USENT] = 1; -#endif - -#if MPPE_SUPPORT - Set_Start_Key(pcb, rchallenge, secret, secret_len); -#endif /* MPPE_SUPPORT */ -} - - -/* - * If PeerChallenge is NULL, one is generated and the PeerChallenge - * field of response is filled in. Call this way when generating a response. - * If PeerChallenge is supplied, it is copied into the PeerChallenge field. - * Call this way when verifying a response (or debugging). - * Do not call with PeerChallenge = response. - * - * The PeerChallenge field of response is then used for calculation of the - * Authenticator Response. - */ -static void ChapMS2(ppp_pcb *pcb, const u_char *rchallenge, const u_char *PeerChallenge, - const char *user, const char *secret, int secret_len, unsigned char *response, - u_char authResponse[], int authenticator) { - /* ARGSUSED */ - LWIP_UNUSED_ARG(authenticator); -#if !MPPE_SUPPORT - LWIP_UNUSED_ARG(pcb); -#endif /* !MPPE_SUPPORT */ - - BZERO(response, MS_CHAP2_RESPONSE_LEN); - - /* Generate the Peer-Challenge if requested, or copy it if supplied. */ - if (!PeerChallenge) - magic_random_bytes(&response[MS_CHAP2_PEER_CHALLENGE], MS_CHAP2_PEER_CHAL_LEN); - else - MEMCPY(&response[MS_CHAP2_PEER_CHALLENGE], PeerChallenge, - MS_CHAP2_PEER_CHAL_LEN); - - /* Generate the NT-Response */ - ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user, - secret, secret_len, &response[MS_CHAP2_NTRESP]); - - /* Generate the Authenticator Response. */ - GenerateAuthenticatorResponsePlain(secret, secret_len, - &response[MS_CHAP2_NTRESP], - &response[MS_CHAP2_PEER_CHALLENGE], - rchallenge, user, authResponse); - -#if MPPE_SUPPORT - SetMasterKeys(pcb, secret, secret_len, - &response[MS_CHAP2_NTRESP], authenticator); -#endif /* MPPE_SUPPORT */ -} - -#if 0 /* UNUSED */ -#if MPPE_SUPPORT -/* - * Set MPPE options from plugins. - */ -void set_mppe_enc_types(int policy, int types) { - /* Early exit for unknown policies. */ - if (policy != MPPE_ENC_POL_ENC_ALLOWED || - policy != MPPE_ENC_POL_ENC_REQUIRED) - return; - - /* Don't modify MPPE if it's optional and wasn't already configured. */ - if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe) - return; - - /* - * Disable undesirable encryption types. Note that we don't ENABLE - * any encryption types, to avoid overriding manual configuration. - */ - switch(types) { - case MPPE_ENC_TYPES_RC4_40: - ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */ - break; - case MPPE_ENC_TYPES_RC4_128: - ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */ - break; - default: - break; - } -} -#endif /* MPPE_SUPPORT */ -#endif /* UNUSED */ - -const struct chap_digest_type chapms_digest = { - CHAP_MICROSOFT, /* code */ -#if PPP_SERVER - chapms_generate_challenge, - chapms_verify_response, -#endif /* PPP_SERVER */ - chapms_make_response, - NULL, /* check_success */ - chapms_handle_failure, -}; - -const struct chap_digest_type chapms2_digest = { - CHAP_MICROSOFT_V2, /* code */ -#if PPP_SERVER - chapms2_generate_challenge, - chapms2_verify_response, -#endif /* PPP_SERVER */ - chapms2_make_response, - chapms2_check_success, - chapms_handle_failure, -}; - -#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/demand.c b/ext/lwip/src/netif/ppp/demand.c deleted file mode 100644 index 26c6c30..0000000 --- a/ext/lwip/src/netif/ppp/demand.c +++ /dev/null @@ -1,465 +0,0 @@ -/* - * demand.c - Support routines for demand-dialling. - * - * Copyright (c) 1996-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. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && DEMAND_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef PPP_FILTER -#include -#endif - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/fsm.h" -#include "netif/ppp/ipcp.h" -#include "netif/ppp/lcp.h" - -char *frame; -int framelen; -int framemax; -int escape_flag; -int flush_flag; -int fcs; - -struct packet { - int length; - struct packet *next; - unsigned char data[1]; -}; - -struct packet *pend_q; -struct packet *pend_qtail; - -static int active_packet (unsigned char *, int); - -/* - * demand_conf - configure the interface for doing dial-on-demand. - */ -void -demand_conf() -{ - int i; - const struct protent *protp; - -/* framemax = lcp_allowoptions[0].mru; - if (framemax < PPP_MRU) */ - framemax = PPP_MRU; - framemax += PPP_HDRLEN + PPP_FCSLEN; - frame = malloc(framemax); - if (frame == NULL) - novm("demand frame"); - framelen = 0; - pend_q = NULL; - escape_flag = 0; - flush_flag = 0; - fcs = PPP_INITFCS; - - netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_MRU)); - if (ppp_send_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0 - || ppp_recv_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0) - fatal("Couldn't set up demand-dialled PPP interface: %m"); - -#ifdef PPP_FILTER - set_filters(&pass_filter, &active_filter); -#endif - - /* - * Call the demand_conf procedure for each protocol that's got one. - */ - for (i = 0; (protp = protocols[i]) != NULL; ++i) - if (protp->demand_conf != NULL) - ((*protp->demand_conf)(pcb)); -/* FIXME: find a way to die() here */ -#if 0 - if (!((*protp->demand_conf)(pcb))) - die(1); -#endif -} - - -/* - * demand_block - set each network protocol to block further packets. - */ -void -demand_block() -{ - int i; - const struct protent *protp; - - for (i = 0; (protp = protocols[i]) != NULL; ++i) - if (protp->demand_conf != NULL) - sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_QUEUE); - get_loop_output(); -} - -/* - * demand_discard - set each network protocol to discard packets - * with an error. - */ -void -demand_discard() -{ - struct packet *pkt, *nextpkt; - int i; - const struct protent *protp; - - for (i = 0; (protp = protocols[i]) != NULL; ++i) - if (protp->demand_conf != NULL) - sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_ERROR); - get_loop_output(); - - /* discard all saved packets */ - for (pkt = pend_q; pkt != NULL; pkt = nextpkt) { - nextpkt = pkt->next; - free(pkt); - } - pend_q = NULL; - framelen = 0; - flush_flag = 0; - escape_flag = 0; - fcs = PPP_INITFCS; -} - -/* - * demand_unblock - set each enabled network protocol to pass packets. - */ -void -demand_unblock() -{ - int i; - const struct protent *protp; - - for (i = 0; (protp = protocols[i]) != NULL; ++i) - if (protp->demand_conf != NULL) - sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_PASS); -} - -/* - * FCS lookup table as calculated by genfcstab. - */ -static u_short fcstab[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - -/* - * loop_chars - process characters received from the loopback. - * Calls loop_frame when a complete frame has been accumulated. - * Return value is 1 if we need to bring up the link, 0 otherwise. - */ -int -loop_chars(p, n) - unsigned char *p; - int n; -{ - int c, rv; - - rv = 0; - -/* check for synchronous connection... */ - - if ( (p[0] == 0xFF) && (p[1] == 0x03) ) { - rv = loop_frame(p,n); - return rv; - } - - for (; n > 0; --n) { - c = *p++; - if (c == PPP_FLAG) { - if (!escape_flag && !flush_flag - && framelen > 2 && fcs == PPP_GOODFCS) { - framelen -= 2; - if (loop_frame((unsigned char *)frame, framelen)) - rv = 1; - } - framelen = 0; - flush_flag = 0; - escape_flag = 0; - fcs = PPP_INITFCS; - continue; - } - if (flush_flag) - continue; - if (escape_flag) { - c ^= PPP_TRANS; - escape_flag = 0; - } else if (c == PPP_ESCAPE) { - escape_flag = 1; - continue; - } - if (framelen >= framemax) { - flush_flag = 1; - continue; - } - frame[framelen++] = c; - fcs = PPP_FCS(fcs, c); - } - return rv; -} - -/* - * loop_frame - given a frame obtained from the loopback, - * decide whether to bring up the link or not, and, if we want - * to transmit this frame later, put it on the pending queue. - * Return value is 1 if we need to bring up the link, 0 otherwise. - * We assume that the kernel driver has already applied the - * pass_filter, so we won't get packets it rejected. - * We apply the active_filter to see if we want this packet to - * bring up the link. - */ -int -loop_frame(frame, len) - unsigned char *frame; - int len; -{ - struct packet *pkt; - - /* dbglog("from loop: %P", frame, len); */ - if (len < PPP_HDRLEN) - return 0; - if ((PPP_PROTOCOL(frame) & 0x8000) != 0) - return 0; /* shouldn't get any of these anyway */ - if (!active_packet(frame, len)) - return 0; - - pkt = (struct packet *) malloc(sizeof(struct packet) + len); - if (pkt != NULL) { - pkt->length = len; - pkt->next = NULL; - memcpy(pkt->data, frame, len); - if (pend_q == NULL) - pend_q = pkt; - else - pend_qtail->next = pkt; - pend_qtail = pkt; - } - return 1; -} - -/* - * demand_rexmit - Resend all those frames which we got via the - * loopback, now that the real serial link is up. - */ -void -demand_rexmit(proto, newip) - int proto; - u32_t newip; -{ - struct packet *pkt, *prev, *nextpkt; - unsigned short checksum; - unsigned short pkt_checksum = 0; - unsigned iphdr; - struct timeval tv; - char cv = 0; - char ipstr[16]; - - prev = NULL; - pkt = pend_q; - pend_q = NULL; - tv.tv_sec = 1; - tv.tv_usec = 0; - select(0,NULL,NULL,NULL,&tv); /* Sleep for 1 Seconds */ - for (; pkt != NULL; pkt = nextpkt) { - nextpkt = pkt->next; - if (PPP_PROTOCOL(pkt->data) == proto) { - if ( (proto == PPP_IP) && newip ) { - /* Get old checksum */ - - iphdr = (pkt->data[4] & 15) << 2; - checksum = *((unsigned short *) (pkt->data+14)); - if (checksum == 0xFFFF) { - checksum = 0; - } - - - if (pkt->data[13] == 17) { - pkt_checksum = *((unsigned short *) (pkt->data+10+iphdr)); - if (pkt_checksum) { - cv = 1; - if (pkt_checksum == 0xFFFF) { - pkt_checksum = 0; - } - } - else { - cv = 0; - } - } - - if (pkt->data[13] == 6) { - pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr)); - cv = 1; - if (pkt_checksum == 0xFFFF) { - pkt_checksum = 0; - } - } - - /* Delete old Source-IP-Address */ - checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; - checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; - - pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; - pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; - - /* Change Source-IP-Address */ - * ((u32_t *) (pkt->data + 16)) = newip; - - /* Add new Source-IP-Address */ - checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; - checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; - - pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; - pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; - - /* Write new checksum */ - if (!checksum) { - checksum = 0xFFFF; - } - *((unsigned short *) (pkt->data+14)) = checksum; - if (pkt->data[13] == 6) { - *((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum; - } - if (cv && (pkt->data[13] == 17) ) { - *((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum; - } - - /* Log Packet */ - strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16)))); - if (pkt->data[13] == 1) { - syslog(LOG_INFO,"Open ICMP %s -> %s\n", - ipstr, - inet_ntoa(*( (struct in_addr *) (pkt->data+20)))); - } else { - syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n", - pkt->data[13] == 6 ? "TCP" : "UDP", - ipstr, - ntohs(*( (short *) (pkt->data+iphdr+4))), - inet_ntoa(*( (struct in_addr *) (pkt->data+20))), - ntohs(*( (short *) (pkt->data+iphdr+6)))); - } - } - output(pcb, pkt->data, pkt->length); - free(pkt); - } else { - if (prev == NULL) - pend_q = pkt; - else - prev->next = pkt; - prev = pkt; - } - } - pend_qtail = prev; - if (prev != NULL) - prev->next = NULL; -} - -/* - * Scan a packet to decide whether it is an "active" packet, - * that is, whether it is worth bringing up the link for. - */ -static int -active_packet(p, len) - unsigned char *p; - int len; -{ - int proto, i; - const struct protent *protp; - - if (len < PPP_HDRLEN) - return 0; - proto = PPP_PROTOCOL(p); -#ifdef PPP_FILTER - p[0] = 1; /* outbound packet indicator */ - if ((pass_filter.bf_len != 0 - && bpf_filter(pass_filter.bf_insns, p, len, len) == 0) - || (active_filter.bf_len != 0 - && bpf_filter(active_filter.bf_insns, p, len, len) == 0)) { - p[0] = 0xff; - return 0; - } - p[0] = 0xff; -#endif - for (i = 0; (protp = protocols[i]) != NULL; ++i) { - if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) { - if (protp->active_pkt == NULL) - return 1; - return (*protp->active_pkt)(p, len); - } - } - return 0; /* not a supported protocol !!?? */ -} - -#endif /* PPP_SUPPORT && DEMAND_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/eap.c b/ext/lwip/src/netif/ppp/eap.c deleted file mode 100644 index 8fb5636..0000000 --- a/ext/lwip/src/netif/ppp/eap.c +++ /dev/null @@ -1,2423 +0,0 @@ -/* - * eap.c - 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 - * - * This implementation of EAP supports MD5-Challenge and SRP-SHA1 - * authentication styles. Note that support of MD5-Challenge is a - * requirement of RFC 2284, and that it's essentially just a - * reimplementation of regular RFC 1994 CHAP using EAP messages. - * - * As an authenticator ("server"), there are multiple phases for each - * style. In the first phase of each style, the unauthenticated peer - * name is queried using the EAP Identity request type. If the - * "remotename" option is used, then this phase is skipped, because - * the peer's name is presumed to be known. - * - * For MD5-Challenge, there are two phases, and the second phase - * consists of sending the challenge itself and handling the - * associated response. - * - * For SRP-SHA1, there are four phases. The second sends 's', 'N', - * and 'g'. The reply contains 'A'. The third sends 'B', and the - * reply contains 'M1'. The forth sends the 'M2' value. - * - * As an authenticatee ("client"), there's just a single phase -- - * responding to the queries generated by the peer. EAP is an - * authenticator-driven protocol. - * - * Based on draft-ietf-pppext-eap-srp-03.txt. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && EAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#include "netif/ppp/ppp_impl.h" -#include "netif/ppp/eap.h" -#include "netif/ppp/magic.h" -#include "netif/ppp/pppcrypt.h" - -#ifdef USE_SRP -#include -#include -#include -#endif /* USE_SRP */ - -#ifndef SHA_DIGESTSIZE -#define SHA_DIGESTSIZE 20 -#endif - -#ifdef USE_SRP -static char *pn_secret = NULL; /* Pseudonym generating secret */ -#endif - -#if PPP_OPTIONS -/* - * Command-line options. - */ -static option_t eap_option_list[] = { - { "eap-restart", o_int, &eap_states[0].es_server.ea_timeout, - "Set retransmit timeout for EAP Requests (server)" }, - { "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests, - "Set max number of EAP Requests sent (server)" }, - { "eap-timeout", o_int, &eap_states[0].es_client.ea_timeout, - "Set time limit for peer EAP authentication" }, - { "eap-max-rreq", o_int, &eap_states[0].es_client.ea_maxrequests, - "Set max number of EAP Requests allows (client)" }, - { "eap-interval", o_int, &eap_states[0].es_rechallenge, - "Set interval for EAP rechallenge" }, -#ifdef USE_SRP - { "srp-interval", o_int, &eap_states[0].es_lwrechallenge, - "Set interval for SRP lightweight rechallenge" }, - { "srp-pn-secret", o_string, &pn_secret, - "Long term pseudonym generation secret" }, - { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo, - "Use pseudonym if offered one by server", 1 }, -#endif - { NULL } -}; -#endif /* PPP_OPTIONS */ - -/* - * Protocol entry points. - */ -static void eap_init(ppp_pcb *pcb); -static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen); -static void eap_protrej(ppp_pcb *pcb); -static void eap_lowerup(ppp_pcb *pcb); -static void eap_lowerdown(ppp_pcb *pcb); -#if PRINTPKT_SUPPORT -static int eap_printpkt(const u_char *inp, int inlen, - void (*)(void *arg, const char *fmt, ...), void *arg); -#endif /* PRINTPKT_SUPPORT */ - -const struct protent eap_protent = { - PPP_EAP, /* protocol number */ - eap_init, /* initialization procedure */ - eap_input, /* process a received packet */ - eap_protrej, /* process a received protocol-reject */ - eap_lowerup, /* lower layer has gone up */ - eap_lowerdown, /* lower layer has gone down */ - NULL, /* open the protocol */ - NULL, /* close the protocol */ -#if PRINTPKT_SUPPORT - eap_printpkt, /* print a packet in readable form */ -#endif /* PRINTPKT_SUPPORT */ -#if PPP_DATAINPUT - NULL, /* process a received data packet */ -#endif /* PPP_DATAINPUT */ -#if PRINTPKT_SUPPORT - "EAP", /* text name of protocol */ - NULL, /* text name of corresponding data protocol */ -#endif /* PRINTPKT_SUPPORT */ -#if PPP_OPTIONS - eap_option_list, /* list of command-line options */ - NULL, /* check requested options; assign defaults */ -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT - NULL, /* configure interface for demand-dial */ - NULL /* say whether to bring up link for this pkt */ -#endif /* DEMAND_SUPPORT */ -}; - -#ifdef USE_SRP -/* - * A well-known 2048 bit modulus. - */ -static const u_char wkmodulus[] = { - 0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B, - 0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F, - 0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07, - 0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50, - 0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED, - 0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D, - 0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D, - 0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50, - 0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0, - 0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3, - 0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8, - 0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8, - 0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA, - 0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74, - 0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7, - 0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B, - 0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16, - 0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81, - 0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A, - 0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48, - 0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D, - 0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA, - 0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78, - 0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6, - 0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29, - 0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8, - 0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82, - 0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6, - 0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4, - 0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75, - 0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, - 0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73 -}; -#endif - -#if PPP_SERVER -/* Local forward declarations. */ -static void eap_server_timeout(void *arg); -#endif /* PPP_SERVER */ - -/* - * Convert EAP state code to printable string for debug. - */ -static const char * eap_state_name(enum eap_state_code esc) -{ - static const char *state_names[] = { EAP_STATES }; - - return (state_names[(int)esc]); -} - -/* - * eap_init - Initialize state for an EAP user. This is currently - * called once by main() during start-up. - */ -static void eap_init(ppp_pcb *pcb) { - - BZERO(&pcb->eap, sizeof(eap_state)); -#if PPP_SERVER - pcb->eap.es_server.ea_id = magic(); -#endif /* PPP_SERVER */ -} - -/* - * eap_client_timeout - Give up waiting for the peer to send any - * Request messages. - */ -static void eap_client_timeout(void *arg) { - ppp_pcb *pcb = (ppp_pcb*)arg; - - if (!eap_client_active(pcb)) - return; - - ppp_error("EAP: timeout waiting for Request from peer"); - auth_withpeer_fail(pcb, PPP_EAP); - pcb->eap.es_client.ea_state = eapBadAuth; -} - -/* - * eap_authwithpeer - Authenticate to our peer (behave as client). - * - * Start client state and wait for requests. This is called only - * after eap_lowerup. - */ -void eap_authwithpeer(ppp_pcb *pcb, const char *localname) { - - if(NULL == localname) - return; - - /* Save the peer name we're given */ - pcb->eap.es_client.ea_name = localname; - pcb->eap.es_client.ea_namelen = strlen(localname); - - pcb->eap.es_client.ea_state = eapListen; - - /* - * Start a timer so that if the other end just goes - * silent, we don't sit here waiting forever. - */ - if (pcb->settings.eap_req_time > 0) - TIMEOUT(eap_client_timeout, pcb, - pcb->settings.eap_req_time); -} - -#if PPP_SERVER -/* - * Format a standard EAP Failure message and send it to the peer. - * (Server operation) - */ -static void eap_send_failure(ppp_pcb *pcb) { - struct pbuf *p; - u_char *outp; - - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = (u_char*)p->payload; - - MAKEHEADER(outp, PPP_EAP); - - PUTCHAR(EAP_FAILURE, outp); - pcb->eap.es_server.ea_id++; - PUTCHAR(pcb->eap.es_server.ea_id, outp); - PUTSHORT(EAP_HEADERLEN, outp); - - ppp_write(pcb, p); - - pcb->eap.es_server.ea_state = eapBadAuth; - auth_peer_fail(pcb, PPP_EAP); -} - -/* - * Format a standard EAP Success message and send it to the peer. - * (Server operation) - */ -static void eap_send_success(ppp_pcb *pcb) { - struct pbuf *p; - u_char *outp; - - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = (u_char*)p->payload; - - MAKEHEADER(outp, PPP_EAP); - - PUTCHAR(EAP_SUCCESS, outp); - pcb->eap.es_server.ea_id++; - PUTCHAR(pcb->eap.es_server.ea_id, outp); - PUTSHORT(EAP_HEADERLEN, outp); - - ppp_write(pcb, p); - - auth_peer_success(pcb, PPP_EAP, 0, - pcb->eap.es_server.ea_peer, pcb->eap.es_server.ea_peerlen); -} -#endif /* PPP_SERVER */ - -#ifdef USE_SRP -/* - * Set DES key according to pseudonym-generating secret and current - * date. - */ -static bool -pncrypt_setkey(int timeoffs) -{ - struct tm *tp; - char tbuf[9]; - SHA1_CTX ctxt; - u_char dig[SHA_DIGESTSIZE]; - time_t reftime; - - if (pn_secret == NULL) - return (0); - reftime = time(NULL) + timeoffs; - tp = localtime(&reftime); - SHA1Init(&ctxt); - SHA1Update(&ctxt, pn_secret, strlen(pn_secret)); - strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp); - SHA1Update(&ctxt, tbuf, strlen(tbuf)); - SHA1Final(dig, &ctxt); - /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ - return (DesSetkey(dig)); -} - -static char base64[] = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -struct b64state { - u32_t bs_bits; - int bs_offs; -}; - -static int -b64enc(bs, inp, inlen, outp) -struct b64state *bs; -u_char *inp; -int inlen; -u_char *outp; -{ - int outlen = 0; - - while (inlen > 0) { - bs->bs_bits = (bs->bs_bits << 8) | *inp++; - inlen--; - bs->bs_offs += 8; - if (bs->bs_offs >= 24) { - *outp++ = base64[(bs->bs_bits >> 18) & 0x3F]; - *outp++ = base64[(bs->bs_bits >> 12) & 0x3F]; - *outp++ = base64[(bs->bs_bits >> 6) & 0x3F]; - *outp++ = base64[bs->bs_bits & 0x3F]; - outlen += 4; - bs->bs_offs = 0; - bs->bs_bits = 0; - } - } - return (outlen); -} - -static int -b64flush(bs, outp) -struct b64state *bs; -u_char *outp; -{ - int outlen = 0; - - if (bs->bs_offs == 8) { - *outp++ = base64[(bs->bs_bits >> 2) & 0x3F]; - *outp++ = base64[(bs->bs_bits << 4) & 0x3F]; - outlen = 2; - } else if (bs->bs_offs == 16) { - *outp++ = base64[(bs->bs_bits >> 10) & 0x3F]; - *outp++ = base64[(bs->bs_bits >> 4) & 0x3F]; - *outp++ = base64[(bs->bs_bits << 2) & 0x3F]; - outlen = 3; - } - bs->bs_offs = 0; - bs->bs_bits = 0; - return (outlen); -} - -static int -b64dec(bs, inp, inlen, outp) -struct b64state *bs; -u_char *inp; -int inlen; -u_char *outp; -{ - int outlen = 0; - char *cp; - - while (inlen > 0) { - if ((cp = strchr(base64, *inp++)) == NULL) - break; - bs->bs_bits = (bs->bs_bits << 6) | (cp - base64); - inlen--; - bs->bs_offs += 6; - if (bs->bs_offs >= 8) { - *outp++ = bs->bs_bits >> (bs->bs_offs - 8); - outlen++; - bs->bs_offs -= 8; - } - } - return (outlen); -} -#endif /* USE_SRP */ - -#if PPP_SERVER -/* - * Assume that current waiting server state is complete and figure - * next state to use based on available authentication data. 'status' - * indicates if there was an error in handling the last query. It is - * 0 for success and non-zero for failure. - */ -static void eap_figure_next_state(ppp_pcb *pcb, int status) { -#ifdef USE_SRP - unsigned char secbuf[MAXSECRETLEN], clear[8], *sp, *dp; - struct t_pw tpw; - struct t_confent *tce, mytce; - char *cp, *cp2; - struct t_server *ts; - int id, i, plen, toffs; - u_char vals[2]; - struct b64state bs; -#endif /* USE_SRP */ - - pcb->settings.eap_timeout_time = pcb->eap.es_savedtime; - switch (pcb->eap.es_server.ea_state) { - case eapBadAuth: - return; - - case eapIdentify: -#ifdef USE_SRP - /* Discard any previous session. */ - ts = (struct t_server *)pcb->eap.es_server.ea_session; - if (ts != NULL) { - t_serverclose(ts); - pcb->eap.es_server.ea_session = NULL; - pcb->eap.es_server.ea_skey = NULL; - } -#endif /* USE_SRP */ - if (status != 0) { - pcb->eap.es_server.ea_state = eapBadAuth; - break; - } -#ifdef USE_SRP - /* If we've got a pseudonym, try to decode to real name. */ - if (pcb->eap.es_server.ea_peerlen > SRP_PSEUDO_LEN && - strncmp(pcb->eap.es_server.ea_peer, SRP_PSEUDO_ID, - SRP_PSEUDO_LEN) == 0 && - (pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 < - sizeof (secbuf)) { - BZERO(&bs, sizeof (bs)); - plen = b64dec(&bs, - pcb->eap.es_server.ea_peer + SRP_PSEUDO_LEN, - pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN, - secbuf); - toffs = 0; - for (i = 0; i < 5; i++) { - pncrypt_setkey(toffs); - toffs -= 86400; - /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ - if (!DesDecrypt(secbuf, clear)) { - ppp_dbglog("no DES here; cannot decode " - "pseudonym"); - return; - } - id = *(unsigned char *)clear; - if (id + 1 <= plen && id + 9 > plen) - break; - } - if (plen % 8 == 0 && i < 5) { - /* - * Note that this is always shorter than the - * original stored string, so there's no need - * to realloc. - */ - if ((i = plen = *(unsigned char *)clear) > 7) - i = 7; - pcb->eap.es_server.ea_peerlen = plen; - dp = (unsigned char *)pcb->eap.es_server.ea_peer; - MEMCPY(dp, clear + 1, i); - plen -= i; - dp += i; - sp = secbuf + 8; - while (plen > 0) { - /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ - (void) DesDecrypt(sp, dp); - sp += 8; - dp += 8; - plen -= 8; - } - pcb->eap.es_server.ea_peer[ - pcb->eap.es_server.ea_peerlen] = '\0'; - ppp_dbglog("decoded pseudonym to \"%.*q\"", - pcb->eap.es_server.ea_peerlen, - pcb->eap.es_server.ea_peer); - } else { - ppp_dbglog("failed to decode real name"); - /* Stay in eapIdentfy state; requery */ - break; - } - } - /* Look up user in secrets database. */ - if (get_srp_secret(pcb->eap.es_unit, pcb->eap.es_server.ea_peer, - pcb->eap.es_server.ea_name, (char *)secbuf, 1) != 0) { - /* Set up default in case SRP entry is bad */ - pcb->eap.es_server.ea_state = eapMD5Chall; - /* Get t_confent based on index in srp-secrets */ - id = strtol((char *)secbuf, &cp, 10); - if (*cp++ != ':' || id < 0) - break; - if (id == 0) { - mytce.index = 0; - mytce.modulus.data = (u_char *)wkmodulus; - mytce.modulus.len = sizeof (wkmodulus); - mytce.generator.data = (u_char *)"\002"; - mytce.generator.len = 1; - tce = &mytce; - } else if ((tce = gettcid(id)) != NULL) { - /* - * Client will have to verify this modulus/ - * generator combination, and that will take - * a while. Lengthen the timeout here. - */ - if (pcb->settings.eap_timeout_time > 0 && - pcb->settings.eap_timeout_time < 30) - pcb->settings.eap_timeout_time = 30; - } else { - break; - } - if ((cp2 = strchr(cp, ':')) == NULL) - break; - *cp2++ = '\0'; - tpw.pebuf.name = pcb->eap.es_server.ea_peer; - tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf, - cp); - tpw.pebuf.password.data = tpw.pwbuf; - tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf, - cp2); - tpw.pebuf.salt.data = tpw.saltbuf; - if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL) - break; - pcb->eap.es_server.ea_session = (void *)ts; - pcb->eap.es_server.ea_state = eapSRP1; - vals[0] = pcb->eap.es_server.ea_id + 1; - vals[1] = EAPT_SRP; - t_serveraddexdata(ts, vals, 2); - /* Generate B; must call before t_servergetkey() */ - t_servergenexp(ts); - break; - } -#endif /* USE_SRP */ - pcb->eap.es_server.ea_state = eapMD5Chall; - break; - - case eapSRP1: -#ifdef USE_SRP - ts = (struct t_server *)pcb->eap.es_server.ea_session; - if (ts != NULL && status != 0) { - t_serverclose(ts); - pcb->eap.es_server.ea_session = NULL; - pcb->eap.es_server.ea_skey = NULL; - } -#endif /* USE_SRP */ - if (status == 1) { - pcb->eap.es_server.ea_state = eapMD5Chall; - } else if (status != 0 || pcb->eap.es_server.ea_session == NULL) { - pcb->eap.es_server.ea_state = eapBadAuth; - } else { - pcb->eap.es_server.ea_state = eapSRP2; - } - break; - - case eapSRP2: -#ifdef USE_SRP - ts = (struct t_server *)pcb->eap.es_server.ea_session; - if (ts != NULL && status != 0) { - t_serverclose(ts); - pcb->eap.es_server.ea_session = NULL; - pcb->eap.es_server.ea_skey = NULL; - } -#endif /* USE_SRP */ - if (status != 0 || pcb->eap.es_server.ea_session == NULL) { - pcb->eap.es_server.ea_state = eapBadAuth; - } else { - pcb->eap.es_server.ea_state = eapSRP3; - } - break; - - case eapSRP3: - case eapSRP4: -#ifdef USE_SRP - ts = (struct t_server *)pcb->eap.es_server.ea_session; - if (ts != NULL && status != 0) { - t_serverclose(ts); - pcb->eap.es_server.ea_session = NULL; - pcb->eap.es_server.ea_skey = NULL; - } -#endif /* USE_SRP */ - if (status != 0 || pcb->eap.es_server.ea_session == NULL) { - pcb->eap.es_server.ea_state = eapBadAuth; - } else { - pcb->eap.es_server.ea_state = eapOpen; - } - break; - - case eapMD5Chall: - if (status != 0) { - pcb->eap.es_server.ea_state = eapBadAuth; - } else { - pcb->eap.es_server.ea_state = eapOpen; - } - break; - - default: - pcb->eap.es_server.ea_state = eapBadAuth; - break; - } - if (pcb->eap.es_server.ea_state == eapBadAuth) - eap_send_failure(pcb); -} - -/* - * Format an EAP Request message and send it to the peer. Message - * type depends on current state. (Server operation) - */ -static void eap_send_request(ppp_pcb *pcb) { - struct pbuf *p; - u_char *outp; - u_char *lenloc; - int outlen; - int len; - const char *str; -#ifdef USE_SRP - struct t_server *ts; - u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp; - int i, j; - struct b64state b64; - SHA1_CTX ctxt; -#endif /* USE_SRP */ - - /* Handle both initial auth and restart */ - if (pcb->eap.es_server.ea_state < eapIdentify && - pcb->eap.es_server.ea_state != eapInitial) { - pcb->eap.es_server.ea_state = eapIdentify; -#if PPP_REMOTENAME - if (pcb->settings.explicit_remote && pcb->remote_name) { - /* - * If we already know the peer's - * unauthenticated name, then there's no - * reason to ask. Go to next state instead. - */ - int len = (int)strlen(pcb->remote_name); - if (len > MAXNAMELEN) { - len = MAXNAMELEN; - } - MEMCPY(pcb->eap.es_server.ea_peer, pcb->remote_name, len); - pcb->eap.es_server.ea_peer[len] = '\0'; - pcb->eap.es_server.ea_peerlen = len; - eap_figure_next_state(pcb, 0); - } -#endif /* PPP_REMOTENAME */ - } - - if (pcb->settings.eap_max_transmits > 0 && - pcb->eap.es_server.ea_requests >= pcb->settings.eap_max_transmits) { - if (pcb->eap.es_server.ea_responses > 0) - ppp_error("EAP: too many Requests sent"); - else - ppp_error("EAP: no response to Requests"); - eap_send_failure(pcb); - return; - } - - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = (u_char*)p->payload; - - MAKEHEADER(outp, PPP_EAP); - - PUTCHAR(EAP_REQUEST, outp); - PUTCHAR(pcb->eap.es_server.ea_id, outp); - lenloc = outp; - INCPTR(2, outp); - - switch (pcb->eap.es_server.ea_state) { - case eapIdentify: - PUTCHAR(EAPT_IDENTITY, outp); - str = "Name"; - len = strlen(str); - MEMCPY(outp, str, len); - INCPTR(len, outp); - break; - - case eapMD5Chall: - PUTCHAR(EAPT_MD5CHAP, outp); - /* - * pick a random challenge length between - * EAP_MIN_CHALLENGE_LENGTH and EAP_MAX_CHALLENGE_LENGTH - */ - pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH + - magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH); - PUTCHAR(pcb->eap.es_challen, outp); - magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen); - MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen); - INCPTR(pcb->eap.es_challen, outp); - MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen); - INCPTR(pcb->eap.es_server.ea_namelen, outp); - break; - -#ifdef USE_SRP - case eapSRP1: - PUTCHAR(EAPT_SRP, outp); - PUTCHAR(EAPSRP_CHALLENGE, outp); - - PUTCHAR(pcb->eap.es_server.ea_namelen, outp); - MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen); - INCPTR(pcb->eap.es_server.ea_namelen, outp); - - ts = (struct t_server *)pcb->eap.es_server.ea_session; - assert(ts != NULL); - PUTCHAR(ts->s.len, outp); - MEMCPY(outp, ts->s.data, ts->s.len); - INCPTR(ts->s.len, outp); - - if (ts->g.len == 1 && ts->g.data[0] == 2) { - PUTCHAR(0, outp); - } else { - PUTCHAR(ts->g.len, outp); - MEMCPY(outp, ts->g.data, ts->g.len); - INCPTR(ts->g.len, outp); - } - - if (ts->n.len != sizeof (wkmodulus) || - BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) { - MEMCPY(outp, ts->n.data, ts->n.len); - INCPTR(ts->n.len, outp); - } - break; - - case eapSRP2: - PUTCHAR(EAPT_SRP, outp); - PUTCHAR(EAPSRP_SKEY, outp); - - ts = (struct t_server *)pcb->eap.es_server.ea_session; - assert(ts != NULL); - MEMCPY(outp, ts->B.data, ts->B.len); - INCPTR(ts->B.len, outp); - break; - - case eapSRP3: - PUTCHAR(EAPT_SRP, outp); - PUTCHAR(EAPSRP_SVALIDATOR, outp); - PUTLONG(SRPVAL_EBIT, outp); - ts = (struct t_server *)pcb->eap.es_server.ea_session; - assert(ts != NULL); - MEMCPY(outp, t_serverresponse(ts), SHA_DIGESTSIZE); - INCPTR(SHA_DIGESTSIZE, outp); - - if (pncrypt_setkey(0)) { - /* Generate pseudonym */ - optr = outp; - cp = (unsigned char *)pcb->eap.es_server.ea_peer; - if ((j = i = pcb->eap.es_server.ea_peerlen) > 7) - j = 7; - clear[0] = i; - MEMCPY(clear + 1, cp, j); - i -= j; - cp += j; - /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ - if (!DesEncrypt(clear, cipher)) { - ppp_dbglog("no DES here; not generating pseudonym"); - break; - } - BZERO(&b64, sizeof (b64)); - outp++; /* space for pseudonym length */ - outp += b64enc(&b64, cipher, 8, outp); - while (i >= 8) { - /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ - (void) DesEncrypt(cp, cipher); - outp += b64enc(&b64, cipher, 8, outp); - cp += 8; - i -= 8; - } - if (i > 0) { - MEMCPY(clear, cp, i); - cp += i; - magic_random_bytes(cp, 8-i); - /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ - (void) DesEncrypt(clear, cipher); - outp += b64enc(&b64, cipher, 8, outp); - } - outp += b64flush(&b64, outp); - - /* Set length and pad out to next 20 octet boundary */ - i = outp - optr - 1; - *optr = i; - i %= SHA_DIGESTSIZE; - if (i != 0) { - magic_random_bytes(outp, SHA_DIGESTSIZE-i); - INCPTR(SHA_DIGESTSIZE-i, outp); - } - - /* Obscure the pseudonym with SHA1 hash */ - SHA1Init(&ctxt); - SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1); - SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, - SESSION_KEY_LEN); - SHA1Update(&ctxt, pcb->eap.es_server.ea_peer, - pcb->eap.es_server.ea_peerlen); - while (optr < outp) { - SHA1Final(dig, &ctxt); - cp = dig; - while (cp < dig + SHA_DIGESTSIZE) - *optr++ ^= *cp++; - SHA1Init(&ctxt); - SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1); - SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, - SESSION_KEY_LEN); - SHA1Update(&ctxt, optr - SHA_DIGESTSIZE, - SHA_DIGESTSIZE); - } - } - break; - - case eapSRP4: - PUTCHAR(EAPT_SRP, outp); - PUTCHAR(EAPSRP_LWRECHALLENGE, outp); - pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH + - magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH); - magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen); - MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen); - INCPTR(pcb->eap.es_challen, outp); - break; -#endif /* USE_SRP */ - - default: - return; - } - - outlen = (outp - (unsigned char*)p->payload) - PPP_HDRLEN; - PUTSHORT(outlen, lenloc); - - pbuf_realloc(p, outlen + PPP_HDRLEN); - ppp_write(pcb, p); - - pcb->eap.es_server.ea_requests++; - - if (pcb->settings.eap_timeout_time > 0) - TIMEOUT(eap_server_timeout, pcb, pcb->settings.eap_timeout_time); -} - -/* - * eap_authpeer - Authenticate our peer (behave as server). - * - * Start server state and send first request. This is called only - * after eap_lowerup. - */ -void eap_authpeer(ppp_pcb *pcb, const char *localname) { - - /* Save the name we're given. */ - pcb->eap.es_server.ea_name = localname; - pcb->eap.es_server.ea_namelen = strlen(localname); - - pcb->eap.es_savedtime = pcb->settings.eap_timeout_time; - - /* Lower layer up yet? */ - if (pcb->eap.es_server.ea_state == eapInitial || - pcb->eap.es_server.ea_state == eapPending) { - pcb->eap.es_server.ea_state = eapPending; - return; - } - - pcb->eap.es_server.ea_state = eapPending; - - /* ID number not updated here intentionally; hashed into M1 */ - eap_send_request(pcb); -} - -/* - * eap_server_timeout - Retransmission timer for sending Requests - * expired. - */ -static void eap_server_timeout(void *arg) { - ppp_pcb *pcb = (ppp_pcb*)arg; - - if (!eap_server_active(pcb)) - return; - - /* EAP ID number must not change on timeout. */ - eap_send_request(pcb); -} - -/* - * When it's time to send rechallenge the peer, this timeout is - * called. Once the rechallenge is successful, the response handler - * will restart the timer. If it fails, then the link is dropped. - */ -static void eap_rechallenge(void *arg) { - ppp_pcb *pcb = (ppp_pcb*)arg; - - if (pcb->eap.es_server.ea_state != eapOpen && - pcb->eap.es_server.ea_state != eapSRP4) - return; - - pcb->eap.es_server.ea_requests = 0; - pcb->eap.es_server.ea_state = eapIdentify; - eap_figure_next_state(pcb, 0); - pcb->eap.es_server.ea_id++; - eap_send_request(pcb); -} - -static void srp_lwrechallenge(void *arg) { - ppp_pcb *pcb = (ppp_pcb*)arg; - - if (pcb->eap.es_server.ea_state != eapOpen || - pcb->eap.es_server.ea_type != EAPT_SRP) - return; - - pcb->eap.es_server.ea_requests = 0; - pcb->eap.es_server.ea_state = eapSRP4; - pcb->eap.es_server.ea_id++; - eap_send_request(pcb); -} -#endif /* PPP_SERVER */ - -/* - * eap_lowerup - The lower layer is now up. - * - * This is called before either eap_authpeer or eap_authwithpeer. See - * link_established() in auth.c. All that's necessary here is to - * return to closed state so that those two routines will do the right - * thing. - */ -static void eap_lowerup(ppp_pcb *pcb) { - pcb->eap.es_client.ea_state = eapClosed; -#if PPP_SERVER - pcb->eap.es_server.ea_state = eapClosed; -#endif /* PPP_SERVER */ -} - -/* - * eap_lowerdown - The lower layer is now down. - * - * Cancel all timeouts and return to initial state. - */ -static void eap_lowerdown(ppp_pcb *pcb) { - - if (eap_client_active(pcb) && pcb->settings.eap_req_time > 0) { - UNTIMEOUT(eap_client_timeout, pcb); - } -#if PPP_SERVER - if (eap_server_active(pcb)) { - if (pcb->settings.eap_timeout_time > 0) { - UNTIMEOUT(eap_server_timeout, pcb); - } - } else { - if ((pcb->eap.es_server.ea_state == eapOpen || - pcb->eap.es_server.ea_state == eapSRP4) && - pcb->eap.es_rechallenge > 0) { - UNTIMEOUT(eap_rechallenge, (void *)pcb); - } - if (pcb->eap.es_server.ea_state == eapOpen && - pcb->eap.es_lwrechallenge > 0) { - UNTIMEOUT(srp_lwrechallenge, (void *)pcb); - } - } - - pcb->eap.es_client.ea_state = pcb->eap.es_server.ea_state = eapInitial; - pcb->eap.es_client.ea_requests = pcb->eap.es_server.ea_requests = 0; -#endif /* PPP_SERVER */ -} - -/* - * eap_protrej - Peer doesn't speak this protocol. - * - * This shouldn't happen. If it does, it represents authentication - * failure. - */ -static void eap_protrej(ppp_pcb *pcb) { - - if (eap_client_active(pcb)) { - ppp_error("EAP authentication failed due to Protocol-Reject"); - auth_withpeer_fail(pcb, PPP_EAP); - } -#if PPP_SERVER - if (eap_server_active(pcb)) { - ppp_error("EAP authentication of peer failed on Protocol-Reject"); - auth_peer_fail(pcb, PPP_EAP); - } -#endif /* PPP_SERVER */ - eap_lowerdown(pcb); -} - -/* - * Format and send a regular EAP Response message. - */ -static void eap_send_response(ppp_pcb *pcb, u_char id, u_char typenum, const u_char *str, int lenstr) { - struct pbuf *p; - u_char *outp; - int msglen; - - msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = (u_char*)p->payload; - - MAKEHEADER(outp, PPP_EAP); - - PUTCHAR(EAP_RESPONSE, outp); - PUTCHAR(id, outp); - pcb->eap.es_client.ea_id = id; - PUTSHORT(msglen, outp); - PUTCHAR(typenum, outp); - if (lenstr > 0) { - MEMCPY(outp, str, lenstr); - } - - ppp_write(pcb, p); -} - -/* - * Format and send an MD5-Challenge EAP Response message. - */ -static void eap_chap_response(ppp_pcb *pcb, u_char id, u_char *hash, const char *name, int namelen) { - struct pbuf *p; - u_char *outp; - int msglen; - - msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE + - namelen; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = (u_char*)p->payload; - - MAKEHEADER(outp, PPP_EAP); - - PUTCHAR(EAP_RESPONSE, outp); - PUTCHAR(id, outp); - pcb->eap.es_client.ea_id = id; - PUTSHORT(msglen, outp); - PUTCHAR(EAPT_MD5CHAP, outp); - PUTCHAR(MD5_SIGNATURE_SIZE, outp); - MEMCPY(outp, hash, MD5_SIGNATURE_SIZE); - INCPTR(MD5_SIGNATURE_SIZE, outp); - if (namelen > 0) { - MEMCPY(outp, name, namelen); - } - - ppp_write(pcb, p); -} - -#ifdef USE_SRP -/* - * Format and send a SRP EAP Response message. - */ -static void -eap_srp_response(esp, id, subtypenum, str, lenstr) -eap_state *esp; -u_char id; -u_char subtypenum; -u_char *str; -int lenstr; -{ - ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit]; - struct pbuf *p; - u_char *outp; - int msglen; - - msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = p->payload; - - MAKEHEADER(outp, PPP_EAP); - - PUTCHAR(EAP_RESPONSE, outp); - PUTCHAR(id, outp); - pcb->eap.es_client.ea_id = id; - PUTSHORT(msglen, outp); - PUTCHAR(EAPT_SRP, outp); - PUTCHAR(subtypenum, outp); - if (lenstr > 0) { - MEMCPY(outp, str, lenstr); - } - - ppp_write(pcb, p); -} - -/* - * Format and send a SRP EAP Client Validator Response message. - */ -static void -eap_srpval_response(esp, id, flags, str) -eap_state *esp; -u_char id; -u32_t flags; -u_char *str; -{ - ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit]; - struct pbuf *p; - u_char *outp; - int msglen; - - msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u32_t) + - SHA_DIGESTSIZE; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = p->payload; - - MAKEHEADER(outp, PPP_EAP); - - PUTCHAR(EAP_RESPONSE, outp); - PUTCHAR(id, outp); - pcb->eap.es_client.ea_id = id; - PUTSHORT(msglen, outp); - PUTCHAR(EAPT_SRP, outp); - PUTCHAR(EAPSRP_CVALIDATOR, outp); - PUTLONG(flags, outp); - MEMCPY(outp, str, SHA_DIGESTSIZE); - - ppp_write(pcb, p); -} -#endif /* USE_SRP */ - -static void eap_send_nak(ppp_pcb *pcb, u_char id, u_char type) { - struct pbuf *p; - u_char *outp; - int msglen; - - msglen = EAP_HEADERLEN + 2 * sizeof (u_char); - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = (u_char*)p->payload; - - MAKEHEADER(outp, PPP_EAP); - - PUTCHAR(EAP_RESPONSE, outp); - PUTCHAR(id, outp); - pcb->eap.es_client.ea_id = id; - PUTSHORT(msglen, outp); - PUTCHAR(EAPT_NAK, outp); - PUTCHAR(type, outp); - - ppp_write(pcb, p); -} - -#ifdef USE_SRP -static char * -name_of_pn_file() -{ - char *user, *path, *file; - struct passwd *pw; - size_t pl; - static bool pnlogged = 0; - - pw = getpwuid(getuid()); - if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0) { - errno = EINVAL; - return (NULL); - } - file = _PATH_PSEUDONYM; - pl = strlen(user) + strlen(file) + 2; - path = malloc(pl); - if (path == NULL) - return (NULL); - (void) slprintf(path, pl, "%s/%s", user, file); - if (!pnlogged) { - ppp_dbglog("pseudonym file: %s", path); - pnlogged = 1; - } - return (path); -} - -static int -open_pn_file(modebits) -mode_t modebits; -{ - char *path; - int fd, err; - - if ((path = name_of_pn_file()) == NULL) - return (-1); - fd = open(path, modebits, S_IRUSR | S_IWUSR); - err = errno; - free(path); - errno = err; - return (fd); -} - -static void -remove_pn_file() -{ - char *path; - - if ((path = name_of_pn_file()) != NULL) { - (void) unlink(path); - (void) free(path); - } -} - -static void -write_pseudonym(esp, inp, len, id) -eap_state *esp; -u_char *inp; -int len, id; -{ - u_char val; - u_char *datp, *digp; - SHA1_CTX ctxt; - u_char dig[SHA_DIGESTSIZE]; - int dsize, fd, olen = len; - - /* - * Do the decoding by working backwards. This eliminates the need - * to save the decoded output in a separate buffer. - */ - val = id; - while (len > 0) { - if ((dsize = len % SHA_DIGESTSIZE) == 0) - dsize = SHA_DIGESTSIZE; - len -= dsize; - datp = inp + len; - SHA1Init(&ctxt); - SHA1Update(&ctxt, &val, 1); - SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, SESSION_KEY_LEN); - if (len > 0) { - SHA1Update(&ctxt, datp, SHA_DIGESTSIZE); - } else { - SHA1Update(&ctxt, pcb->eap.es_client.ea_name, - pcb->eap.es_client.ea_namelen); - } - SHA1Final(dig, &ctxt); - for (digp = dig; digp < dig + SHA_DIGESTSIZE; digp++) - *datp++ ^= *digp; - } - - /* Now check that the result is sane */ - if (olen <= 0 || *inp + 1 > olen) { - ppp_dbglog("EAP: decoded pseudonym is unusable <%.*B>", olen, inp); - return; - } - - /* Save it away */ - fd = open_pn_file(O_WRONLY | O_CREAT | O_TRUNC); - if (fd < 0) { - ppp_dbglog("EAP: error saving pseudonym: %m"); - return; - } - len = write(fd, inp + 1, *inp); - if (close(fd) != -1 && len == *inp) { - ppp_dbglog("EAP: saved pseudonym"); - pcb->eap.es_usedpseudo = 0; - } else { - ppp_dbglog("EAP: failed to save pseudonym"); - remove_pn_file(); - } -} -#endif /* USE_SRP */ - -/* - * eap_request - Receive EAP Request message (client mode). - */ -static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { - u_char typenum; - u_char vallen; - int secret_len; - char secret[MAXSECRETLEN]; - char rhostname[MAXNAMELEN]; - lwip_md5_context mdContext; - u_char hash[MD5_SIGNATURE_SIZE]; -#ifdef USE_SRP - struct t_client *tc; - struct t_num sval, gval, Nval, *Ap, Bval; - u_char vals[2]; - SHA1_CTX ctxt; - u_char dig[SHA_DIGESTSIZE]; - int fd; -#endif /* USE_SRP */ - - /* - * Note: we update es_client.ea_id *only if* a Response - * message is being generated. Otherwise, we leave it the - * same for duplicate detection purposes. - */ - - pcb->eap.es_client.ea_requests++; - if (pcb->settings.eap_allow_req != 0 && - pcb->eap.es_client.ea_requests > pcb->settings.eap_allow_req) { - ppp_info("EAP: received too many Request messages"); - if (pcb->settings.eap_req_time > 0) { - UNTIMEOUT(eap_client_timeout, pcb); - } - auth_withpeer_fail(pcb, PPP_EAP); - return; - } - - if (len <= 0) { - ppp_error("EAP: empty Request message discarded"); - return; - } - - GETCHAR(typenum, inp); - len--; - - switch (typenum) { - case EAPT_IDENTITY: - if (len > 0) - ppp_info("EAP: Identity prompt \"%.*q\"", len, inp); -#ifdef USE_SRP - if (pcb->eap.es_usepseudo && - (pcb->eap.es_usedpseudo == 0 || - (pcb->eap.es_usedpseudo == 1 && - id == pcb->eap.es_client.ea_id))) { - pcb->eap.es_usedpseudo = 1; - /* Try to get a pseudonym */ - if ((fd = open_pn_file(O_RDONLY)) >= 0) { - strcpy(rhostname, SRP_PSEUDO_ID); - len = read(fd, rhostname + SRP_PSEUDO_LEN, - sizeof (rhostname) - SRP_PSEUDO_LEN); - /* XXX NAI unsupported */ - if (len > 0) { - eap_send_response(pcb, id, typenum, - rhostname, len + SRP_PSEUDO_LEN); - } - (void) close(fd); - if (len > 0) - break; - } - } - /* Stop using pseudonym now. */ - if (pcb->eap.es_usepseudo && pcb->eap.es_usedpseudo != 2) { - remove_pn_file(); - pcb->eap.es_usedpseudo = 2; - } -#endif /* USE_SRP */ - eap_send_response(pcb, id, typenum, (const u_char*)pcb->eap.es_client.ea_name, - pcb->eap.es_client.ea_namelen); - break; - - case EAPT_NOTIFICATION: - if (len > 0) - ppp_info("EAP: Notification \"%.*q\"", len, inp); - eap_send_response(pcb, id, typenum, NULL, 0); - break; - - case EAPT_NAK: - /* - * Avoid the temptation to send Response Nak in reply - * to Request Nak here. It can only lead to trouble. - */ - ppp_warn("EAP: unexpected Nak in Request; ignored"); - /* Return because we're waiting for something real. */ - return; - - case EAPT_MD5CHAP: - if (len < 1) { - ppp_error("EAP: received MD5-Challenge with no data"); - /* Bogus request; wait for something real. */ - return; - } - GETCHAR(vallen, inp); - len--; - if (vallen < 8 || vallen > len) { - ppp_error("EAP: MD5-Challenge with bad length %d (8..%d)", - vallen, len); - /* Try something better. */ - eap_send_nak(pcb, id, EAPT_SRP); - break; - } - - /* Not so likely to happen. */ - if (vallen >= len + sizeof (rhostname)) { - ppp_dbglog("EAP: trimming really long peer name down"); - MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1); - rhostname[sizeof (rhostname) - 1] = '\0'; - } else { - MEMCPY(rhostname, inp + vallen, len - vallen); - rhostname[len - vallen] = '\0'; - } - -#if PPP_REMOTENAME - /* In case the remote doesn't give us his name. */ - if (pcb->settings.explicit_remote || - (pcb->settings.remote_name[0] != '\0' && vallen == len)) - strlcpy(rhostname, pcb->settings.remote_name, sizeof (rhostname)); -#endif /* PPP_REMOTENAME */ - - /* - * Get the secret for authenticating ourselves with - * the specified host. - */ - if (!get_secret(pcb, pcb->eap.es_client.ea_name, - rhostname, secret, &secret_len, 0)) { - ppp_dbglog("EAP: no MD5 secret for auth to %q", rhostname); - eap_send_nak(pcb, id, EAPT_SRP); - break; - } - lwip_md5_init(&mdContext); - lwip_md5_starts(&mdContext); - typenum = id; - lwip_md5_update(&mdContext, &typenum, 1); - lwip_md5_update(&mdContext, (u_char *)secret, secret_len); - BZERO(secret, sizeof (secret)); - lwip_md5_update(&mdContext, inp, vallen); - lwip_md5_finish(&mdContext, hash); - lwip_md5_free(&mdContext); - eap_chap_response(pcb, id, hash, pcb->eap.es_client.ea_name, - pcb->eap.es_client.ea_namelen); - break; - -#ifdef USE_SRP - case EAPT_SRP: - if (len < 1) { - ppp_error("EAP: received empty SRP Request"); - /* Bogus request; wait for something real. */ - return; - } - - /* Get subtype */ - GETCHAR(vallen, inp); - len--; - switch (vallen) { - case EAPSRP_CHALLENGE: - tc = NULL; - if (pcb->eap.es_client.ea_session != NULL) { - tc = (struct t_client *)pcb->eap.es_client. - ea_session; - /* - * If this is a new challenge, then start - * over with a new client session context. - * Otherwise, just resend last response. - */ - if (id != pcb->eap.es_client.ea_id) { - t_clientclose(tc); - pcb->eap.es_client.ea_session = NULL; - tc = NULL; - } - } - /* No session key just yet */ - pcb->eap.es_client.ea_skey = NULL; - if (tc == NULL) { - int rhostnamelen; - - GETCHAR(vallen, inp); - len--; - if (vallen >= len) { - ppp_error("EAP: badly-formed SRP Challenge" - " (name)"); - /* Ignore badly-formed messages */ - return; - } - MEMCPY(rhostname, inp, vallen); - rhostname[vallen] = '\0'; - INCPTR(vallen, inp); - len -= vallen; - - /* - * In case the remote doesn't give us his name, - * use configured name. - */ - if (explicit_remote || - (remote_name[0] != '\0' && vallen == 0)) { - strlcpy(rhostname, remote_name, - sizeof (rhostname)); - } - - rhostnamelen = (int)strlen(rhostname); - if (rhostnamelen > MAXNAMELEN) { - rhostnamelen = MAXNAMELEN; - } - MEMCPY(pcb->eap.es_client.ea_peer, rhostname, rhostnamelen); - pcb->eap.es_client.ea_peer[rhostnamelen] = '\0'; - pcb->eap.es_client.ea_peerlen = rhostnamelen; - - GETCHAR(vallen, inp); - len--; - if (vallen >= len) { - ppp_error("EAP: badly-formed SRP Challenge" - " (s)"); - /* Ignore badly-formed messages */ - return; - } - sval.data = inp; - sval.len = vallen; - INCPTR(vallen, inp); - len -= vallen; - - GETCHAR(vallen, inp); - len--; - if (vallen > len) { - ppp_error("EAP: badly-formed SRP Challenge" - " (g)"); - /* Ignore badly-formed messages */ - return; - } - /* If no generator present, then use value 2 */ - if (vallen == 0) { - gval.data = (u_char *)"\002"; - gval.len = 1; - } else { - gval.data = inp; - gval.len = vallen; - } - INCPTR(vallen, inp); - len -= vallen; - - /* - * If no modulus present, then use well-known - * value. - */ - if (len == 0) { - Nval.data = (u_char *)wkmodulus; - Nval.len = sizeof (wkmodulus); - } else { - Nval.data = inp; - Nval.len = len; - } - tc = t_clientopen(pcb->eap.es_client.ea_name, - &Nval, &gval, &sval); - if (tc == NULL) { - eap_send_nak(pcb, id, EAPT_MD5CHAP); - break; - } - pcb->eap.es_client.ea_session = (void *)tc; - - /* Add Challenge ID & type to verifier */ - vals[0] = id; - vals[1] = EAPT_SRP; - t_clientaddexdata(tc, vals, 2); - } - Ap = t_clientgenexp(tc); - eap_srp_response(esp, id, EAPSRP_CKEY, Ap->data, - Ap->len); - break; - - case EAPSRP_SKEY: - tc = (struct t_client *)pcb->eap.es_client.ea_session; - if (tc == NULL) { - ppp_warn("EAP: peer sent Subtype 2 without 1"); - eap_send_nak(pcb, id, EAPT_MD5CHAP); - break; - } - if (pcb->eap.es_client.ea_skey != NULL) { - /* - * ID number should not change here. Warn - * if it does (but otherwise ignore). - */ - if (id != pcb->eap.es_client.ea_id) { - ppp_warn("EAP: ID changed from %d to %d " - "in SRP Subtype 2 rexmit", - pcb->eap.es_client.ea_id, id); - } - } else { - if (get_srp_secret(pcb->eap.es_unit, - pcb->eap.es_client.ea_name, - pcb->eap.es_client.ea_peer, secret, 0) == 0) { - /* - * Can't work with this peer because - * the secret is missing. Just give - * up. - */ - eap_send_nak(pcb, id, EAPT_MD5CHAP); - break; - } - Bval.data = inp; - Bval.len = len; - t_clientpasswd(tc, secret); - BZERO(secret, sizeof (secret)); - pcb->eap.es_client.ea_skey = - t_clientgetkey(tc, &Bval); - if (pcb->eap.es_client.ea_skey == NULL) { - /* Server is rogue; stop now */ - ppp_error("EAP: SRP server is rogue"); - goto client_failure; - } - } - eap_srpval_response(esp, id, SRPVAL_EBIT, - t_clientresponse(tc)); - break; - - case EAPSRP_SVALIDATOR: - tc = (struct t_client *)pcb->eap.es_client.ea_session; - if (tc == NULL || pcb->eap.es_client.ea_skey == NULL) { - ppp_warn("EAP: peer sent Subtype 3 without 1/2"); - eap_send_nak(pcb, id, EAPT_MD5CHAP); - break; - } - /* - * If we're already open, then this ought to be a - * duplicate. Otherwise, check that the server is - * who we think it is. - */ - if (pcb->eap.es_client.ea_state == eapOpen) { - if (id != pcb->eap.es_client.ea_id) { - ppp_warn("EAP: ID changed from %d to %d " - "in SRP Subtype 3 rexmit", - pcb->eap.es_client.ea_id, id); - } - } else { - len -= sizeof (u32_t) + SHA_DIGESTSIZE; - if (len < 0 || t_clientverify(tc, inp + - sizeof (u32_t)) != 0) { - ppp_error("EAP: SRP server verification " - "failed"); - goto client_failure; - } - GETLONG(pcb->eap.es_client.ea_keyflags, inp); - /* Save pseudonym if user wants it. */ - if (len > 0 && pcb->eap.es_usepseudo) { - INCPTR(SHA_DIGESTSIZE, inp); - write_pseudonym(esp, inp, len, id); - } - } - /* - * We've verified our peer. We're now mostly done, - * except for waiting on the regular EAP Success - * message. - */ - eap_srp_response(esp, id, EAPSRP_ACK, NULL, 0); - break; - - case EAPSRP_LWRECHALLENGE: - if (len < 4) { - ppp_warn("EAP: malformed Lightweight rechallenge"); - return; - } - SHA1Init(&ctxt); - vals[0] = id; - SHA1Update(&ctxt, vals, 1); - SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, - SESSION_KEY_LEN); - SHA1Update(&ctxt, inp, len); - SHA1Update(&ctxt, pcb->eap.es_client.ea_name, - pcb->eap.es_client.ea_namelen); - SHA1Final(dig, &ctxt); - eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig, - SHA_DIGESTSIZE); - break; - - default: - ppp_error("EAP: unknown SRP Subtype %d", vallen); - eap_send_nak(pcb, id, EAPT_MD5CHAP); - break; - } - break; -#endif /* USE_SRP */ - - default: - ppp_info("EAP: unknown authentication type %d; Naking", typenum); - eap_send_nak(pcb, id, EAPT_SRP); - break; - } - - if (pcb->settings.eap_req_time > 0) { - UNTIMEOUT(eap_client_timeout, pcb); - TIMEOUT(eap_client_timeout, pcb, - pcb->settings.eap_req_time); - } - return; - -#ifdef USE_SRP -client_failure: - pcb->eap.es_client.ea_state = eapBadAuth; - if (pcb->settings.eap_req_time > 0) { - UNTIMEOUT(eap_client_timeout, (void *)esp); - } - pcb->eap.es_client.ea_session = NULL; - t_clientclose(tc); - auth_withpeer_fail(pcb, PPP_EAP); -#endif /* USE_SRP */ -} - -#if PPP_SERVER -/* - * eap_response - Receive EAP Response message (server mode). - */ -static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { - u_char typenum; - u_char vallen; - int secret_len; - char secret[MAXSECRETLEN]; - char rhostname[MAXNAMELEN]; - lwip_md5_context mdContext; - u_char hash[MD5_SIGNATURE_SIZE]; -#ifdef USE_SRP - struct t_server *ts; - struct t_num A; - SHA1_CTX ctxt; - u_char dig[SHA_DIGESTSIZE]; -#endif /* USE_SRP */ - - if (pcb->eap.es_server.ea_id != id) { - ppp_dbglog("EAP: discarding Response %d; expected ID %d", id, - pcb->eap.es_server.ea_id); - return; - } - - pcb->eap.es_server.ea_responses++; - - if (len <= 0) { - ppp_error("EAP: empty Response message discarded"); - return; - } - - GETCHAR(typenum, inp); - len--; - - switch (typenum) { - case EAPT_IDENTITY: - if (pcb->eap.es_server.ea_state != eapIdentify) { - ppp_dbglog("EAP discarding unwanted Identify \"%.q\"", len, - inp); - break; - } - ppp_info("EAP: unauthenticated peer name \"%.*q\"", len, inp); - if (len > MAXNAMELEN) { - len = MAXNAMELEN; - } - MEMCPY(pcb->eap.es_server.ea_peer, inp, len); - pcb->eap.es_server.ea_peer[len] = '\0'; - pcb->eap.es_server.ea_peerlen = len; - eap_figure_next_state(pcb, 0); - break; - - case EAPT_NOTIFICATION: - ppp_dbglog("EAP unexpected Notification; response discarded"); - break; - - case EAPT_NAK: - if (len < 1) { - ppp_info("EAP: Nak Response with no suggested protocol"); - eap_figure_next_state(pcb, 1); - break; - } - - GETCHAR(vallen, inp); - len--; - - if ( -#if PPP_REMOTENAME - !pcb->explicit_remote && -#endif /* PPP_REMOTENAME */ - pcb->eap.es_server.ea_state == eapIdentify){ - /* Peer cannot Nak Identify Request */ - eap_figure_next_state(pcb, 1); - break; - } - - switch (vallen) { - case EAPT_SRP: - /* Run through SRP validator selection again. */ - pcb->eap.es_server.ea_state = eapIdentify; - eap_figure_next_state(pcb, 0); - break; - - case EAPT_MD5CHAP: - pcb->eap.es_server.ea_state = eapMD5Chall; - break; - - default: - ppp_dbglog("EAP: peer requesting unknown Type %d", vallen); - switch (pcb->eap.es_server.ea_state) { - case eapSRP1: - case eapSRP2: - case eapSRP3: - pcb->eap.es_server.ea_state = eapMD5Chall; - break; - case eapMD5Chall: - case eapSRP4: - pcb->eap.es_server.ea_state = eapIdentify; - eap_figure_next_state(pcb, 0); - break; - default: - break; - } - break; - } - break; - - case EAPT_MD5CHAP: - if (pcb->eap.es_server.ea_state != eapMD5Chall) { - ppp_error("EAP: unexpected MD5-Response"); - eap_figure_next_state(pcb, 1); - break; - } - if (len < 1) { - ppp_error("EAP: received MD5-Response with no data"); - eap_figure_next_state(pcb, 1); - break; - } - GETCHAR(vallen, inp); - len--; - if (vallen != 16 || vallen > len) { - ppp_error("EAP: MD5-Response with bad length %d", vallen); - eap_figure_next_state(pcb, 1); - break; - } - - /* Not so likely to happen. */ - if (vallen >= len + sizeof (rhostname)) { - ppp_dbglog("EAP: trimming really long peer name down"); - MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1); - rhostname[sizeof (rhostname) - 1] = '\0'; - } else { - MEMCPY(rhostname, inp + vallen, len - vallen); - rhostname[len - vallen] = '\0'; - } - -#if PPP_REMOTENAME - /* In case the remote doesn't give us his name. */ - if (explicit_remote || - (remote_name[0] != '\0' && vallen == len)) - strlcpy(rhostname, remote_name, sizeof (rhostname)); -#endif /* PPP_REMOTENAME */ - - /* - * Get the secret for authenticating the specified - * host. - */ - if (!get_secret(pcb, rhostname, - pcb->eap.es_server.ea_name, secret, &secret_len, 1)) { - ppp_dbglog("EAP: no MD5 secret for auth of %q", rhostname); - eap_send_failure(pcb); - break; - } - lwip_md5_init(&mdContext); - lwip_md5_starts(&mdContext); - lwip_md5_update(&mdContext, &pcb->eap.es_server.ea_id, 1); - lwip_md5_update(&mdContext, (u_char *)secret, secret_len); - BZERO(secret, sizeof (secret)); - lwip_md5_update(&mdContext, pcb->eap.es_challenge, pcb->eap.es_challen); - lwip_md5_finish(&mdContext, hash); - lwip_md5_free(&mdContext); - if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) { - eap_send_failure(pcb); - break; - } - pcb->eap.es_server.ea_type = EAPT_MD5CHAP; - eap_send_success(pcb); - eap_figure_next_state(pcb, 0); - if (pcb->eap.es_rechallenge != 0) - TIMEOUT(eap_rechallenge, pcb, pcb->eap.es_rechallenge); - break; - -#ifdef USE_SRP - case EAPT_SRP: - if (len < 1) { - ppp_error("EAP: empty SRP Response"); - eap_figure_next_state(pcb, 1); - break; - } - GETCHAR(typenum, inp); - len--; - switch (typenum) { - case EAPSRP_CKEY: - if (pcb->eap.es_server.ea_state != eapSRP1) { - ppp_error("EAP: unexpected SRP Subtype 1 Response"); - eap_figure_next_state(pcb, 1); - break; - } - A.data = inp; - A.len = len; - ts = (struct t_server *)pcb->eap.es_server.ea_session; - assert(ts != NULL); - pcb->eap.es_server.ea_skey = t_servergetkey(ts, &A); - if (pcb->eap.es_server.ea_skey == NULL) { - /* Client's A value is bogus; terminate now */ - ppp_error("EAP: bogus A value from client"); - eap_send_failure(pcb); - } else { - eap_figure_next_state(pcb, 0); - } - break; - - case EAPSRP_CVALIDATOR: - if (pcb->eap.es_server.ea_state != eapSRP2) { - ppp_error("EAP: unexpected SRP Subtype 2 Response"); - eap_figure_next_state(pcb, 1); - break; - } - if (len < sizeof (u32_t) + SHA_DIGESTSIZE) { - ppp_error("EAP: M1 length %d < %d", len, - sizeof (u32_t) + SHA_DIGESTSIZE); - eap_figure_next_state(pcb, 1); - break; - } - GETLONG(pcb->eap.es_server.ea_keyflags, inp); - ts = (struct t_server *)pcb->eap.es_server.ea_session; - assert(ts != NULL); - if (t_serververify(ts, inp)) { - ppp_info("EAP: unable to validate client identity"); - eap_send_failure(pcb); - break; - } - eap_figure_next_state(pcb, 0); - break; - - case EAPSRP_ACK: - if (pcb->eap.es_server.ea_state != eapSRP3) { - ppp_error("EAP: unexpected SRP Subtype 3 Response"); - eap_send_failure(esp); - break; - } - pcb->eap.es_server.ea_type = EAPT_SRP; - eap_send_success(pcb, esp); - eap_figure_next_state(pcb, 0); - if (pcb->eap.es_rechallenge != 0) - TIMEOUT(eap_rechallenge, pcb, - pcb->eap.es_rechallenge); - if (pcb->eap.es_lwrechallenge != 0) - TIMEOUT(srp_lwrechallenge, pcb, - pcb->eap.es_lwrechallenge); - break; - - case EAPSRP_LWRECHALLENGE: - if (pcb->eap.es_server.ea_state != eapSRP4) { - ppp_info("EAP: unexpected SRP Subtype 4 Response"); - return; - } - if (len != SHA_DIGESTSIZE) { - ppp_error("EAP: bad Lightweight rechallenge " - "response"); - return; - } - SHA1Init(&ctxt); - vallen = id; - SHA1Update(&ctxt, &vallen, 1); - SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, - SESSION_KEY_LEN); - SHA1Update(&ctxt, pcb->eap.es_challenge, pcb->eap.es_challen); - SHA1Update(&ctxt, pcb->eap.es_server.ea_peer, - pcb->eap.es_server.ea_peerlen); - SHA1Final(dig, &ctxt); - if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) { - ppp_error("EAP: failed Lightweight rechallenge"); - eap_send_failure(pcb); - break; - } - pcb->eap.es_server.ea_state = eapOpen; - if (pcb->eap.es_lwrechallenge != 0) - TIMEOUT(srp_lwrechallenge, esp, - pcb->eap.es_lwrechallenge); - break; - } - break; -#endif /* USE_SRP */ - - default: - /* This can't happen. */ - ppp_error("EAP: unknown Response type %d; ignored", typenum); - return; - } - - if (pcb->settings.eap_timeout_time > 0) { - UNTIMEOUT(eap_server_timeout, pcb); - } - - if (pcb->eap.es_server.ea_state != eapBadAuth && - pcb->eap.es_server.ea_state != eapOpen) { - pcb->eap.es_server.ea_id++; - eap_send_request(pcb); - } -} -#endif /* PPP_SERVER */ - -/* - * eap_success - Receive EAP Success message (client mode). - */ -static void eap_success(ppp_pcb *pcb, u_char *inp, int id, int len) { - LWIP_UNUSED_ARG(id); - - if (pcb->eap.es_client.ea_state != eapOpen && !eap_client_active(pcb)) { - ppp_dbglog("EAP unexpected success message in state %s (%d)", - eap_state_name(pcb->eap.es_client.ea_state), - pcb->eap.es_client.ea_state); - return; - } - - if (pcb->settings.eap_req_time > 0) { - UNTIMEOUT(eap_client_timeout, pcb); - } - - if (len > 0) { - /* This is odd. The spec doesn't allow for this. */ - PRINTMSG(inp, len); - } - - pcb->eap.es_client.ea_state = eapOpen; - auth_withpeer_success(pcb, PPP_EAP, 0); -} - -/* - * eap_failure - Receive EAP Failure message (client mode). - */ -static void eap_failure(ppp_pcb *pcb, u_char *inp, int id, int len) { - LWIP_UNUSED_ARG(id); - - if (!eap_client_active(pcb)) { - ppp_dbglog("EAP unexpected failure message in state %s (%d)", - eap_state_name(pcb->eap.es_client.ea_state), - pcb->eap.es_client.ea_state); - } - - if (pcb->settings.eap_req_time > 0) { - UNTIMEOUT(eap_client_timeout, pcb); - } - - if (len > 0) { - /* This is odd. The spec doesn't allow for this. */ - PRINTMSG(inp, len); - } - - pcb->eap.es_client.ea_state = eapBadAuth; - - ppp_error("EAP: peer reports authentication failure"); - auth_withpeer_fail(pcb, PPP_EAP); -} - -/* - * eap_input - Handle received EAP message. - */ -static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen) { - u_char code, id; - int len; - - /* - * Parse header (code, id and length). If packet too short, - * drop it. - */ - if (inlen < EAP_HEADERLEN) { - ppp_error("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN); - return; - } - GETCHAR(code, inp); - GETCHAR(id, inp); - GETSHORT(len, inp); - if (len < EAP_HEADERLEN || len > inlen) { - ppp_error("EAP: packet has illegal length field %d (%d..%d)", len, - EAP_HEADERLEN, inlen); - return; - } - len -= EAP_HEADERLEN; - - /* Dispatch based on message code */ - switch (code) { - case EAP_REQUEST: - eap_request(pcb, inp, id, len); - break; - -#if PPP_SERVER - case EAP_RESPONSE: - eap_response(pcb, inp, id, len); - break; -#endif /* PPP_SERVER */ - - case EAP_SUCCESS: - eap_success(pcb, inp, id, len); - break; - - case EAP_FAILURE: - eap_failure(pcb, inp, id, len); - break; - - default: /* XXX Need code reject */ - /* Note: it's not legal to send EAP Nak here. */ - ppp_warn("EAP: unknown code %d received", code); - break; - } -} - -#if PRINTPKT_SUPPORT -/* - * eap_printpkt - print the contents of an EAP packet. - */ -static const char* const eap_codenames[] = { - "Request", "Response", "Success", "Failure" -}; - -static const char* const eap_typenames[] = { - "Identity", "Notification", "Nak", "MD5-Challenge", - "OTP", "Generic-Token", NULL, NULL, - "RSA", "DSS", "KEA", "KEA-Validate", - "TLS", "Defender", "Windows 2000", "Arcot", - "Cisco", "Nokia", "SRP" -}; - -static int eap_printpkt(const u_char *inp, int inlen, void (*printer) (void *, const char *, ...), void *arg) { - int code, id, len, rtype, vallen; - const u_char *pstart; - u32_t uval; - - if (inlen < EAP_HEADERLEN) - return (0); - pstart = inp; - GETCHAR(code, inp); - GETCHAR(id, inp); - GETSHORT(len, inp); - if (len < EAP_HEADERLEN || len > inlen) - return (0); - - if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(eap_codenames)) - printer(arg, " %s", eap_codenames[code-1]); - else - printer(arg, " code=0x%x", code); - printer(arg, " id=0x%x", id); - len -= EAP_HEADERLEN; - switch (code) { - case EAP_REQUEST: - if (len < 1) { - printer(arg, " "); - break; - } - GETCHAR(rtype, inp); - len--; - if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames)) - printer(arg, " %s", eap_typenames[rtype-1]); - else - printer(arg, " type=0x%x", rtype); - switch (rtype) { - case EAPT_IDENTITY: - case EAPT_NOTIFICATION: - if (len > 0) { - printer(arg, " "); - INCPTR(len, inp); - len = 0; - } else { - printer(arg, " "); - } - break; - - case EAPT_MD5CHAP: - if (len <= 0) - break; - GETCHAR(vallen, inp); - len--; - if (vallen > len) - goto truncated; - printer(arg, " ", vallen, inp); - INCPTR(vallen, inp); - len -= vallen; - if (len > 0) { - printer(arg, " "); - INCPTR(len, inp); - len = 0; - } else { - printer(arg, " "); - } - break; - - case EAPT_SRP: - if (len < 3) - goto truncated; - GETCHAR(vallen, inp); - len--; - printer(arg, "-%d", vallen); - switch (vallen) { - case EAPSRP_CHALLENGE: - GETCHAR(vallen, inp); - len--; - if (vallen >= len) - goto truncated; - if (vallen > 0) { - printer(arg, " "); - } else { - printer(arg, " "); - } - INCPTR(vallen, inp); - len -= vallen; - GETCHAR(vallen, inp); - len--; - if (vallen >= len) - goto truncated; - printer(arg, " ", vallen, inp); - INCPTR(vallen, inp); - len -= vallen; - GETCHAR(vallen, inp); - len--; - if (vallen > len) - goto truncated; - if (vallen == 0) { - printer(arg, " "); - } else { - printer(arg, " ", vallen, inp); - } - INCPTR(vallen, inp); - len -= vallen; - if (len == 0) { - printer(arg, " "); - } else { - printer(arg, " ", len, inp); - INCPTR(len, inp); - len = 0; - } - break; - - case EAPSRP_SKEY: - printer(arg, " ", len, inp); - INCPTR(len, inp); - len = 0; - break; - - case EAPSRP_SVALIDATOR: - if (len < (int)sizeof (u32_t)) - break; - GETLONG(uval, inp); - len -= sizeof (u32_t); - if (uval & SRPVAL_EBIT) { - printer(arg, " E"); - uval &= ~SRPVAL_EBIT; - } - if (uval != 0) { - printer(arg, " f<%X>", uval); - } - if ((vallen = len) > SHA_DIGESTSIZE) - vallen = SHA_DIGESTSIZE; - printer(arg, " ", len, inp, - len < SHA_DIGESTSIZE ? "?" : ""); - INCPTR(vallen, inp); - len -= vallen; - if (len > 0) { - printer(arg, " ", len, inp); - INCPTR(len, inp); - len = 0; - } - break; - - case EAPSRP_LWRECHALLENGE: - printer(arg, " ", len, inp); - INCPTR(len, inp); - len = 0; - break; - default: - break; - } - break; - default: - break; - } - break; - - case EAP_RESPONSE: - if (len < 1) - break; - GETCHAR(rtype, inp); - len--; - if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames)) - printer(arg, " %s", eap_typenames[rtype-1]); - else - printer(arg, " type=0x%x", rtype); - switch (rtype) { - case EAPT_IDENTITY: - if (len > 0) { - printer(arg, " "); - INCPTR(len, inp); - len = 0; - } - break; - - case EAPT_NAK: - if (len <= 0) { - printer(arg, " "); - break; - } - GETCHAR(rtype, inp); - len--; - printer(arg, " = 1 && rtype < (int)LWIP_ARRAYSIZE(eap_typenames)) - printer(arg, " (%s)", eap_typenames[rtype-1]); - printer(arg, ">"); - break; - - case EAPT_MD5CHAP: - if (len <= 0) { - printer(arg, " "); - break; - } - GETCHAR(vallen, inp); - len--; - if (vallen > len) - goto truncated; - printer(arg, " ", vallen, inp); - INCPTR(vallen, inp); - len -= vallen; - if (len > 0) { - printer(arg, " "); - INCPTR(len, inp); - len = 0; - } else { - printer(arg, " "); - } - break; - - case EAPT_SRP: - if (len < 1) - goto truncated; - GETCHAR(vallen, inp); - len--; - printer(arg, "-%d", vallen); - switch (vallen) { - case EAPSRP_CKEY: - printer(arg, " ", len, inp); - INCPTR(len, inp); - len = 0; - break; - - case EAPSRP_CVALIDATOR: - if (len < (int)sizeof (u32_t)) - break; - GETLONG(uval, inp); - len -= sizeof (u32_t); - if (uval & SRPVAL_EBIT) { - printer(arg, " E"); - uval &= ~SRPVAL_EBIT; - } - if (uval != 0) { - printer(arg, " f<%X>", uval); - } - printer(arg, " ", len, inp, - len == SHA_DIGESTSIZE ? "" : "?"); - INCPTR(len, inp); - len = 0; - break; - - case EAPSRP_ACK: - break; - - case EAPSRP_LWRECHALLENGE: - printer(arg, " ", len, inp, - len == SHA_DIGESTSIZE ? "" : "?"); - if ((vallen = len) > SHA_DIGESTSIZE) - vallen = SHA_DIGESTSIZE; - INCPTR(vallen, inp); - len -= vallen; - break; - default: - break; - } - break; - default: - break; - } - break; - - case EAP_SUCCESS: /* No payload expected for these! */ - case EAP_FAILURE: - default: - break; - - truncated: - printer(arg, " "); - break; - } - - if (len > 8) - printer(arg, "%8B...", inp); - else if (len > 0) - printer(arg, "%.*B", len, inp); - INCPTR(len, inp); - - return (inp - pstart); -} -#endif /* PRINTPKT_SUPPORT */ - -#endif /* PPP_SUPPORT && EAP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/ecp.c b/ext/lwip/src/netif/ppp/ecp.c deleted file mode 100644 index 4d84f60..0000000 --- a/ext/lwip/src/netif/ppp/ecp.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * ecp.c - 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. - * - * Derived from ccp.c, which is: - * - * 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && ECP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#include - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/fsm.h" -#include "netif/ppp/ecp.h" - -#if PPP_OPTIONS -static option_t ecp_option_list[] = { - { "noecp", o_bool, &ecp_protent.enabled_flag, - "Disable ECP negotiation" }, - { "-ecp", o_bool, &ecp_protent.enabled_flag, - "Disable ECP negotiation", OPT_ALIAS }, - - { NULL } -}; -#endif /* PPP_OPTIONS */ - -/* - * Protocol entry points from main code. - */ -static void ecp_init (int unit); -/* -static void ecp_open (int unit); -static void ecp_close (int unit, char *); -static void ecp_lowerup (int unit); -static void ecp_lowerdown (int); -static void ecp_input (int unit, u_char *pkt, int len); -static void ecp_protrej (int unit); -*/ -#if PRINTPKT_SUPPORT -static int ecp_printpkt (const u_char *pkt, int len, - void (*printer) (void *, char *, ...), - void *arg); -#endif /* PRINTPKT_SUPPORT */ -/* -static void ecp_datainput (int unit, u_char *pkt, int len); -*/ - -const struct protent ecp_protent = { - PPP_ECP, - ecp_init, - NULL, /* ecp_input, */ - NULL, /* ecp_protrej, */ - NULL, /* ecp_lowerup, */ - NULL, /* ecp_lowerdown, */ - NULL, /* ecp_open, */ - NULL, /* ecp_close, */ -#if PRINTPKT_SUPPORT - ecp_printpkt, -#endif /* PRINTPKT_SUPPORT */ -#if PPP_DATAINPUT - NULL, /* ecp_datainput, */ -#endif /* PPP_DATAINPUT */ -#if PRINTPKT_SUPPORT - "ECP", - "Encrypted", -#endif /* PRINTPKT_SUPPORT */ -#if PPP_OPTIONS - ecp_option_list, - NULL, -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT - NULL, - NULL -#endif /* DEMAND_SUPPORT */ -}; - -fsm ecp_fsm[NUM_PPP]; -ecp_options ecp_wantoptions[NUM_PPP]; /* what to request the peer to use */ -ecp_options ecp_gotoptions[NUM_PPP]; /* what the peer agreed to do */ -ecp_options ecp_allowoptions[NUM_PPP]; /* what we'll agree to do */ -ecp_options ecp_hisoptions[NUM_PPP]; /* what we agreed to do */ - -static const fsm_callbacks ecp_callbacks = { - NULL, /* ecp_resetci, */ - NULL, /* ecp_cilen, */ - NULL, /* ecp_addci, */ - NULL, /* ecp_ackci, */ - NULL, /* ecp_nakci, */ - NULL, /* ecp_rejci, */ - NULL, /* ecp_reqci, */ - NULL, /* ecp_up, */ - NULL, /* ecp_down, */ - NULL, - NULL, - NULL, - NULL, - NULL, /* ecp_extcode, */ - "ECP" -}; - -/* - * ecp_init - initialize ECP. - */ -static void -ecp_init(unit) - int unit; -{ - fsm *f = &ecp_fsm[unit]; - - f->unit = unit; - f->protocol = PPP_ECP; - f->callbacks = &ecp_callbacks; - fsm_init(f); - -#if 0 /* Not necessary, everything is cleared in ppp_new() */ - memset(&ecp_wantoptions[unit], 0, sizeof(ecp_options)); - memset(&ecp_gotoptions[unit], 0, sizeof(ecp_options)); - memset(&ecp_allowoptions[unit], 0, sizeof(ecp_options)); - memset(&ecp_hisoptions[unit], 0, sizeof(ecp_options)); -#endif /* 0 */ - -} - - -#if PRINTPKT_SUPPORT -static int -ecp_printpkt(p, plen, printer, arg) - const u_char *p; - int plen; - void (*printer) (void *, char *, ...); - void *arg; -{ - return 0; -} -#endif /* PRINTPKT_SUPPORT */ - -#endif /* PPP_SUPPORT && ECP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/eui64.c b/ext/lwip/src/netif/ppp/eui64.c deleted file mode 100644 index 01493bc..0000000 --- a/ext/lwip/src/netif/ppp/eui64.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * eui64.c - 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.c,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 */ - -#include "netif/ppp/ppp_impl.h" -#include "netif/ppp/eui64.h" - -/* - * eui64_ntoa - Make an ascii representation of an interface identifier - */ -char *eui64_ntoa(eui64_t e) { - static char buf[20]; - - sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x", - e.e8[0], e.e8[1], e.e8[2], e.e8[3], - e.e8[4], e.e8[5], e.e8[6], e.e8[7]); - return buf; -} - -#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/fsm.c b/ext/lwip/src/netif/ppp/fsm.c deleted file mode 100644 index 81eba11..0000000 --- a/ext/lwip/src/netif/ppp/fsm.c +++ /dev/null @@ -1,799 +0,0 @@ -/* - * fsm.c - {Link, IP} Control Protocol Finite State Machine. - * - * 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -/* - * @todo: - * Randomize fsm id on link/init. - * Deal with variable outgoing MTU. - */ - -#if 0 /* UNUSED */ -#include -#include -#include -#endif /* UNUSED */ - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/fsm.h" - -static void fsm_timeout (void *); -static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len); -static void fsm_rconfack(fsm *f, int id, u_char *inp, int len); -static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len); -static void fsm_rtermreq(fsm *f, int id, u_char *p, int len); -static void fsm_rtermack(fsm *f); -static void fsm_rcoderej(fsm *f, u_char *inp, int len); -static void fsm_sconfreq(fsm *f, int retransmit); - -#define PROTO_NAME(f) ((f)->callbacks->proto_name) - -/* - * fsm_init - Initialize fsm. - * - * Initialize fsm state. - */ -void fsm_init(fsm *f) { - ppp_pcb *pcb = f->pcb; - f->state = PPP_FSM_INITIAL; - f->flags = 0; - f->id = 0; /* XXX Start with random id? */ - f->maxnakloops = pcb->settings.fsm_max_nak_loops; - f->term_reason_len = 0; -} - - -/* - * fsm_lowerup - The lower layer is up. - */ -void fsm_lowerup(fsm *f) { - switch( f->state ){ - case PPP_FSM_INITIAL: - f->state = PPP_FSM_CLOSED; - break; - - case PPP_FSM_STARTING: - if( f->flags & OPT_SILENT ) - f->state = PPP_FSM_STOPPED; - else { - /* Send an initial configure-request */ - fsm_sconfreq(f, 0); - f->state = PPP_FSM_REQSENT; - } - break; - - default: - FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state)); - /* no break */ - } -} - - -/* - * fsm_lowerdown - The lower layer is down. - * - * Cancel all timeouts and inform upper layers. - */ -void fsm_lowerdown(fsm *f) { - switch( f->state ){ - case PPP_FSM_CLOSED: - f->state = PPP_FSM_INITIAL; - break; - - case PPP_FSM_STOPPED: - f->state = PPP_FSM_STARTING; - if( f->callbacks->starting ) - (*f->callbacks->starting)(f); - break; - - case PPP_FSM_CLOSING: - f->state = PPP_FSM_INITIAL; - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - break; - - case PPP_FSM_STOPPING: - case PPP_FSM_REQSENT: - case PPP_FSM_ACKRCVD: - case PPP_FSM_ACKSENT: - f->state = PPP_FSM_STARTING; - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - break; - - case PPP_FSM_OPENED: - if( f->callbacks->down ) - (*f->callbacks->down)(f); - f->state = PPP_FSM_STARTING; - break; - - default: - FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state)); - /* no break */ - } -} - - -/* - * fsm_open - Link is allowed to come up. - */ -void fsm_open(fsm *f) { - switch( f->state ){ - case PPP_FSM_INITIAL: - f->state = PPP_FSM_STARTING; - if( f->callbacks->starting ) - (*f->callbacks->starting)(f); - break; - - case PPP_FSM_CLOSED: - if( f->flags & OPT_SILENT ) - f->state = PPP_FSM_STOPPED; - else { - /* Send an initial configure-request */ - fsm_sconfreq(f, 0); - f->state = PPP_FSM_REQSENT; - } - break; - - case PPP_FSM_CLOSING: - f->state = PPP_FSM_STOPPING; - /* fall through */ - /* no break */ - case PPP_FSM_STOPPED: - case PPP_FSM_OPENED: - if( f->flags & OPT_RESTART ){ - fsm_lowerdown(f); - fsm_lowerup(f); - } - break; - default: - break; - } -} - -/* - * terminate_layer - Start process of shutting down the FSM - * - * Cancel any timeout running, notify upper layers we're done, and - * send a terminate-request message as configured. - */ -static void terminate_layer(fsm *f, int nextstate) { - ppp_pcb *pcb = f->pcb; - - if( f->state != PPP_FSM_OPENED ) - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - else if( f->callbacks->down ) - (*f->callbacks->down)(f); /* Inform upper layers we're down */ - - /* Init restart counter and send Terminate-Request */ - f->retransmits = pcb->settings.fsm_max_term_transmits; - fsm_sdata(f, TERMREQ, f->reqid = ++f->id, - (const u_char *) f->term_reason, f->term_reason_len); - - if (f->retransmits == 0) { - /* - * User asked for no terminate requests at all; just close it. - * We've already fired off one Terminate-Request just to be nice - * to the peer, but we're not going to wait for a reply. - */ - f->state = nextstate == PPP_FSM_CLOSING ? PPP_FSM_CLOSED : PPP_FSM_STOPPED; - if( f->callbacks->finished ) - (*f->callbacks->finished)(f); - return; - } - - TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); - --f->retransmits; - - f->state = nextstate; -} - -/* - * fsm_close - Start closing connection. - * - * Cancel timeouts and either initiate close or possibly go directly to - * the PPP_FSM_CLOSED state. - */ -void fsm_close(fsm *f, const char *reason) { - f->term_reason = reason; - f->term_reason_len = (reason == NULL? 0: LWIP_MIN(strlen(reason), 0xFF) ); - switch( f->state ){ - case PPP_FSM_STARTING: - f->state = PPP_FSM_INITIAL; - break; - case PPP_FSM_STOPPED: - f->state = PPP_FSM_CLOSED; - break; - case PPP_FSM_STOPPING: - f->state = PPP_FSM_CLOSING; - break; - - case PPP_FSM_REQSENT: - case PPP_FSM_ACKRCVD: - case PPP_FSM_ACKSENT: - case PPP_FSM_OPENED: - terminate_layer(f, PPP_FSM_CLOSING); - break; - default: - break; - } -} - - -/* - * fsm_timeout - Timeout expired. - */ -static void fsm_timeout(void *arg) { - fsm *f = (fsm *) arg; - ppp_pcb *pcb = f->pcb; - - switch (f->state) { - case PPP_FSM_CLOSING: - case PPP_FSM_STOPPING: - if( f->retransmits <= 0 ){ - /* - * We've waited for an ack long enough. Peer probably heard us. - */ - f->state = (f->state == PPP_FSM_CLOSING)? PPP_FSM_CLOSED: PPP_FSM_STOPPED; - if( f->callbacks->finished ) - (*f->callbacks->finished)(f); - } else { - /* Send Terminate-Request */ - fsm_sdata(f, TERMREQ, f->reqid = ++f->id, - (const u_char *) f->term_reason, f->term_reason_len); - TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); - --f->retransmits; - } - break; - - case PPP_FSM_REQSENT: - case PPP_FSM_ACKRCVD: - case PPP_FSM_ACKSENT: - if (f->retransmits <= 0) { - ppp_warn("%s: timeout sending Config-Requests", PROTO_NAME(f)); - f->state = PPP_FSM_STOPPED; - if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) - (*f->callbacks->finished)(f); - - } else { - /* Retransmit the configure-request */ - if (f->callbacks->retransmit) - (*f->callbacks->retransmit)(f); - fsm_sconfreq(f, 1); /* Re-send Configure-Request */ - if( f->state == PPP_FSM_ACKRCVD ) - f->state = PPP_FSM_REQSENT; - } - break; - - default: - FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state)); - /* no break */ - } -} - - -/* - * fsm_input - Input packet. - */ -void fsm_input(fsm *f, u_char *inpacket, int l) { - u_char *inp; - u_char code, id; - int len; - - /* - * Parse header (code, id and length). - * If packet too short, drop it. - */ - inp = inpacket; - if (l < HEADERLEN) { - FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol)); - return; - } - GETCHAR(code, inp); - GETCHAR(id, inp); - GETSHORT(len, inp); - if (len < HEADERLEN) { - FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol)); - return; - } - if (len > l) { - FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol)); - return; - } - len -= HEADERLEN; /* subtract header length */ - - if( f->state == PPP_FSM_INITIAL || f->state == PPP_FSM_STARTING ){ - FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.", - f->protocol, f->state)); - return; - } - - /* - * Action depends on code. - */ - switch (code) { - case CONFREQ: - fsm_rconfreq(f, id, inp, len); - break; - - case CONFACK: - fsm_rconfack(f, id, inp, len); - break; - - case CONFNAK: - case CONFREJ: - fsm_rconfnakrej(f, code, id, inp, len); - break; - - case TERMREQ: - fsm_rtermreq(f, id, inp, len); - break; - - case TERMACK: - fsm_rtermack(f); - break; - - case CODEREJ: - fsm_rcoderej(f, inp, len); - break; - - default: - if( !f->callbacks->extcode - || !(*f->callbacks->extcode)(f, code, id, inp, len) ) - fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); - break; - } -} - - -/* - * fsm_rconfreq - Receive Configure-Request. - */ -static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) { - int code, reject_if_disagree; - - switch( f->state ){ - case PPP_FSM_CLOSED: - /* Go away, we're closed */ - fsm_sdata(f, TERMACK, id, NULL, 0); - return; - case PPP_FSM_CLOSING: - case PPP_FSM_STOPPING: - return; - - case PPP_FSM_OPENED: - /* Go down and restart negotiation */ - if( f->callbacks->down ) - (*f->callbacks->down)(f); /* Inform upper layers */ - fsm_sconfreq(f, 0); /* Send initial Configure-Request */ - f->state = PPP_FSM_REQSENT; - break; - - case PPP_FSM_STOPPED: - /* Negotiation started by our peer */ - fsm_sconfreq(f, 0); /* Send initial Configure-Request */ - f->state = PPP_FSM_REQSENT; - break; - default: - break; - } - - /* - * Pass the requested configuration options - * to protocol-specific code for checking. - */ - if (f->callbacks->reqci){ /* Check CI */ - reject_if_disagree = (f->nakloops >= f->maxnakloops); - code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); - } else if (len) - code = CONFREJ; /* Reject all CI */ - else - code = CONFACK; - - /* send the Ack, Nak or Rej to the peer */ - fsm_sdata(f, code, id, inp, len); - - if (code == CONFACK) { - if (f->state == PPP_FSM_ACKRCVD) { - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - f->state = PPP_FSM_OPENED; - if (f->callbacks->up) - (*f->callbacks->up)(f); /* Inform upper layers */ - } else - f->state = PPP_FSM_ACKSENT; - f->nakloops = 0; - - } else { - /* we sent CONFACK or CONFREJ */ - if (f->state != PPP_FSM_ACKRCVD) - f->state = PPP_FSM_REQSENT; - if( code == CONFNAK ) - ++f->nakloops; - } -} - - -/* - * fsm_rconfack - Receive Configure-Ack. - */ -static void fsm_rconfack(fsm *f, int id, u_char *inp, int len) { - ppp_pcb *pcb = f->pcb; - - if (id != f->reqid || f->seen_ack) /* Expected id? */ - return; /* Nope, toss... */ - if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): - (len == 0)) ){ - /* Ack is bad - ignore it */ - ppp_error("Received bad configure-ack: %P", inp, len); - return; - } - f->seen_ack = 1; - f->rnakloops = 0; - - switch (f->state) { - case PPP_FSM_CLOSED: - case PPP_FSM_STOPPED: - fsm_sdata(f, TERMACK, id, NULL, 0); - break; - - case PPP_FSM_REQSENT: - f->state = PPP_FSM_ACKRCVD; - f->retransmits = pcb->settings.fsm_max_conf_req_transmits; - break; - - case PPP_FSM_ACKRCVD: - /* Huh? an extra valid Ack? oh well... */ - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - fsm_sconfreq(f, 0); - f->state = PPP_FSM_REQSENT; - break; - - case PPP_FSM_ACKSENT: - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - f->state = PPP_FSM_OPENED; - f->retransmits = pcb->settings.fsm_max_conf_req_transmits; - if (f->callbacks->up) - (*f->callbacks->up)(f); /* Inform upper layers */ - break; - - case PPP_FSM_OPENED: - /* Go down and restart negotiation */ - if (f->callbacks->down) - (*f->callbacks->down)(f); /* Inform upper layers */ - fsm_sconfreq(f, 0); /* Send initial Configure-Request */ - f->state = PPP_FSM_REQSENT; - break; - default: - break; - } -} - - -/* - * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. - */ -static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) { - int ret; - int treat_as_reject; - - if (id != f->reqid || f->seen_ack) /* Expected id? */ - return; /* Nope, toss... */ - - if (code == CONFNAK) { - ++f->rnakloops; - treat_as_reject = (f->rnakloops >= f->maxnakloops); - if (f->callbacks->nakci == NULL - || !(ret = f->callbacks->nakci(f, inp, len, treat_as_reject))) { - ppp_error("Received bad configure-nak: %P", inp, len); - return; - } - } else { - f->rnakloops = 0; - if (f->callbacks->rejci == NULL - || !(ret = f->callbacks->rejci(f, inp, len))) { - ppp_error("Received bad configure-rej: %P", inp, len); - return; - } - } - - f->seen_ack = 1; - - switch (f->state) { - case PPP_FSM_CLOSED: - case PPP_FSM_STOPPED: - fsm_sdata(f, TERMACK, id, NULL, 0); - break; - - case PPP_FSM_REQSENT: - case PPP_FSM_ACKSENT: - /* They didn't agree to what we wanted - try another request */ - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - if (ret < 0) - f->state = PPP_FSM_STOPPED; /* kludge for stopping CCP */ - else - fsm_sconfreq(f, 0); /* Send Configure-Request */ - break; - - case PPP_FSM_ACKRCVD: - /* Got a Nak/reject when we had already had an Ack?? oh well... */ - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - fsm_sconfreq(f, 0); - f->state = PPP_FSM_REQSENT; - break; - - case PPP_FSM_OPENED: - /* Go down and restart negotiation */ - if (f->callbacks->down) - (*f->callbacks->down)(f); /* Inform upper layers */ - fsm_sconfreq(f, 0); /* Send initial Configure-Request */ - f->state = PPP_FSM_REQSENT; - break; - default: - break; - } -} - - -/* - * fsm_rtermreq - Receive Terminate-Req. - */ -static void fsm_rtermreq(fsm *f, int id, u_char *p, int len) { - ppp_pcb *pcb = f->pcb; - - switch (f->state) { - case PPP_FSM_ACKRCVD: - case PPP_FSM_ACKSENT: - f->state = PPP_FSM_REQSENT; /* Start over but keep trying */ - break; - - case PPP_FSM_OPENED: - if (len > 0) { - ppp_info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p); - } else - ppp_info("%s terminated by peer", PROTO_NAME(f)); - f->retransmits = 0; - f->state = PPP_FSM_STOPPING; - if (f->callbacks->down) - (*f->callbacks->down)(f); /* Inform upper layers */ - TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); - break; - default: - break; - } - - fsm_sdata(f, TERMACK, id, NULL, 0); -} - - -/* - * fsm_rtermack - Receive Terminate-Ack. - */ -static void fsm_rtermack(fsm *f) { - switch (f->state) { - case PPP_FSM_CLOSING: - UNTIMEOUT(fsm_timeout, f); - f->state = PPP_FSM_CLOSED; - if( f->callbacks->finished ) - (*f->callbacks->finished)(f); - break; - case PPP_FSM_STOPPING: - UNTIMEOUT(fsm_timeout, f); - f->state = PPP_FSM_STOPPED; - if( f->callbacks->finished ) - (*f->callbacks->finished)(f); - break; - - case PPP_FSM_ACKRCVD: - f->state = PPP_FSM_REQSENT; - break; - - case PPP_FSM_OPENED: - if (f->callbacks->down) - (*f->callbacks->down)(f); /* Inform upper layers */ - fsm_sconfreq(f, 0); - f->state = PPP_FSM_REQSENT; - break; - default: - break; - } -} - - -/* - * fsm_rcoderej - Receive an Code-Reject. - */ -static void fsm_rcoderej(fsm *f, u_char *inp, int len) { - u_char code, id; - - if (len < HEADERLEN) { - FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!")); - return; - } - GETCHAR(code, inp); - GETCHAR(id, inp); - ppp_warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id); - - if( f->state == PPP_FSM_ACKRCVD ) - f->state = PPP_FSM_REQSENT; -} - - -/* - * fsm_protreject - Peer doesn't speak this protocol. - * - * Treat this as a catastrophic error (RXJ-). - */ -void fsm_protreject(fsm *f) { - switch( f->state ){ - case PPP_FSM_CLOSING: - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - /* fall through */ - /* no break */ - case PPP_FSM_CLOSED: - f->state = PPP_FSM_CLOSED; - if( f->callbacks->finished ) - (*f->callbacks->finished)(f); - break; - - case PPP_FSM_STOPPING: - case PPP_FSM_REQSENT: - case PPP_FSM_ACKRCVD: - case PPP_FSM_ACKSENT: - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - /* fall through */ - /* no break */ - case PPP_FSM_STOPPED: - f->state = PPP_FSM_STOPPED; - if( f->callbacks->finished ) - (*f->callbacks->finished)(f); - break; - - case PPP_FSM_OPENED: - terminate_layer(f, PPP_FSM_STOPPING); - break; - - default: - FSMDEBUG(("%s: Protocol-reject event in state %d!", - PROTO_NAME(f), f->state)); - /* no break */ - } -} - - -/* - * fsm_sconfreq - Send a Configure-Request. - */ -static void fsm_sconfreq(fsm *f, int retransmit) { - ppp_pcb *pcb = f->pcb; - struct pbuf *p; - u_char *outp; - int cilen; - - if( f->state != PPP_FSM_REQSENT && f->state != PPP_FSM_ACKRCVD && f->state != PPP_FSM_ACKSENT ){ - /* Not currently negotiating - reset options */ - if( f->callbacks->resetci ) - (*f->callbacks->resetci)(f); - f->nakloops = 0; - f->rnakloops = 0; - } - - if( !retransmit ){ - /* New request - reset retransmission counter, use new ID */ - f->retransmits = pcb->settings.fsm_max_conf_req_transmits; - f->reqid = ++f->id; - } - - f->seen_ack = 0; - - /* - * Make up the request packet - */ - if( f->callbacks->cilen && f->callbacks->addci ){ - cilen = (*f->callbacks->cilen)(f); - if( cilen > pcb->peer_mru - HEADERLEN ) - cilen = pcb->peer_mru - HEADERLEN; - } else - cilen = 0; - - p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - /* send the request to our peer */ - outp = (u_char*)p->payload; - MAKEHEADER(outp, f->protocol); - PUTCHAR(CONFREQ, outp); - PUTCHAR(f->reqid, outp); - PUTSHORT(cilen + HEADERLEN, outp); - if (cilen != 0) { - (*f->callbacks->addci)(f, outp, &cilen); - LWIP_ASSERT("cilen == p->len - HEADERLEN - PPP_HDRLEN", cilen == p->len - HEADERLEN - PPP_HDRLEN); - } - - ppp_write(pcb, p); - - /* start the retransmit timer */ - --f->retransmits; - TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); -} - - -/* - * fsm_sdata - Send some data. - * - * Used for all packets sent to our peer by this module. - */ -void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen) { - ppp_pcb *pcb = f->pcb; - struct pbuf *p; - u_char *outp; - int outlen; - - /* Adjust length to be smaller than MTU */ - if (datalen > pcb->peer_mru - HEADERLEN) - datalen = pcb->peer_mru - HEADERLEN; - outlen = datalen + HEADERLEN; - - p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = (u_char*)p->payload; - if (datalen) /* && data != outp + PPP_HDRLEN + HEADERLEN) -- was only for fsm_sconfreq() */ - MEMCPY(outp + PPP_HDRLEN + HEADERLEN, data, datalen); - MAKEHEADER(outp, f->protocol); - PUTCHAR(code, outp); - PUTCHAR(id, outp); - PUTSHORT(outlen, outp); - ppp_write(pcb, p); -} - -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/ipcp.c b/ext/lwip/src/netif/ppp/ipcp.c deleted file mode 100644 index 2cdcba8..0000000 --- a/ext/lwip/src/netif/ppp/ipcp.c +++ /dev/null @@ -1,2408 +0,0 @@ -/* - * ipcp.c - PPP IP Control Protocol. - * - * 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PPP_IPV4_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -/* - * @todo: - */ - -#if 0 /* UNUSED */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif /* UNUSED */ - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/fsm.h" -#include "netif/ppp/ipcp.h" - -#if 0 /* UNUSED */ -/* global vars */ -u32_t netmask = 0; /* IP netmask to set on interface */ -#endif /* UNUSED */ - -#if 0 /* UNUSED */ -bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */ -#endif /* UNUSED */ - -#if 0 /* moved to ppp_settings */ -bool noremoteip = 0; /* Let him have no IP address */ -#endif /* moved to ppp_setting */ - -#if 0 /* UNUSED */ -/* Hook for a plugin to know when IP protocol has come up */ -void (*ip_up_hook) (void) = NULL; - -/* Hook for a plugin to know when IP protocol has come down */ -void (*ip_down_hook) (void) = NULL; - -/* Hook for a plugin to choose the remote IP address */ -void (*ip_choose_hook) (u32_t *) = NULL; -#endif /* UNUSED */ - -#if PPP_NOTIFY -/* Notifiers for when IPCP goes up and down */ -struct notifier *ip_up_notifier = NULL; -struct notifier *ip_down_notifier = NULL; -#endif /* PPP_NOTIFY */ - -/* local vars */ -#if 0 /* moved to ppp_pcb */ -static int default_route_set[NUM_PPP]; /* Have set up a default route */ -static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */ -static int ipcp_is_up; /* have called np_up() */ -static int ipcp_is_open; /* haven't called np_finished() */ -static bool ask_for_local; /* request our address from peer */ -#endif /* moved to ppp_pcb */ -#if 0 /* UNUSED */ -static char vj_value[8]; /* string form of vj option value */ -static char netmask_str[20]; /* string form of netmask value */ -#endif /* UNUSED */ - -/* - * Callbacks for fsm code. (CI = Configuration Information) - */ -static void ipcp_resetci(fsm *f); /* Reset our CI */ -static int ipcp_cilen(fsm *f); /* Return length of our CI */ -static void ipcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */ -static int ipcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ -static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject);/* Peer nak'd our CI */ -static int ipcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ -static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */ -static void ipcp_up(fsm *f); /* We're UP */ -static void ipcp_down(fsm *f); /* We're DOWN */ -static void ipcp_finished(fsm *f); /* Don't need lower layer */ - -static const fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ - ipcp_resetci, /* Reset our Configuration Information */ - ipcp_cilen, /* Length of our Configuration Information */ - ipcp_addci, /* Add our Configuration Information */ - ipcp_ackci, /* ACK our Configuration Information */ - ipcp_nakci, /* NAK our Configuration Information */ - ipcp_rejci, /* Reject our Configuration Information */ - ipcp_reqci, /* Request peer's Configuration Information */ - ipcp_up, /* Called when fsm reaches OPENED state */ - ipcp_down, /* Called when fsm leaves OPENED state */ - NULL, /* Called when we want the lower layer up */ - ipcp_finished, /* Called when we want the lower layer down */ - NULL, /* Called when Protocol-Reject received */ - NULL, /* Retransmission is necessary */ - NULL, /* Called to handle protocol-specific codes */ - "IPCP" /* String name of protocol */ -}; - -/* - * Command-line options. - */ -#if PPP_OPTIONS -static int setvjslots (char **); -static int setdnsaddr (char **); -static int setwinsaddr (char **); -static int setnetmask (char **); -int setipaddr (char *, char **, int); - -static void printipaddr (option_t *, void (*)(void *, char *,...),void *); - -static option_t ipcp_option_list[] = { - { "noip", o_bool, &ipcp_protent.enabled_flag, - "Disable IP and IPCP" }, - { "-ip", o_bool, &ipcp_protent.enabled_flag, - "Disable IP and IPCP", OPT_ALIAS }, - - { "novj", o_bool, &ipcp_wantoptions[0].neg_vj, - "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj }, - { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj, - "Disable VJ compression", OPT_ALIAS | OPT_A2CLR, - &ipcp_allowoptions[0].neg_vj }, - - { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag, - "Disable VJ connection-ID compression", OPT_A2CLR, - &ipcp_allowoptions[0].cflag }, - { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag, - "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR, - &ipcp_allowoptions[0].cflag }, - - { "vj-max-slots", o_special, (void *)setvjslots, - "Set maximum VJ header slots", - OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value }, - - { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local, - "Accept peer's address for us", 1 }, - { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote, - "Accept peer's address for it", 1 }, - - { "ipparam", o_string, &ipparam, - "Set ip script parameter", OPT_PRIO }, - - { "noipdefault", o_bool, &disable_defaultip, - "Don't use name for default IP adrs", 1 }, - - { "ms-dns", 1, (void *)setdnsaddr, - "DNS address for the peer's use" }, - { "ms-wins", 1, (void *)setwinsaddr, - "Nameserver for SMB over TCP/IP for peer" }, - - { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime, - "Set timeout for IPCP", OPT_PRIO }, - { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits, - "Set max #xmits for term-reqs", OPT_PRIO }, - { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits, - "Set max #xmits for conf-reqs", OPT_PRIO }, - { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops, - "Set max #conf-naks for IPCP", OPT_PRIO }, - - { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route, - "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route }, - { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route, - "disable defaultroute option", OPT_A2CLR, - &ipcp_wantoptions[0].default_route }, - { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route, - "disable defaultroute option", OPT_ALIAS | OPT_A2CLR, - &ipcp_wantoptions[0].default_route }, - - { "replacedefaultroute", o_bool, - &ipcp_wantoptions[0].replace_default_route, - "Replace default route", 1 - }, - { "noreplacedefaultroute", o_bool, - &ipcp_allowoptions[0].replace_default_route, - "Never replace default route", OPT_A2COPY, - &ipcp_wantoptions[0].replace_default_route }, - { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp, - "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp }, - { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, - "disable proxyarp option", OPT_A2CLR, - &ipcp_wantoptions[0].proxy_arp }, - { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, - "disable proxyarp option", OPT_ALIAS | OPT_A2CLR, - &ipcp_wantoptions[0].proxy_arp }, - - { "usepeerdns", o_bool, &usepeerdns, - "Ask peer for DNS address(es)", 1 }, - - { "netmask", o_special, (void *)setnetmask, - "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str }, - - { "ipcp-no-addresses", o_bool, &ipcp_wantoptions[0].old_addrs, - "Disable old-style IP-Addresses usage", OPT_A2CLR, - &ipcp_allowoptions[0].old_addrs }, - { "ipcp-no-address", o_bool, &ipcp_wantoptions[0].neg_addr, - "Disable IP-Address usage", OPT_A2CLR, - &ipcp_allowoptions[0].neg_addr }, - - { "noremoteip", o_bool, &noremoteip, - "Allow peer to have no IP address", 1 }, - - { "nosendip", o_bool, &ipcp_wantoptions[0].neg_addr, - "Don't send our IP address to peer", OPT_A2CLR, - &ipcp_wantoptions[0].old_addrs}, - - { "IP addresses", o_wild, (void *) &setipaddr, - "set local and remote IP addresses", - OPT_NOARG | OPT_A2PRINTER, (void *) &printipaddr }, - - { NULL } -}; -#endif /* PPP_OPTIONS */ - -/* - * Protocol entry points from main code. - */ -static void ipcp_init(ppp_pcb *pcb); -static void ipcp_open(ppp_pcb *pcb); -static void ipcp_close(ppp_pcb *pcb, const char *reason); -static void ipcp_lowerup(ppp_pcb *pcb); -static void ipcp_lowerdown(ppp_pcb *pcb); -static void ipcp_input(ppp_pcb *pcb, u_char *p, int len); -static void ipcp_protrej(ppp_pcb *pcb); -#if PRINTPKT_SUPPORT -static int ipcp_printpkt(const u_char *p, int plen, - void (*printer) (void *, const char *, ...), void *arg); -#endif /* PRINTPKT_SUPPORT */ -#if PPP_OPTIONS -static void ip_check_options (void); -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT -static int ip_demand_conf (int); -static int ip_active_pkt (u_char *, int); -#endif /* DEMAND_SUPPORT */ -#if 0 /* UNUSED */ -static void create_resolv (u32_t, u32_t); -#endif /* UNUSED */ - -const struct protent ipcp_protent = { - PPP_IPCP, - ipcp_init, - ipcp_input, - ipcp_protrej, - ipcp_lowerup, - ipcp_lowerdown, - ipcp_open, - ipcp_close, -#if PRINTPKT_SUPPORT - ipcp_printpkt, -#endif /* PRINTPKT_SUPPORT */ -#if PPP_DATAINPUT - NULL, -#endif /* PPP_DATAINPUT */ -#if PRINTPKT_SUPPORT - "IPCP", - "IP", -#endif /* PRINTPKT_SUPPORT */ -#if PPP_OPTIONS - ipcp_option_list, - ip_check_options, -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT - ip_demand_conf, - ip_active_pkt -#endif /* DEMAND_SUPPORT */ -}; - -static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute); - -/* - * Lengths of configuration options. - */ -#define CILEN_VOID 2 -#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */ -#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */ -#define CILEN_ADDR 6 /* new-style single address option */ -#define CILEN_ADDRS 10 /* old-style dual address option */ - - -#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ - (x) == CONFNAK ? "NAK" : "REJ") - -#if 0 /* UNUSED, already defined by lwIP */ -/* - * Make a string representation of a network IP address. - */ -char * -ip_ntoa(ipaddr) -u32_t ipaddr; -{ - static char b[64]; - - slprintf(b, sizeof(b), "%I", ipaddr); - return b; -} -#endif /* UNUSED, already defined by lwIP */ - -/* - * Option parsing. - */ -#if PPP_OPTIONS -/* - * setvjslots - set maximum number of connection slots for VJ compression - */ -static int -setvjslots(argv) - char **argv; -{ - int value; - -/* FIXME: found what int_option() did */ -#if PPP_OPTIONS - if (!int_option(*argv, &value)) - return 0; -#endif /* PPP_OPTIONS */ - - if (value < 2 || value > 16) { - option_error("vj-max-slots value must be between 2 and 16"); - return 0; - } - ipcp_wantoptions [0].maxslotindex = - ipcp_allowoptions[0].maxslotindex = value - 1; - slprintf(vj_value, sizeof(vj_value), "%d", value); - return 1; -} - -/* - * setdnsaddr - set the dns address(es) - */ -static int -setdnsaddr(argv) - char **argv; -{ - u32_t dns; - struct hostent *hp; - - dns = inet_addr(*argv); - if (dns == (u32_t) -1) { - if ((hp = gethostbyname(*argv)) == NULL) { - option_error("invalid address parameter '%s' for ms-dns option", - *argv); - return 0; - } - dns = *(u32_t *)hp->h_addr; - } - - /* We take the last 2 values given, the 2nd-last as the primary - and the last as the secondary. If only one is given it - becomes both primary and secondary. */ - if (ipcp_allowoptions[0].dnsaddr[1] == 0) - ipcp_allowoptions[0].dnsaddr[0] = dns; - else - ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1]; - - /* always set the secondary address value. */ - ipcp_allowoptions[0].dnsaddr[1] = dns; - - return (1); -} - -/* - * setwinsaddr - set the wins address(es) - * This is primrarly used with the Samba package under UNIX or for pointing - * the caller to the existing WINS server on a Windows NT platform. - */ -static int -setwinsaddr(argv) - char **argv; -{ - u32_t wins; - struct hostent *hp; - - wins = inet_addr(*argv); - if (wins == (u32_t) -1) { - if ((hp = gethostbyname(*argv)) == NULL) { - option_error("invalid address parameter '%s' for ms-wins option", - *argv); - return 0; - } - wins = *(u32_t *)hp->h_addr; - } - - /* We take the last 2 values given, the 2nd-last as the primary - and the last as the secondary. If only one is given it - becomes both primary and secondary. */ - if (ipcp_allowoptions[0].winsaddr[1] == 0) - ipcp_allowoptions[0].winsaddr[0] = wins; - else - ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1]; - - /* always set the secondary address value. */ - ipcp_allowoptions[0].winsaddr[1] = wins; - - return (1); -} - -/* - * setipaddr - Set the IP address - * If doit is 0, the call is to check whether this option is - * potentially an IP address specification. - * Not static so that plugins can call it to set the addresses - */ -int -setipaddr(arg, argv, doit) - char *arg; - char **argv; - int doit; -{ - struct hostent *hp; - char *colon; - u32_t local, remote; - ipcp_options *wo = &ipcp_wantoptions[0]; - static int prio_local = 0, prio_remote = 0; - - /* - * IP address pair separated by ":". - */ - if ((colon = strchr(arg, ':')) == NULL) - return 0; - if (!doit) - return 1; - - /* - * If colon first character, then no local addr. - */ - if (colon != arg && option_priority >= prio_local) { - *colon = '\0'; - if ((local = inet_addr(arg)) == (u32_t) -1) { - if ((hp = gethostbyname(arg)) == NULL) { - option_error("unknown host: %s", arg); - return 0; - } - local = *(u32_t *)hp->h_addr; - } - if (bad_ip_adrs(local)) { - option_error("bad local IP address %s", ip_ntoa(local)); - return 0; - } - if (local != 0) - wo->ouraddr = local; - *colon = ':'; - prio_local = option_priority; - } - - /* - * If colon last character, then no remote addr. - */ - if (*++colon != '\0' && option_priority >= prio_remote) { - if ((remote = inet_addr(colon)) == (u32_t) -1) { - if ((hp = gethostbyname(colon)) == NULL) { - option_error("unknown host: %s", colon); - return 0; - } - remote = *(u32_t *)hp->h_addr; - if (remote_name[0] == 0) - strlcpy(remote_name, colon, sizeof(remote_name)); - } - if (bad_ip_adrs(remote)) { - option_error("bad remote IP address %s", ip_ntoa(remote)); - return 0; - } - if (remote != 0) - wo->hisaddr = remote; - prio_remote = option_priority; - } - - return 1; -} - -static void -printipaddr(opt, printer, arg) - option_t *opt; - void (*printer) (void *, char *, ...); - void *arg; -{ - ipcp_options *wo = &ipcp_wantoptions[0]; - - if (wo->ouraddr != 0) - printer(arg, "%I", wo->ouraddr); - printer(arg, ":"); - if (wo->hisaddr != 0) - printer(arg, "%I", wo->hisaddr); -} - -/* - * setnetmask - set the netmask to be used on the interface. - */ -static int -setnetmask(argv) - char **argv; -{ - u32_t mask; - int n; - char *p; - - /* - * Unfortunately, if we use inet_addr, we can't tell whether - * a result of all 1s is an error or a valid 255.255.255.255. - */ - p = *argv; - n = parse_dotted_ip(p, &mask); - - mask = htonl(mask); - - if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) { - option_error("invalid netmask value '%s'", *argv); - return 0; - } - - netmask = mask; - slprintf(netmask_str, sizeof(netmask_str), "%I", mask); - - return (1); -} - -int -parse_dotted_ip(p, vp) - char *p; - u32_t *vp; -{ - int n; - u32_t v, b; - char *endp, *p0 = p; - - v = 0; - for (n = 3;; --n) { - b = strtoul(p, &endp, 0); - if (endp == p) - return 0; - if (b > 255) { - if (n < 3) - return 0; - /* accept e.g. 0xffffff00 */ - *vp = b; - return endp - p0; - } - v |= b << (n * 8); - p = endp; - if (n == 0) - break; - if (*p != '.') - return 0; - ++p; - } - *vp = v; - return p - p0; -} -#endif /* PPP_OPTIONS */ - -/* - * ipcp_init - Initialize IPCP. - */ -static void ipcp_init(ppp_pcb *pcb) { - fsm *f = &pcb->ipcp_fsm; - - ipcp_options *wo = &pcb->ipcp_wantoptions; - ipcp_options *ao = &pcb->ipcp_allowoptions; - - f->pcb = pcb; - f->protocol = PPP_IPCP; - f->callbacks = &ipcp_callbacks; - fsm_init(f); - - /* - * Some 3G modems use repeated IPCP NAKs as a way of stalling - * until they can contact a server on the network, so we increase - * the default number of NAKs we accept before we start treating - * them as rejects. - */ - f->maxnakloops = 100; - -#if 0 /* Not necessary, everything is cleared in ppp_new() */ - memset(wo, 0, sizeof(*wo)); - memset(ao, 0, sizeof(*ao)); -#endif /* 0 */ - - wo->neg_addr = wo->old_addrs = 1; -#if VJ_SUPPORT - wo->neg_vj = 1; - wo->vj_protocol = IPCP_VJ_COMP; - wo->maxslotindex = MAX_STATES - 1; /* really max index */ - wo->cflag = 1; -#endif /* VJ_SUPPORT */ - -#if 0 /* UNUSED */ - /* wanting default route by default */ - wo->default_route = 1; -#endif /* UNUSED */ - - ao->neg_addr = ao->old_addrs = 1; -#if VJ_SUPPORT - /* max slots and slot-id compression are currently hardwired in */ - /* ppp_if.c to 16 and 1, this needs to be changed (among other */ - /* things) gmc */ - - ao->neg_vj = 1; - ao->maxslotindex = MAX_STATES - 1; - ao->cflag = 1; -#endif /* #if VJ_SUPPORT */ - -#if 0 /* UNUSED */ - /* - * XXX These control whether the user may use the proxyarp - * and defaultroute options. - */ - ao->proxy_arp = 1; - ao->default_route = 1; -#endif /* UNUSED */ -} - - -/* - * ipcp_open - IPCP is allowed to come up. - */ -static void ipcp_open(ppp_pcb *pcb) { - fsm *f = &pcb->ipcp_fsm; - fsm_open(f); - pcb->ipcp_is_open = 1; -} - - -/* - * ipcp_close - Take IPCP down. - */ -static void ipcp_close(ppp_pcb *pcb, const char *reason) { - fsm *f = &pcb->ipcp_fsm; - fsm_close(f, reason); -} - - -/* - * ipcp_lowerup - The lower layer is up. - */ -static void ipcp_lowerup(ppp_pcb *pcb) { - fsm *f = &pcb->ipcp_fsm; - fsm_lowerup(f); -} - - -/* - * ipcp_lowerdown - The lower layer is down. - */ -static void ipcp_lowerdown(ppp_pcb *pcb) { - fsm *f = &pcb->ipcp_fsm; - fsm_lowerdown(f); -} - - -/* - * ipcp_input - Input IPCP packet. - */ -static void ipcp_input(ppp_pcb *pcb, u_char *p, int len) { - fsm *f = &pcb->ipcp_fsm; - fsm_input(f, p, len); -} - - -/* - * ipcp_protrej - A Protocol-Reject was received for IPCP. - * - * Pretend the lower layer went down, so we shut up. - */ -static void ipcp_protrej(ppp_pcb *pcb) { - fsm *f = &pcb->ipcp_fsm; - fsm_lowerdown(f); -} - - -/* - * ipcp_resetci - Reset our CI. - * Called by fsm_sconfreq, Send Configure Request. - */ -static void ipcp_resetci(fsm *f) { - ppp_pcb *pcb = f->pcb; - ipcp_options *wo = &pcb->ipcp_wantoptions; - ipcp_options *go = &pcb->ipcp_gotoptions; - ipcp_options *ao = &pcb->ipcp_allowoptions; - - wo->req_addr = (wo->neg_addr || wo->old_addrs) && - (ao->neg_addr || ao->old_addrs); - if (wo->ouraddr == 0) - wo->accept_local = 1; - if (wo->hisaddr == 0) - wo->accept_remote = 1; -#if LWIP_DNS - wo->req_dns1 = wo->req_dns2 = pcb->settings.usepeerdns; /* Request DNS addresses from the peer */ -#endif /* LWIP_DNS */ - *go = *wo; -#if 0 /* UNUSED */ - /* We don't need ask_for_local, this is only useful for setup which - * can determine the local IP address from the system hostname. - */ - if (!ask_for_local) - go->ouraddr = 0; -#endif /* UNUSED */ -#if 0 /* UNUSED */ - if (ip_choose_hook) { - ip_choose_hook(&wo->hisaddr); - if (wo->hisaddr) { - wo->accept_remote = 0; - } - } -#endif /* UNUSED */ - BZERO(&pcb->ipcp_hisoptions, sizeof(ipcp_options)); -} - - -/* - * ipcp_cilen - Return length of our CI. - * Called by fsm_sconfreq, Send Configure Request. - */ -static int ipcp_cilen(fsm *f) { - ppp_pcb *pcb = f->pcb; - ipcp_options *go = &pcb->ipcp_gotoptions; -#if VJ_SUPPORT - ipcp_options *wo = &pcb->ipcp_wantoptions; -#endif /* VJ_SUPPORT */ - ipcp_options *ho = &pcb->ipcp_hisoptions; - -#define LENCIADDRS(neg) (neg ? CILEN_ADDRS : 0) -#if VJ_SUPPORT -#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) -#endif /* VJ_SUPPORT */ -#define LENCIADDR(neg) (neg ? CILEN_ADDR : 0) -#if LWIP_DNS -#define LENCIDNS(neg) LENCIADDR(neg) -#endif /* LWIP_DNS */ -#if 0 /* UNUSED - WINS */ -#define LENCIWINS(neg) LENCIADDR(neg) -#endif /* UNUSED - WINS */ - - /* - * First see if we want to change our options to the old - * forms because we have received old forms from the peer. - */ - if (go->neg_addr && go->old_addrs && !ho->neg_addr && ho->old_addrs) - go->neg_addr = 0; - -#if VJ_SUPPORT - if (wo->neg_vj && !go->neg_vj && !go->old_vj) { - /* try an older style of VJ negotiation */ - /* use the old style only if the peer did */ - if (ho->neg_vj && ho->old_vj) { - go->neg_vj = 1; - go->old_vj = 1; - go->vj_protocol = ho->vj_protocol; - } - } -#endif /* VJ_SUPPORT */ - - return (LENCIADDRS(!go->neg_addr && go->old_addrs) + -#if VJ_SUPPORT - LENCIVJ(go->neg_vj, go->old_vj) + -#endif /* VJ_SUPPORT */ - LENCIADDR(go->neg_addr) + -#if LWIP_DNS - LENCIDNS(go->req_dns1) + - LENCIDNS(go->req_dns2) + -#endif /* LWIP_DNS */ -#if 0 /* UNUSED - WINS */ - LENCIWINS(go->winsaddr[0]) + - LENCIWINS(go->winsaddr[1]) + -#endif /* UNUSED - WINS */ - 0); -} - - -/* - * ipcp_addci - Add our desired CIs to a packet. - * Called by fsm_sconfreq, Send Configure Request. - */ -static void ipcp_addci(fsm *f, u_char *ucp, int *lenp) { - ppp_pcb *pcb = f->pcb; - ipcp_options *go = &pcb->ipcp_gotoptions; - int len = *lenp; - -#define ADDCIADDRS(opt, neg, val1, val2) \ - if (neg) { \ - if (len >= CILEN_ADDRS) { \ - u32_t l; \ - PUTCHAR(opt, ucp); \ - PUTCHAR(CILEN_ADDRS, ucp); \ - l = ntohl(val1); \ - PUTLONG(l, ucp); \ - l = ntohl(val2); \ - PUTLONG(l, ucp); \ - len -= CILEN_ADDRS; \ - } else \ - go->old_addrs = 0; \ - } - -#if VJ_SUPPORT -#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ - if (neg) { \ - int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ - if (len >= vjlen) { \ - PUTCHAR(opt, ucp); \ - PUTCHAR(vjlen, ucp); \ - PUTSHORT(val, ucp); \ - if (!old) { \ - PUTCHAR(maxslotindex, ucp); \ - PUTCHAR(cflag, ucp); \ - } \ - len -= vjlen; \ - } else \ - neg = 0; \ - } -#endif /* VJ_SUPPORT */ - -#define ADDCIADDR(opt, neg, val) \ - if (neg) { \ - if (len >= CILEN_ADDR) { \ - u32_t l; \ - PUTCHAR(opt, ucp); \ - PUTCHAR(CILEN_ADDR, ucp); \ - l = ntohl(val); \ - PUTLONG(l, ucp); \ - len -= CILEN_ADDR; \ - } else \ - neg = 0; \ - } - -#if LWIP_DNS -#define ADDCIDNS(opt, neg, addr) \ - if (neg) { \ - if (len >= CILEN_ADDR) { \ - u32_t l; \ - PUTCHAR(opt, ucp); \ - PUTCHAR(CILEN_ADDR, ucp); \ - l = ntohl(addr); \ - PUTLONG(l, ucp); \ - len -= CILEN_ADDR; \ - } else \ - neg = 0; \ - } -#endif /* LWIP_DNS */ - -#if 0 /* UNUSED - WINS */ -#define ADDCIWINS(opt, addr) \ - if (addr) { \ - if (len >= CILEN_ADDR) { \ - u32_t l; \ - PUTCHAR(opt, ucp); \ - PUTCHAR(CILEN_ADDR, ucp); \ - l = ntohl(addr); \ - PUTLONG(l, ucp); \ - len -= CILEN_ADDR; \ - } else \ - addr = 0; \ - } -#endif /* UNUSED - WINS */ - - ADDCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, - go->hisaddr); - -#if VJ_SUPPORT - ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, - go->maxslotindex, go->cflag); -#endif /* VJ_SUPPORT */ - - ADDCIADDR(CI_ADDR, go->neg_addr, go->ouraddr); - -#if LWIP_DNS - ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); - - ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); -#endif /* LWIP_DNS */ - -#if 0 /* UNUSED - WINS */ - ADDCIWINS(CI_MS_WINS1, go->winsaddr[0]); - - ADDCIWINS(CI_MS_WINS2, go->winsaddr[1]); -#endif /* UNUSED - WINS */ - - *lenp -= len; -} - - -/* - * ipcp_ackci - Ack our CIs. - * Called by fsm_rconfack, Receive Configure ACK. - * - * Returns: - * 0 - Ack was bad. - * 1 - Ack was good. - */ -static int ipcp_ackci(fsm *f, u_char *p, int len) { - ppp_pcb *pcb = f->pcb; - ipcp_options *go = &pcb->ipcp_gotoptions; - u_short cilen, citype; - u32_t cilong; -#if VJ_SUPPORT - u_short cishort; - u_char cimaxslotindex, cicflag; -#endif /* VJ_SUPPORT */ - - /* - * CIs must be in exactly the same order that we sent... - * Check packet length and CI length at each step. - * If we find any deviations, then this packet is bad. - */ - -#define ACKCIADDRS(opt, neg, val1, val2) \ - if (neg) { \ - u32_t l; \ - if ((len -= CILEN_ADDRS) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_ADDRS || \ - citype != opt) \ - goto bad; \ - GETLONG(l, p); \ - cilong = htonl(l); \ - if (val1 != cilong) \ - goto bad; \ - GETLONG(l, p); \ - cilong = htonl(l); \ - if (val2 != cilong) \ - goto bad; \ - } - -#if VJ_SUPPORT -#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \ - if (neg) { \ - int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ - if ((len -= vjlen) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != vjlen || \ - citype != opt) \ - goto bad; \ - GETSHORT(cishort, p); \ - if (cishort != val) \ - goto bad; \ - if (!old) { \ - GETCHAR(cimaxslotindex, p); \ - if (cimaxslotindex != maxslotindex) \ - goto bad; \ - GETCHAR(cicflag, p); \ - if (cicflag != cflag) \ - goto bad; \ - } \ - } -#endif /* VJ_SUPPORT */ - -#define ACKCIADDR(opt, neg, val) \ - if (neg) { \ - u32_t l; \ - if ((len -= CILEN_ADDR) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_ADDR || \ - citype != opt) \ - goto bad; \ - GETLONG(l, p); \ - cilong = htonl(l); \ - if (val != cilong) \ - goto bad; \ - } - -#if LWIP_DNS -#define ACKCIDNS(opt, neg, addr) \ - if (neg) { \ - u32_t l; \ - if ((len -= CILEN_ADDR) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_ADDR || citype != opt) \ - goto bad; \ - GETLONG(l, p); \ - cilong = htonl(l); \ - if (addr != cilong) \ - goto bad; \ - } -#endif /* LWIP_DNS */ - -#if 0 /* UNUSED - WINS */ -#define ACKCIWINS(opt, addr) \ - if (addr) { \ - u32_t l; \ - if ((len -= CILEN_ADDR) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_ADDR || citype != opt) \ - goto bad; \ - GETLONG(l, p); \ - cilong = htonl(l); \ - if (addr != cilong) \ - goto bad; \ - } -#endif /* UNUSED - WINS */ - - ACKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, - go->hisaddr); - -#if VJ_SUPPORT - ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, - go->maxslotindex, go->cflag); -#endif /* VJ_SUPPORT */ - - ACKCIADDR(CI_ADDR, go->neg_addr, go->ouraddr); - -#if LWIP_DNS - ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); - - ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); -#endif /* LWIP_DNS */ - -#if 0 /* UNUSED - WINS */ - ACKCIWINS(CI_MS_WINS1, go->winsaddr[0]); - - ACKCIWINS(CI_MS_WINS2, go->winsaddr[1]); -#endif /* UNUSED - WINS */ - - /* - * If there are any remaining CIs, then this packet is bad. - */ - if (len != 0) - goto bad; - return (1); - -bad: - IPCPDEBUG(("ipcp_ackci: received bad Ack!")); - return (0); -} - -/* - * ipcp_nakci - Peer has sent a NAK for some of our CIs. - * This should not modify any state if the Nak is bad - * or if IPCP is in the OPENED state. - * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. - * - * Returns: - * 0 - Nak was bad. - * 1 - Nak was good. - */ -static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { - ppp_pcb *pcb = f->pcb; - ipcp_options *go = &pcb->ipcp_gotoptions; - u_char citype, cilen, *next; -#if VJ_SUPPORT - u_char cimaxslotindex, cicflag; - u_short cishort; -#endif /* VJ_SUPPORT */ - u32_t ciaddr1, ciaddr2, l; -#if LWIP_DNS - u32_t cidnsaddr; -#endif /* LWIP_DNS */ - ipcp_options no; /* options we've seen Naks for */ - ipcp_options try_; /* options to request next time */ - - BZERO(&no, sizeof(no)); - try_ = *go; - - /* - * Any Nak'd CIs must be in exactly the same order that we sent. - * Check packet length and CI length at each step. - * If we find any deviations, then this packet is bad. - */ -#define NAKCIADDRS(opt, neg, code) \ - if ((neg) && \ - (cilen = p[1]) == CILEN_ADDRS && \ - len >= cilen && \ - p[0] == opt) { \ - len -= cilen; \ - INCPTR(2, p); \ - GETLONG(l, p); \ - ciaddr1 = htonl(l); \ - GETLONG(l, p); \ - ciaddr2 = htonl(l); \ - no.old_addrs = 1; \ - code \ - } - -#if VJ_SUPPORT -#define NAKCIVJ(opt, neg, code) \ - if (go->neg && \ - ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \ - len >= cilen && \ - p[0] == opt) { \ - len -= cilen; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - no.neg = 1; \ - code \ - } -#endif /* VJ_SUPPORT */ - -#define NAKCIADDR(opt, neg, code) \ - if (go->neg && \ - (cilen = p[1]) == CILEN_ADDR && \ - len >= cilen && \ - p[0] == opt) { \ - len -= cilen; \ - INCPTR(2, p); \ - GETLONG(l, p); \ - ciaddr1 = htonl(l); \ - no.neg = 1; \ - code \ - } - -#if LWIP_DNS -#define NAKCIDNS(opt, neg, code) \ - if (go->neg && \ - ((cilen = p[1]) == CILEN_ADDR) && \ - len >= cilen && \ - p[0] == opt) { \ - len -= cilen; \ - INCPTR(2, p); \ - GETLONG(l, p); \ - cidnsaddr = htonl(l); \ - no.neg = 1; \ - code \ - } -#endif /* LWIP_DNS */ - - /* - * Accept the peer's idea of {our,his} address, if different - * from our idea, only if the accept_{local,remote} flag is set. - */ - NAKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, - if (treat_as_reject) { - try_.old_addrs = 0; - } else { - if (go->accept_local && ciaddr1) { - /* take his idea of our address */ - try_.ouraddr = ciaddr1; - } - if (go->accept_remote && ciaddr2) { - /* take his idea of his address */ - try_.hisaddr = ciaddr2; - } - } - ); - -#if VJ_SUPPORT - /* - * Accept the peer's value of maxslotindex provided that it - * is less than what we asked for. Turn off slot-ID compression - * if the peer wants. Send old-style compress-type option if - * the peer wants. - */ - NAKCIVJ(CI_COMPRESSTYPE, neg_vj, - if (treat_as_reject) { - try_.neg_vj = 0; - } else if (cilen == CILEN_VJ) { - GETCHAR(cimaxslotindex, p); - GETCHAR(cicflag, p); - if (cishort == IPCP_VJ_COMP) { - try_.old_vj = 0; - if (cimaxslotindex < go->maxslotindex) - try_.maxslotindex = cimaxslotindex; - if (!cicflag) - try_.cflag = 0; - } else { - try_.neg_vj = 0; - } - } else { - if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) { - try_.old_vj = 1; - try_.vj_protocol = cishort; - } else { - try_.neg_vj = 0; - } - } - ); -#endif /* VJ_SUPPORT */ - - NAKCIADDR(CI_ADDR, neg_addr, - if (treat_as_reject) { - try_.neg_addr = 0; - try_.old_addrs = 0; - } else if (go->accept_local && ciaddr1) { - /* take his idea of our address */ - try_.ouraddr = ciaddr1; - } - ); - -#if LWIP_DNS - NAKCIDNS(CI_MS_DNS1, req_dns1, - if (treat_as_reject) { - try_.req_dns1 = 0; - } else { - try_.dnsaddr[0] = cidnsaddr; - } - ); - - NAKCIDNS(CI_MS_DNS2, req_dns2, - if (treat_as_reject) { - try_.req_dns2 = 0; - } else { - try_.dnsaddr[1] = cidnsaddr; - } - ); -#endif /* #if LWIP_DNS */ - - /* - * There may be remaining CIs, if the peer is requesting negotiation - * on an option that we didn't include in our request packet. - * If they want to negotiate about IP addresses, we comply. - * If they want us to ask for compression, we refuse. - * If they want us to ask for ms-dns, we do that, since some - * peers get huffy if we don't. - */ - while (len >= CILEN_VOID) { - GETCHAR(citype, p); - GETCHAR(cilen, p); - if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) - goto bad; - next = p + cilen - 2; - - switch (citype) { -#if VJ_SUPPORT - case CI_COMPRESSTYPE: - if (go->neg_vj || no.neg_vj || - (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) - goto bad; - no.neg_vj = 1; - break; -#endif /* VJ_SUPPORT */ - case CI_ADDRS: - if ((!go->neg_addr && go->old_addrs) || no.old_addrs - || cilen != CILEN_ADDRS) - goto bad; - try_.neg_addr = 0; - GETLONG(l, p); - ciaddr1 = htonl(l); - if (ciaddr1 && go->accept_local) - try_.ouraddr = ciaddr1; - GETLONG(l, p); - ciaddr2 = htonl(l); - if (ciaddr2 && go->accept_remote) - try_.hisaddr = ciaddr2; - no.old_addrs = 1; - break; - case CI_ADDR: - if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) - goto bad; - try_.old_addrs = 0; - GETLONG(l, p); - ciaddr1 = htonl(l); - if (ciaddr1 && go->accept_local) - try_.ouraddr = ciaddr1; - if (try_.ouraddr != 0) - try_.neg_addr = 1; - no.neg_addr = 1; - break; -#if LWIP_DNS - case CI_MS_DNS1: - if (go->req_dns1 || no.req_dns1 || cilen != CILEN_ADDR) - goto bad; - GETLONG(l, p); - try_.dnsaddr[0] = htonl(l); - try_.req_dns1 = 1; - no.req_dns1 = 1; - break; - case CI_MS_DNS2: - if (go->req_dns2 || no.req_dns2 || cilen != CILEN_ADDR) - goto bad; - GETLONG(l, p); - try_.dnsaddr[1] = htonl(l); - try_.req_dns2 = 1; - no.req_dns2 = 1; - break; -#endif /* LWIP_DNS */ -#if 0 /* UNUSED - WINS */ - case CI_MS_WINS1: - case CI_MS_WINS2: - if (cilen != CILEN_ADDR) - goto bad; - GETLONG(l, p); - ciaddr1 = htonl(l); - if (ciaddr1) - try_.winsaddr[citype == CI_MS_WINS2] = ciaddr1; - break; -#endif /* UNUSED - WINS */ - default: - break; - } - p = next; - } - - /* - * OK, the Nak is good. Now we can update state. - * If there are any remaining options, we ignore them. - */ - if (f->state != PPP_FSM_OPENED) - *go = try_; - - return 1; - -bad: - IPCPDEBUG(("ipcp_nakci: received bad Nak!")); - return 0; -} - - -/* - * ipcp_rejci - Reject some of our CIs. - * Callback from fsm_rconfnakrej. - */ -static int ipcp_rejci(fsm *f, u_char *p, int len) { - ppp_pcb *pcb = f->pcb; - ipcp_options *go = &pcb->ipcp_gotoptions; - u_char cilen; -#if VJ_SUPPORT - u_char cimaxslotindex, ciflag; - u_short cishort; -#endif /* VJ_SUPPORT */ - u32_t cilong; - ipcp_options try_; /* options to request next time */ - - try_ = *go; - /* - * Any Rejected CIs must be in exactly the same order that we sent. - * Check packet length and CI length at each step. - * If we find any deviations, then this packet is bad. - */ -#define REJCIADDRS(opt, neg, val1, val2) \ - if ((neg) && \ - (cilen = p[1]) == CILEN_ADDRS && \ - len >= cilen && \ - p[0] == opt) { \ - u32_t l; \ - len -= cilen; \ - INCPTR(2, p); \ - GETLONG(l, p); \ - cilong = htonl(l); \ - /* Check rejected value. */ \ - if (cilong != val1) \ - goto bad; \ - GETLONG(l, p); \ - cilong = htonl(l); \ - /* Check rejected value. */ \ - if (cilong != val2) \ - goto bad; \ - try_.old_addrs = 0; \ - } - -#if VJ_SUPPORT -#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \ - if (go->neg && \ - p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \ - len >= p[1] && \ - p[0] == opt) { \ - len -= p[1]; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - /* Check rejected value. */ \ - if (cishort != val) \ - goto bad; \ - if (!old) { \ - GETCHAR(cimaxslotindex, p); \ - if (cimaxslotindex != maxslot) \ - goto bad; \ - GETCHAR(ciflag, p); \ - if (ciflag != cflag) \ - goto bad; \ - } \ - try_.neg = 0; \ - } -#endif /* VJ_SUPPORT */ - -#define REJCIADDR(opt, neg, val) \ - if (go->neg && \ - (cilen = p[1]) == CILEN_ADDR && \ - len >= cilen && \ - p[0] == opt) { \ - u32_t l; \ - len -= cilen; \ - INCPTR(2, p); \ - GETLONG(l, p); \ - cilong = htonl(l); \ - /* Check rejected value. */ \ - if (cilong != val) \ - goto bad; \ - try_.neg = 0; \ - } - -#if LWIP_DNS -#define REJCIDNS(opt, neg, dnsaddr) \ - if (go->neg && \ - ((cilen = p[1]) == CILEN_ADDR) && \ - len >= cilen && \ - p[0] == opt) { \ - u32_t l; \ - len -= cilen; \ - INCPTR(2, p); \ - GETLONG(l, p); \ - cilong = htonl(l); \ - /* Check rejected value. */ \ - if (cilong != dnsaddr) \ - goto bad; \ - try_.neg = 0; \ - } -#endif /* LWIP_DNS */ - -#if 0 /* UNUSED - WINS */ -#define REJCIWINS(opt, addr) \ - if (addr && \ - ((cilen = p[1]) == CILEN_ADDR) && \ - len >= cilen && \ - p[0] == opt) { \ - u32_t l; \ - len -= cilen; \ - INCPTR(2, p); \ - GETLONG(l, p); \ - cilong = htonl(l); \ - /* Check rejected value. */ \ - if (cilong != addr) \ - goto bad; \ - try_.winsaddr[opt == CI_MS_WINS2] = 0; \ - } -#endif /* UNUSED - WINS */ - - REJCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, - go->ouraddr, go->hisaddr); - -#if VJ_SUPPORT - REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, - go->maxslotindex, go->cflag); -#endif /* VJ_SUPPORT */ - - REJCIADDR(CI_ADDR, neg_addr, go->ouraddr); - -#if LWIP_DNS - REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]); - - REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]); -#endif /* LWIP_DNS */ - -#if 0 /* UNUSED - WINS */ - REJCIWINS(CI_MS_WINS1, go->winsaddr[0]); - - REJCIWINS(CI_MS_WINS2, go->winsaddr[1]); -#endif /* UNUSED - WINS */ - - /* - * If there are any remaining CIs, then this packet is bad. - */ - if (len != 0) - goto bad; - /* - * Now we can update state. - */ - if (f->state != PPP_FSM_OPENED) - *go = try_; - return 1; - -bad: - IPCPDEBUG(("ipcp_rejci: received bad Reject!")); - return 0; -} - - -/* - * ipcp_reqci - Check the peer's requested CIs and send appropriate response. - * Callback from fsm_rconfreq, Receive Configure Request - * - * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified - * appropriately. If reject_if_disagree is non-zero, doesn't return - * CONFNAK; returns CONFREJ if it can't return CONFACK. - * - * inp = Requested CIs - * len = Length of requested CIs - */ -static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { - ppp_pcb *pcb = f->pcb; - ipcp_options *wo = &pcb->ipcp_wantoptions; - ipcp_options *ho = &pcb->ipcp_hisoptions; - ipcp_options *ao = &pcb->ipcp_allowoptions; - u_char *cip, *next; /* Pointer to current and next CIs */ - u_short cilen, citype; /* Parsed len, type */ -#if VJ_SUPPORT - u_short cishort; /* Parsed short value */ -#endif /* VJ_SUPPORT */ - u32_t tl, ciaddr1, ciaddr2;/* Parsed address values */ - int rc = CONFACK; /* Final packet return code */ - int orc; /* Individual option return code */ - u_char *p; /* Pointer to next char to parse */ - u_char *ucp = inp; /* Pointer to current output char */ - int l = *len; /* Length left */ -#if VJ_SUPPORT - u_char maxslotindex, cflag; -#endif /* VJ_SUPPORT */ -#if LWIP_DNS - int d; -#endif /* LWIP_DNS */ - - /* - * Reset all his options. - */ - BZERO(ho, sizeof(*ho)); - - /* - * Process all his options. - */ - next = inp; - while (l) { - orc = CONFACK; /* Assume success */ - cip = p = next; /* Remember begining of CI */ - if (l < 2 || /* Not enough data for CI header or */ - p[1] < 2 || /* CI length too small or */ - p[1] > l) { /* CI length too big? */ - IPCPDEBUG(("ipcp_reqci: bad CI length!")); - orc = CONFREJ; /* Reject bad CI */ - cilen = l; /* Reject till end of packet */ - l = 0; /* Don't loop again */ - goto endswitch; - } - GETCHAR(citype, p); /* Parse CI type */ - GETCHAR(cilen, p); /* Parse CI length */ - l -= cilen; /* Adjust remaining length */ - next += cilen; /* Step to next CI */ - - switch (citype) { /* Check CI type */ - case CI_ADDRS: - if (!ao->old_addrs || ho->neg_addr || - cilen != CILEN_ADDRS) { /* Check CI length */ - orc = CONFREJ; /* Reject CI */ - break; - } - - /* - * If he has no address, or if we both have his address but - * disagree about it, then NAK it with our idea. - * In particular, if we don't know his address, but he does, - * then accept it. - */ - GETLONG(tl, p); /* Parse source address (his) */ - ciaddr1 = htonl(tl); - if (ciaddr1 != wo->hisaddr - && (ciaddr1 == 0 || !wo->accept_remote)) { - orc = CONFNAK; - if (!reject_if_disagree) { - DECPTR(sizeof(u32_t), p); - tl = ntohl(wo->hisaddr); - PUTLONG(tl, p); - } - } else if (ciaddr1 == 0 && wo->hisaddr == 0) { - /* - * If neither we nor he knows his address, reject the option. - */ - orc = CONFREJ; - wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ - break; - } - - /* - * If he doesn't know our address, or if we both have our address - * but disagree about it, then NAK it with our idea. - */ - GETLONG(tl, p); /* Parse desination address (ours) */ - ciaddr2 = htonl(tl); - if (ciaddr2 != wo->ouraddr) { - if (ciaddr2 == 0 || !wo->accept_local) { - orc = CONFNAK; - if (!reject_if_disagree) { - DECPTR(sizeof(u32_t), p); - tl = ntohl(wo->ouraddr); - PUTLONG(tl, p); - } - } else { - wo->ouraddr = ciaddr2; /* accept peer's idea */ - } - } - - ho->old_addrs = 1; - ho->hisaddr = ciaddr1; - ho->ouraddr = ciaddr2; - break; - - case CI_ADDR: - if (!ao->neg_addr || ho->old_addrs || - cilen != CILEN_ADDR) { /* Check CI length */ - orc = CONFREJ; /* Reject CI */ - break; - } - - /* - * If he has no address, or if we both have his address but - * disagree about it, then NAK it with our idea. - * In particular, if we don't know his address, but he does, - * then accept it. - */ - GETLONG(tl, p); /* Parse source address (his) */ - ciaddr1 = htonl(tl); - if (ciaddr1 != wo->hisaddr - && (ciaddr1 == 0 || !wo->accept_remote)) { - orc = CONFNAK; - if (!reject_if_disagree) { - DECPTR(sizeof(u32_t), p); - tl = ntohl(wo->hisaddr); - PUTLONG(tl, p); - } - } else if (ciaddr1 == 0 && wo->hisaddr == 0) { - /* - * Don't ACK an address of 0.0.0.0 - reject it instead. - */ - orc = CONFREJ; - wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ - break; - } - - ho->neg_addr = 1; - ho->hisaddr = ciaddr1; - break; - -#if LWIP_DNS - case CI_MS_DNS1: - case CI_MS_DNS2: - /* Microsoft primary or secondary DNS request */ - d = citype == CI_MS_DNS2; - - /* If we do not have a DNS address then we cannot send it */ - if (ao->dnsaddr[d] == 0 || - cilen != CILEN_ADDR) { /* Check CI length */ - orc = CONFREJ; /* Reject CI */ - break; - } - GETLONG(tl, p); - if (htonl(tl) != ao->dnsaddr[d]) { - DECPTR(sizeof(u32_t), p); - tl = ntohl(ao->dnsaddr[d]); - PUTLONG(tl, p); - orc = CONFNAK; - } - break; -#endif /* LWIP_DNS */ - -#if 0 /* UNUSED - WINS */ - case CI_MS_WINS1: - case CI_MS_WINS2: - /* Microsoft primary or secondary WINS request */ - d = citype == CI_MS_WINS2; - - /* If we do not have a DNS address then we cannot send it */ - if (ao->winsaddr[d] == 0 || - cilen != CILEN_ADDR) { /* Check CI length */ - orc = CONFREJ; /* Reject CI */ - break; - } - GETLONG(tl, p); - if (htonl(tl) != ao->winsaddr[d]) { - DECPTR(sizeof(u32_t), p); - tl = ntohl(ao->winsaddr[d]); - PUTLONG(tl, p); - orc = CONFNAK; - } - break; -#endif /* UNUSED - WINS */ - -#if VJ_SUPPORT - case CI_COMPRESSTYPE: - if (!ao->neg_vj || - (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) { - orc = CONFREJ; - break; - } - GETSHORT(cishort, p); - - if (!(cishort == IPCP_VJ_COMP || - (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { - orc = CONFREJ; - break; - } - - ho->neg_vj = 1; - ho->vj_protocol = cishort; - if (cilen == CILEN_VJ) { - GETCHAR(maxslotindex, p); - if (maxslotindex > ao->maxslotindex) { - orc = CONFNAK; - if (!reject_if_disagree){ - DECPTR(1, p); - PUTCHAR(ao->maxslotindex, p); - } - } - GETCHAR(cflag, p); - if (cflag && !ao->cflag) { - orc = CONFNAK; - if (!reject_if_disagree){ - DECPTR(1, p); - PUTCHAR(wo->cflag, p); - } - } - ho->maxslotindex = maxslotindex; - ho->cflag = cflag; - } else { - ho->old_vj = 1; - ho->maxslotindex = MAX_STATES - 1; - ho->cflag = 1; - } - break; -#endif /* VJ_SUPPORT */ - - default: - orc = CONFREJ; - break; - } -endswitch: - if (orc == CONFACK && /* Good CI */ - rc != CONFACK) /* but prior CI wasnt? */ - continue; /* Don't send this one */ - - if (orc == CONFNAK) { /* Nak this CI? */ - if (reject_if_disagree) /* Getting fed up with sending NAKs? */ - orc = CONFREJ; /* Get tough if so */ - else { - if (rc == CONFREJ) /* Rejecting prior CI? */ - continue; /* Don't send this one */ - if (rc == CONFACK) { /* Ack'd all prior CIs? */ - rc = CONFNAK; /* Not anymore... */ - ucp = inp; /* Backup */ - } - } - } - - if (orc == CONFREJ && /* Reject this CI */ - rc != CONFREJ) { /* but no prior ones? */ - rc = CONFREJ; - ucp = inp; /* Backup */ - } - - /* Need to move CI? */ - if (ucp != cip) - MEMCPY(ucp, cip, cilen); /* Move it */ - - /* Update output pointer */ - INCPTR(cilen, ucp); - } - - /* - * If we aren't rejecting this packet, and we want to negotiate - * their address, and they didn't send their address, then we - * send a NAK with a CI_ADDR option appended. We assume the - * input buffer is long enough that we can append the extra - * option safely. - */ - if (rc != CONFREJ && !ho->neg_addr && !ho->old_addrs && - wo->req_addr && !reject_if_disagree && !pcb->settings.noremoteip) { - if (rc == CONFACK) { - rc = CONFNAK; - ucp = inp; /* reset pointer */ - wo->req_addr = 0; /* don't ask again */ - } - PUTCHAR(CI_ADDR, ucp); - PUTCHAR(CILEN_ADDR, ucp); - tl = ntohl(wo->hisaddr); - PUTLONG(tl, ucp); - } - - *len = ucp - inp; /* Compute output length */ - IPCPDEBUG(("ipcp: returning Configure-%s", CODENAME(rc))); - return (rc); /* Return final code */ -} - - -#if 0 /* UNUSED */ -/* - * ip_check_options - check that any IP-related options are OK, - * and assign appropriate defaults. - */ -static void -ip_check_options() -{ - struct hostent *hp; - u32_t local; - ipcp_options *wo = &ipcp_wantoptions[0]; - - /* - * Default our local IP address based on our hostname. - * If local IP address already given, don't bother. - */ - if (wo->ouraddr == 0 && !disable_defaultip) { - /* - * Look up our hostname (possibly with domain name appended) - * and take the first IP address as our local IP address. - * If there isn't an IP address for our hostname, too bad. - */ - wo->accept_local = 1; /* don't insist on this default value */ - if ((hp = gethostbyname(hostname)) != NULL) { - local = *(u32_t *)hp->h_addr; - if (local != 0 && !bad_ip_adrs(local)) - wo->ouraddr = local; - } - } - ask_for_local = wo->ouraddr != 0 || !disable_defaultip; -} -#endif /* UNUSED */ - -#if DEMAND_SUPPORT -/* - * ip_demand_conf - configure the interface as though - * IPCP were up, for use with dial-on-demand. - */ -static int -ip_demand_conf(u) - int u; -{ - ppp_pcb *pcb = &ppp_pcb_list[u]; - ipcp_options *wo = &ipcp_wantoptions[u]; - - if (wo->hisaddr == 0 && !pcb->settings.noremoteip) { - /* make up an arbitrary address for the peer */ - wo->hisaddr = htonl(0x0a707070 + ifunit); - wo->accept_remote = 1; - } - if (wo->ouraddr == 0) { - /* make up an arbitrary address for us */ - wo->ouraddr = htonl(0x0a404040 + ifunit); - wo->accept_local = 1; - ask_for_local = 0; /* don't tell the peer this address */ - } - if (!sifaddr(pcb, wo->ouraddr, wo->hisaddr, get_mask(wo->ouraddr))) - return 0; - if (!sifup(pcb)) - return 0; - if (!sifnpmode(pcb, PPP_IP, NPMODE_QUEUE)) - return 0; -#if 0 /* UNUSED */ - if (wo->default_route) - if (sifdefaultroute(pcb, wo->ouraddr, wo->hisaddr, - wo->replace_default_route)) - default_route_set[u] = 1; -#endif /* UNUSED */ -#if 0 /* UNUSED - PROXY ARP */ - if (wo->proxy_arp) - if (sifproxyarp(pcb, wo->hisaddr)) - proxy_arp_set[u] = 1; -#endif /* UNUSED - PROXY ARP */ - - ppp_notice("local IP address %I", wo->ouraddr); - if (wo->hisaddr) - ppp_notice("remote IP address %I", wo->hisaddr); - - return 1; -} -#endif /* DEMAND_SUPPORT */ - -/* - * ipcp_up - IPCP has come UP. - * - * Configure the IP network interface appropriately and bring it up. - */ -static void ipcp_up(fsm *f) { - ppp_pcb *pcb = f->pcb; - u32_t mask; - ipcp_options *ho = &pcb->ipcp_hisoptions; - ipcp_options *go = &pcb->ipcp_gotoptions; - ipcp_options *wo = &pcb->ipcp_wantoptions; - - IPCPDEBUG(("ipcp: up")); - - /* - * We must have a non-zero IP address for both ends of the link. - */ - if (!ho->neg_addr && !ho->old_addrs) - ho->hisaddr = wo->hisaddr; - - if (!(go->neg_addr || go->old_addrs) && (wo->neg_addr || wo->old_addrs) - && wo->ouraddr != 0) { - ppp_error("Peer refused to agree to our IP address"); - ipcp_close(f->pcb, "Refused our IP address"); - return; - } - if (go->ouraddr == 0) { - ppp_error("Could not determine local IP address"); - ipcp_close(f->pcb, "Could not determine local IP address"); - return; - } - if (ho->hisaddr == 0 && !pcb->settings.noremoteip) { - ho->hisaddr = htonl(0x0a404040); - ppp_warn("Could not determine remote IP address: defaulting to %I", - ho->hisaddr); - } -#if 0 /* UNUSED */ - script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0); - if (ho->hisaddr != 0) - script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1); -#endif /* UNUSED */ - -#if LWIP_DNS - if (!go->req_dns1) - go->dnsaddr[0] = 0; - if (!go->req_dns2) - go->dnsaddr[1] = 0; -#if 0 /* UNUSED */ - if (go->dnsaddr[0]) - script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0); - if (go->dnsaddr[1]) - script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0); -#endif /* UNUSED */ - if (pcb->settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { - sdns(pcb, go->dnsaddr[0], go->dnsaddr[1]); -#if 0 /* UNUSED */ - script_setenv("USEPEERDNS", "1", 0); - create_resolv(go->dnsaddr[0], go->dnsaddr[1]); -#endif /* UNUSED */ - } -#endif /* LWIP_DNS */ - -/* FIXME: check why it fails, just to know */ -#if 0 /* Unused */ - /* - * Check that the peer is allowed to use the IP address it wants. - */ - if (ho->hisaddr != 0 && !auth_ip_addr(f->unit, ho->hisaddr)) { - ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr); - ipcp_close(f->unit, "Unauthorized remote IP address"); - return; - } -#endif /* Unused */ - -#if VJ_SUPPORT - /* set tcp compression */ - sifvjcomp(pcb, ho->neg_vj, ho->cflag, ho->maxslotindex); -#endif /* VJ_SUPPORT */ - -#if DEMAND_SUPPORT - /* - * If we are doing dial-on-demand, the interface is already - * configured, so we put out any saved-up packets, then set the - * interface to pass IP packets. - */ - if (demand) { - if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) { - ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr, - wo->replace_default_route); - if (go->ouraddr != wo->ouraddr) { - ppp_warn("Local IP address changed to %I", go->ouraddr); - script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0); - wo->ouraddr = go->ouraddr; - } else - script_unsetenv("OLDIPLOCAL"); - if (ho->hisaddr != wo->hisaddr && wo->hisaddr != 0) { - ppp_warn("Remote IP address changed to %I", ho->hisaddr); - script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0); - wo->hisaddr = ho->hisaddr; - } else - script_unsetenv("OLDIPREMOTE"); - - /* Set the interface to the new addresses */ - mask = get_mask(go->ouraddr); - if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { -#if PPP_DEBUG - ppp_warn("Interface configuration failed"); -#endif /* PPP_DEBUG */ - ipcp_close(f->unit, "Interface configuration failed"); - return; - } - - /* assign a default route through the interface if required */ - if (ipcp_wantoptions[f->unit].default_route) - if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr, - wo->replace_default_route)) - default_route_set[f->unit] = 1; - -#if 0 /* UNUSED - PROXY ARP */ - /* Make a proxy ARP entry if requested. */ - if (ho->hisaddr != 0 && ipcp_wantoptions[f->unit].proxy_arp) - if (sifproxyarp(pcb, ho->hisaddr)) - proxy_arp_set[f->unit] = 1; -#endif /* UNUSED - PROXY ARP */ - - } - demand_rexmit(PPP_IP,go->ouraddr); - sifnpmode(pcb, PPP_IP, NPMODE_PASS); - - } else -#endif /* DEMAND_SUPPORT */ - { - /* - * Set IP addresses and (if specified) netmask. - */ - mask = get_mask(go->ouraddr); - -#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) - if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { -#if PPP_DEBUG - ppp_warn("Interface configuration failed"); -#endif /* PPP_DEBUG */ - ipcp_close(f->pcb, "Interface configuration failed"); - return; - } -#endif - - /* bring the interface up for IP */ - if (!sifup(pcb)) { -#if PPP_DEBUG - ppp_warn("Interface failed to come up"); -#endif /* PPP_DEBUG */ - ipcp_close(f->pcb, "Interface configuration failed"); - return; - } - -#if (defined(SVR4) && (defined(SNI) || defined(__USLC__))) - if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { -#if PPP_DEBUG - ppp_warn("Interface configuration failed"); -#endif /* PPP_DEBUG */ - ipcp_close(f->unit, "Interface configuration failed"); - return; - } -#endif -#if DEMAND_SUPPORT - sifnpmode(pcb, PPP_IP, NPMODE_PASS); -#endif /* DEMAND_SUPPORT */ - -#if 0 /* UNUSED */ - /* assign a default route through the interface if required */ - if (wo->default_route) - if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr, - wo->replace_default_route)) - pcb->default_route_set = 1; -#endif /* UNUSED */ - -#if 0 /* UNUSED - PROXY ARP */ - /* Make a proxy ARP entry if requested. */ - if (ho->hisaddr != 0 && wo->proxy_arp) - if (sifproxyarp(pcb, ho->hisaddr)) - pcb->proxy_arp_set = 1; -#endif /* UNUSED - PROXY ARP */ - - wo->ouraddr = go->ouraddr; - - ppp_notice("local IP address %I", go->ouraddr); - if (ho->hisaddr != 0) - ppp_notice("remote IP address %I", ho->hisaddr); -#if LWIP_DNS - if (go->dnsaddr[0]) - ppp_notice("primary DNS address %I", go->dnsaddr[0]); - if (go->dnsaddr[1]) - ppp_notice("secondary DNS address %I", go->dnsaddr[1]); -#endif /* LWIP_DNS */ - } - -#if PPP_STATS_SUPPORT - reset_link_stats(f->unit); -#endif /* PPP_STATS_SUPPORT */ - - np_up(pcb, PPP_IP); - pcb->ipcp_is_up = 1; - -#if PPP_NOTIFY - notify(ip_up_notifier, 0); -#endif /* PPP_NOTIFY */ -#if 0 /* UNUSED */ - if (ip_up_hook) - ip_up_hook(); -#endif /* UNUSED */ -} - - -/* - * ipcp_down - IPCP has gone DOWN. - * - * Take the IP network interface down, clear its addresses - * and delete routes through it. - */ -static void ipcp_down(fsm *f) { - ppp_pcb *pcb = f->pcb; - ipcp_options *ho = &pcb->ipcp_hisoptions; - ipcp_options *go = &pcb->ipcp_gotoptions; - - IPCPDEBUG(("ipcp: down")); -#if PPP_STATS_SUPPORT - /* XXX a bit IPv4-centric here, we only need to get the stats - * before the interface is marked down. */ - /* XXX more correct: we must get the stats before running the notifiers, - * at least for the radius plugin */ - update_link_stats(f->unit); -#endif /* PPP_STATS_SUPPORT */ -#if PPP_NOTIFY - notify(ip_down_notifier, 0); -#endif /* PPP_NOTIFY */ -#if 0 /* UNUSED */ - if (ip_down_hook) - ip_down_hook(); -#endif /* UNUSED */ - if (pcb->ipcp_is_up) { - pcb->ipcp_is_up = 0; - np_down(pcb, PPP_IP); - } -#if VJ_SUPPORT - sifvjcomp(pcb, 0, 0, 0); -#endif /* VJ_SUPPORT */ - -#if PPP_STATS_SUPPORT - print_link_stats(); /* _after_ running the notifiers and ip_down_hook(), - * because print_link_stats() sets link_stats_valid - * to 0 (zero) */ -#endif /* PPP_STATS_SUPPORT */ - -#if DEMAND_SUPPORT - /* - * If we are doing dial-on-demand, set the interface - * to queue up outgoing packets (for now). - */ - if (demand) { - sifnpmode(pcb, PPP_IP, NPMODE_QUEUE); - } else -#endif /* DEMAND_SUPPORT */ - { -#if DEMAND_SUPPORT - sifnpmode(pcb, PPP_IP, NPMODE_DROP); -#endif /* DEMAND_SUPPORT */ - sifdown(pcb); - ipcp_clear_addrs(pcb, go->ouraddr, - ho->hisaddr, 0); -#if LWIP_DNS - cdns(pcb, go->dnsaddr[0], go->dnsaddr[1]); -#endif /* LWIP_DNS */ - } -} - - -/* - * ipcp_clear_addrs() - clear the interface addresses, routes, - * proxy arp entries, etc. - */ -static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute) { - LWIP_UNUSED_ARG(replacedefaultroute); - -#if 0 /* UNUSED - PROXY ARP */ - if (pcb->proxy_arp_set) { - cifproxyarp(pcb, hisaddr); - pcb->proxy_arp_set = 0; - } -#endif /* UNUSED - PROXY ARP */ -#if 0 /* UNUSED */ - /* If replacedefaultroute, sifdefaultroute will be called soon - * with replacedefaultroute set and that will overwrite the current - * default route. This is the case only when doing demand, otherwise - * during demand, this cifdefaultroute would restore the old default - * route which is not what we want in this case. In the non-demand - * case, we'll delete the default route and restore the old if there - * is one saved by an sifdefaultroute with replacedefaultroute. - */ - if (!replacedefaultroute && pcb->default_route_set) { - cifdefaultroute(pcb, ouraddr, hisaddr); - pcb->default_route_set = 0; - } -#endif /* UNUSED */ - cifaddr(pcb, ouraddr, hisaddr); -} - - -/* - * ipcp_finished - possibly shut down the lower layers. - */ -static void ipcp_finished(fsm *f) { - ppp_pcb *pcb = f->pcb; - if (pcb->ipcp_is_open) { - pcb->ipcp_is_open = 0; - np_finished(pcb, PPP_IP); - } -} - - -#if 0 /* UNUSED */ -/* - * create_resolv - create the replacement resolv.conf file - */ -static void -create_resolv(peerdns1, peerdns2) - u32_t peerdns1, peerdns2; -{ - -} -#endif /* UNUSED */ - -#if PRINTPKT_SUPPORT -/* - * ipcp_printpkt - print the contents of an IPCP packet. - */ -static const char* const ipcp_codenames[] = { - "ConfReq", "ConfAck", "ConfNak", "ConfRej", - "TermReq", "TermAck", "CodeRej" -}; - -static int ipcp_printpkt(const u_char *p, int plen, - void (*printer) (void *, const char *, ...), void *arg) { - int code, id, len, olen; - const u_char *pstart, *optend; -#if VJ_SUPPORT - u_short cishort; -#endif /* VJ_SUPPORT */ - u32_t cilong; - - if (plen < HEADERLEN) - return 0; - pstart = p; - GETCHAR(code, p); - GETCHAR(id, p); - GETSHORT(len, p); - if (len < HEADERLEN || len > plen) - return 0; - - if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipcp_codenames)) - printer(arg, " %s", ipcp_codenames[code-1]); - else - printer(arg, " code=0x%x", code); - printer(arg, " id=0x%x", id); - len -= HEADERLEN; - switch (code) { - case CONFREQ: - case CONFACK: - case CONFNAK: - case CONFREJ: - /* print option list */ - while (len >= 2) { - GETCHAR(code, p); - GETCHAR(olen, p); - p -= 2; - if (olen < 2 || olen > len) { - break; - } - printer(arg, " <"); - len -= olen; - optend = p + olen; - switch (code) { - case CI_ADDRS: - if (olen == CILEN_ADDRS) { - p += 2; - GETLONG(cilong, p); - printer(arg, "addrs %I", htonl(cilong)); - GETLONG(cilong, p); - printer(arg, " %I", htonl(cilong)); - } - break; -#if VJ_SUPPORT - case CI_COMPRESSTYPE: - if (olen >= CILEN_COMPRESS) { - p += 2; - GETSHORT(cishort, p); - printer(arg, "compress "); - switch (cishort) { - case IPCP_VJ_COMP: - printer(arg, "VJ"); - break; - case IPCP_VJ_COMP_OLD: - printer(arg, "old-VJ"); - break; - default: - printer(arg, "0x%x", cishort); - } - } - break; -#endif /* VJ_SUPPORT */ - case CI_ADDR: - if (olen == CILEN_ADDR) { - p += 2; - GETLONG(cilong, p); - printer(arg, "addr %I", htonl(cilong)); - } - break; -#if LWIP_DNS - case CI_MS_DNS1: - case CI_MS_DNS2: - p += 2; - GETLONG(cilong, p); - printer(arg, "ms-dns%d %I", (code == CI_MS_DNS1? 1: 2), - htonl(cilong)); - break; -#endif /* LWIP_DNS */ -#if 0 /* UNUSED - WINS */ - case CI_MS_WINS1: - case CI_MS_WINS2: - p += 2; - GETLONG(cilong, p); - printer(arg, "ms-wins %I", htonl(cilong)); - break; -#endif /* UNUSED - WINS */ - default: - break; - } - while (p < optend) { - GETCHAR(code, p); - printer(arg, " %.2x", code); - } - printer(arg, ">"); - } - break; - - case TERMACK: - case TERMREQ: - if (len > 0 && *p >= ' ' && *p < 0x7f) { - printer(arg, " "); - ppp_print_string(p, len, printer, arg); - p += len; - len = 0; - } - break; - default: - break; - } - - /* print the rest of the bytes in the packet */ - for (; len > 0; --len) { - GETCHAR(code, p); - printer(arg, " %.2x", code); - } - - return p - pstart; -} -#endif /* PRINTPKT_SUPPORT */ - -#if DEMAND_SUPPORT -/* - * ip_active_pkt - see if this IP packet is worth bringing the link up for. - * We don't bring the link up for IP fragments or for TCP FIN packets - * with no data. - */ -#define IP_HDRLEN 20 /* bytes */ -#define IP_OFFMASK 0x1fff -#ifndef IPPROTO_TCP -#define IPPROTO_TCP 6 -#endif -#define TCP_HDRLEN 20 -#define TH_FIN 0x01 - -/* - * We use these macros because the IP header may be at an odd address, - * and some compilers might use word loads to get th_off or ip_hl. - */ - -#define net_short(x) (((x)[0] << 8) + (x)[1]) -#define get_iphl(x) (((unsigned char *)(x))[0] & 0xF) -#define get_ipoff(x) net_short((unsigned char *)(x) + 6) -#define get_ipproto(x) (((unsigned char *)(x))[9]) -#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) -#define get_tcpflags(x) (((unsigned char *)(x))[13]) - -static int -ip_active_pkt(pkt, len) - u_char *pkt; - int len; -{ - u_char *tcp; - int hlen; - - len -= PPP_HDRLEN; - pkt += PPP_HDRLEN; - if (len < IP_HDRLEN) - return 0; - if ((get_ipoff(pkt) & IP_OFFMASK) != 0) - return 0; - if (get_ipproto(pkt) != IPPROTO_TCP) - return 1; - hlen = get_iphl(pkt) * 4; - if (len < hlen + TCP_HDRLEN) - return 0; - tcp = pkt + hlen; - if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) - return 0; - return 1; -} -#endif /* DEMAND_SUPPORT */ - -#endif /* PPP_SUPPORT && PPP_IPV4_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/ipv6cp.c b/ext/lwip/src/netif/ppp/ipv6cp.c deleted file mode 100644 index f0f4eee..0000000 --- a/ext/lwip/src/netif/ppp/ipv6cp.c +++ /dev/null @@ -1,1533 +0,0 @@ -/* - * ipv6cp.c - 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.c - PPP IP Control Protocol. - * - * 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.c,v 1.21 2005/08/25 23:59:34 paulus Exp $ - */ - -/* - * @todo: - * - * Proxy Neighbour Discovery. - * - * Better defines for selecting the ordering of - * interface up / set address. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#if 0 /* UNUSED */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif /* UNUSED */ - -#include "netif/ppp/ppp_impl.h" -#include "netif/ppp/fsm.h" -#include "netif/ppp/ipcp.h" -#include "netif/ppp/ipv6cp.h" -#include "netif/ppp/magic.h" - -/* global vars */ -#if 0 /* UNUSED */ -int no_ifaceid_neg = 0; -#endif /* UNUSED */ - -/* - * Callbacks for fsm code. (CI = Configuration Information) - */ -static void ipv6cp_resetci(fsm *f); /* Reset our CI */ -static int ipv6cp_cilen(fsm *f); /* Return length of our CI */ -static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */ -static int ipv6cp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ -static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */ -static int ipv6cp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ -static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */ -static void ipv6cp_up(fsm *f); /* We're UP */ -static void ipv6cp_down(fsm *f); /* We're DOWN */ -static void ipv6cp_finished(fsm *f); /* Don't need lower layer */ - -static const fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */ - ipv6cp_resetci, /* Reset our Configuration Information */ - ipv6cp_cilen, /* Length of our Configuration Information */ - ipv6cp_addci, /* Add our Configuration Information */ - ipv6cp_ackci, /* ACK our Configuration Information */ - ipv6cp_nakci, /* NAK our Configuration Information */ - ipv6cp_rejci, /* Reject our Configuration Information */ - ipv6cp_reqci, /* Request peer's Configuration Information */ - ipv6cp_up, /* Called when fsm reaches OPENED state */ - ipv6cp_down, /* Called when fsm leaves OPENED state */ - NULL, /* Called when we want the lower layer up */ - ipv6cp_finished, /* Called when we want the lower layer down */ - NULL, /* Called when Protocol-Reject received */ - NULL, /* Retransmission is necessary */ - NULL, /* Called to handle protocol-specific codes */ - "IPV6CP" /* String name of protocol */ -}; - -#if PPP_OPTIONS -/* - * Command-line options. - */ -static int setifaceid(char **arg)); -static void printifaceid(option_t *, - void (*)(void *, char *, ...), void *)); - -static option_t ipv6cp_option_list[] = { - { "ipv6", o_special, (void *)setifaceid, - "Set interface identifiers for IPV6", - OPT_A2PRINTER, (void *)printifaceid }, - - { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag, - "Enable IPv6 and IPv6CP", OPT_PRIO | 1 }, - { "noipv6", o_bool, &ipv6cp_protent.enabled_flag, - "Disable IPv6 and IPv6CP", OPT_PRIOSUB }, - { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag, - "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS }, - - { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local, - "Accept peer's interface identifier for us", 1 }, - - { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip, - "Use (default) IPv4 address as interface identifier", 1 }, - - { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent, - "Use uniquely-available persistent value for link local address", 1 }, - - { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime, - "Set timeout for IPv6CP", OPT_PRIO }, - { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits, - "Set max #xmits for term-reqs", OPT_PRIO }, - { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits, - "Set max #xmits for conf-reqs", OPT_PRIO }, - { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops, - "Set max #conf-naks for IPv6CP", OPT_PRIO }, - - { NULL } -}; -#endif /* PPP_OPTIONS */ - -/* - * Protocol entry points from main code. - */ -static void ipv6cp_init(ppp_pcb *pcb); -static void ipv6cp_open(ppp_pcb *pcb); -static void ipv6cp_close(ppp_pcb *pcb, const char *reason); -static void ipv6cp_lowerup(ppp_pcb *pcb); -static void ipv6cp_lowerdown(ppp_pcb *pcb); -static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len); -static void ipv6cp_protrej(ppp_pcb *pcb); -#if PPP_OPTIONS -static void ipv6_check_options(void); -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT -static int ipv6_demand_conf(int u); -#endif /* DEMAND_SUPPORT */ -#if PRINTPKT_SUPPORT -static int ipv6cp_printpkt(const u_char *p, int plen, - void (*printer)(void *, const char *, ...), void *arg); -#endif /* PRINTPKT_SUPPORT */ -#if DEMAND_SUPPORT -static int ipv6_active_pkt(u_char *pkt, int len); -#endif /* DEMAND_SUPPORT */ - -const struct protent ipv6cp_protent = { - PPP_IPV6CP, - ipv6cp_init, - ipv6cp_input, - ipv6cp_protrej, - ipv6cp_lowerup, - ipv6cp_lowerdown, - ipv6cp_open, - ipv6cp_close, -#if PRINTPKT_SUPPORT - ipv6cp_printpkt, -#endif /* PRINTPKT_SUPPORT */ -#if PPP_DATAINPUT - NULL, -#endif /* PPP_DATAINPUT */ -#if PRINTPKT_SUPPORT - "IPV6CP", - "IPV6", -#endif /* PRINTPKT_SUPPORT */ -#if PPP_OPTIONS - ipv6cp_option_list, - ipv6_check_options, -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT - ipv6_demand_conf, - ipv6_active_pkt -#endif /* DEMAND_SUPPORT */ -}; - -static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid); -#if 0 /* UNUSED */ -static void ipv6cp_script(char *)); -static void ipv6cp_script_done(void *)); -#endif /* UNUSED */ - -/* - * Lengths of configuration options. - */ -#define CILEN_VOID 2 -#define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */ -#define CILEN_IFACEID 10 /* RFC2472, interface identifier */ - -#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ - (x) == CONFNAK ? "NAK" : "REJ") - -#if 0 /* UNUSED */ -/* - * This state variable is used to ensure that we don't - * run an ipcp-up/down script while one is already running. - */ -static enum script_state { - s_down, - s_up, -} ipv6cp_script_state; -static pid_t ipv6cp_script_pid; -#endif /* UNUSED */ - -static char *llv6_ntoa(eui64_t ifaceid); - -#if PPP_OPTIONS -/* - * setifaceid - set the interface identifiers manually - */ -static int -setifaceid(argv) - char **argv; -{ - char *comma, *arg, c; - ipv6cp_options *wo = &ipv6cp_wantoptions[0]; - struct in6_addr addr; - static int prio_local, prio_remote; - -#define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \ - (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) ) - - arg = *argv; - if ((comma = strchr(arg, ',')) == NULL) - comma = arg + strlen(arg); - - /* - * If comma first character, then no local identifier - */ - if (comma != arg) { - c = *comma; - *comma = '\0'; - - if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) { - option_error("Illegal interface identifier (local): %s", arg); - return 0; - } - - if (option_priority >= prio_local) { - eui64_copy(addr.s6_addr32[2], wo->ourid); - wo->opt_local = 1; - prio_local = option_priority; - } - *comma = c; - } - - /* - * If comma last character, the no remote identifier - */ - if (*comma != 0 && *++comma != '\0') { - if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) { - option_error("Illegal interface identifier (remote): %s", comma); - return 0; - } - if (option_priority >= prio_remote) { - eui64_copy(addr.s6_addr32[2], wo->hisid); - wo->opt_remote = 1; - prio_remote = option_priority; - } - } - - if (override_value("+ipv6", option_priority, option_source)) - ipv6cp_protent.enabled_flag = 1; - return 1; -} - -static void -printifaceid(opt, printer, arg) - option_t *opt; - void (*printer)(void *, char *, ...)); - void *arg; -{ - ipv6cp_options *wo = &ipv6cp_wantoptions[0]; - - if (wo->opt_local) - printer(arg, "%s", llv6_ntoa(wo->ourid)); - printer(arg, ","); - if (wo->opt_remote) - printer(arg, "%s", llv6_ntoa(wo->hisid)); -} -#endif /* PPP_OPTIONS */ - -/* - * Make a string representation of a network address. - */ -static char * -llv6_ntoa(eui64_t ifaceid) -{ - static char b[26]; - - sprintf(b, "fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x", - ifaceid.e8[0], ifaceid.e8[1], ifaceid.e8[2], ifaceid.e8[3], - ifaceid.e8[4], ifaceid.e8[5], ifaceid.e8[6], ifaceid.e8[7]); - - return b; -} - - -/* - * ipv6cp_init - Initialize IPV6CP. - */ -static void ipv6cp_init(ppp_pcb *pcb) { - fsm *f = &pcb->ipv6cp_fsm; - ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; - ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; - - f->pcb = pcb; - f->protocol = PPP_IPV6CP; - f->callbacks = &ipv6cp_callbacks; - fsm_init(f); - -#if 0 /* Not necessary, everything is cleared in ppp_new() */ - memset(wo, 0, sizeof(*wo)); - memset(ao, 0, sizeof(*ao)); -#endif /* 0 */ - - wo->accept_local = 1; - wo->neg_ifaceid = 1; - ao->neg_ifaceid = 1; - -#ifdef IPV6CP_COMP - wo->neg_vj = 1; - ao->neg_vj = 1; - wo->vj_protocol = IPV6CP_COMP; -#endif - -} - - -/* - * ipv6cp_open - IPV6CP is allowed to come up. - */ -static void ipv6cp_open(ppp_pcb *pcb) { - fsm_open(&pcb->ipv6cp_fsm); -} - - -/* - * ipv6cp_close - Take IPV6CP down. - */ -static void ipv6cp_close(ppp_pcb *pcb, const char *reason) { - fsm_close(&pcb->ipv6cp_fsm, reason); -} - - -/* - * ipv6cp_lowerup - The lower layer is up. - */ -static void ipv6cp_lowerup(ppp_pcb *pcb) { - fsm_lowerup(&pcb->ipv6cp_fsm); -} - - -/* - * ipv6cp_lowerdown - The lower layer is down. - */ -static void ipv6cp_lowerdown(ppp_pcb *pcb) { - fsm_lowerdown(&pcb->ipv6cp_fsm); -} - - -/* - * ipv6cp_input - Input IPV6CP packet. - */ -static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len) { - fsm_input(&pcb->ipv6cp_fsm, p, len); -} - - -/* - * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP. - * - * Pretend the lower layer went down, so we shut up. - */ -static void ipv6cp_protrej(ppp_pcb *pcb) { - fsm_lowerdown(&pcb->ipv6cp_fsm); -} - - -/* - * ipv6cp_resetci - Reset our CI. - */ -static void ipv6cp_resetci(fsm *f) { - ppp_pcb *pcb = f->pcb; - ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; - ipv6cp_options *go = &pcb->ipv6cp_gotoptions; - ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; - - wo->req_ifaceid = wo->neg_ifaceid && ao->neg_ifaceid; - - if (!wo->opt_local) { - eui64_magic_nz(wo->ourid); - } - - *go = *wo; - eui64_zero(go->hisid); /* last proposed interface identifier */ -} - - -/* - * ipv6cp_cilen - Return length of our CI. - */ -static int ipv6cp_cilen(fsm *f) { - ppp_pcb *pcb = f->pcb; - ipv6cp_options *go = &pcb->ipv6cp_gotoptions; - -#ifdef IPV6CP_COMP -#define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0) -#endif /* IPV6CP_COMP */ -#define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0) - - return (LENCIIFACEID(go->neg_ifaceid) + -#ifdef IPV6CP_COMP - LENCIVJ(go->neg_vj) + -#endif /* IPV6CP_COMP */ - 0); -} - - -/* - * ipv6cp_addci - Add our desired CIs to a packet. - */ -static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp) { - ppp_pcb *pcb = f->pcb; - ipv6cp_options *go = &pcb->ipv6cp_gotoptions; - int len = *lenp; - -#ifdef IPV6CP_COMP -#define ADDCIVJ(opt, neg, val) \ - if (neg) { \ - int vjlen = CILEN_COMPRESS; \ - if (len >= vjlen) { \ - PUTCHAR(opt, ucp); \ - PUTCHAR(vjlen, ucp); \ - PUTSHORT(val, ucp); \ - len -= vjlen; \ - } else \ - neg = 0; \ - } -#endif /* IPV6CP_COMP */ - -#define ADDCIIFACEID(opt, neg, val1) \ - if (neg) { \ - int idlen = CILEN_IFACEID; \ - if (len >= idlen) { \ - PUTCHAR(opt, ucp); \ - PUTCHAR(idlen, ucp); \ - eui64_put(val1, ucp); \ - len -= idlen; \ - } else \ - neg = 0; \ - } - - ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); - -#ifdef IPV6CP_COMP - ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); -#endif /* IPV6CP_COMP */ - - *lenp -= len; -} - - -/* - * ipv6cp_ackci - Ack our CIs. - * - * Returns: - * 0 - Ack was bad. - * 1 - Ack was good. - */ -static int ipv6cp_ackci(fsm *f, u_char *p, int len) { - ppp_pcb *pcb = f->pcb; - ipv6cp_options *go = &pcb->ipv6cp_gotoptions; - u_short cilen, citype; -#ifdef IPV6CP_COMP - u_short cishort; -#endif /* IPV6CP_COMP */ - eui64_t ifaceid; - - /* - * CIs must be in exactly the same order that we sent... - * Check packet length and CI length at each step. - * If we find any deviations, then this packet is bad. - */ - -#ifdef IPV6CP_COMP -#define ACKCIVJ(opt, neg, val) \ - if (neg) { \ - int vjlen = CILEN_COMPRESS; \ - if ((len -= vjlen) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != vjlen || \ - citype != opt) \ - goto bad; \ - GETSHORT(cishort, p); \ - if (cishort != val) \ - goto bad; \ - } -#endif /* IPV6CP_COMP */ - -#define ACKCIIFACEID(opt, neg, val1) \ - if (neg) { \ - int idlen = CILEN_IFACEID; \ - if ((len -= idlen) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != idlen || \ - citype != opt) \ - goto bad; \ - eui64_get(ifaceid, p); \ - if (! eui64_equals(val1, ifaceid)) \ - goto bad; \ - } - - ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); - -#ifdef IPV6CP_COMP - ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); -#endif /* IPV6CP_COMP */ - - /* - * If there are any remaining CIs, then this packet is bad. - */ - if (len != 0) - goto bad; - return (1); - -bad: - IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!")); - return (0); -} - -/* - * ipv6cp_nakci - Peer has sent a NAK for some of our CIs. - * This should not modify any state if the Nak is bad - * or if IPV6CP is in the OPENED state. - * - * Returns: - * 0 - Nak was bad. - * 1 - Nak was good. - */ -static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { - ppp_pcb *pcb = f->pcb; - ipv6cp_options *go = &pcb->ipv6cp_gotoptions; - u_char citype, cilen, *next; -#ifdef IPV6CP_COMP - u_short cishort; -#endif /* IPV6CP_COMP */ - eui64_t ifaceid; - ipv6cp_options no; /* options we've seen Naks for */ - ipv6cp_options try_; /* options to request next time */ - - BZERO(&no, sizeof(no)); - try_ = *go; - - /* - * Any Nak'd CIs must be in exactly the same order that we sent. - * Check packet length and CI length at each step. - * If we find any deviations, then this packet is bad. - */ -#define NAKCIIFACEID(opt, neg, code) \ - if (go->neg && \ - len >= (cilen = CILEN_IFACEID) && \ - p[1] == cilen && \ - p[0] == opt) { \ - len -= cilen; \ - INCPTR(2, p); \ - eui64_get(ifaceid, p); \ - no.neg = 1; \ - code \ - } - -#ifdef IPV6CP_COMP -#define NAKCIVJ(opt, neg, code) \ - if (go->neg && \ - ((cilen = p[1]) == CILEN_COMPRESS) && \ - len >= cilen && \ - p[0] == opt) { \ - len -= cilen; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - no.neg = 1; \ - code \ - } -#endif /* IPV6CP_COMP */ - - /* - * Accept the peer's idea of {our,his} interface identifier, if different - * from our idea, only if the accept_{local,remote} flag is set. - */ - NAKCIIFACEID(CI_IFACEID, neg_ifaceid, - if (treat_as_reject) { - try_.neg_ifaceid = 0; - } else if (go->accept_local) { - while (eui64_iszero(ifaceid) || - eui64_equals(ifaceid, go->hisid)) /* bad luck */ - eui64_magic(ifaceid); - try_.ourid = ifaceid; - IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid))); - } - ); - -#ifdef IPV6CP_COMP - NAKCIVJ(CI_COMPRESSTYPE, neg_vj, - { - if (cishort == IPV6CP_COMP && !treat_as_reject) { - try_.vj_protocol = cishort; - } else { - try_.neg_vj = 0; - } - } - ); -#endif /* IPV6CP_COMP */ - - /* - * There may be remaining CIs, if the peer is requesting negotiation - * on an option that we didn't include in our request packet. - * If they want to negotiate about interface identifier, we comply. - * If they want us to ask for compression, we refuse. - */ - while (len >= CILEN_VOID) { - GETCHAR(citype, p); - GETCHAR(cilen, p); - if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) - goto bad; - next = p + cilen - 2; - - switch (citype) { -#ifdef IPV6CP_COMP - case CI_COMPRESSTYPE: - if (go->neg_vj || no.neg_vj || - (cilen != CILEN_COMPRESS)) - goto bad; - no.neg_vj = 1; - break; -#endif /* IPV6CP_COMP */ - case CI_IFACEID: - if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID) - goto bad; - try_.neg_ifaceid = 1; - eui64_get(ifaceid, p); - if (go->accept_local) { - while (eui64_iszero(ifaceid) || - eui64_equals(ifaceid, go->hisid)) /* bad luck */ - eui64_magic(ifaceid); - try_.ourid = ifaceid; - } - no.neg_ifaceid = 1; - break; - default: - break; - } - p = next; - } - - /* If there is still anything left, this packet is bad. */ - if (len != 0) - goto bad; - - /* - * OK, the Nak is good. Now we can update state. - */ - if (f->state != PPP_FSM_OPENED) - *go = try_; - - return 1; - -bad: - IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!")); - return 0; -} - - -/* - * ipv6cp_rejci - Reject some of our CIs. - */ -static int ipv6cp_rejci(fsm *f, u_char *p, int len) { - ppp_pcb *pcb = f->pcb; - ipv6cp_options *go = &pcb->ipv6cp_gotoptions; - u_char cilen; -#ifdef IPV6CP_COMP - u_short cishort; -#endif /* IPV6CP_COMP */ - eui64_t ifaceid; - ipv6cp_options try_; /* options to request next time */ - - try_ = *go; - /* - * Any Rejected CIs must be in exactly the same order that we sent. - * Check packet length and CI length at each step. - * If we find any deviations, then this packet is bad. - */ -#define REJCIIFACEID(opt, neg, val1) \ - if (go->neg && \ - len >= (cilen = CILEN_IFACEID) && \ - p[1] == cilen && \ - p[0] == opt) { \ - len -= cilen; \ - INCPTR(2, p); \ - eui64_get(ifaceid, p); \ - /* Check rejected value. */ \ - if (! eui64_equals(ifaceid, val1)) \ - goto bad; \ - try_.neg = 0; \ - } - -#ifdef IPV6CP_COMP -#define REJCIVJ(opt, neg, val) \ - if (go->neg && \ - p[1] == CILEN_COMPRESS && \ - len >= p[1] && \ - p[0] == opt) { \ - len -= p[1]; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - /* Check rejected value. */ \ - if (cishort != val) \ - goto bad; \ - try_.neg = 0; \ - } -#endif /* IPV6CP_COMP */ - - REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid); - -#ifdef IPV6CP_COMP - REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol); -#endif /* IPV6CP_COMP */ - - /* - * If there are any remaining CIs, then this packet is bad. - */ - if (len != 0) - goto bad; - /* - * Now we can update state. - */ - if (f->state != PPP_FSM_OPENED) - *go = try_; - return 1; - -bad: - IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!")); - return 0; -} - - -/* - * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response. - * - * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified - * appropriately. If reject_if_disagree is non-zero, doesn't return - * CONFNAK; returns CONFREJ if it can't return CONFACK. - * - * inp = Requested CIs - * len = Length of requested CIs - * - */ -static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { - ppp_pcb *pcb = f->pcb; - ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; - ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; - ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; - ipv6cp_options *go = &pcb->ipv6cp_gotoptions; - u_char *cip, *next; /* Pointer to current and next CIs */ - u_short cilen, citype; /* Parsed len, type */ -#ifdef IPV6CP_COMP - u_short cishort; /* Parsed short value */ -#endif /* IPV6CP_COMP */ - eui64_t ifaceid; /* Parsed interface identifier */ - int rc = CONFACK; /* Final packet return code */ - int orc; /* Individual option return code */ - u_char *p; /* Pointer to next char to parse */ - u_char *ucp = inp; /* Pointer to current output char */ - int l = *len; /* Length left */ - - /* - * Reset all his options. - */ - BZERO(ho, sizeof(*ho)); - - /* - * Process all his options. - */ - next = inp; - while (l) { - orc = CONFACK; /* Assume success */ - cip = p = next; /* Remember begining of CI */ - if (l < 2 || /* Not enough data for CI header or */ - p[1] < 2 || /* CI length too small or */ - p[1] > l) { /* CI length too big? */ - IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!")); - orc = CONFREJ; /* Reject bad CI */ - cilen = l; /* Reject till end of packet */ - l = 0; /* Don't loop again */ - goto endswitch; - } - GETCHAR(citype, p); /* Parse CI type */ - GETCHAR(cilen, p); /* Parse CI length */ - l -= cilen; /* Adjust remaining length */ - next += cilen; /* Step to next CI */ - - switch (citype) { /* Check CI type */ - case CI_IFACEID: - IPV6CPDEBUG(("ipv6cp: received interface identifier ")); - - if (!ao->neg_ifaceid || - cilen != CILEN_IFACEID) { /* Check CI length */ - orc = CONFREJ; /* Reject CI */ - break; - } - - /* - * If he has no interface identifier, or if we both have same - * identifier then NAK it with new idea. - * In particular, if we don't know his identifier, but he does, - * then accept it. - */ - eui64_get(ifaceid, p); - IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid))); - if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) { - orc = CONFREJ; /* Reject CI */ - break; - } - if (!eui64_iszero(wo->hisid) && - !eui64_equals(ifaceid, wo->hisid) && - eui64_iszero(go->hisid)) { - - orc = CONFNAK; - ifaceid = wo->hisid; - go->hisid = ifaceid; - DECPTR(sizeof(ifaceid), p); - eui64_put(ifaceid, p); - } else - if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) { - orc = CONFNAK; - if (eui64_iszero(go->hisid)) /* first time, try option */ - ifaceid = wo->hisid; - while (eui64_iszero(ifaceid) || - eui64_equals(ifaceid, go->ourid)) /* bad luck */ - eui64_magic(ifaceid); - go->hisid = ifaceid; - DECPTR(sizeof(ifaceid), p); - eui64_put(ifaceid, p); - } - - ho->neg_ifaceid = 1; - ho->hisid = ifaceid; - break; - -#ifdef IPV6CP_COMP - case CI_COMPRESSTYPE: - IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE ")); - if (!ao->neg_vj || - (cilen != CILEN_COMPRESS)) { - orc = CONFREJ; - break; - } - GETSHORT(cishort, p); - IPV6CPDEBUG(("(%d)", cishort)); - - if (!(cishort == IPV6CP_COMP)) { - orc = CONFREJ; - break; - } - - ho->neg_vj = 1; - ho->vj_protocol = cishort; - break; -#endif /* IPV6CP_COMP */ - - default: - orc = CONFREJ; - break; - } - -endswitch: - IPV6CPDEBUG((" (%s)\n", CODENAME(orc))); - - if (orc == CONFACK && /* Good CI */ - rc != CONFACK) /* but prior CI wasnt? */ - continue; /* Don't send this one */ - - if (orc == CONFNAK) { /* Nak this CI? */ - if (reject_if_disagree) /* Getting fed up with sending NAKs? */ - orc = CONFREJ; /* Get tough if so */ - else { - if (rc == CONFREJ) /* Rejecting prior CI? */ - continue; /* Don't send this one */ - if (rc == CONFACK) { /* Ack'd all prior CIs? */ - rc = CONFNAK; /* Not anymore... */ - ucp = inp; /* Backup */ - } - } - } - - if (orc == CONFREJ && /* Reject this CI */ - rc != CONFREJ) { /* but no prior ones? */ - rc = CONFREJ; - ucp = inp; /* Backup */ - } - - /* Need to move CI? */ - if (ucp != cip) - MEMCPY(ucp, cip, cilen); /* Move it */ - - /* Update output pointer */ - INCPTR(cilen, ucp); - } - - /* - * If we aren't rejecting this packet, and we want to negotiate - * their identifier and they didn't send their identifier, then we - * send a NAK with a CI_IFACEID option appended. We assume the - * input buffer is long enough that we can append the extra - * option safely. - */ - if (rc != CONFREJ && !ho->neg_ifaceid && - wo->req_ifaceid && !reject_if_disagree) { - if (rc == CONFACK) { - rc = CONFNAK; - ucp = inp; /* reset pointer */ - wo->req_ifaceid = 0; /* don't ask again */ - } - PUTCHAR(CI_IFACEID, ucp); - PUTCHAR(CILEN_IFACEID, ucp); - eui64_put(wo->hisid, ucp); - } - - *len = ucp - inp; /* Compute output length */ - IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc))); - return (rc); /* Return final code */ -} - -#if PPP_OPTIONS -/* - * ipv6_check_options - check that any IP-related options are OK, - * and assign appropriate defaults. - */ -static void ipv6_check_options() { - ipv6cp_options *wo = &ipv6cp_wantoptions[0]; - - if (!ipv6cp_protent.enabled_flag) - return; - - /* - * Persistent link-local id is only used when user has not explicitly - * configure/hard-code the id - */ - if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) { - - /* - * On systems where there are no Ethernet interfaces used, there - * may be other ways to obtain a persistent id. Right now, it - * will fall back to using magic [see eui64_magic] below when - * an EUI-48 from MAC address can't be obtained. Other possibilities - * include obtaining EEPROM serial numbers, or some other unique - * yet persistent number. On Sparc platforms, this is possible, - * but too bad there's no standards yet for x86 machines. - */ - if (ether_to_eui64(&wo->ourid)) { - wo->opt_local = 1; - } - } - - if (!wo->opt_local) { /* init interface identifier */ - if (wo->use_ip && eui64_iszero(wo->ourid)) { - eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr)); - if (!eui64_iszero(wo->ourid)) - wo->opt_local = 1; - } - - while (eui64_iszero(wo->ourid)) - eui64_magic(wo->ourid); - } - - if (!wo->opt_remote) { - if (wo->use_ip && eui64_iszero(wo->hisid)) { - eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr)); - if (!eui64_iszero(wo->hisid)) - wo->opt_remote = 1; - } - } - - if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) { - option_error("local/remote LL address required for demand-dialling\n"); - exit(1); - } -} -#endif /* PPP_OPTIONS */ - -#if DEMAND_SUPPORT -/* - * ipv6_demand_conf - configure the interface as though - * IPV6CP were up, for use with dial-on-demand. - */ -static int ipv6_demand_conf(int u) { - ipv6cp_options *wo = &ipv6cp_wantoptions[u]; - - if (!sif6up(u)) - return 0; - - if (!sif6addr(u, wo->ourid, wo->hisid)) - return 0; - - if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) - return 0; - - ppp_notice("ipv6_demand_conf"); - ppp_notice("local LL address %s", llv6_ntoa(wo->ourid)); - ppp_notice("remote LL address %s", llv6_ntoa(wo->hisid)); - - return 1; -} -#endif /* DEMAND_SUPPORT */ - - -/* - * ipv6cp_up - IPV6CP has come UP. - * - * Configure the IPv6 network interface appropriately and bring it up. - */ -static void ipv6cp_up(fsm *f) { - ppp_pcb *pcb = f->pcb; - ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; - ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; - ipv6cp_options *go = &pcb->ipv6cp_gotoptions; - - IPV6CPDEBUG(("ipv6cp: up")); - - /* - * We must have a non-zero LL address for both ends of the link. - */ - if (!ho->neg_ifaceid) - ho->hisid = wo->hisid; - -#if 0 /* UNUSED */ - if(!no_ifaceid_neg) { -#endif /* UNUSED */ - if (eui64_iszero(ho->hisid)) { - ppp_error("Could not determine remote LL address"); - ipv6cp_close(f->pcb, "Could not determine remote LL address"); - return; - } - if (eui64_iszero(go->ourid)) { - ppp_error("Could not determine local LL address"); - ipv6cp_close(f->pcb, "Could not determine local LL address"); - return; - } - if (eui64_equals(go->ourid, ho->hisid)) { - ppp_error("local and remote LL addresses are equal"); - ipv6cp_close(f->pcb, "local and remote LL addresses are equal"); - return; - } -#if 0 /* UNUSED */ - } -#endif /* UNUSED */ -#if 0 /* UNUSED */ - script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0); - script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0); -#endif /* UNUSED */ - -#ifdef IPV6CP_COMP - /* set tcp compression */ - sif6comp(f->unit, ho->neg_vj); -#endif - -#if DEMAND_SUPPORT - /* - * If we are doing dial-on-demand, the interface is already - * configured, so we put out any saved-up packets, then set the - * interface to pass IPv6 packets. - */ - if (demand) { - if (! eui64_equals(go->ourid, wo->ourid) || - ! eui64_equals(ho->hisid, wo->hisid)) { - if (! eui64_equals(go->ourid, wo->ourid)) - warn("Local LL address changed to %s", - llv6_ntoa(go->ourid)); - if (! eui64_equals(ho->hisid, wo->hisid)) - warn("Remote LL address changed to %s", - llv6_ntoa(ho->hisid)); - ipv6cp_clear_addrs(f->pcb, go->ourid, ho->hisid); - - /* Set the interface to the new addresses */ - if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { - if (debug) - warn("sif6addr failed"); - ipv6cp_close(f->unit, "Interface configuration failed"); - return; - } - - } - demand_rexmit(PPP_IPV6); - sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS); - - } else -#endif /* DEMAND_SUPPORT */ - { - /* - * Set LL addresses - */ - if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { - PPPDEBUG(LOG_DEBUG, ("sif6addr failed")); - ipv6cp_close(f->pcb, "Interface configuration failed"); - return; - } - - /* bring the interface up for IPv6 */ - if (!sif6up(f->pcb)) { - PPPDEBUG(LOG_DEBUG, ("sif6up failed (IPV6)")); - ipv6cp_close(f->pcb, "Interface configuration failed"); - return; - } -#if DEMAND_SUPPORT - sifnpmode(f->pcb, PPP_IPV6, NPMODE_PASS); -#endif /* DEMAND_SUPPORT */ - - ppp_notice("local LL address %s", llv6_ntoa(go->ourid)); - ppp_notice("remote LL address %s", llv6_ntoa(ho->hisid)); - } - - np_up(f->pcb, PPP_IPV6); - pcb->ipv6cp_is_up = 1; - -#if 0 /* UNUSED */ - /* - * Execute the ipv6-up script, like this: - * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL - */ - if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) { - ipv6cp_script_state = s_up; - ipv6cp_script(_PATH_IPV6UP); - } -#endif /* UNUSED */ -} - - -/* - * ipv6cp_down - IPV6CP has gone DOWN. - * - * Take the IPv6 network interface down, clear its addresses - * and delete routes through it. - */ -static void ipv6cp_down(fsm *f) { - ppp_pcb *pcb = f->pcb; - ipv6cp_options *go = &pcb->ipv6cp_gotoptions; - ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; - - IPV6CPDEBUG(("ipv6cp: down")); -#if PPP_STATS_SUPPORT - update_link_stats(f->unit); -#endif /* PPP_STATS_SUPPORT */ - if (pcb->ipv6cp_is_up) { - pcb->ipv6cp_is_up = 0; - np_down(f->pcb, PPP_IPV6); - } -#ifdef IPV6CP_COMP - sif6comp(f->unit, 0); -#endif - -#if DEMAND_SUPPORT - /* - * If we are doing dial-on-demand, set the interface - * to queue up outgoing packets (for now). - */ - if (demand) { - sifnpmode(f->pcb, PPP_IPV6, NPMODE_QUEUE); - } else -#endif /* DEMAND_SUPPORT */ - { -#if DEMAND_SUPPORT - sifnpmode(f->pcb, PPP_IPV6, NPMODE_DROP); -#endif /* DEMAND_SUPPORT */ - ipv6cp_clear_addrs(f->pcb, - go->ourid, - ho->hisid); - sif6down(f->pcb); - } - -#if 0 /* UNUSED */ - /* Execute the ipv6-down script */ - if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) { - ipv6cp_script_state = s_down; - ipv6cp_script(_PATH_IPV6DOWN); - } -#endif /* UNUSED */ -} - - -/* - * ipv6cp_clear_addrs() - clear the interface addresses, routes, - * proxy neighbour discovery entries, etc. - */ -static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid) { - cif6addr(pcb, ourid, hisid); -} - - -/* - * ipv6cp_finished - possibly shut down the lower layers. - */ -static void ipv6cp_finished(fsm *f) { - np_finished(f->pcb, PPP_IPV6); -} - - -#if 0 /* UNUSED */ -/* - * ipv6cp_script_done - called when the ipv6-up or ipv6-down script - * has finished. - */ -static void -ipv6cp_script_done(arg) - void *arg; -{ - ipv6cp_script_pid = 0; - switch (ipv6cp_script_state) { - case s_up: - if (ipv6cp_fsm[0].state != PPP_FSM_OPENED) { - ipv6cp_script_state = s_down; - ipv6cp_script(_PATH_IPV6DOWN); - } - break; - case s_down: - if (ipv6cp_fsm[0].state == PPP_FSM_OPENED) { - ipv6cp_script_state = s_up; - ipv6cp_script(_PATH_IPV6UP); - } - break; - } -} - - -/* - * ipv6cp_script - Execute a script with arguments - * interface-name tty-name speed local-LL remote-LL. - */ -static void -ipv6cp_script(script) - char *script; -{ - char strspeed[32], strlocal[32], strremote[32]; - char *argv[8]; - - sprintf(strspeed, "%d", baud_rate); - strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid)); - strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid)); - - argv[0] = script; - argv[1] = ifname; - argv[2] = devnam; - argv[3] = strspeed; - argv[4] = strlocal; - argv[5] = strremote; - argv[6] = ipparam; - argv[7] = NULL; - - ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, - NULL, 0); -} -#endif /* UNUSED */ - -#if PRINTPKT_SUPPORT -/* - * ipv6cp_printpkt - print the contents of an IPV6CP packet. - */ -static const char* const ipv6cp_codenames[] = { - "ConfReq", "ConfAck", "ConfNak", "ConfRej", - "TermReq", "TermAck", "CodeRej" -}; - -static int ipv6cp_printpkt(const u_char *p, int plen, - void (*printer)(void *, const char *, ...), void *arg) { - int code, id, len, olen; - const u_char *pstart, *optend; -#ifdef IPV6CP_COMP - u_short cishort; -#endif /* IPV6CP_COMP */ - eui64_t ifaceid; - - if (plen < HEADERLEN) - return 0; - pstart = p; - GETCHAR(code, p); - GETCHAR(id, p); - GETSHORT(len, p); - if (len < HEADERLEN || len > plen) - return 0; - - if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipv6cp_codenames)) - printer(arg, " %s", ipv6cp_codenames[code-1]); - else - printer(arg, " code=0x%x", code); - printer(arg, " id=0x%x", id); - len -= HEADERLEN; - switch (code) { - case CONFREQ: - case CONFACK: - case CONFNAK: - case CONFREJ: - /* print option list */ - while (len >= 2) { - GETCHAR(code, p); - GETCHAR(olen, p); - p -= 2; - if (olen < 2 || olen > len) { - break; - } - printer(arg, " <"); - len -= olen; - optend = p + olen; - switch (code) { -#ifdef IPV6CP_COMP - case CI_COMPRESSTYPE: - if (olen >= CILEN_COMPRESS) { - p += 2; - GETSHORT(cishort, p); - printer(arg, "compress "); - printer(arg, "0x%x", cishort); - } - break; -#endif /* IPV6CP_COMP */ - case CI_IFACEID: - if (olen == CILEN_IFACEID) { - p += 2; - eui64_get(ifaceid, p); - printer(arg, "addr %s", llv6_ntoa(ifaceid)); - } - break; - default: - break; - } - while (p < optend) { - GETCHAR(code, p); - printer(arg, " %.2x", code); - } - printer(arg, ">"); - } - break; - - case TERMACK: - case TERMREQ: - if (len > 0 && *p >= ' ' && *p < 0x7f) { - printer(arg, " "); - ppp_print_string(p, len, printer, arg); - p += len; - len = 0; - } - break; - default: - break; - } - - /* print the rest of the bytes in the packet */ - for (; len > 0; --len) { - GETCHAR(code, p); - printer(arg, " %.2x", code); - } - - return p - pstart; -} -#endif /* PRINTPKT_SUPPORT */ - -#if DEMAND_SUPPORT -/* - * ipv6_active_pkt - see if this IP packet is worth bringing the link up for. - * We don't bring the link up for IP fragments or for TCP FIN packets - * with no data. - */ -#define IP6_HDRLEN 40 /* bytes */ -#define IP6_NHDR_FRAG 44 /* fragment IPv6 header */ -#define TCP_HDRLEN 20 -#define TH_FIN 0x01 - -/* - * We use these macros because the IP header may be at an odd address, - * and some compilers might use word loads to get th_off or ip_hl. - */ - -#define get_ip6nh(x) (((unsigned char *)(x))[6]) -#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) -#define get_tcpflags(x) (((unsigned char *)(x))[13]) - -static int ipv6_active_pkt(u_char *pkt, int len) { - u_char *tcp; - - len -= PPP_HDRLEN; - pkt += PPP_HDRLEN; - if (len < IP6_HDRLEN) - return 0; - if (get_ip6nh(pkt) == IP6_NHDR_FRAG) - return 0; - if (get_ip6nh(pkt) != IPPROTO_TCP) - return 1; - if (len < IP6_HDRLEN + TCP_HDRLEN) - return 0; - tcp = pkt + IP6_HDRLEN; - if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4) - return 0; - return 1; -} -#endif /* DEMAND_SUPPORT */ - -#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/lcp.c b/ext/lwip/src/netif/ppp/lcp.c deleted file mode 100644 index b17964b..0000000 --- a/ext/lwip/src/netif/ppp/lcp.c +++ /dev/null @@ -1,2786 +0,0 @@ -/* - * lcp.c - PPP Link Control Protocol. - * - * 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -/* - * @todo: - */ - -#if 0 /* UNUSED */ -#include -#include -#include -#endif /* UNUSED */ - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/fsm.h" -#include "netif/ppp/lcp.h" -#if CHAP_SUPPORT -#include "netif/ppp/chap-new.h" -#endif /* CHAP_SUPPORT */ -#include "netif/ppp/magic.h" - -/* - * When the link comes up we want to be able to wait for a short while, - * or until seeing some input from the peer, before starting to send - * configure-requests. We do this by delaying the fsm_lowerup call. - */ -/* steal a bit in fsm flags word */ -#define DELAYED_UP 0x80 - -static void lcp_delayed_up(void *arg); - -/* - * LCP-related command-line options. - */ -#if 0 /* UNUSED */ -int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ -int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ -#endif /* UNUSED */ - -#if 0 /* UNUSED */ -/* options */ -static u_int lcp_echo_interval = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */ -static u_int lcp_echo_fails = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */ -#endif /* UNUSED */ - -#if 0 /* UNUSED */ -#if PPP_LCP_ADAPTIVE -bool lcp_echo_adaptive = 0; /* request echo only if the link was idle */ -#endif -bool lax_recv = 0; /* accept control chars in asyncmap */ -bool noendpoint = 0; /* don't send/accept endpoint discriminator */ -#endif /* UNUSED */ - -#if PPP_OPTIONS -static int noopt (char **); -#endif /* PPP_OPTIONS */ - -#ifdef HAVE_MULTILINK -static int setendpoint (char **); -static void printendpoint (option_t *, void (*)(void *, char *, ...), - void *); -#endif /* HAVE_MULTILINK */ - -#if PPP_OPTIONS -static option_t lcp_option_list[] = { - /* LCP options */ - { "-all", o_special_noarg, (void *)noopt, - "Don't request/allow any LCP options" }, - - { "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression, - "Disable address/control compression", - OPT_A2CLR, &lcp_allowoptions[0].neg_accompression }, - { "-ac", o_bool, &lcp_wantoptions[0].neg_accompression, - "Disable address/control compression", - OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_accompression }, - - { "asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap, - "Set asyncmap (for received packets)", - OPT_OR, &lcp_wantoptions[0].neg_asyncmap }, - { "-as", o_uint32, &lcp_wantoptions[0].asyncmap, - "Set asyncmap (for received packets)", - OPT_ALIAS | OPT_OR, &lcp_wantoptions[0].neg_asyncmap }, - { "default-asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap, - "Disable asyncmap negotiation", - OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR, - &lcp_allowoptions[0].neg_asyncmap }, - { "-am", o_uint32, &lcp_wantoptions[0].asyncmap, - "Disable asyncmap negotiation", - OPT_ALIAS | OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR, - &lcp_allowoptions[0].neg_asyncmap }, - - { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber, - "Disable magic number negotiation (looped-back line detection)", - OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber }, - { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber, - "Disable magic number negotiation (looped-back line detection)", - OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber }, - - { "mru", o_int, &lcp_wantoptions[0].mru, - "Set MRU (maximum received packet size) for negotiation", - OPT_PRIO, &lcp_wantoptions[0].neg_mru }, - { "default-mru", o_bool, &lcp_wantoptions[0].neg_mru, - "Disable MRU negotiation (use default 1500)", - OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru }, - { "-mru", o_bool, &lcp_wantoptions[0].neg_mru, - "Disable MRU negotiation (use default 1500)", - OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru }, - - { "mtu", o_int, &lcp_allowoptions[0].mru, - "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU }, - - { "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression, - "Disable protocol field compression", - OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression }, - { "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression, - "Disable protocol field compression", - OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression }, - - { "passive", o_bool, &lcp_wantoptions[0].passive, - "Set passive mode", 1 }, - { "-p", o_bool, &lcp_wantoptions[0].passive, - "Set passive mode", OPT_ALIAS | 1 }, - - { "silent", o_bool, &lcp_wantoptions[0].silent, - "Set silent mode", 1 }, - - { "lcp-echo-failure", o_int, &lcp_echo_fails, - "Set number of consecutive echo failures to indicate link failure", - OPT_PRIO }, - { "lcp-echo-interval", o_int, &lcp_echo_interval, - "Set time in seconds between LCP echo requests", OPT_PRIO }, -#if PPP_LCP_ADAPTIVE - { "lcp-echo-adaptive", o_bool, &lcp_echo_adaptive, - "Suppress LCP echo requests if traffic was received", 1 }, -#endif - { "lcp-restart", o_int, &lcp_fsm[0].timeouttime, - "Set time in seconds between LCP retransmissions", OPT_PRIO }, - { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits, - "Set maximum number of LCP terminate-request transmissions", OPT_PRIO }, - { "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits, - "Set maximum number of LCP configure-request transmissions", OPT_PRIO }, - { "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops, - "Set limit on number of LCP configure-naks", OPT_PRIO }, - - { "receive-all", o_bool, &lax_recv, - "Accept all received control characters", 1 }, - -#ifdef HAVE_MULTILINK - { "mrru", o_int, &lcp_wantoptions[0].mrru, - "Maximum received packet size for multilink bundle", - OPT_PRIO, &lcp_wantoptions[0].neg_mrru }, - - { "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf, - "Use short sequence numbers in multilink headers", - OPT_PRIO | 1, &lcp_allowoptions[0].neg_ssnhf }, - { "nompshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf, - "Don't use short sequence numbers in multilink headers", - OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_ssnhf }, - - { "endpoint", o_special, (void *) setendpoint, - "Endpoint discriminator for multilink", - OPT_PRIO | OPT_A2PRINTER, (void *) printendpoint }, -#endif /* HAVE_MULTILINK */ - - { "noendpoint", o_bool, &noendpoint, - "Don't send or accept multilink endpoint discriminator", 1 }, - - {NULL} -}; -#endif /* PPP_OPTIONS */ - -/* - * Callbacks for fsm code. (CI = Configuration Information) - */ -static void lcp_resetci(fsm *f); /* Reset our CI */ -static int lcp_cilen(fsm *f); /* Return length of our CI */ -static void lcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI to pkt */ -static int lcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ -static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */ -static int lcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ -static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree); /* Rcv peer CI */ -static void lcp_up(fsm *f); /* We're UP */ -static void lcp_down(fsm *f); /* We're DOWN */ -static void lcp_starting (fsm *); /* We need lower layer up */ -static void lcp_finished (fsm *); /* We need lower layer down */ -static int lcp_extcode(fsm *f, int code, int id, u_char *inp, int len); -static void lcp_rprotrej(fsm *f, u_char *inp, int len); - -/* - * routines to send LCP echos to peer - */ - -static void lcp_echo_lowerup(ppp_pcb *pcb); -static void lcp_echo_lowerdown(ppp_pcb *pcb); -static void LcpEchoTimeout(void *arg); -static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len); -static void LcpSendEchoRequest(fsm *f); -static void LcpLinkFailure(fsm *f); -static void LcpEchoCheck(fsm *f); - -static const fsm_callbacks lcp_callbacks = { /* LCP callback routines */ - lcp_resetci, /* Reset our Configuration Information */ - lcp_cilen, /* Length of our Configuration Information */ - lcp_addci, /* Add our Configuration Information */ - lcp_ackci, /* ACK our Configuration Information */ - lcp_nakci, /* NAK our Configuration Information */ - lcp_rejci, /* Reject our Configuration Information */ - lcp_reqci, /* Request peer's Configuration Information */ - lcp_up, /* Called when fsm reaches OPENED state */ - lcp_down, /* Called when fsm leaves OPENED state */ - lcp_starting, /* Called when we want the lower layer up */ - lcp_finished, /* Called when we want the lower layer down */ - NULL, /* Called when Protocol-Reject received */ - NULL, /* Retransmission is necessary */ - lcp_extcode, /* Called to handle LCP-specific codes */ - "LCP" /* String name of protocol */ -}; - -/* - * Protocol entry points. - * Some of these are called directly. - */ - -static void lcp_init(ppp_pcb *pcb); -static void lcp_input(ppp_pcb *pcb, u_char *p, int len); -static void lcp_protrej(ppp_pcb *pcb); -#if PRINTPKT_SUPPORT -static int lcp_printpkt(const u_char *p, int plen, - void (*printer) (void *, const char *, ...), void *arg); -#endif /* PRINTPKT_SUPPORT */ - -const struct protent lcp_protent = { - PPP_LCP, - lcp_init, - lcp_input, - lcp_protrej, - lcp_lowerup, - lcp_lowerdown, - lcp_open, - lcp_close, -#if PRINTPKT_SUPPORT - lcp_printpkt, -#endif /* PRINTPKT_SUPPORT */ -#if PPP_DATAINPUT - NULL, -#endif /* PPP_DATAINPUT */ -#if PRINTPKT_SUPPORT - "LCP", - NULL, -#endif /* PRINTPKT_SUPPORT */ -#if PPP_OPTIONS - lcp_option_list, - NULL, -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT - NULL, - NULL -#endif /* DEMAND_SUPPORT */ -}; - -/* - * Length of each type of configuration option (in octets) - */ -#define CILEN_VOID 2 -#define CILEN_CHAR 3 -#define CILEN_SHORT 4 /* CILEN_VOID + 2 */ -#if CHAP_SUPPORT -#define CILEN_CHAP 5 /* CILEN_VOID + 2 + 1 */ -#endif /* CHAP_SUPPORT */ -#define CILEN_LONG 6 /* CILEN_VOID + 4 */ -#if LQR_SUPPORT -#define CILEN_LQR 8 /* CILEN_VOID + 2 + 4 */ -#endif /* LQR_SUPPORT */ -#define CILEN_CBCP 3 - -#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ - (x) == CONFNAK ? "NAK" : "REJ") - -#if PPP_OPTIONS -/* - * noopt - Disable all options (why?). - */ -static int -noopt(argv) - char **argv; -{ - BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options)); - BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options)); - - return (1); -} -#endif /* PPP_OPTIONS */ - -#ifdef HAVE_MULTILINK -static int -setendpoint(argv) - char **argv; -{ - if (str_to_epdisc(&lcp_wantoptions[0].endpoint, *argv)) { - lcp_wantoptions[0].neg_endpoint = 1; - return 1; - } - option_error("Can't parse '%s' as an endpoint discriminator", *argv); - return 0; -} - -static void -printendpoint(opt, printer, arg) - option_t *opt; - void (*printer) (void *, char *, ...); - void *arg; -{ - printer(arg, "%s", epdisc_to_str(&lcp_wantoptions[0].endpoint)); -} -#endif /* HAVE_MULTILINK */ - -/* - * lcp_init - Initialize LCP. - */ -static void lcp_init(ppp_pcb *pcb) { - fsm *f = &pcb->lcp_fsm; - lcp_options *wo = &pcb->lcp_wantoptions; - lcp_options *ao = &pcb->lcp_allowoptions; - - f->pcb = pcb; - f->protocol = PPP_LCP; - f->callbacks = &lcp_callbacks; - - fsm_init(f); - - BZERO(wo, sizeof(*wo)); - wo->neg_mru = 1; - wo->mru = PPP_DEFMRU; - wo->neg_asyncmap = 1; - wo->neg_magicnumber = 1; - wo->neg_pcompression = 1; - wo->neg_accompression = 1; - - BZERO(ao, sizeof(*ao)); - ao->neg_mru = 1; - ao->mru = PPP_MAXMRU; - ao->neg_asyncmap = 1; -#if CHAP_SUPPORT - ao->neg_chap = 1; - ao->chap_mdtype = CHAP_MDTYPE_SUPPORTED; -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - ao->neg_upap = 1; -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - ao->neg_eap = 1; -#endif /* EAP_SUPPORT */ - ao->neg_magicnumber = 1; - ao->neg_pcompression = 1; - ao->neg_accompression = 1; - ao->neg_endpoint = 1; -} - - -/* - * lcp_open - LCP is allowed to come up. - */ -void lcp_open(ppp_pcb *pcb) { - fsm *f = &pcb->lcp_fsm; - lcp_options *wo = &pcb->lcp_wantoptions; - - f->flags &= ~(OPT_PASSIVE | OPT_SILENT); - if (wo->passive) - f->flags |= OPT_PASSIVE; - if (wo->silent) - f->flags |= OPT_SILENT; - fsm_open(f); -} - - -/* - * lcp_close - Take LCP down. - */ -void lcp_close(ppp_pcb *pcb, const char *reason) { - fsm *f = &pcb->lcp_fsm; - int oldstate; - - if (pcb->phase != PPP_PHASE_DEAD && pcb->phase != PPP_PHASE_MASTER) - new_phase(pcb, PPP_PHASE_TERMINATE); - - if (f->flags & DELAYED_UP) { - UNTIMEOUT(lcp_delayed_up, f); - f->state = PPP_FSM_STOPPED; - } - oldstate = f->state; - - fsm_close(f, reason); - if (oldstate == PPP_FSM_STOPPED && (f->flags & (OPT_PASSIVE|OPT_SILENT|DELAYED_UP))) { - /* - * This action is not strictly according to the FSM in RFC1548, - * but it does mean that the program terminates if you do a - * lcp_close() when a connection hasn't been established - * because we are in passive/silent mode or because we have - * delayed the fsm_lowerup() call and it hasn't happened yet. - */ - f->flags &= ~DELAYED_UP; - lcp_finished(f); - } -} - - -/* - * lcp_lowerup - The lower layer is up. - */ -void lcp_lowerup(ppp_pcb *pcb) { - lcp_options *wo = &pcb->lcp_wantoptions; - fsm *f = &pcb->lcp_fsm; - /* - * Don't use A/C or protocol compression on transmission, - * but accept A/C and protocol compressed packets - * if we are going to ask for A/C and protocol compression. - */ - if (ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0) < 0 - || ppp_recv_config(pcb, PPP_MRU, (pcb->settings.lax_recv? 0: 0xffffffff), - wo->neg_pcompression, wo->neg_accompression) < 0) - return; - pcb->peer_mru = PPP_MRU; - - if (pcb->settings.listen_time != 0) { - f->flags |= DELAYED_UP; - TIMEOUTMS(lcp_delayed_up, f, pcb->settings.listen_time); - } else - fsm_lowerup(f); -} - - -/* - * lcp_lowerdown - The lower layer is down. - */ -void lcp_lowerdown(ppp_pcb *pcb) { - fsm *f = &pcb->lcp_fsm; - - if (f->flags & DELAYED_UP) { - f->flags &= ~DELAYED_UP; - UNTIMEOUT(lcp_delayed_up, f); - } else - fsm_lowerdown(f); -} - - -/* - * lcp_delayed_up - Bring the lower layer up now. - */ -static void lcp_delayed_up(void *arg) { - fsm *f = (fsm*)arg; - - if (f->flags & DELAYED_UP) { - f->flags &= ~DELAYED_UP; - fsm_lowerup(f); - } -} - - -/* - * lcp_input - Input LCP packet. - */ -static void lcp_input(ppp_pcb *pcb, u_char *p, int len) { - fsm *f = &pcb->lcp_fsm; - - if (f->flags & DELAYED_UP) { - f->flags &= ~DELAYED_UP; - UNTIMEOUT(lcp_delayed_up, f); - fsm_lowerup(f); - } - fsm_input(f, p, len); -} - -/* - * lcp_extcode - Handle a LCP-specific code. - */ -static int lcp_extcode(fsm *f, int code, int id, u_char *inp, int len) { - ppp_pcb *pcb = f->pcb; - lcp_options *go = &pcb->lcp_gotoptions; - u_char *magp; - - switch( code ){ - case PROTREJ: - lcp_rprotrej(f, inp, len); - break; - - case ECHOREQ: - if (f->state != PPP_FSM_OPENED) - break; - magp = inp; - PUTLONG(go->magicnumber, magp); - fsm_sdata(f, ECHOREP, id, inp, len); - break; - - case ECHOREP: - lcp_received_echo_reply(f, id, inp, len); - break; - - case DISCREQ: - case IDENTIF: - case TIMEREM: - break; - - default: - return 0; - } - return 1; -} - - -/* - * lcp_rprotrej - Receive an Protocol-Reject. - * - * Figure out which protocol is rejected and inform it. - */ -static void lcp_rprotrej(fsm *f, u_char *inp, int len) { - int i; - const struct protent *protp; - u_short prot; -#if PPP_PROTOCOLNAME - const char *pname; -#endif /* PPP_PROTOCOLNAME */ - - if (len < 2) { - LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!")); - return; - } - - GETSHORT(prot, inp); - - /* - * Protocol-Reject packets received in any state other than the LCP - * OPENED state SHOULD be silently discarded. - */ - if( f->state != PPP_FSM_OPENED ){ - LCPDEBUG(("Protocol-Reject discarded: LCP in state %d", f->state)); - return; - } - -#if PPP_PROTOCOLNAME - pname = protocol_name(prot); -#endif /* PPP_PROTOCOLNAME */ - - /* - * Upcall the proper Protocol-Reject routine. - */ - for (i = 0; (protp = protocols[i]) != NULL; ++i) - if (protp->protocol == prot) { -#if PPP_PROTOCOLNAME - if (pname != NULL) - ppp_dbglog("Protocol-Reject for '%s' (0x%x) received", pname, - prot); - else -#endif /* PPP_PROTOCOLNAME */ - ppp_dbglog("Protocol-Reject for 0x%x received", prot); - (*protp->protrej)(f->pcb); - return; - } - -#if PPP_PROTOCOLNAME - if (pname != NULL) - ppp_warn("Protocol-Reject for unsupported protocol '%s' (0x%x)", pname, - prot); - else -#endif /* #if PPP_PROTOCOLNAME */ - ppp_warn("Protocol-Reject for unsupported protocol 0x%x", prot); -} - - -/* - * lcp_protrej - A Protocol-Reject was received. - */ -/*ARGSUSED*/ -static void lcp_protrej(ppp_pcb *pcb) { - /* - * Can't reject LCP! - */ - ppp_error("Received Protocol-Reject for LCP!"); - fsm_protreject(&pcb->lcp_fsm); -} - - -/* - * lcp_sprotrej - Send a Protocol-Reject for some protocol. - */ -void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len) { - fsm *f = &pcb->lcp_fsm; - /* - * Send back the protocol and the information field of the - * rejected packet. We only get here if LCP is in the OPENED state. - */ -#if 0 - p += 2; - len -= 2; -#endif - - fsm_sdata(f, PROTREJ, ++f->id, - p, len); -} - - -/* - * lcp_resetci - Reset our CI. - */ -static void lcp_resetci(fsm *f) { - ppp_pcb *pcb = f->pcb; - lcp_options *wo = &pcb->lcp_wantoptions; - lcp_options *go = &pcb->lcp_gotoptions; - lcp_options *ao = &pcb->lcp_allowoptions; - -#if PPP_AUTH_SUPPORT - - /* note: default value is true for allow options */ - if (pcb->settings.user && pcb->settings.passwd) { -#if PAP_SUPPORT - if (pcb->settings.refuse_pap) { - ao->neg_upap = 0; - } -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - if (pcb->settings.refuse_chap) { - ao->chap_mdtype &= ~MDTYPE_MD5; - } -#if MSCHAP_SUPPORT - if (pcb->settings.refuse_mschap) { - ao->chap_mdtype &= ~MDTYPE_MICROSOFT; - } - if (pcb->settings.refuse_mschap_v2) { - ao->chap_mdtype &= ~MDTYPE_MICROSOFT_V2; - } -#endif /* MSCHAP_SUPPORT */ - ao->neg_chap = (ao->chap_mdtype != MDTYPE_NONE); -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - if (pcb->settings.refuse_eap) { - ao->neg_eap = 0; - } -#endif /* EAP_SUPPORT */ - -#if PPP_SERVER - /* note: default value is false for wanted options */ - if (pcb->settings.auth_required) { -#if PAP_SUPPORT - if (!pcb->settings.refuse_pap) { - wo->neg_upap = 1; - } -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - if (!pcb->settings.refuse_chap) { - wo->chap_mdtype |= MDTYPE_MD5; - } -#if MSCHAP_SUPPORT - if (!pcb->settings.refuse_mschap) { - wo->chap_mdtype |= MDTYPE_MICROSOFT; - } - if (!pcb->settings.refuse_mschap_v2) { - wo->chap_mdtype |= MDTYPE_MICROSOFT_V2; - } -#endif /* MSCHAP_SUPPORT */ - wo->neg_chap = (wo->chap_mdtype != MDTYPE_NONE); -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - if (!pcb->settings.refuse_eap) { - wo->neg_eap = 1; - } -#endif /* EAP_SUPPORT */ - } -#endif /* PPP_SERVER */ - - } else { -#if PAP_SUPPORT - ao->neg_upap = 0; -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - ao->neg_chap = 0; - ao->chap_mdtype = MDTYPE_NONE; -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - ao->neg_eap = 0; -#endif /* EAP_SUPPORT */ - } - - PPPDEBUG(LOG_DEBUG, ("ppp: auth protocols:")); -#if PAP_SUPPORT - PPPDEBUG(LOG_DEBUG, (" PAP=%d", ao->neg_upap)); -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - PPPDEBUG(LOG_DEBUG, (" CHAP=%d CHAP_MD5=%d", ao->neg_chap, !!(ao->chap_mdtype&MDTYPE_MD5))); -#if MSCHAP_SUPPORT - PPPDEBUG(LOG_DEBUG, (" CHAP_MS=%d CHAP_MS2=%d", !!(ao->chap_mdtype&MDTYPE_MICROSOFT), !!(ao->chap_mdtype&MDTYPE_MICROSOFT_V2))); -#endif /* MSCHAP_SUPPORT */ -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - PPPDEBUG(LOG_DEBUG, (" EAP=%d", ao->neg_eap)); -#endif /* EAP_SUPPORT */ - PPPDEBUG(LOG_DEBUG, ("\n")); - -#endif /* PPP_AUTH_SUPPORT */ - - wo->magicnumber = magic(); - wo->numloops = 0; - *go = *wo; -#ifdef HAVE_MULTILINK - if (!multilink) { - go->neg_mrru = 0; -#endif /* HAVE_MULTILINK */ - go->neg_ssnhf = 0; - go->neg_endpoint = 0; -#ifdef HAVE_MULTILINK - } -#endif /* HAVE_MULTILINK */ - if (pcb->settings.noendpoint) - ao->neg_endpoint = 0; - pcb->peer_mru = PPP_MRU; -#if 0 /* UNUSED */ - auth_reset(pcb); -#endif /* UNUSED */ -} - - -/* - * lcp_cilen - Return length of our CI. - */ -static int lcp_cilen(fsm *f) { - ppp_pcb *pcb = f->pcb; - lcp_options *go = &pcb->lcp_gotoptions; - -#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0) -#if CHAP_SUPPORT -#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0) -#endif /* CHAP_SUPPORT */ -#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0) -#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0) -#if LQR_SUPPORT -#define LENCILQR(neg) ((neg) ? CILEN_LQR: 0) -#endif /* LQR_SUPPORT */ -#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0) - /* - * NB: we only ask for one of CHAP, UPAP, or EAP, even if we will - * accept more than one. We prefer EAP first, then CHAP, then - * PAP. - */ - return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) + - LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) + -#if EAP_SUPPORT - LENCISHORT(go->neg_eap) + -#endif /* EAP_SUPPORT */ -#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ -#if EAP_SUPPORT - LENCICHAP(!go->neg_eap && go->neg_chap) + -#endif /* EAP_SUPPORT */ -#if !EAP_SUPPORT - LENCICHAP(go->neg_chap) + -#endif /* !EAP_SUPPORT */ -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ -#if EAP_SUPPORT && CHAP_SUPPORT - LENCISHORT(!go->neg_eap && !go->neg_chap && go->neg_upap) + -#endif /* EAP_SUPPORT && CHAP_SUPPORT */ -#if EAP_SUPPORT && !CHAP_SUPPORT - LENCISHORT(!go->neg_eap && go->neg_upap) + -#endif /* EAP_SUPPORT && !CHAP_SUPPORT */ -#if !EAP_SUPPORT && CHAP_SUPPORT - LENCISHORT(!go->neg_chap && go->neg_upap) + -#endif /* !EAP_SUPPORT && CHAP_SUPPORT */ -#if !EAP_SUPPORT && !CHAP_SUPPORT - LENCISHORT(go->neg_upap) + -#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ -#endif /* PAP_SUPPORT */ -#if LQR_SUPPORT - LENCILQR(go->neg_lqr) + -#endif /* LQR_SUPPORT */ - LENCICBCP(go->neg_cbcp) + - LENCILONG(go->neg_magicnumber) + - LENCIVOID(go->neg_pcompression) + - LENCIVOID(go->neg_accompression) + -#ifdef HAVE_MULTILINK - LENCISHORT(go->neg_mrru) + -#endif /* HAVE_MULTILINK */ - LENCIVOID(go->neg_ssnhf) + - (go->neg_endpoint? CILEN_CHAR + go->endpoint.length: 0)); -} - - -/* - * lcp_addci - Add our desired CIs to a packet. - */ -static void lcp_addci(fsm *f, u_char *ucp, int *lenp) { - ppp_pcb *pcb = f->pcb; - lcp_options *go = &pcb->lcp_gotoptions; - u_char *start_ucp = ucp; - -#define ADDCIVOID(opt, neg) \ - if (neg) { \ - PUTCHAR(opt, ucp); \ - PUTCHAR(CILEN_VOID, ucp); \ - } -#define ADDCISHORT(opt, neg, val) \ - if (neg) { \ - PUTCHAR(opt, ucp); \ - PUTCHAR(CILEN_SHORT, ucp); \ - PUTSHORT(val, ucp); \ - } -#if CHAP_SUPPORT -#define ADDCICHAP(opt, neg, val) \ - if (neg) { \ - PUTCHAR((opt), ucp); \ - PUTCHAR(CILEN_CHAP, ucp); \ - PUTSHORT(PPP_CHAP, ucp); \ - PUTCHAR((CHAP_DIGEST(val)), ucp); \ - } -#endif /* CHAP_SUPPORT */ -#define ADDCILONG(opt, neg, val) \ - if (neg) { \ - PUTCHAR(opt, ucp); \ - PUTCHAR(CILEN_LONG, ucp); \ - PUTLONG(val, ucp); \ - } -#if LQR_SUPPORT -#define ADDCILQR(opt, neg, val) \ - if (neg) { \ - PUTCHAR(opt, ucp); \ - PUTCHAR(CILEN_LQR, ucp); \ - PUTSHORT(PPP_LQR, ucp); \ - PUTLONG(val, ucp); \ - } -#endif /* LQR_SUPPORT */ -#define ADDCICHAR(opt, neg, val) \ - if (neg) { \ - PUTCHAR(opt, ucp); \ - PUTCHAR(CILEN_CHAR, ucp); \ - PUTCHAR(val, ucp); \ - } -#define ADDCIENDP(opt, neg, class, val, len) \ - if (neg) { \ - int i; \ - PUTCHAR(opt, ucp); \ - PUTCHAR(CILEN_CHAR + len, ucp); \ - PUTCHAR(class, ucp); \ - for (i = 0; i < len; ++i) \ - PUTCHAR(val[i], ucp); \ - } - - ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); - ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, - go->asyncmap); -#if EAP_SUPPORT - ADDCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP); -#endif /* EAP_SUPPORT */ -#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ -#if EAP_SUPPORT - ADDCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype); -#endif /* EAP_SUPPORT */ -#if !EAP_SUPPORT - ADDCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype); -#endif /* !EAP_SUPPORT */ -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ -#if EAP_SUPPORT && CHAP_SUPPORT - ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP); -#endif /* EAP_SUPPORT && CHAP_SUPPORT */ -#if EAP_SUPPORT && !CHAP_SUPPORT - ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP); -#endif /* EAP_SUPPORT && !CHAP_SUPPORT */ -#if !EAP_SUPPORT && CHAP_SUPPORT - ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); -#endif /* !EAP_SUPPORT && CHAP_SUPPORT */ -#if !EAP_SUPPORT && !CHAP_SUPPORT - ADDCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP); -#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ -#endif /* PAP_SUPPORT */ -#if LQR_SUPPORT - ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); -#endif /* LQR_SUPPORT */ - ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); - ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); - ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression); - ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression); -#ifdef HAVE_MULTILINK - ADDCISHORT(CI_MRRU, go->neg_mrru, go->mrru); -#endif - ADDCIVOID(CI_SSNHF, go->neg_ssnhf); - ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_, - go->endpoint.value, go->endpoint.length); - - if (ucp - start_ucp != *lenp) { - /* this should never happen, because peer_mtu should be 1500 */ - ppp_error("Bug in lcp_addci: wrong length"); - } -} - - -/* - * lcp_ackci - Ack our CIs. - * This should not modify any state if the Ack is bad. - * - * Returns: - * 0 - Ack was bad. - * 1 - Ack was good. - */ -static int lcp_ackci(fsm *f, u_char *p, int len) { - ppp_pcb *pcb = f->pcb; - lcp_options *go = &pcb->lcp_gotoptions; - u_char cilen, citype, cichar; - u_short cishort; - u32_t cilong; - - /* - * CIs must be in exactly the same order that we sent. - * Check packet length and CI length at each step. - * If we find any deviations, then this packet is bad. - */ -#define ACKCIVOID(opt, neg) \ - if (neg) { \ - if ((len -= CILEN_VOID) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_VOID || \ - citype != opt) \ - goto bad; \ - } -#define ACKCISHORT(opt, neg, val) \ - if (neg) { \ - if ((len -= CILEN_SHORT) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_SHORT || \ - citype != opt) \ - goto bad; \ - GETSHORT(cishort, p); \ - if (cishort != val) \ - goto bad; \ - } -#define ACKCICHAR(opt, neg, val) \ - if (neg) { \ - if ((len -= CILEN_CHAR) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_CHAR || \ - citype != opt) \ - goto bad; \ - GETCHAR(cichar, p); \ - if (cichar != val) \ - goto bad; \ - } -#if CHAP_SUPPORT -#define ACKCICHAP(opt, neg, val) \ - if (neg) { \ - if ((len -= CILEN_CHAP) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_CHAP || \ - citype != (opt)) \ - goto bad; \ - GETSHORT(cishort, p); \ - if (cishort != PPP_CHAP) \ - goto bad; \ - GETCHAR(cichar, p); \ - if (cichar != (CHAP_DIGEST(val))) \ - goto bad; \ - } -#endif /* CHAP_SUPPORT */ -#define ACKCILONG(opt, neg, val) \ - if (neg) { \ - if ((len -= CILEN_LONG) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_LONG || \ - citype != opt) \ - goto bad; \ - GETLONG(cilong, p); \ - if (cilong != val) \ - goto bad; \ - } -#if LQR_SUPPORT -#define ACKCILQR(opt, neg, val) \ - if (neg) { \ - if ((len -= CILEN_LQR) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_LQR || \ - citype != opt) \ - goto bad; \ - GETSHORT(cishort, p); \ - if (cishort != PPP_LQR) \ - goto bad; \ - GETLONG(cilong, p); \ - if (cilong != val) \ - goto bad; \ - } -#endif /* LQR_SUPPORT */ -#define ACKCIENDP(opt, neg, class, val, vlen) \ - if (neg) { \ - int i; \ - if ((len -= CILEN_CHAR + vlen) < 0) \ - goto bad; \ - GETCHAR(citype, p); \ - GETCHAR(cilen, p); \ - if (cilen != CILEN_CHAR + vlen || \ - citype != opt) \ - goto bad; \ - GETCHAR(cichar, p); \ - if (cichar != class) \ - goto bad; \ - for (i = 0; i < vlen; ++i) { \ - GETCHAR(cichar, p); \ - if (cichar != val[i]) \ - goto bad; \ - } \ - } - - ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); - ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, - go->asyncmap); -#if EAP_SUPPORT - ACKCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP); -#endif /* EAP_SUPPORT */ -#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ -#if EAP_SUPPORT - ACKCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype); -#endif /* EAP_SUPPORT */ -#if !EAP_SUPPORT - ACKCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype); -#endif /* !EAP_SUPPORT */ -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ -#if EAP_SUPPORT && CHAP_SUPPORT - ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP); -#endif /* EAP_SUPPORT && CHAP_SUPPORT */ -#if EAP_SUPPORT && !CHAP_SUPPORT - ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP); -#endif /* EAP_SUPPORT && !CHAP_SUPPORT */ -#if !EAP_SUPPORT && CHAP_SUPPORT - ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); -#endif /* !EAP_SUPPORT && CHAP_SUPPORT */ -#if !EAP_SUPPORT && !CHAP_SUPPORT - ACKCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP); -#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ -#endif /* PAP_SUPPORT */ -#if LQR_SUPPORT - ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); -#endif /* LQR_SUPPORT */ - ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); - ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); - ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); - ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); -#ifdef HAVE_MULTILINK - ACKCISHORT(CI_MRRU, go->neg_mrru, go->mrru); -#endif /* HAVE_MULTILINK */ - ACKCIVOID(CI_SSNHF, go->neg_ssnhf); - ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_, - go->endpoint.value, go->endpoint.length); - - /* - * If there are any remaining CIs, then this packet is bad. - */ - if (len != 0) - goto bad; - return (1); -bad: - LCPDEBUG(("lcp_acki: received bad Ack!")); - return (0); -} - - -/* - * lcp_nakci - Peer has sent a NAK for some of our CIs. - * This should not modify any state if the Nak is bad - * or if LCP is in the OPENED state. - * - * Returns: - * 0 - Nak was bad. - * 1 - Nak was good. - */ -static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { - ppp_pcb *pcb = f->pcb; - lcp_options *go = &pcb->lcp_gotoptions; - lcp_options *wo = &pcb->lcp_wantoptions; - u_char citype, cichar, *next; - u_short cishort; - u32_t cilong; - lcp_options no; /* options we've seen Naks for */ - lcp_options try_; /* options to request next time */ - int looped_back = 0; - int cilen; - - BZERO(&no, sizeof(no)); - try_ = *go; - - /* - * Any Nak'd CIs must be in exactly the same order that we sent. - * Check packet length and CI length at each step. - * If we find any deviations, then this packet is bad. - */ -#define NAKCIVOID(opt, neg) \ - if (go->neg && \ - len >= CILEN_VOID && \ - p[1] == CILEN_VOID && \ - p[0] == opt) { \ - len -= CILEN_VOID; \ - INCPTR(CILEN_VOID, p); \ - no.neg = 1; \ - try_.neg = 0; \ - } -#if CHAP_SUPPORT -#define NAKCICHAP(opt, neg, code) \ - if (go->neg && \ - len >= CILEN_CHAP && \ - p[1] == CILEN_CHAP && \ - p[0] == opt) { \ - len -= CILEN_CHAP; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - GETCHAR(cichar, p); \ - no.neg = 1; \ - code \ - } -#endif /* CHAP_SUPPORT */ -#define NAKCICHAR(opt, neg, code) \ - if (go->neg && \ - len >= CILEN_CHAR && \ - p[1] == CILEN_CHAR && \ - p[0] == opt) { \ - len -= CILEN_CHAR; \ - INCPTR(2, p); \ - GETCHAR(cichar, p); \ - no.neg = 1; \ - code \ - } -#define NAKCISHORT(opt, neg, code) \ - if (go->neg && \ - len >= CILEN_SHORT && \ - p[1] == CILEN_SHORT && \ - p[0] == opt) { \ - len -= CILEN_SHORT; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - no.neg = 1; \ - code \ - } -#define NAKCILONG(opt, neg, code) \ - if (go->neg && \ - len >= CILEN_LONG && \ - p[1] == CILEN_LONG && \ - p[0] == opt) { \ - len -= CILEN_LONG; \ - INCPTR(2, p); \ - GETLONG(cilong, p); \ - no.neg = 1; \ - code \ - } -#if LQR_SUPPORT -#define NAKCILQR(opt, neg, code) \ - if (go->neg && \ - len >= CILEN_LQR && \ - p[1] == CILEN_LQR && \ - p[0] == opt) { \ - len -= CILEN_LQR; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - GETLONG(cilong, p); \ - no.neg = 1; \ - code \ - } -#endif /* LQR_SUPPORT */ -#define NAKCIENDP(opt, neg) \ - if (go->neg && \ - len >= CILEN_CHAR && \ - p[0] == opt && \ - p[1] >= CILEN_CHAR && \ - p[1] <= len) { \ - len -= p[1]; \ - INCPTR(p[1], p); \ - no.neg = 1; \ - try_.neg = 0; \ - } - - /* - * NOTE! There must be no assignments to individual fields of *go in - * the code below. Any such assignment is a BUG! - */ - /* - * We don't care if they want to send us smaller packets than - * we want. Therefore, accept any MRU less than what we asked for, - * but then ignore the new value when setting the MRU in the kernel. - * If they send us a bigger MRU than what we asked, accept it, up to - * the limit of the default MRU we'd get if we didn't negotiate. - */ - if (go->neg_mru && go->mru != PPP_DEFMRU) { - NAKCISHORT(CI_MRU, neg_mru, - if (cishort <= wo->mru || cishort <= PPP_DEFMRU) - try_.mru = cishort; - ); - } - - /* - * Add any characters they want to our (receive-side) asyncmap. - */ - if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) { - NAKCILONG(CI_ASYNCMAP, neg_asyncmap, - try_.asyncmap = go->asyncmap | cilong; - ); - } - - /* - * If they've nak'd our authentication-protocol, check whether - * they are proposing a different protocol, or a different - * hash algorithm for CHAP. - */ - if ((0 -#if CHAP_SUPPORT - || go->neg_chap -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - || go->neg_upap -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - || go->neg_eap -#endif /* EAP_SUPPORT */ - ) - && len >= CILEN_SHORT - && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) { - cilen = p[1]; - len -= cilen; -#if CHAP_SUPPORT - no.neg_chap = go->neg_chap; -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - no.neg_upap = go->neg_upap; -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - no.neg_eap = go->neg_eap; -#endif /* EAP_SUPPORT */ - INCPTR(2, p); - GETSHORT(cishort, p); - -#if PAP_SUPPORT - if (cishort == PPP_PAP && cilen == CILEN_SHORT) { -#if EAP_SUPPORT - /* If we were asking for EAP, then we need to stop that. */ - if (go->neg_eap) - try_.neg_eap = 0; - else -#endif /* EAP_SUPPORT */ - -#if CHAP_SUPPORT - /* If we were asking for CHAP, then we need to stop that. */ - if (go->neg_chap) - try_.neg_chap = 0; - else -#endif /* CHAP_SUPPORT */ - - /* - * If we weren't asking for CHAP or EAP, then we were asking for - * PAP, in which case this Nak is bad. - */ - goto bad; - } else -#endif /* PAP_SUPPORT */ - -#if CHAP_SUPPORT - if (cishort == PPP_CHAP && cilen == CILEN_CHAP) { - GETCHAR(cichar, p); -#if EAP_SUPPORT - /* Stop asking for EAP, if we were. */ - if (go->neg_eap) { - try_.neg_eap = 0; - /* Try to set up to use their suggestion, if possible */ - if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) - try_.chap_mdtype = CHAP_MDTYPE_D(cichar); - } else -#endif /* EAP_SUPPORT */ - if (go->neg_chap) { - /* - * We were asking for our preferred algorithm, they must - * want something different. - */ - if (cichar != CHAP_DIGEST(go->chap_mdtype)) { - if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) { - /* Use their suggestion if we support it ... */ - try_.chap_mdtype = CHAP_MDTYPE_D(cichar); - } else { - /* ... otherwise, try our next-preferred algorithm. */ - try_.chap_mdtype &= ~(CHAP_MDTYPE(try_.chap_mdtype)); - if (try_.chap_mdtype == MDTYPE_NONE) /* out of algos */ - try_.neg_chap = 0; - } - } else { - /* - * Whoops, they Nak'd our algorithm of choice - * but then suggested it back to us. - */ - goto bad; - } - } else { - /* - * Stop asking for PAP if we were asking for it. - */ -#if PAP_SUPPORT - try_.neg_upap = 0; -#endif /* PAP_SUPPORT */ - } - - } else -#endif /* CHAP_SUPPORT */ - { - -#if EAP_SUPPORT - /* - * If we were asking for EAP, and they're Conf-Naking EAP, - * well, that's just strange. Nobody should do that. - */ - if (cishort == PPP_EAP && cilen == CILEN_SHORT && go->neg_eap) - ppp_dbglog("Unexpected Conf-Nak for EAP"); - - /* - * We don't recognize what they're suggesting. - * Stop asking for what we were asking for. - */ - if (go->neg_eap) - try_.neg_eap = 0; - else -#endif /* EAP_SUPPORT */ - -#if CHAP_SUPPORT - if (go->neg_chap) - try_.neg_chap = 0; - else -#endif /* CHAP_SUPPORT */ - -#if PAP_SUPPORT - if(1) - try_.neg_upap = 0; - else -#endif /* PAP_SUPPORT */ - {} - - p += cilen - CILEN_SHORT; - } - } - -#if LQR_SUPPORT - /* - * If they can't cope with our link quality protocol, we'll have - * to stop asking for LQR. We haven't got any other protocol. - * If they Nak the reporting period, take their value XXX ? - */ - NAKCILQR(CI_QUALITY, neg_lqr, - if (cishort != PPP_LQR) - try_.neg_lqr = 0; - else - try_.lqr_period = cilong; - ); -#endif /* LQR_SUPPORT */ - - /* - * Only implementing CBCP...not the rest of the callback options - */ - NAKCICHAR(CI_CALLBACK, neg_cbcp, - try_.neg_cbcp = 0; - (void)cichar; /* if CHAP support is not compiled, cichar is set but not used, which makes some compilers complaining */ - ); - - /* - * Check for a looped-back line. - */ - NAKCILONG(CI_MAGICNUMBER, neg_magicnumber, - try_.magicnumber = magic(); - looped_back = 1; - ); - - /* - * Peer shouldn't send Nak for protocol compression or - * address/control compression requests; they should send - * a Reject instead. If they send a Nak, treat it as a Reject. - */ - NAKCIVOID(CI_PCOMPRESSION, neg_pcompression); - NAKCIVOID(CI_ACCOMPRESSION, neg_accompression); - -#ifdef HAVE_MULTILINK - /* - * Nak for MRRU option - accept their value if it is smaller - * than the one we want. - */ - if (go->neg_mrru) { - NAKCISHORT(CI_MRRU, neg_mrru, - if (treat_as_reject) - try_.neg_mrru = 0; - else if (cishort <= wo->mrru) - try_.mrru = cishort; - ); - } -#else /* HAVE_MULTILINK */ - LWIP_UNUSED_ARG(treat_as_reject); -#endif /* HAVE_MULTILINK */ - - /* - * Nak for short sequence numbers shouldn't be sent, treat it - * like a reject. - */ - NAKCIVOID(CI_SSNHF, neg_ssnhf); - - /* - * Nak of the endpoint discriminator option is not permitted, - * treat it like a reject. - */ - NAKCIENDP(CI_EPDISC, neg_endpoint); - - /* - * There may be remaining CIs, if the peer is requesting negotiation - * on an option that we didn't include in our request packet. - * If we see an option that we requested, or one we've already seen - * in this packet, then this packet is bad. - * If we wanted to respond by starting to negotiate on the requested - * option(s), we could, but we don't, because except for the - * authentication type and quality protocol, if we are not negotiating - * an option, it is because we were told not to. - * For the authentication type, the Nak from the peer means - * `let me authenticate myself with you' which is a bit pointless. - * For the quality protocol, the Nak means `ask me to send you quality - * reports', but if we didn't ask for them, we don't want them. - * An option we don't recognize represents the peer asking to - * negotiate some option we don't support, so ignore it. - */ - while (len >= CILEN_VOID) { - GETCHAR(citype, p); - GETCHAR(cilen, p); - if (cilen < CILEN_VOID || (len -= cilen) < 0) - goto bad; - next = p + cilen - 2; - - switch (citype) { - case CI_MRU: - if ((go->neg_mru && go->mru != PPP_DEFMRU) - || no.neg_mru || cilen != CILEN_SHORT) - goto bad; - GETSHORT(cishort, p); - if (cishort < PPP_DEFMRU) { - try_.neg_mru = 1; - try_.mru = cishort; - } - break; - case CI_ASYNCMAP: - if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) - || no.neg_asyncmap || cilen != CILEN_LONG) - goto bad; - break; - case CI_AUTHTYPE: - if (0 -#if CHAP_SUPPORT - || go->neg_chap || no.neg_chap -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - || go->neg_upap || no.neg_upap -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - || go->neg_eap || no.neg_eap -#endif /* EAP_SUPPORT */ - ) - goto bad; - break; - case CI_MAGICNUMBER: - if (go->neg_magicnumber || no.neg_magicnumber || - cilen != CILEN_LONG) - goto bad; - break; - case CI_PCOMPRESSION: - if (go->neg_pcompression || no.neg_pcompression - || cilen != CILEN_VOID) - goto bad; - break; - case CI_ACCOMPRESSION: - if (go->neg_accompression || no.neg_accompression - || cilen != CILEN_VOID) - goto bad; - break; -#if LQR_SUPPORT - case CI_QUALITY: - if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) - goto bad; - break; -#endif /* LQR_SUPPORT */ -#ifdef HAVE_MULTILINK - case CI_MRRU: - if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT) - goto bad; - break; -#endif /* HAVE_MULTILINK */ - case CI_SSNHF: - if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID) - goto bad; - try_.neg_ssnhf = 1; - break; - case CI_EPDISC: - if (go->neg_endpoint || no.neg_endpoint || cilen < CILEN_CHAR) - goto bad; - break; - default: - break; - } - p = next; - } - - /* - * OK, the Nak is good. Now we can update state. - * If there are any options left we ignore them. - */ - if (f->state != PPP_FSM_OPENED) { - if (looped_back) { - if (++try_.numloops >= pcb->settings.lcp_loopbackfail) { - ppp_notice("Serial line is looped back."); - pcb->err_code = PPPERR_LOOPBACK; - lcp_close(f->pcb, "Loopback detected"); - } - } else - try_.numloops = 0; - *go = try_; - } - - return 1; - -bad: - LCPDEBUG(("lcp_nakci: received bad Nak!")); - return 0; -} - - -/* - * lcp_rejci - Peer has Rejected some of our CIs. - * This should not modify any state if the Reject is bad - * or if LCP is in the OPENED state. - * - * Returns: - * 0 - Reject was bad. - * 1 - Reject was good. - */ -static int lcp_rejci(fsm *f, u_char *p, int len) { - ppp_pcb *pcb = f->pcb; - lcp_options *go = &pcb->lcp_gotoptions; - u_char cichar; - u_short cishort; - u32_t cilong; - lcp_options try_; /* options to request next time */ - - try_ = *go; - - /* - * Any Rejected CIs must be in exactly the same order that we sent. - * Check packet length and CI length at each step. - * If we find any deviations, then this packet is bad. - */ -#define REJCIVOID(opt, neg) \ - if (go->neg && \ - len >= CILEN_VOID && \ - p[1] == CILEN_VOID && \ - p[0] == opt) { \ - len -= CILEN_VOID; \ - INCPTR(CILEN_VOID, p); \ - try_.neg = 0; \ - } -#define REJCISHORT(opt, neg, val) \ - if (go->neg && \ - len >= CILEN_SHORT && \ - p[1] == CILEN_SHORT && \ - p[0] == opt) { \ - len -= CILEN_SHORT; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - /* Check rejected value. */ \ - if (cishort != val) \ - goto bad; \ - try_.neg = 0; \ - } - -#if CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT -#define REJCICHAP(opt, neg, val) \ - if (go->neg && \ - len >= CILEN_CHAP && \ - p[1] == CILEN_CHAP && \ - p[0] == opt) { \ - len -= CILEN_CHAP; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - GETCHAR(cichar, p); \ - /* Check rejected value. */ \ - if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ - goto bad; \ - try_.neg = 0; \ - try_.neg_eap = try_.neg_upap = 0; \ - } -#endif /* CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT */ - -#if CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT -#define REJCICHAP(opt, neg, val) \ - if (go->neg && \ - len >= CILEN_CHAP && \ - p[1] == CILEN_CHAP && \ - p[0] == opt) { \ - len -= CILEN_CHAP; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - GETCHAR(cichar, p); \ - /* Check rejected value. */ \ - if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ - goto bad; \ - try_.neg = 0; \ - try_.neg_upap = 0; \ - } -#endif /* CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT */ - -#if CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT -#define REJCICHAP(opt, neg, val) \ - if (go->neg && \ - len >= CILEN_CHAP && \ - p[1] == CILEN_CHAP && \ - p[0] == opt) { \ - len -= CILEN_CHAP; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - GETCHAR(cichar, p); \ - /* Check rejected value. */ \ - if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ - goto bad; \ - try_.neg = 0; \ - try_.neg_eap = 0; \ - } -#endif /* CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT */ - -#if CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT -#define REJCICHAP(opt, neg, val) \ - if (go->neg && \ - len >= CILEN_CHAP && \ - p[1] == CILEN_CHAP && \ - p[0] == opt) { \ - len -= CILEN_CHAP; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - GETCHAR(cichar, p); \ - /* Check rejected value. */ \ - if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ - goto bad; \ - try_.neg = 0; \ - } -#endif /* CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT */ - -#define REJCILONG(opt, neg, val) \ - if (go->neg && \ - len >= CILEN_LONG && \ - p[1] == CILEN_LONG && \ - p[0] == opt) { \ - len -= CILEN_LONG; \ - INCPTR(2, p); \ - GETLONG(cilong, p); \ - /* Check rejected value. */ \ - if (cilong != val) \ - goto bad; \ - try_.neg = 0; \ - } -#if LQR_SUPPORT -#define REJCILQR(opt, neg, val) \ - if (go->neg && \ - len >= CILEN_LQR && \ - p[1] == CILEN_LQR && \ - p[0] == opt) { \ - len -= CILEN_LQR; \ - INCPTR(2, p); \ - GETSHORT(cishort, p); \ - GETLONG(cilong, p); \ - /* Check rejected value. */ \ - if (cishort != PPP_LQR || cilong != val) \ - goto bad; \ - try_.neg = 0; \ - } -#endif /* LQR_SUPPORT */ -#define REJCICBCP(opt, neg, val) \ - if (go->neg && \ - len >= CILEN_CBCP && \ - p[1] == CILEN_CBCP && \ - p[0] == opt) { \ - len -= CILEN_CBCP; \ - INCPTR(2, p); \ - GETCHAR(cichar, p); \ - /* Check rejected value. */ \ - if (cichar != val) \ - goto bad; \ - try_.neg = 0; \ - } -#define REJCIENDP(opt, neg, class, val, vlen) \ - if (go->neg && \ - len >= CILEN_CHAR + vlen && \ - p[0] == opt && \ - p[1] == CILEN_CHAR + vlen) { \ - int i; \ - len -= CILEN_CHAR + vlen; \ - INCPTR(2, p); \ - GETCHAR(cichar, p); \ - if (cichar != class) \ - goto bad; \ - for (i = 0; i < vlen; ++i) { \ - GETCHAR(cichar, p); \ - if (cichar != val[i]) \ - goto bad; \ - } \ - try_.neg = 0; \ - } - - REJCISHORT(CI_MRU, neg_mru, go->mru); - REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); -#if EAP_SUPPORT - REJCISHORT(CI_AUTHTYPE, neg_eap, PPP_EAP); - if (!go->neg_eap) { -#endif /* EAP_SUPPORT */ -#if CHAP_SUPPORT - REJCICHAP(CI_AUTHTYPE, neg_chap, go->chap_mdtype); - if (!go->neg_chap) { -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - } -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - } -#endif /* EAP_SUPPORT */ -#if LQR_SUPPORT - REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); -#endif /* LQR_SUPPORT */ - REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT); - REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); - REJCIVOID(CI_PCOMPRESSION, neg_pcompression); - REJCIVOID(CI_ACCOMPRESSION, neg_accompression); -#ifdef HAVE_MULTILINK - REJCISHORT(CI_MRRU, neg_mrru, go->mrru); -#endif /* HAVE_MULTILINK */ - REJCIVOID(CI_SSNHF, neg_ssnhf); - REJCIENDP(CI_EPDISC, neg_endpoint, go->endpoint.class_, - go->endpoint.value, go->endpoint.length); - - /* - * If there are any remaining CIs, then this packet is bad. - */ - if (len != 0) - goto bad; - /* - * Now we can update state. - */ - if (f->state != PPP_FSM_OPENED) - *go = try_; - return 1; - -bad: - LCPDEBUG(("lcp_rejci: received bad Reject!")); - return 0; -} - - -/* - * lcp_reqci - Check the peer's requested CIs and send appropriate response. - * - * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified - * appropriately. If reject_if_disagree is non-zero, doesn't return - * CONFNAK; returns CONFREJ if it can't return CONFACK. - * - * inp = Requested CIs - * lenp = Length of requested CIs - */ -static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) { - ppp_pcb *pcb = f->pcb; - lcp_options *go = &pcb->lcp_gotoptions; - lcp_options *ho = &pcb->lcp_hisoptions; - lcp_options *ao = &pcb->lcp_allowoptions; - u_char *cip, *next; /* Pointer to current and next CIs */ - int cilen, citype, cichar; /* Parsed len, type, char value */ - u_short cishort; /* Parsed short value */ - u32_t cilong; /* Parse long value */ - int rc = CONFACK; /* Final packet return code */ - int orc; /* Individual option return code */ - u_char *p; /* Pointer to next char to parse */ - u_char *rejp; /* Pointer to next char in reject frame */ - struct pbuf *nakp; /* Nak buffer */ - u_char *nakoutp; /* Pointer to next char in Nak frame */ - int l = *lenp; /* Length left */ - - /* - * Reset all his options. - */ - BZERO(ho, sizeof(*ho)); - - /* - * Process all his options. - */ - next = inp; - nakp = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE); - if(NULL == nakp) - return 0; - if(nakp->tot_len != nakp->len) { - pbuf_free(nakp); - return 0; - } - - nakoutp = (u_char*)nakp->payload; - rejp = inp; - while (l) { - orc = CONFACK; /* Assume success */ - cip = p = next; /* Remember begining of CI */ - if (l < 2 || /* Not enough data for CI header or */ - p[1] < 2 || /* CI length too small or */ - p[1] > l) { /* CI length too big? */ - LCPDEBUG(("lcp_reqci: bad CI length!")); - orc = CONFREJ; /* Reject bad CI */ - cilen = l; /* Reject till end of packet */ - l = 0; /* Don't loop again */ - citype = 0; - goto endswitch; - } - GETCHAR(citype, p); /* Parse CI type */ - GETCHAR(cilen, p); /* Parse CI length */ - l -= cilen; /* Adjust remaining length */ - next += cilen; /* Step to next CI */ - - switch (citype) { /* Check CI type */ - case CI_MRU: - if (!ao->neg_mru || /* Allow option? */ - cilen != CILEN_SHORT) { /* Check CI length */ - orc = CONFREJ; /* Reject CI */ - break; - } - GETSHORT(cishort, p); /* Parse MRU */ - - /* - * He must be able to receive at least our minimum. - * No need to check a maximum. If he sends a large number, - * we'll just ignore it. - */ - if (cishort < PPP_MINMRU) { - orc = CONFNAK; /* Nak CI */ - PUTCHAR(CI_MRU, nakoutp); - PUTCHAR(CILEN_SHORT, nakoutp); - PUTSHORT(PPP_MINMRU, nakoutp); /* Give him a hint */ - break; - } - ho->neg_mru = 1; /* Remember he sent MRU */ - ho->mru = cishort; /* And remember value */ - break; - - case CI_ASYNCMAP: - if (!ao->neg_asyncmap || - cilen != CILEN_LONG) { - orc = CONFREJ; - break; - } - GETLONG(cilong, p); - - /* - * Asyncmap must have set at least the bits - * which are set in lcp_allowoptions[unit].asyncmap. - */ - if ((ao->asyncmap & ~cilong) != 0) { - orc = CONFNAK; - PUTCHAR(CI_ASYNCMAP, nakoutp); - PUTCHAR(CILEN_LONG, nakoutp); - PUTLONG(ao->asyncmap | cilong, nakoutp); - break; - } - ho->neg_asyncmap = 1; - ho->asyncmap = cilong; - break; - - case CI_AUTHTYPE: - if (cilen < CILEN_SHORT || - !(0 -#if PAP_SUPPORT - || ao->neg_upap -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - || ao->neg_chap -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - || ao->neg_eap -#endif /* EAP_SUPPORT */ - )) { - /* - * Reject the option if we're not willing to authenticate. - */ - ppp_dbglog("No auth is possible"); - orc = CONFREJ; - break; - } - GETSHORT(cishort, p); - - /* - * Authtype must be PAP, CHAP, or EAP. - * - * Note: if more than one of ao->neg_upap, ao->neg_chap, and - * ao->neg_eap are set, and the peer sends a Configure-Request - * with two or more authenticate-protocol requests, then we will - * reject the second request. - * Whether we end up doing CHAP, UPAP, or EAP depends then on - * the ordering of the CIs in the peer's Configure-Request. - */ - -#if PAP_SUPPORT - if (cishort == PPP_PAP) { - /* we've already accepted CHAP or EAP */ - if (0 -#if CHAP_SUPPORT - || ho->neg_chap -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - || ho->neg_eap -#endif /* EAP_SUPPORT */ - || cilen != CILEN_SHORT) { - LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting...")); - orc = CONFREJ; - break; - } - if (!ao->neg_upap) { /* we don't want to do PAP */ - orc = CONFNAK; /* NAK it and suggest CHAP or EAP */ - PUTCHAR(CI_AUTHTYPE, nakoutp); -#if EAP_SUPPORT - if (ao->neg_eap) { - PUTCHAR(CILEN_SHORT, nakoutp); - PUTSHORT(PPP_EAP, nakoutp); - } else { -#endif /* EAP_SUPPORT */ -#if CHAP_SUPPORT - PUTCHAR(CILEN_CHAP, nakoutp); - PUTSHORT(PPP_CHAP, nakoutp); - PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - } -#endif /* EAP_SUPPORT */ - break; - } - ho->neg_upap = 1; - break; - } -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - if (cishort == PPP_CHAP) { - /* we've already accepted PAP or EAP */ - if ( -#if PAP_SUPPORT - ho->neg_upap || -#endif /* PAP_SUPPORT */ -#if EAP_SUPPORT - ho->neg_eap || -#endif /* EAP_SUPPORT */ - cilen != CILEN_CHAP) { - LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting...")); - orc = CONFREJ; - break; - } - if (!ao->neg_chap) { /* we don't want to do CHAP */ - orc = CONFNAK; /* NAK it and suggest EAP or PAP */ - PUTCHAR(CI_AUTHTYPE, nakoutp); - PUTCHAR(CILEN_SHORT, nakoutp); -#if EAP_SUPPORT - if (ao->neg_eap) { - PUTSHORT(PPP_EAP, nakoutp); - } else -#endif /* EAP_SUPPORT */ -#if PAP_SUPPORT - if(1) { - PUTSHORT(PPP_PAP, nakoutp); - } - else -#endif /* PAP_SUPPORT */ - {} - break; - } - GETCHAR(cichar, p); /* get digest type */ - if (!(CHAP_CANDIGEST(ao->chap_mdtype, cichar))) { - /* - * We can't/won't do the requested type, - * suggest something else. - */ - orc = CONFNAK; - PUTCHAR(CI_AUTHTYPE, nakoutp); - PUTCHAR(CILEN_CHAP, nakoutp); - PUTSHORT(PPP_CHAP, nakoutp); - PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); - break; - } - ho->chap_mdtype = CHAP_MDTYPE_D(cichar); /* save md type */ - ho->neg_chap = 1; - break; - } -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - if (cishort == PPP_EAP) { - /* we've already accepted CHAP or PAP */ - if ( -#if CHAP_SUPPORT - ho->neg_chap || -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - ho->neg_upap || -#endif /* PAP_SUPPORT */ - cilen != CILEN_SHORT) { - LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE EAP, rejecting...")); - orc = CONFREJ; - break; - } - if (!ao->neg_eap) { /* we don't want to do EAP */ - orc = CONFNAK; /* NAK it and suggest CHAP or PAP */ - PUTCHAR(CI_AUTHTYPE, nakoutp); -#if CHAP_SUPPORT - if (ao->neg_chap) { - PUTCHAR(CILEN_CHAP, nakoutp); - PUTSHORT(PPP_CHAP, nakoutp); - PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); - } else -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - if(1) { - PUTCHAR(CILEN_SHORT, nakoutp); - PUTSHORT(PPP_PAP, nakoutp); - } else -#endif /* PAP_SUPPORT */ - {} - break; - } - ho->neg_eap = 1; - break; - } -#endif /* EAP_SUPPORT */ - - /* - * We don't recognize the protocol they're asking for. - * Nak it with something we're willing to do. - * (At this point we know ao->neg_upap || ao->neg_chap || - * ao->neg_eap.) - */ - orc = CONFNAK; - PUTCHAR(CI_AUTHTYPE, nakoutp); - -#if EAP_SUPPORT - if (ao->neg_eap) { - PUTCHAR(CILEN_SHORT, nakoutp); - PUTSHORT(PPP_EAP, nakoutp); - } else -#endif /* EAP_SUPPORT */ -#if CHAP_SUPPORT - if (ao->neg_chap) { - PUTCHAR(CILEN_CHAP, nakoutp); - PUTSHORT(PPP_CHAP, nakoutp); - PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); - } else -#endif /* CHAP_SUPPORT */ -#if PAP_SUPPORT - if(1) { - PUTCHAR(CILEN_SHORT, nakoutp); - PUTSHORT(PPP_PAP, nakoutp); - } else -#endif /* PAP_SUPPORT */ - {} - break; - -#if LQR_SUPPORT - case CI_QUALITY: - if (!ao->neg_lqr || - cilen != CILEN_LQR) { - orc = CONFREJ; - break; - } - - GETSHORT(cishort, p); - GETLONG(cilong, p); - - /* - * Check the protocol and the reporting period. - * XXX When should we Nak this, and what with? - */ - if (cishort != PPP_LQR) { - orc = CONFNAK; - PUTCHAR(CI_QUALITY, nakoutp); - PUTCHAR(CILEN_LQR, nakoutp); - PUTSHORT(PPP_LQR, nakoutp); - PUTLONG(ao->lqr_period, nakoutp); - break; - } - break; -#endif /* LQR_SUPPORT */ - - case CI_MAGICNUMBER: - if (!(ao->neg_magicnumber || go->neg_magicnumber) || - cilen != CILEN_LONG) { - orc = CONFREJ; - break; - } - GETLONG(cilong, p); - - /* - * He must have a different magic number. - */ - if (go->neg_magicnumber && - cilong == go->magicnumber) { - cilong = magic(); /* Don't put magic() inside macro! */ - orc = CONFNAK; - PUTCHAR(CI_MAGICNUMBER, nakoutp); - PUTCHAR(CILEN_LONG, nakoutp); - PUTLONG(cilong, nakoutp); - break; - } - ho->neg_magicnumber = 1; - ho->magicnumber = cilong; - break; - - - case CI_PCOMPRESSION: - if (!ao->neg_pcompression || - cilen != CILEN_VOID) { - orc = CONFREJ; - break; - } - ho->neg_pcompression = 1; - break; - - case CI_ACCOMPRESSION: - if (!ao->neg_accompression || - cilen != CILEN_VOID) { - orc = CONFREJ; - break; - } - ho->neg_accompression = 1; - break; - -#ifdef HAVE_MULTILINK - case CI_MRRU: - if (!ao->neg_mrru - || !multilink - || cilen != CILEN_SHORT) { - orc = CONFREJ; - break; - } - - GETSHORT(cishort, p); - /* possibly should insist on a minimum/maximum MRRU here */ - ho->neg_mrru = 1; - ho->mrru = cishort; - break; -#endif /* HAVE_MULTILINK */ - - case CI_SSNHF: - if (!ao->neg_ssnhf -#ifdef HAVE_MULTILINK - || !multilink -#endif /* HAVE_MULTILINK */ - || cilen != CILEN_VOID) { - orc = CONFREJ; - break; - } - ho->neg_ssnhf = 1; - break; - - case CI_EPDISC: - if (!ao->neg_endpoint || - cilen < CILEN_CHAR || - cilen > CILEN_CHAR + MAX_ENDP_LEN) { - orc = CONFREJ; - break; - } - GETCHAR(cichar, p); - cilen -= CILEN_CHAR; - ho->neg_endpoint = 1; - ho->endpoint.class_ = cichar; - ho->endpoint.length = cilen; - MEMCPY(ho->endpoint.value, p, cilen); - INCPTR(cilen, p); - break; - - default: - LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype)); - orc = CONFREJ; - break; - } - -endswitch: - if (orc == CONFACK && /* Good CI */ - rc != CONFACK) /* but prior CI wasnt? */ - continue; /* Don't send this one */ - - if (orc == CONFNAK) { /* Nak this CI? */ - if (reject_if_disagree /* Getting fed up with sending NAKs? */ - && citype != CI_MAGICNUMBER) { - orc = CONFREJ; /* Get tough if so */ - } else { - if (rc == CONFREJ) /* Rejecting prior CI? */ - continue; /* Don't send this one */ - rc = CONFNAK; - } - } - if (orc == CONFREJ) { /* Reject this CI */ - rc = CONFREJ; - if (cip != rejp) /* Need to move rejected CI? */ - MEMCPY(rejp, cip, cilen); /* Move it */ - INCPTR(cilen, rejp); /* Update output pointer */ - } - } - - /* - * If we wanted to send additional NAKs (for unsent CIs), the - * code would go here. The extra NAKs would go at *nakoutp. - * At present there are no cases where we want to ask the - * peer to negotiate an option. - */ - - switch (rc) { - case CONFACK: - *lenp = next - inp; - break; - case CONFNAK: - /* - * Copy the Nak'd options from the nak buffer to the caller's buffer. - */ - *lenp = nakoutp - (u_char*)nakp->payload; - MEMCPY(inp, nakp->payload, *lenp); - break; - case CONFREJ: - *lenp = rejp - inp; - break; - default: - break; - } - - pbuf_free(nakp); - LCPDEBUG(("lcp_reqci: returning CONF%s.", CODENAME(rc))); - return (rc); /* Return final code */ -} - - -/* - * lcp_up - LCP has come UP. - */ -static void lcp_up(fsm *f) { - ppp_pcb *pcb = f->pcb; - lcp_options *wo = &pcb->lcp_wantoptions; - lcp_options *ho = &pcb->lcp_hisoptions; - lcp_options *go = &pcb->lcp_gotoptions; - lcp_options *ao = &pcb->lcp_allowoptions; - int mtu, mru; - - if (!go->neg_magicnumber) - go->magicnumber = 0; - if (!ho->neg_magicnumber) - ho->magicnumber = 0; - - /* - * Set our MTU to the smaller of the MTU we wanted and - * the MRU our peer wanted. If we negotiated an MRU, - * set our MRU to the larger of value we wanted and - * the value we got in the negotiation. - * Note on the MTU: the link MTU can be the MRU the peer wanted, - * the interface MTU is set to the lowest of that, the - * MTU we want to use, and our link MRU. - */ - mtu = ho->neg_mru? ho->mru: PPP_MRU; - mru = go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU; -#ifdef HAVE_MULTILINK - if (!(multilink && go->neg_mrru && ho->neg_mrru)) -#endif /* HAVE_MULTILINK */ - netif_set_mtu(pcb, LWIP_MIN(LWIP_MIN(mtu, mru), ao->mru)); - ppp_send_config(pcb, mtu, - (ho->neg_asyncmap? ho->asyncmap: 0xffffffff), - ho->neg_pcompression, ho->neg_accompression); - ppp_recv_config(pcb, mru, - (pcb->settings.lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff), - go->neg_pcompression, go->neg_accompression); - - if (ho->neg_mru) - pcb->peer_mru = ho->mru; - - lcp_echo_lowerup(f->pcb); /* Enable echo messages */ - - link_established(pcb); -} - - -/* - * lcp_down - LCP has gone DOWN. - * - * Alert other protocols. - */ -static void lcp_down(fsm *f) { - ppp_pcb *pcb = f->pcb; - lcp_options *go = &pcb->lcp_gotoptions; - - lcp_echo_lowerdown(f->pcb); - - link_down(pcb); - - ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0); - ppp_recv_config(pcb, PPP_MRU, - (go->neg_asyncmap? go->asyncmap: 0xffffffff), - go->neg_pcompression, go->neg_accompression); - pcb->peer_mru = PPP_MRU; -} - - -/* - * lcp_starting - LCP needs the lower layer up. - */ -static void lcp_starting(fsm *f) { - ppp_pcb *pcb = f->pcb; - link_required(pcb); -} - - -/* - * lcp_finished - LCP has finished with the lower layer. - */ -static void lcp_finished(fsm *f) { - ppp_pcb *pcb = f->pcb; - link_terminated(pcb); -} - - -#if PRINTPKT_SUPPORT -/* - * lcp_printpkt - print the contents of an LCP packet. - */ -static const char* const lcp_codenames[] = { - "ConfReq", "ConfAck", "ConfNak", "ConfRej", - "TermReq", "TermAck", "CodeRej", "ProtRej", - "EchoReq", "EchoRep", "DiscReq", "Ident", - "TimeRem" -}; - -static int lcp_printpkt(const u_char *p, int plen, - void (*printer) (void *, const char *, ...), void *arg) { - int code, id, len, olen, i; - const u_char *pstart, *optend; - u_short cishort; - u32_t cilong; - - if (plen < HEADERLEN) - return 0; - pstart = p; - GETCHAR(code, p); - GETCHAR(id, p); - GETSHORT(len, p); - if (len < HEADERLEN || len > plen) - return 0; - - if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(lcp_codenames)) - printer(arg, " %s", lcp_codenames[code-1]); - else - printer(arg, " code=0x%x", code); - printer(arg, " id=0x%x", id); - len -= HEADERLEN; - switch (code) { - case CONFREQ: - case CONFACK: - case CONFNAK: - case CONFREJ: - /* print option list */ - while (len >= 2) { - GETCHAR(code, p); - GETCHAR(olen, p); - p -= 2; - if (olen < 2 || olen > len) { - break; - } - printer(arg, " <"); - len -= olen; - optend = p + olen; - switch (code) { - case CI_MRU: - if (olen == CILEN_SHORT) { - p += 2; - GETSHORT(cishort, p); - printer(arg, "mru %d", cishort); - } - break; - case CI_ASYNCMAP: - if (olen == CILEN_LONG) { - p += 2; - GETLONG(cilong, p); - printer(arg, "asyncmap 0x%x", cilong); - } - break; - case CI_AUTHTYPE: - if (olen >= CILEN_SHORT) { - p += 2; - printer(arg, "auth "); - GETSHORT(cishort, p); - switch (cishort) { -#if PAP_SUPPORT - case PPP_PAP: - printer(arg, "pap"); - break; -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - case PPP_CHAP: - printer(arg, "chap"); - if (p < optend) { - switch (*p) { - case CHAP_MD5: - printer(arg, " MD5"); - ++p; - break; -#if MSCHAP_SUPPORT - case CHAP_MICROSOFT: - printer(arg, " MS"); - ++p; - break; - - case CHAP_MICROSOFT_V2: - printer(arg, " MS-v2"); - ++p; - break; -#endif /* MSCHAP_SUPPORT */ - default: - break; - } - } - break; -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - case PPP_EAP: - printer(arg, "eap"); - break; -#endif /* EAP_SUPPORT */ - default: - printer(arg, "0x%x", cishort); - } - } - break; -#if LQR_SUPPORT - case CI_QUALITY: - if (olen >= CILEN_SHORT) { - p += 2; - printer(arg, "quality "); - GETSHORT(cishort, p); - switch (cishort) { - case PPP_LQR: - printer(arg, "lqr"); - break; - default: - printer(arg, "0x%x", cishort); - } - } - break; -#endif /* LQR_SUPPORT */ - case CI_CALLBACK: - if (olen >= CILEN_CHAR) { - p += 2; - printer(arg, "callback "); - GETCHAR(cishort, p); - switch (cishort) { - case CBCP_OPT: - printer(arg, "CBCP"); - break; - default: - printer(arg, "0x%x", cishort); - } - } - break; - case CI_MAGICNUMBER: - if (olen == CILEN_LONG) { - p += 2; - GETLONG(cilong, p); - printer(arg, "magic 0x%x", cilong); - } - break; - case CI_PCOMPRESSION: - if (olen == CILEN_VOID) { - p += 2; - printer(arg, "pcomp"); - } - break; - case CI_ACCOMPRESSION: - if (olen == CILEN_VOID) { - p += 2; - printer(arg, "accomp"); - } - break; - case CI_MRRU: - if (olen == CILEN_SHORT) { - p += 2; - GETSHORT(cishort, p); - printer(arg, "mrru %d", cishort); - } - break; - case CI_SSNHF: - if (olen == CILEN_VOID) { - p += 2; - printer(arg, "ssnhf"); - } - break; - case CI_EPDISC: -#ifdef HAVE_MULTILINK - if (olen >= CILEN_CHAR) { - struct epdisc epd; - p += 2; - GETCHAR(epd.class, p); - epd.length = olen - CILEN_CHAR; - if (epd.length > MAX_ENDP_LEN) - epd.length = MAX_ENDP_LEN; - if (epd.length > 0) { - MEMCPY(epd.value, p, epd.length); - p += epd.length; - } - printer(arg, "endpoint [%s]", epdisc_to_str(&epd)); - } -#else - printer(arg, "endpoint"); -#endif - break; - default: - break; - } - while (p < optend) { - GETCHAR(code, p); - printer(arg, " %.2x", code); - } - printer(arg, ">"); - } - break; - - case TERMACK: - case TERMREQ: - if (len > 0 && *p >= ' ' && *p < 0x7f) { - printer(arg, " "); - ppp_print_string(p, len, printer, arg); - p += len; - len = 0; - } - break; - - case ECHOREQ: - case ECHOREP: - case DISCREQ: - if (len >= 4) { - GETLONG(cilong, p); - printer(arg, " magic=0x%x", cilong); - len -= 4; - } - break; - - case IDENTIF: - case TIMEREM: - if (len >= 4) { - GETLONG(cilong, p); - printer(arg, " magic=0x%x", cilong); - len -= 4; - } - if (code == TIMEREM) { - if (len < 4) - break; - GETLONG(cilong, p); - printer(arg, " seconds=%u", cilong); - len -= 4; - } - if (len > 0) { - printer(arg, " "); - ppp_print_string(p, len, printer, arg); - p += len; - len = 0; - } - break; - default: - break; - } - - /* print the rest of the bytes in the packet */ - for (i = 0; i < len && i < 32; ++i) { - GETCHAR(code, p); - printer(arg, " %.2x", code); - } - if (i < len) { - printer(arg, " ..."); - p += len - i; - } - - return p - pstart; -} -#endif /* PRINTPKT_SUPPORT */ - -/* - * Time to shut down the link because there is nothing out there. - */ - -static void LcpLinkFailure(fsm *f) { - ppp_pcb *pcb = f->pcb; - if (f->state == PPP_FSM_OPENED) { - ppp_info("No response to %d echo-requests", pcb->lcp_echos_pending); - ppp_notice("Serial link appears to be disconnected."); - pcb->err_code = PPPERR_PEERDEAD; - lcp_close(pcb, "Peer not responding"); - } -} - -/* - * Timer expired for the LCP echo requests from this process. - */ - -static void LcpEchoCheck(fsm *f) { - ppp_pcb *pcb = f->pcb; - - LcpSendEchoRequest (f); - if (f->state != PPP_FSM_OPENED) - return; - - /* - * Start the timer for the next interval. - */ - if (pcb->lcp_echo_timer_running) - ppp_warn("assertion lcp_echo_timer_running==0 failed"); - TIMEOUT (LcpEchoTimeout, f, pcb->settings.lcp_echo_interval); - pcb->lcp_echo_timer_running = 1; -} - -/* - * LcpEchoTimeout - Timer expired on the LCP echo - */ - -static void LcpEchoTimeout(void *arg) { - fsm *f = (fsm*)arg; - ppp_pcb *pcb = f->pcb; - if (pcb->lcp_echo_timer_running != 0) { - pcb->lcp_echo_timer_running = 0; - LcpEchoCheck ((fsm *) arg); - } -} - -/* - * LcpEchoReply - LCP has received a reply to the echo - */ - -static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len) { - ppp_pcb *pcb = f->pcb; - lcp_options *go = &pcb->lcp_gotoptions; - u32_t magic_val; - LWIP_UNUSED_ARG(id); - - /* Check the magic number - don't count replies from ourselves. */ - if (len < 4) { - ppp_dbglog("lcp: received short Echo-Reply, length %d", len); - return; - } - GETLONG(magic_val, inp); - if (go->neg_magicnumber - && magic_val == go->magicnumber) { - ppp_warn("appear to have received our own echo-reply!"); - return; - } - - /* Reset the number of outstanding echo frames */ - pcb->lcp_echos_pending = 0; -} - -/* - * LcpSendEchoRequest - Send an echo request frame to the peer - */ - -static void LcpSendEchoRequest(fsm *f) { - ppp_pcb *pcb = f->pcb; - lcp_options *go = &pcb->lcp_gotoptions; - u32_t lcp_magic; - u_char pkt[4], *pktp; - - /* - * Detect the failure of the peer at this point. - */ - if (pcb->settings.lcp_echo_fails != 0) { - if (pcb->lcp_echos_pending >= pcb->settings.lcp_echo_fails) { - LcpLinkFailure(f); - pcb->lcp_echos_pending = 0; - } - } - -#if PPP_LCP_ADAPTIVE - /* - * If adaptive echos have been enabled, only send the echo request if - * no traffic was received since the last one. - */ - if (pcb->settings.lcp_echo_adaptive) { - static unsigned int last_pkts_in = 0; - -#if PPP_STATS_SUPPORT - update_link_stats(f->unit); - link_stats_valid = 0; -#endif /* PPP_STATS_SUPPORT */ - - if (link_stats.pkts_in != last_pkts_in) { - last_pkts_in = link_stats.pkts_in; - return; - } - } -#endif - - /* - * Make and send the echo request frame. - */ - if (f->state == PPP_FSM_OPENED) { - lcp_magic = go->magicnumber; - pktp = pkt; - PUTLONG(lcp_magic, pktp); - fsm_sdata(f, ECHOREQ, pcb->lcp_echo_number++, pkt, pktp - pkt); - ++pcb->lcp_echos_pending; - } -} - -/* - * lcp_echo_lowerup - Start the timer for the LCP frame - */ - -static void lcp_echo_lowerup(ppp_pcb *pcb) { - fsm *f = &pcb->lcp_fsm; - - /* Clear the parameters for generating echo frames */ - pcb->lcp_echos_pending = 0; - pcb->lcp_echo_number = 0; - pcb->lcp_echo_timer_running = 0; - - /* If a timeout interval is specified then start the timer */ - if (pcb->settings.lcp_echo_interval != 0) - LcpEchoCheck (f); -} - -/* - * lcp_echo_lowerdown - Stop the timer for the LCP frame - */ - -static void lcp_echo_lowerdown(ppp_pcb *pcb) { - fsm *f = &pcb->lcp_fsm; - - if (pcb->lcp_echo_timer_running != 0) { - UNTIMEOUT (LcpEchoTimeout, f); - pcb->lcp_echo_timer_running = 0; - } -} - -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/magic.c b/ext/lwip/src/netif/ppp/magic.c deleted file mode 100644 index d0d87c5..0000000 --- a/ext/lwip/src/netif/ppp/magic.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * magic.c - PPP Magic Number routines. - * - * 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. - */ -/***************************************************************************** -* randm.c - Random number generator program file. -* -* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. -* Copyright (c) 1998 by 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-06-03 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 */ - -#include "netif/ppp/ppp_impl.h" -#include "netif/ppp/magic.h" - -#if PPP_MD5_RANDM /* Using MD5 for better randomness if enabled */ - -#include "netif/ppp/pppcrypt.h" - -#define MD5_HASH_SIZE 16 -static char magic_randpool[MD5_HASH_SIZE]; /* Pool of randomness. */ -static long magic_randcount; /* Pseudo-random incrementer */ -static u32_t magic_randomseed; /* Seed used for random number generation. */ - -/* - * Churn the randomness pool on a random event. Call this early and often - * on random and semi-random system events to build randomness in time for - * usage. For randomly timed events, pass a null pointer and a zero length - * and this will use the system timer and other sources to add randomness. - * If new random data is available, pass a pointer to that and it will be - * included. - * - * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 - */ -static void magic_churnrand(char *rand_data, u32_t rand_len) { - lwip_md5_context md5_ctx; - - /* LWIP_DEBUGF(LOG_INFO, ("magic_churnrand: %u@%P\n", rand_len, rand_data)); */ - lwip_md5_init(&md5_ctx); - lwip_md5_starts(&md5_ctx); - lwip_md5_update(&md5_ctx, (u_char *)magic_randpool, sizeof(magic_randpool)); - if (rand_data) { - lwip_md5_update(&md5_ctx, (u_char *)rand_data, rand_len); - } else { - struct { - /* INCLUDE fields for any system sources of randomness */ - u32_t jiffies; -#ifdef LWIP_RAND - u32_t rand; -#endif /* LWIP_RAND */ - } sys_data; - magic_randomseed += sys_jiffies(); - sys_data.jiffies = magic_randomseed; -#ifdef LWIP_RAND - sys_data.rand = LWIP_RAND(); -#endif /* LWIP_RAND */ - /* Load sys_data fields here. */ - lwip_md5_update(&md5_ctx, (u_char *)&sys_data, sizeof(sys_data)); - } - lwip_md5_finish(&md5_ctx, (u_char *)magic_randpool); - lwip_md5_free(&md5_ctx); -/* LWIP_DEBUGF(LOG_INFO, ("magic_churnrand: -> 0\n")); */ -} - -/* - * Initialize the random number generator. - */ -void magic_init(void) { - magic_churnrand(NULL, 0); -} - -/* - * Randomize our random seed value. - */ -void magic_randomize(void) { - magic_churnrand(NULL, 0); -} - -/* - * magic_random_bytes - Fill a 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(). - * Note: It's important that there be sufficient randomness in magic_randpool - * before this is called for otherwise the range of the result may be - * narrow enough to make a search feasible. - * - * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 - * - * XXX Why does he not just call magic_churnrand() for each block? Probably - * so that you don't ever publish the seed which could possibly help - * predict future values. - * XXX Why don't we preserve md5 between blocks and just update it with - * magic_randcount each time? Probably there is a weakness but I wish that - * it was documented. - */ -void magic_random_bytes(unsigned char *buf, u32_t buf_len) { - lwip_md5_context md5_ctx; - u_char tmp[MD5_HASH_SIZE]; - u32_t n; - - while (buf_len > 0) { - lwip_md5_init(&md5_ctx); - lwip_md5_starts(&md5_ctx); - lwip_md5_update(&md5_ctx, (u_char *)magic_randpool, sizeof(magic_randpool)); - lwip_md5_update(&md5_ctx, (u_char *)&magic_randcount, sizeof(magic_randcount)); - lwip_md5_finish(&md5_ctx, tmp); - lwip_md5_free(&md5_ctx); - magic_randcount++; - n = LWIP_MIN(buf_len, MD5_HASH_SIZE); - MEMCPY(buf, tmp, n); - buf += n; - buf_len -= n; - } -} - -/* - * Return a new random number. - */ -u32_t magic(void) { - u32_t new_rand; - - magic_random_bytes((unsigned char *)&new_rand, sizeof(new_rand)); - - return new_rand; -} - -#else /* PPP_MD5_RANDM */ - -/*****************************/ -/*** LOCAL DATA STRUCTURES ***/ -/*****************************/ -#ifndef LWIP_RAND -static int magic_randomized; /* Set when truely randomized. */ -#endif /* LWIP_RAND */ -static u32_t magic_randomseed; /* Seed used for random number generation. */ - - -/***********************************/ -/*** PUBLIC FUNCTION DEFINITIONS ***/ -/***********************************/ - -/* - * Initialize the random number generator. - * - * Here we attempt to compute a random number seed but even if - * it isn't random, we'll randomize it later. - * - * The current method uses the fields from the real time clock, - * the idle process counter, the millisecond counter, and the - * hardware timer tick counter. When this is invoked - * in startup(), then the idle counter and timer values may - * repeat after each boot and the real time clock may not be - * operational. Thus we call it again on the first random - * event. - */ -void magic_init(void) { - magic_randomseed += sys_jiffies(); -#ifndef LWIP_RAND - /* Initialize the Borland random number generator. */ - srand((unsigned)magic_randomseed); -#endif /* LWIP_RAND */ -} - -/* - * magic_init - Initialize the magic number generator. - * - * Randomize our random seed value. Here we use the fact that - * this function is called at *truely random* times by the polling - * and network functions. Here we only get 16 bits of new random - * value but we use the previous value to randomize the other 16 - * bits. - */ -void magic_randomize(void) { -#ifndef LWIP_RAND - if (!magic_randomized) { - magic_randomized = !0; - magic_init(); - /* The initialization function also updates the seed. */ - } else { -#endif /* LWIP_RAND */ - magic_randomseed += sys_jiffies(); -#ifndef LWIP_RAND - } -#endif /* LWIP_RAND */ -} - -/* - * Return a new random number. - * - * Here we use the Borland rand() function to supply a pseudo random - * number which we make truely random by combining it with our own - * seed which is randomized by truely random events. - * Thus the numbers will be truely random unless there have been no - * operator or network events in which case it will be pseudo random - * seeded by the real time clock. - */ -u32_t magic(void) { -#ifdef LWIP_RAND - return LWIP_RAND() + magic_randomseed; -#else /* LWIP_RAND */ - return ((u32_t)rand() << 16) + (u32_t)rand() + magic_randomseed; -#endif /* LWIP_RAND */ -} - -/* - * magic_random_bytes - Fill a buffer with random bytes. - */ -void magic_random_bytes(unsigned char *buf, u32_t buf_len) { - u32_t new_rand, n; - - while (buf_len > 0) { - new_rand = magic(); - n = LWIP_MIN(buf_len, sizeof(new_rand)); - MEMCPY(buf, &new_rand, n); - buf += n; - buf_len -= n; - } -} -#endif /* PPP_MD5_RANDM */ - -/* - * Return a new random number between 0 and (2^pow)-1 included. - */ -u32_t magic_pow(u8_t pow) { - return magic() & ~(~0UL<. - * Copyright (c) 2002,2003,2004 Google, Inc. - * All rights reserved. - * - * License: - * Permission to use, copy, modify, and distribute this software and its - * documentation is hereby granted, provided that the above copyright - * notice appears in all copies. This software is provided without any - * warranty, express or implied. - * - * Changelog: - * 08/12/05 - Matt Domsch - * Only need extra skb padding on transmit, not receive. - * 06/18/04 - Matt Domsch , Oleg Makarenko - * Use Linux kernel 2.6 arc4 and sha1 routines rather than - * providing our own. - * 2/15/04 - TS: added #include and testing for Kernel - * version before using - * MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are - * deprecated in 2.6 - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && MPPE_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#include - -#include "lwip/err.h" - -#include "netif/ppp/ppp_impl.h" -#include "netif/ppp/ccp.h" -#include "netif/ppp/mppe.h" -#include "netif/ppp/pppdebug.h" -#include "netif/ppp/pppcrypt.h" - -#define SHA1_SIGNATURE_SIZE 20 - -/* ppp_mppe_state.bits definitions */ -#define MPPE_BIT_A 0x80 /* Encryption table were (re)inititalized */ -#define MPPE_BIT_B 0x40 /* MPPC only (not implemented) */ -#define MPPE_BIT_C 0x20 /* MPPC only (not implemented) */ -#define MPPE_BIT_D 0x10 /* This is an encrypted frame */ - -#define MPPE_BIT_FLUSHED MPPE_BIT_A -#define MPPE_BIT_ENCRYPTED MPPE_BIT_D - -#define MPPE_BITS(p) ((p)[0] & 0xf0) -#define MPPE_CCOUNT(p) ((((p)[0] & 0x0f) << 8) + (p)[1]) -#define MPPE_CCOUNT_SPACE 0x1000 /* The size of the ccount space */ - -#define MPPE_OVHD 2 /* MPPE overhead/packet */ -#define SANITY_MAX 1600 /* Max bogon factor we will tolerate */ - -/* - * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3. - * Well, not what's written there, but rather what they meant. - */ -static void mppe_rekey(ppp_mppe_state * state, int initial_key) -{ - lwip_sha1_context sha1_ctx; - u8_t sha1_digest[SHA1_SIGNATURE_SIZE]; - - /* - * Key Derivation, from RFC 3078, RFC 3079. - * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079. - */ - lwip_sha1_init(&sha1_ctx); - lwip_sha1_starts(&sha1_ctx); - lwip_sha1_update(&sha1_ctx, state->master_key, state->keylen); - lwip_sha1_update(&sha1_ctx, mppe_sha1_pad1, SHA1_PAD_SIZE); - lwip_sha1_update(&sha1_ctx, state->session_key, state->keylen); - lwip_sha1_update(&sha1_ctx, mppe_sha1_pad2, SHA1_PAD_SIZE); - lwip_sha1_finish(&sha1_ctx, sha1_digest); - lwip_sha1_free(&sha1_ctx); - MEMCPY(state->session_key, sha1_digest, state->keylen); - - if (!initial_key) { - lwip_arc4_init(&state->arc4); - lwip_arc4_setup(&state->arc4, sha1_digest, state->keylen); - lwip_arc4_crypt(&state->arc4, state->session_key, state->keylen); - lwip_arc4_free(&state->arc4); - } - if (state->keylen == 8) { - /* See RFC 3078 */ - state->session_key[0] = 0xd1; - state->session_key[1] = 0x26; - state->session_key[2] = 0x9e; - } - lwip_arc4_init(&state->arc4); - lwip_arc4_setup(&state->arc4, state->session_key, state->keylen); -} - -/* - * Set key, used by MSCHAP before mppe_init() is actually called by CCP so we - * don't have to keep multiple copies of keys. - */ -void mppe_set_key(ppp_pcb *pcb, ppp_mppe_state *state, u8_t *key) { - LWIP_UNUSED_ARG(pcb); - MEMCPY(state->master_key, key, MPPE_MAX_KEY_LEN); -} - -/* - * Initialize (de)compressor state. - */ -void -mppe_init(ppp_pcb *pcb, ppp_mppe_state *state, u8_t options) -{ -#if PPP_DEBUG - const u8_t *debugstr = (const u8_t*)"mppe_comp_init"; - if (&pcb->mppe_decomp == state) { - debugstr = (const u8_t*)"mppe_decomp_init"; - } -#endif /* PPP_DEBUG */ - - /* Save keys. */ - MEMCPY(state->session_key, state->master_key, sizeof(state->master_key)); - - if (options & MPPE_OPT_128) - state->keylen = 16; - else if (options & MPPE_OPT_40) - state->keylen = 8; - else { - PPPDEBUG(LOG_DEBUG, ("%s[%d]: unknown key length\n", debugstr, - pcb->netif->num)); - lcp_close(pcb, "MPPE required but peer negotiation failed"); - return; - } - if (options & MPPE_OPT_STATEFUL) - state->stateful = 1; - - /* Generate the initial session key. */ - mppe_rekey(state, 1); - -#if PPP_DEBUG - { - int i; - char mkey[sizeof(state->master_key) * 2 + 1]; - char skey[sizeof(state->session_key) * 2 + 1]; - - PPPDEBUG(LOG_DEBUG, ("%s[%d]: initialized with %d-bit %s mode\n", - debugstr, pcb->netif->num, (state->keylen == 16) ? 128 : 40, - (state->stateful) ? "stateful" : "stateless")); - - for (i = 0; i < (int)sizeof(state->master_key); i++) - sprintf(mkey + i * 2, "%02x", state->master_key[i]); - for (i = 0; i < (int)sizeof(state->session_key); i++) - sprintf(skey + i * 2, "%02x", state->session_key[i]); - PPPDEBUG(LOG_DEBUG, - ("%s[%d]: keys: master: %s initial session: %s\n", - debugstr, pcb->netif->num, mkey, skey)); - } -#endif /* PPP_DEBUG */ - - /* - * Initialize the coherency count. The initial value is not specified - * in RFC 3078, but we can make a reasonable assumption that it will - * start at 0. Setting it to the max here makes the comp/decomp code - * do the right thing (determined through experiment). - */ - state->ccount = MPPE_CCOUNT_SPACE - 1; - - /* - * Note that even though we have initialized the key table, we don't - * set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1. - */ - state->bits = MPPE_BIT_ENCRYPTED; -} - -/* - * We received a CCP Reset-Request (actually, we are sending a Reset-Ack), - * tell the compressor to rekey. Note that we MUST NOT rekey for - * every CCP Reset-Request; we only rekey on the next xmit packet. - * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost. - * So, rekeying for every CCP Reset-Request is broken as the peer will not - * know how many times we've rekeyed. (If we rekey and THEN get another - * CCP Reset-Request, we must rekey again.) - */ -void mppe_comp_reset(ppp_pcb *pcb, ppp_mppe_state *state) -{ - LWIP_UNUSED_ARG(pcb); - state->bits |= MPPE_BIT_FLUSHED; -} - -/* - * Compress (encrypt) a packet. - * It's strange to call this a compressor, since the output is always - * MPPE_OVHD + 2 bytes larger than the input. - */ -err_t -mppe_compress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb, u16_t protocol) -{ - struct pbuf *n, *np; - u8_t *pl; - err_t err; - - LWIP_UNUSED_ARG(pcb); - - /* TCP stack requires that we don't change the packet payload, therefore we copy - * the whole packet before encryption. - */ - np = pbuf_alloc(PBUF_RAW, MPPE_OVHD + sizeof(protocol) + (*pb)->tot_len, PBUF_POOL); - if (!np) { - return ERR_MEM; - } - - /* Hide MPPE header + protocol */ - pbuf_header(np, -(s16_t)(MPPE_OVHD + sizeof(protocol))); - - if ((err = pbuf_copy(np, *pb)) != ERR_OK) { - pbuf_free(np); - return err; - } - - /* Reveal MPPE header + protocol */ - pbuf_header(np, (s16_t)(MPPE_OVHD + sizeof(protocol))); - - *pb = np; - pl = (u8_t*)np->payload; - - state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; - PPPDEBUG(LOG_DEBUG, ("mppe_compress[%d]: ccount %d\n", pcb->netif->num, state->ccount)); - /* FIXME: use PUT* macros */ - pl[0] = state->ccount>>8; - pl[1] = state->ccount; - - if (!state->stateful || /* stateless mode */ - ((state->ccount & 0xff) == 0xff) || /* "flag" packet */ - (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */ - /* We must rekey */ - if (state->stateful) { - PPPDEBUG(LOG_DEBUG, ("mppe_compress[%d]: rekeying\n", pcb->netif->num)); - } - mppe_rekey(state, 0); - state->bits |= MPPE_BIT_FLUSHED; - } - pl[0] |= state->bits; - state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */ - pl += MPPE_OVHD; - - /* Add protocol */ - /* FIXME: add PFC support */ - pl[0] = protocol >> 8; - pl[1] = protocol; - - /* Hide MPPE header */ - pbuf_header(np, -(s16_t)MPPE_OVHD); - - /* Encrypt packet */ - for (n = np; n != NULL; n = n->next) { - lwip_arc4_crypt(&state->arc4, (u8_t*)n->payload, n->len); - if (n->tot_len == n->len) { - break; - } - } - - /* Reveal MPPE header */ - pbuf_header(np, (s16_t)MPPE_OVHD); - - return ERR_OK; -} - -/* - * We received a CCP Reset-Ack. Just ignore it. - */ -void mppe_decomp_reset(ppp_pcb *pcb, ppp_mppe_state *state) -{ - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(state); - return; -} - -/* - * Decompress (decrypt) an MPPE packet. - */ -err_t -mppe_decompress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb) -{ - struct pbuf *n0 = *pb, *n; - u8_t *pl; - u16_t ccount; - u8_t flushed; - - /* MPPE Header */ - if (n0->len < MPPE_OVHD) { - PPPDEBUG(LOG_DEBUG, - ("mppe_decompress[%d]: short pkt (%d)\n", - pcb->netif->num, n0->len)); - state->sanity_errors += 100; - goto sanity_error; - } - - pl = (u8_t*)n0->payload; - flushed = MPPE_BITS(pl) & MPPE_BIT_FLUSHED; - ccount = MPPE_CCOUNT(pl); - PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: ccount %d\n", - pcb->netif->num, ccount)); - - /* sanity checks -- terminate with extreme prejudice */ - if (!(MPPE_BITS(pl) & MPPE_BIT_ENCRYPTED)) { - PPPDEBUG(LOG_DEBUG, - ("mppe_decompress[%d]: ENCRYPTED bit not set!\n", - pcb->netif->num)); - state->sanity_errors += 100; - goto sanity_error; - } - if (!state->stateful && !flushed) { - PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: FLUSHED bit not set in " - "stateless mode!\n", pcb->netif->num)); - state->sanity_errors += 100; - goto sanity_error; - } - if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { - PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: FLUSHED bit not set on " - "flag packet!\n", pcb->netif->num)); - state->sanity_errors += 100; - goto sanity_error; - } - - /* - * Check the coherency count. - */ - - if (!state->stateful) { - /* Discard late packet */ - if ((ccount - state->ccount) % MPPE_CCOUNT_SPACE > MPPE_CCOUNT_SPACE / 2) { - state->sanity_errors++; - goto sanity_error; - } - - /* RFC 3078, sec 8.1. Rekey for every packet. */ - while (state->ccount != ccount) { - mppe_rekey(state, 0); - state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; - } - } else { - /* RFC 3078, sec 8.2. */ - if (!state->discard) { - /* normal state */ - state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; - if (ccount != state->ccount) { - /* - * (ccount > state->ccount) - * Packet loss detected, enter the discard state. - * Signal the peer to rekey (by sending a CCP Reset-Request). - */ - state->discard = 1; - ccp_resetrequest(pcb); - return ERR_BUF; - } - } else { - /* discard state */ - if (!flushed) { - /* ccp.c will be silent (no additional CCP Reset-Requests). */ - return ERR_BUF; - } else { - /* Rekey for every missed "flag" packet. */ - while ((ccount & ~0xff) != - (state->ccount & ~0xff)) { - mppe_rekey(state, 0); - state->ccount = - (state->ccount + - 256) % MPPE_CCOUNT_SPACE; - } - - /* reset */ - state->discard = 0; - state->ccount = ccount; - /* - * Another problem with RFC 3078 here. It implies that the - * peer need not send a Reset-Ack packet. But RFC 1962 - * requires it. Hopefully, M$ does send a Reset-Ack; even - * though it isn't required for MPPE synchronization, it is - * required to reset CCP state. - */ - } - } - if (flushed) - mppe_rekey(state, 0); - } - - /* Hide MPPE header */ - pbuf_header(n0, -(s16_t)(MPPE_OVHD)); - - /* Decrypt the packet. */ - for (n = n0; n != NULL; n = n->next) { - lwip_arc4_crypt(&state->arc4, (u8_t*)n->payload, n->len); - if (n->tot_len == n->len) { - break; - } - } - - /* good packet credit */ - state->sanity_errors >>= 1; - - return ERR_OK; - -sanity_error: - if (state->sanity_errors >= SANITY_MAX) { - /* - * Take LCP down if the peer is sending too many bogons. - * We don't want to do this for a single or just a few - * instances since it could just be due to packet corruption. - */ - lcp_close(pcb, "Too many MPPE errors"); - } - return ERR_BUF; -} - -#endif /* PPP_SUPPORT && MPPE_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/multilink.c b/ext/lwip/src/netif/ppp/multilink.c deleted file mode 100644 index 0d617a0..0000000 --- a/ext/lwip/src/netif/ppp/multilink.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - * multilink.c - support routines for multilink. - * - * Copyright (c) 2000-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. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && defined(HAVE_MULTILINK) /* don't build if not configured for use in lwipopts.h */ - -/* Multilink support - * - * Multilink uses Samba TDB (Trivial Database Library), which - * we cannot port, because it needs a filesystem. - * - * We have to choose between doing a memory-shared TDB-clone, - * or dropping multilink support at all. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/fsm.h" -#include "netif/ppp/lcp.h" -#include "netif/ppp/tdb.h" - -bool endpoint_specified; /* user gave explicit endpoint discriminator */ -char *bundle_id; /* identifier for our bundle */ -char *blinks_id; /* key for the list of links */ -bool doing_multilink; /* multilink was enabled and agreed to */ -bool multilink_master; /* we own the multilink bundle */ - -extern TDB_CONTEXT *pppdb; -extern char db_key[]; - -static void make_bundle_links (int append); -static void remove_bundle_link (void); -static void iterate_bundle_links (void (*func) (char *)); - -static int get_default_epdisc (struct epdisc *); -static int parse_num (char *str, const char *key, int *valp); -static int owns_unit (TDB_DATA pid, int unit); - -#define set_ip_epdisc(ep, addr) do { \ - ep->length = 4; \ - ep->value[0] = addr >> 24; \ - ep->value[1] = addr >> 16; \ - ep->value[2] = addr >> 8; \ - ep->value[3] = addr; \ -} while (0) - -#define LOCAL_IP_ADDR(addr) \ - (((addr) & 0xff000000) == 0x0a000000 /* 10.x.x.x */ \ - || ((addr) & 0xfff00000) == 0xac100000 /* 172.16.x.x */ \ - || ((addr) & 0xffff0000) == 0xc0a80000) /* 192.168.x.x */ - -#define process_exists(n) (kill((n), 0) == 0 || errno != ESRCH) - -void -mp_check_options() -{ - lcp_options *wo = &lcp_wantoptions[0]; - lcp_options *ao = &lcp_allowoptions[0]; - - doing_multilink = 0; - if (!multilink) - return; - /* if we're doing multilink, we have to negotiate MRRU */ - if (!wo->neg_mrru) { - /* mrru not specified, default to mru */ - wo->mrru = wo->mru; - wo->neg_mrru = 1; - } - ao->mrru = ao->mru; - ao->neg_mrru = 1; - - if (!wo->neg_endpoint && !noendpoint) { - /* get a default endpoint value */ - wo->neg_endpoint = get_default_epdisc(&wo->endpoint); - } -} - -/* - * Make a new bundle or join us to an existing bundle - * if we are doing multilink. - */ -int -mp_join_bundle() -{ - lcp_options *go = &lcp_gotoptions[0]; - lcp_options *ho = &lcp_hisoptions[0]; - lcp_options *ao = &lcp_allowoptions[0]; - int unit, pppd_pid; - int l, mtu; - char *p; - TDB_DATA key, pid, rec; - - if (doing_multilink) { - /* have previously joined a bundle */ - if (!go->neg_mrru || !ho->neg_mrru) { - notice("oops, didn't get multilink on renegotiation"); - lcp_close(pcb, "multilink required"); - return 0; - } - /* XXX should check the peer_authname and ho->endpoint - are the same as previously */ - return 0; - } - - if (!go->neg_mrru || !ho->neg_mrru) { - /* not doing multilink */ - if (go->neg_mrru) - notice("oops, multilink negotiated only for receive"); - mtu = ho->neg_mru? ho->mru: PPP_MRU; - if (mtu > ao->mru) - mtu = ao->mru; - if (demand) { - /* already have a bundle */ - cfg_bundle(0, 0, 0, 0); - netif_set_mtu(pcb, mtu); - return 0; - } - make_new_bundle(0, 0, 0, 0); - set_ifunit(1); - netif_set_mtu(pcb, mtu); - return 0; - } - - doing_multilink = 1; - - /* - * Find the appropriate bundle or join a new one. - * First we make up a name for the bundle. - * The length estimate is worst-case assuming every - * character has to be quoted. - */ - l = 4 * strlen(peer_authname) + 10; - if (ho->neg_endpoint) - l += 3 * ho->endpoint.length + 8; - if (bundle_name) - l += 3 * strlen(bundle_name) + 2; - bundle_id = malloc(l); - if (bundle_id == 0) - novm("bundle identifier"); - - p = bundle_id; - p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname); - if (ho->neg_endpoint || bundle_name) - *p++ = '/'; - if (ho->neg_endpoint) - p += slprintf(p, bundle_id+l-p, "%s", - epdisc_to_str(&ho->endpoint)); - if (bundle_name) - p += slprintf(p, bundle_id+l-p, "/%v", bundle_name); - - /* Make the key for the list of links belonging to the bundle */ - l = p - bundle_id; - blinks_id = malloc(l + 7); - if (blinks_id == NULL) - novm("bundle links key"); - slprintf(blinks_id, l + 7, "BUNDLE_LINKS=%s", bundle_id + 7); - - /* - * For demand mode, we only need to configure the bundle - * and attach the link. - */ - mtu = LWIP_MIN(ho->mrru, ao->mru); - if (demand) { - cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); - netif_set_mtu(pcb, mtu); - script_setenv("BUNDLE", bundle_id + 7, 1); - return 0; - } - - /* - * Check if the bundle ID is already in the database. - */ - unit = -1; - lock_db(); - key.dptr = bundle_id; - key.dsize = p - bundle_id; - pid = tdb_fetch(pppdb, key); - if (pid.dptr != NULL) { - /* bundle ID exists, see if the pppd record exists */ - rec = tdb_fetch(pppdb, pid); - if (rec.dptr != NULL && rec.dsize > 0) { - /* make sure the string is null-terminated */ - rec.dptr[rec.dsize-1] = 0; - /* parse the interface number */ - parse_num(rec.dptr, "IFNAME=ppp", &unit); - /* check the pid value */ - if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid) - || !process_exists(pppd_pid) - || !owns_unit(pid, unit)) - unit = -1; - free(rec.dptr); - } - free(pid.dptr); - } - - if (unit >= 0) { - /* attach to existing unit */ - if (bundle_attach(unit)) { - set_ifunit(0); - script_setenv("BUNDLE", bundle_id + 7, 0); - make_bundle_links(1); - unlock_db(); - info("Link attached to %s", ifname); - return 1; - } - /* attach failed because bundle doesn't exist */ - } - - /* we have to make a new bundle */ - make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); - set_ifunit(1); - netif_set_mtu(pcb, mtu); - script_setenv("BUNDLE", bundle_id + 7, 1); - make_bundle_links(pcb); - unlock_db(); - info("New bundle %s created", ifname); - multilink_master = 1; - return 0; -} - -void mp_exit_bundle() -{ - lock_db(); - remove_bundle_link(); - unlock_db(); -} - -static void sendhup(char *str) -{ - int pid; - - if (parse_num(str, "PPPD_PID=", &pid) && pid != getpid()) { - if (debug) - dbglog("sending SIGHUP to process %d", pid); - kill(pid, SIGHUP); - } -} - -void mp_bundle_terminated() -{ - TDB_DATA key; - - bundle_terminating = 1; - upper_layers_down(pcb); - notice("Connection terminated."); -#if PPP_STATS_SUPPORT - print_link_stats(); -#endif /* PPP_STATS_SUPPORT */ - if (!demand) { - remove_pidfiles(); - script_unsetenv("IFNAME"); - } - - lock_db(); - destroy_bundle(); - iterate_bundle_links(sendhup); - key.dptr = blinks_id; - key.dsize = strlen(blinks_id); - tdb_delete(pppdb, key); - unlock_db(); - - new_phase(PPP_PHASE_DEAD); - - doing_multilink = 0; - multilink_master = 0; -} - -static void make_bundle_links(int append) -{ - TDB_DATA key, rec; - char *p; - char entry[32]; - int l; - - key.dptr = blinks_id; - key.dsize = strlen(blinks_id); - slprintf(entry, sizeof(entry), "%s;", db_key); - p = entry; - if (append) { - rec = tdb_fetch(pppdb, key); - if (rec.dptr != NULL && rec.dsize > 0) { - rec.dptr[rec.dsize-1] = 0; - if (strstr(rec.dptr, db_key) != NULL) { - /* already in there? strange */ - warn("link entry already exists in tdb"); - return; - } - l = rec.dsize + strlen(entry); - p = malloc(l); - if (p == NULL) - novm("bundle link list"); - slprintf(p, l, "%s%s", rec.dptr, entry); - } else { - warn("bundle link list not found"); - } - if (rec.dptr != NULL) - free(rec.dptr); - } - rec.dptr = p; - rec.dsize = strlen(p) + 1; - if (tdb_store(pppdb, key, rec, TDB_REPLACE)) - error("couldn't %s bundle link list", - append? "update": "create"); - if (p != entry) - free(p); -} - -static void remove_bundle_link() -{ - TDB_DATA key, rec; - char entry[32]; - char *p, *q; - int l; - - key.dptr = blinks_id; - key.dsize = strlen(blinks_id); - slprintf(entry, sizeof(entry), "%s;", db_key); - - rec = tdb_fetch(pppdb, key); - if (rec.dptr == NULL || rec.dsize <= 0) { - if (rec.dptr != NULL) - free(rec.dptr); - return; - } - rec.dptr[rec.dsize-1] = 0; - p = strstr(rec.dptr, entry); - if (p != NULL) { - q = p + strlen(entry); - l = strlen(q) + 1; - memmove(p, q, l); - rec.dsize = p - rec.dptr + l; - if (tdb_store(pppdb, key, rec, TDB_REPLACE)) - error("couldn't update bundle link list (removal)"); - } - free(rec.dptr); -} - -static void iterate_bundle_links(void (*func)(char *)) -{ - TDB_DATA key, rec, pp; - char *p, *q; - - key.dptr = blinks_id; - key.dsize = strlen(blinks_id); - rec = tdb_fetch(pppdb, key); - if (rec.dptr == NULL || rec.dsize <= 0) { - error("bundle link list not found (iterating list)"); - if (rec.dptr != NULL) - free(rec.dptr); - return; - } - p = rec.dptr; - p[rec.dsize-1] = 0; - while ((q = strchr(p, ';')) != NULL) { - *q = 0; - key.dptr = p; - key.dsize = q - p; - pp = tdb_fetch(pppdb, key); - if (pp.dptr != NULL && pp.dsize > 0) { - pp.dptr[pp.dsize-1] = 0; - func(pp.dptr); - } - if (pp.dptr != NULL) - free(pp.dptr); - p = q + 1; - } - free(rec.dptr); -} - -static int -parse_num(str, key, valp) - char *str; - const char *key; - int *valp; -{ - char *p, *endp; - int i; - - p = strstr(str, key); - if (p != 0) { - p += strlen(key); - i = strtol(p, &endp, 10); - if (endp != p && (*endp == 0 || *endp == ';')) { - *valp = i; - return 1; - } - } - return 0; -} - -/* - * Check whether the pppd identified by `key' still owns ppp unit `unit'. - */ -static int -owns_unit(key, unit) - TDB_DATA key; - int unit; -{ - char ifkey[32]; - TDB_DATA kd, vd; - int ret = 0; - - slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit); - kd.dptr = ifkey; - kd.dsize = strlen(ifkey); - vd = tdb_fetch(pppdb, kd); - if (vd.dptr != NULL) { - ret = vd.dsize == key.dsize - && memcmp(vd.dptr, key.dptr, vd.dsize) == 0; - free(vd.dptr); - } - return ret; -} - -static int -get_default_epdisc(ep) - struct epdisc *ep; -{ - char *p; - struct hostent *hp; - u32_t addr; - - /* First try for an ethernet MAC address */ - p = get_first_ethernet(); - if (p != 0 && get_if_hwaddr(ep->value, p) >= 0) { - ep->class = EPD_MAC; - ep->length = 6; - return 1; - } - - /* see if our hostname corresponds to a reasonable IP address */ - hp = gethostbyname(hostname); - if (hp != NULL) { - addr = *(u32_t *)hp->h_addr; - if (!bad_ip_adrs(addr)) { - addr = ntohl(addr); - if (!LOCAL_IP_ADDR(addr)) { - ep->class = EPD_IP; - set_ip_epdisc(ep, addr); - return 1; - } - } - } - - return 0; -} - -/* - * epdisc_to_str - make a printable string from an endpoint discriminator. - */ - -static char *endp_class_names[] = { - "null", "local", "IP", "MAC", "magic", "phone" -}; - -char * -epdisc_to_str(ep) - struct epdisc *ep; -{ - static char str[MAX_ENDP_LEN*3+8]; - u_char *p = ep->value; - int i, mask = 0; - char *q, c, c2; - - if (ep->class == EPD_NULL && ep->length == 0) - return "null"; - if (ep->class == EPD_IP && ep->length == 4) { - u32_t addr; - - GETLONG(addr, p); - slprintf(str, sizeof(str), "IP:%I", htonl(addr)); - return str; - } - - c = ':'; - c2 = '.'; - if (ep->class == EPD_MAC && ep->length == 6) - c2 = ':'; - else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0) - mask = 3; - q = str; - if (ep->class <= EPD_PHONENUM) - q += slprintf(q, sizeof(str)-1, "%s", - endp_class_names[ep->class]); - else - q += slprintf(q, sizeof(str)-1, "%d", ep->class); - c = ':'; - for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) { - if ((i & mask) == 0) { - *q++ = c; - c = c2; - } - q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]); - } - return str; -} - -static int hexc_val(int c) -{ - if (c >= 'a') - return c - 'a' + 10; - if (c >= 'A') - return c - 'A' + 10; - return c - '0'; -} - -int -str_to_epdisc(ep, str) - struct epdisc *ep; - char *str; -{ - int i, l; - char *p, *endp; - - for (i = EPD_NULL; i <= EPD_PHONENUM; ++i) { - int sl = strlen(endp_class_names[i]); - if (strncasecmp(str, endp_class_names[i], sl) == 0) { - str += sl; - break; - } - } - if (i > EPD_PHONENUM) { - /* not a class name, try a decimal class number */ - i = strtol(str, &endp, 10); - if (endp == str) - return 0; /* can't parse class number */ - str = endp; - } - ep->class = i; - if (*str == 0) { - ep->length = 0; - return 1; - } - if (*str != ':' && *str != '.') - return 0; - ++str; - - if (i == EPD_IP) { - u32_t addr; - i = parse_dotted_ip(str, &addr); - if (i == 0 || str[i] != 0) - return 0; - set_ip_epdisc(ep, addr); - return 1; - } - if (i == EPD_MAC && get_if_hwaddr(ep->value, str) >= 0) { - ep->length = 6; - return 1; - } - - p = str; - for (l = 0; l < MAX_ENDP_LEN; ++l) { - if (*str == 0) - break; - if (p <= str) - for (p = str; isxdigit(*p); ++p) - ; - i = p - str; - if (i == 0) - return 0; - ep->value[l] = hexc_val(*str++); - if ((i & 1) == 0) - ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++); - if (*str == ':' || *str == '.') - ++str; - } - if (*str != 0 || (ep->class == EPD_MAC && l != 6)) - return 0; - ep->length = l; - return 1; -} - -#endif /* PPP_SUPPORT && HAVE_MULTILINK */ diff --git a/ext/lwip/src/netif/ppp/polarssl/README b/ext/lwip/src/netif/ppp/polarssl/README deleted file mode 100644 index 3fdf159..0000000 --- a/ext/lwip/src/netif/ppp/polarssl/README +++ /dev/null @@ -1,22 +0,0 @@ -About PolarSSL files into lwIP PPP support ------------------------------------------- - -This folder 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. - - -PolarSSL project website: http://polarssl.org/ diff --git a/ext/lwip/src/netif/ppp/polarssl/arc4.c b/ext/lwip/src/netif/ppp/polarssl/arc4.c deleted file mode 100644 index 6e17ec4..0000000 --- a/ext/lwip/src/netif/ppp/polarssl/arc4.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * An implementation of the ARCFOUR algorithm - * - * 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. - */ -/* - * The ARCFOUR algorithm was publicly disclosed on 94/09. - * - * http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0 - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_ARC4 - -#include "netif/ppp/polarssl/arc4.h" -/* - * ARC4 key schedule - */ -void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen ) -{ - int i, j, k, a; - unsigned char *m; - - ctx->x = 0; - ctx->y = 0; - m = ctx->m; - - for( i = 0; i < 256; i++ ) - m[i] = (unsigned char) i; - - j = k = 0; - - for( i = 0; i < 256; i++, k++ ) - { - if( k >= keylen ) k = 0; - - a = m[i]; - j = ( j + a + key[k] ) & 0xFF; - m[i] = m[j]; - m[j] = (unsigned char) a; - } -} - -/* - * ARC4 cipher function - */ -void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen ) -{ - int i, x, y, a, b; - unsigned char *m; - - x = ctx->x; - y = ctx->y; - m = ctx->m; - - for( i = 0; i < buflen; i++ ) - { - x = ( x + 1 ) & 0xFF; a = m[x]; - y = ( y + a ) & 0xFF; b = m[y]; - - m[x] = (unsigned char) b; - m[y] = (unsigned char) a; - - buf[i] = (unsigned char) - ( buf[i] ^ m[(unsigned char)( a + b )] ); - } - - ctx->x = x; - ctx->y = y; -} - -#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES */ diff --git a/ext/lwip/src/netif/ppp/polarssl/des.c b/ext/lwip/src/netif/ppp/polarssl/des.c deleted file mode 100644 index 9a89d00..0000000 --- a/ext/lwip/src/netif/ppp/polarssl/des.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * FIPS-46-3 compliant Triple-DES implementation - * - * 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. - */ -/* - * DES, on which TDES is based, was originally designed by Horst Feistel - * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). - * - * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES - -#include "netif/ppp/polarssl/des.h" - -/* - * 32-bit integer manipulation macros (big endian) - */ -#ifndef GET_ULONG_BE -#define GET_ULONG_BE(n,b,i) \ -{ \ - (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ - | ( (unsigned long) (b)[(i) + 1] << 16 ) \ - | ( (unsigned long) (b)[(i) + 2] << 8 ) \ - | ( (unsigned long) (b)[(i) + 3] ); \ -} -#endif - -#ifndef PUT_ULONG_BE -#define PUT_ULONG_BE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) ); \ -} -#endif - -/* - * Expanded DES S-boxes - */ -static const unsigned long SB1[64] = -{ - 0x01010400, 0x00000000, 0x00010000, 0x01010404, - 0x01010004, 0x00010404, 0x00000004, 0x00010000, - 0x00000400, 0x01010400, 0x01010404, 0x00000400, - 0x01000404, 0x01010004, 0x01000000, 0x00000004, - 0x00000404, 0x01000400, 0x01000400, 0x00010400, - 0x00010400, 0x01010000, 0x01010000, 0x01000404, - 0x00010004, 0x01000004, 0x01000004, 0x00010004, - 0x00000000, 0x00000404, 0x00010404, 0x01000000, - 0x00010000, 0x01010404, 0x00000004, 0x01010000, - 0x01010400, 0x01000000, 0x01000000, 0x00000400, - 0x01010004, 0x00010000, 0x00010400, 0x01000004, - 0x00000400, 0x00000004, 0x01000404, 0x00010404, - 0x01010404, 0x00010004, 0x01010000, 0x01000404, - 0x01000004, 0x00000404, 0x00010404, 0x01010400, - 0x00000404, 0x01000400, 0x01000400, 0x00000000, - 0x00010004, 0x00010400, 0x00000000, 0x01010004 -}; - -static const unsigned long SB2[64] = -{ - 0x80108020, 0x80008000, 0x00008000, 0x00108020, - 0x00100000, 0x00000020, 0x80100020, 0x80008020, - 0x80000020, 0x80108020, 0x80108000, 0x80000000, - 0x80008000, 0x00100000, 0x00000020, 0x80100020, - 0x00108000, 0x00100020, 0x80008020, 0x00000000, - 0x80000000, 0x00008000, 0x00108020, 0x80100000, - 0x00100020, 0x80000020, 0x00000000, 0x00108000, - 0x00008020, 0x80108000, 0x80100000, 0x00008020, - 0x00000000, 0x00108020, 0x80100020, 0x00100000, - 0x80008020, 0x80100000, 0x80108000, 0x00008000, - 0x80100000, 0x80008000, 0x00000020, 0x80108020, - 0x00108020, 0x00000020, 0x00008000, 0x80000000, - 0x00008020, 0x80108000, 0x00100000, 0x80000020, - 0x00100020, 0x80008020, 0x80000020, 0x00100020, - 0x00108000, 0x00000000, 0x80008000, 0x00008020, - 0x80000000, 0x80100020, 0x80108020, 0x00108000 -}; - -static const unsigned long SB3[64] = -{ - 0x00000208, 0x08020200, 0x00000000, 0x08020008, - 0x08000200, 0x00000000, 0x00020208, 0x08000200, - 0x00020008, 0x08000008, 0x08000008, 0x00020000, - 0x08020208, 0x00020008, 0x08020000, 0x00000208, - 0x08000000, 0x00000008, 0x08020200, 0x00000200, - 0x00020200, 0x08020000, 0x08020008, 0x00020208, - 0x08000208, 0x00020200, 0x00020000, 0x08000208, - 0x00000008, 0x08020208, 0x00000200, 0x08000000, - 0x08020200, 0x08000000, 0x00020008, 0x00000208, - 0x00020000, 0x08020200, 0x08000200, 0x00000000, - 0x00000200, 0x00020008, 0x08020208, 0x08000200, - 0x08000008, 0x00000200, 0x00000000, 0x08020008, - 0x08000208, 0x00020000, 0x08000000, 0x08020208, - 0x00000008, 0x00020208, 0x00020200, 0x08000008, - 0x08020000, 0x08000208, 0x00000208, 0x08020000, - 0x00020208, 0x00000008, 0x08020008, 0x00020200 -}; - -static const unsigned long SB4[64] = -{ - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802080, 0x00800081, 0x00800001, 0x00002001, - 0x00000000, 0x00802000, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00800080, 0x00800001, - 0x00000001, 0x00002000, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002001, 0x00002080, - 0x00800081, 0x00000001, 0x00002080, 0x00800080, - 0x00002000, 0x00802080, 0x00802081, 0x00000081, - 0x00800080, 0x00800001, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00000000, 0x00802000, - 0x00002080, 0x00800080, 0x00800081, 0x00000001, - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802081, 0x00000081, 0x00000001, 0x00002000, - 0x00800001, 0x00002001, 0x00802080, 0x00800081, - 0x00002001, 0x00002080, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002000, 0x00802080 -}; - -static const unsigned long SB5[64] = -{ - 0x00000100, 0x02080100, 0x02080000, 0x42000100, - 0x00080000, 0x00000100, 0x40000000, 0x02080000, - 0x40080100, 0x00080000, 0x02000100, 0x40080100, - 0x42000100, 0x42080000, 0x00080100, 0x40000000, - 0x02000000, 0x40080000, 0x40080000, 0x00000000, - 0x40000100, 0x42080100, 0x42080100, 0x02000100, - 0x42080000, 0x40000100, 0x00000000, 0x42000000, - 0x02080100, 0x02000000, 0x42000000, 0x00080100, - 0x00080000, 0x42000100, 0x00000100, 0x02000000, - 0x40000000, 0x02080000, 0x42000100, 0x40080100, - 0x02000100, 0x40000000, 0x42080000, 0x02080100, - 0x40080100, 0x00000100, 0x02000000, 0x42080000, - 0x42080100, 0x00080100, 0x42000000, 0x42080100, - 0x02080000, 0x00000000, 0x40080000, 0x42000000, - 0x00080100, 0x02000100, 0x40000100, 0x00080000, - 0x00000000, 0x40080000, 0x02080100, 0x40000100 -}; - -static const unsigned long SB6[64] = -{ - 0x20000010, 0x20400000, 0x00004000, 0x20404010, - 0x20400000, 0x00000010, 0x20404010, 0x00400000, - 0x20004000, 0x00404010, 0x00400000, 0x20000010, - 0x00400010, 0x20004000, 0x20000000, 0x00004010, - 0x00000000, 0x00400010, 0x20004010, 0x00004000, - 0x00404000, 0x20004010, 0x00000010, 0x20400010, - 0x20400010, 0x00000000, 0x00404010, 0x20404000, - 0x00004010, 0x00404000, 0x20404000, 0x20000000, - 0x20004000, 0x00000010, 0x20400010, 0x00404000, - 0x20404010, 0x00400000, 0x00004010, 0x20000010, - 0x00400000, 0x20004000, 0x20000000, 0x00004010, - 0x20000010, 0x20404010, 0x00404000, 0x20400000, - 0x00404010, 0x20404000, 0x00000000, 0x20400010, - 0x00000010, 0x00004000, 0x20400000, 0x00404010, - 0x00004000, 0x00400010, 0x20004010, 0x00000000, - 0x20404000, 0x20000000, 0x00400010, 0x20004010 -}; - -static const unsigned long SB7[64] = -{ - 0x00200000, 0x04200002, 0x04000802, 0x00000000, - 0x00000800, 0x04000802, 0x00200802, 0x04200800, - 0x04200802, 0x00200000, 0x00000000, 0x04000002, - 0x00000002, 0x04000000, 0x04200002, 0x00000802, - 0x04000800, 0x00200802, 0x00200002, 0x04000800, - 0x04000002, 0x04200000, 0x04200800, 0x00200002, - 0x04200000, 0x00000800, 0x00000802, 0x04200802, - 0x00200800, 0x00000002, 0x04000000, 0x00200800, - 0x04000000, 0x00200800, 0x00200000, 0x04000802, - 0x04000802, 0x04200002, 0x04200002, 0x00000002, - 0x00200002, 0x04000000, 0x04000800, 0x00200000, - 0x04200800, 0x00000802, 0x00200802, 0x04200800, - 0x00000802, 0x04000002, 0x04200802, 0x04200000, - 0x00200800, 0x00000000, 0x00000002, 0x04200802, - 0x00000000, 0x00200802, 0x04200000, 0x00000800, - 0x04000002, 0x04000800, 0x00000800, 0x00200002 -}; - -static const unsigned long SB8[64] = -{ - 0x10001040, 0x00001000, 0x00040000, 0x10041040, - 0x10000000, 0x10001040, 0x00000040, 0x10000000, - 0x00040040, 0x10040000, 0x10041040, 0x00041000, - 0x10041000, 0x00041040, 0x00001000, 0x00000040, - 0x10040000, 0x10000040, 0x10001000, 0x00001040, - 0x00041000, 0x00040040, 0x10040040, 0x10041000, - 0x00001040, 0x00000000, 0x00000000, 0x10040040, - 0x10000040, 0x10001000, 0x00041040, 0x00040000, - 0x00041040, 0x00040000, 0x10041000, 0x00001000, - 0x00000040, 0x10040040, 0x00001000, 0x00041040, - 0x10001000, 0x00000040, 0x10000040, 0x10040000, - 0x10040040, 0x10000000, 0x00040000, 0x10001040, - 0x00000000, 0x10041040, 0x00040040, 0x10000040, - 0x10040000, 0x10001000, 0x10001040, 0x00000000, - 0x10041040, 0x00041000, 0x00041000, 0x00001040, - 0x00001040, 0x00040040, 0x10000000, 0x10041000 -}; - -/* - * PC1: left and right halves bit-swap - */ -static const unsigned long LHs[16] = -{ - 0x00000000, 0x00000001, 0x00000100, 0x00000101, - 0x00010000, 0x00010001, 0x00010100, 0x00010101, - 0x01000000, 0x01000001, 0x01000100, 0x01000101, - 0x01010000, 0x01010001, 0x01010100, 0x01010101 -}; - -static const unsigned long RHs[16] = -{ - 0x00000000, 0x01000000, 0x00010000, 0x01010000, - 0x00000100, 0x01000100, 0x00010100, 0x01010100, - 0x00000001, 0x01000001, 0x00010001, 0x01010001, - 0x00000101, 0x01000101, 0x00010101, 0x01010101, -}; - -/* - * Initial Permutation macro - */ -#define DES_IP(X,Y) \ -{ \ - T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ - T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ - T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ - T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ - Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ - T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ - X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ -} - -/* - * Final Permutation macro - */ -#define DES_FP(X,Y) \ -{ \ - X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ - T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ - Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ - T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ - T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ - T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ - T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ -} - -/* - * DES round macro - */ -#define DES_ROUND(X,Y) \ -{ \ - T = *SK++ ^ X; \ - Y ^= SB8[ (T ) & 0x3F ] ^ \ - SB6[ (T >> 8) & 0x3F ] ^ \ - SB4[ (T >> 16) & 0x3F ] ^ \ - SB2[ (T >> 24) & 0x3F ]; \ - \ - T = *SK++ ^ ((X << 28) | (X >> 4)); \ - Y ^= SB7[ (T ) & 0x3F ] ^ \ - SB5[ (T >> 8) & 0x3F ] ^ \ - SB3[ (T >> 16) & 0x3F ] ^ \ - SB1[ (T >> 24) & 0x3F ]; \ -} - -#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; } - -static void des_setkey( unsigned long SK[32], unsigned char key[8] ) -{ - int i; - unsigned long X, Y, T; - - GET_ULONG_BE( X, key, 0 ); - GET_ULONG_BE( Y, key, 4 ); - - /* - * Permuted Choice 1 - */ - T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); - T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); - - X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) - | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) - | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) - | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); - - Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) - | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) - | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) - | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); - - X &= 0x0FFFFFFF; - Y &= 0x0FFFFFFF; - - /* - * calculate subkeys - */ - for( i = 0; i < 16; i++ ) - { - if( i < 2 || i == 8 || i == 15 ) - { - X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; - Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; - } - else - { - X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; - Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; - } - - *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) - | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) - | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) - | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) - | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) - | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) - | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) - | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) - | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) - | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) - | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); - - *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) - | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) - | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) - | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) - | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) - | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) - | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) - | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) - | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) - | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) - | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); - } -} - -/* - * DES key schedule (56-bit, encryption) - */ -void des_setkey_enc( des_context *ctx, unsigned char key[8] ) -{ - des_setkey( ctx->sk, key ); -} - -/* - * DES key schedule (56-bit, decryption) - */ -void des_setkey_dec( des_context *ctx, unsigned char key[8] ) -{ - int i; - - des_setkey( ctx->sk, key ); - - for( i = 0; i < 16; i += 2 ) - { - SWAP( ctx->sk[i ], ctx->sk[30 - i] ); - SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); - } -} - -/* - * DES-ECB block encryption/decryption - */ -void des_crypt_ecb( des_context *ctx, - const unsigned char input[8], - unsigned char output[8] ) -{ - int i; - unsigned long X, Y, T, *SK; - - SK = ctx->sk; - - GET_ULONG_BE( X, input, 0 ); - GET_ULONG_BE( Y, input, 4 ); - - DES_IP( X, Y ); - - for( i = 0; i < 8; i++ ) - { - DES_ROUND( Y, X ); - DES_ROUND( X, Y ); - } - - DES_FP( Y, X ); - - PUT_ULONG_BE( Y, output, 0 ); - PUT_ULONG_BE( X, output, 4 ); -} - -#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES */ diff --git a/ext/lwip/src/netif/ppp/polarssl/md4.c b/ext/lwip/src/netif/ppp/polarssl/md4.c deleted file mode 100644 index b1701a0..0000000 --- a/ext/lwip/src/netif/ppp/polarssl/md4.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * RFC 1186/1320 compliant MD4 implementation - * - * 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. - */ -/* - * The MD4 algorithm was designed by Ron Rivest in 1990. - * - * http://www.ietf.org/rfc/rfc1186.txt - * http://www.ietf.org/rfc/rfc1320.txt - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD4 - -#include "netif/ppp/polarssl/md4.h" - -#include - -/* - * 32-bit integer manipulation macros (little endian) - */ -#ifndef GET_ULONG_LE -#define GET_ULONG_LE(n,b,i) \ -{ \ - (n) = ( (unsigned long) (b)[(i) ] ) \ - | ( (unsigned long) (b)[(i) + 1] << 8 ) \ - | ( (unsigned long) (b)[(i) + 2] << 16 ) \ - | ( (unsigned long) (b)[(i) + 3] << 24 ); \ -} -#endif - -#ifndef PUT_ULONG_LE -#define PUT_ULONG_LE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ -} -#endif - -/* - * MD4 context setup - */ -void md4_starts( md4_context *ctx ) -{ - ctx->total[0] = 0; - ctx->total[1] = 0; - - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xEFCDAB89; - ctx->state[2] = 0x98BADCFE; - ctx->state[3] = 0x10325476; -} - -static void md4_process( md4_context *ctx, const unsigned char data[64] ) -{ - unsigned long X[16], A, B, C, D; - - GET_ULONG_LE( X[ 0], data, 0 ); - GET_ULONG_LE( X[ 1], data, 4 ); - GET_ULONG_LE( X[ 2], data, 8 ); - GET_ULONG_LE( X[ 3], data, 12 ); - GET_ULONG_LE( X[ 4], data, 16 ); - GET_ULONG_LE( X[ 5], data, 20 ); - GET_ULONG_LE( X[ 6], data, 24 ); - GET_ULONG_LE( X[ 7], data, 28 ); - GET_ULONG_LE( X[ 8], data, 32 ); - GET_ULONG_LE( X[ 9], data, 36 ); - GET_ULONG_LE( X[10], data, 40 ); - GET_ULONG_LE( X[11], data, 44 ); - GET_ULONG_LE( X[12], data, 48 ); - GET_ULONG_LE( X[13], data, 52 ); - GET_ULONG_LE( X[14], data, 56 ); - GET_ULONG_LE( X[15], data, 60 ); - -#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - -#define F(x, y, z) ((x & y) | ((~x) & z)) -#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); } - - P( A, B, C, D, X[ 0], 3 ); - P( D, A, B, C, X[ 1], 7 ); - P( C, D, A, B, X[ 2], 11 ); - P( B, C, D, A, X[ 3], 19 ); - P( A, B, C, D, X[ 4], 3 ); - P( D, A, B, C, X[ 5], 7 ); - P( C, D, A, B, X[ 6], 11 ); - P( B, C, D, A, X[ 7], 19 ); - P( A, B, C, D, X[ 8], 3 ); - P( D, A, B, C, X[ 9], 7 ); - P( C, D, A, B, X[10], 11 ); - P( B, C, D, A, X[11], 19 ); - P( A, B, C, D, X[12], 3 ); - P( D, A, B, C, X[13], 7 ); - P( C, D, A, B, X[14], 11 ); - P( B, C, D, A, X[15], 19 ); - -#undef P -#undef F - -#define F(x,y,z) ((x & y) | (x & z) | (y & z)) -#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } - - P( A, B, C, D, X[ 0], 3 ); - P( D, A, B, C, X[ 4], 5 ); - P( C, D, A, B, X[ 8], 9 ); - P( B, C, D, A, X[12], 13 ); - P( A, B, C, D, X[ 1], 3 ); - P( D, A, B, C, X[ 5], 5 ); - P( C, D, A, B, X[ 9], 9 ); - P( B, C, D, A, X[13], 13 ); - P( A, B, C, D, X[ 2], 3 ); - P( D, A, B, C, X[ 6], 5 ); - P( C, D, A, B, X[10], 9 ); - P( B, C, D, A, X[14], 13 ); - P( A, B, C, D, X[ 3], 3 ); - P( D, A, B, C, X[ 7], 5 ); - P( C, D, A, B, X[11], 9 ); - P( B, C, D, A, X[15], 13 ); - -#undef P -#undef F - -#define F(x,y,z) (x ^ y ^ z) -#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } - - P( A, B, C, D, X[ 0], 3 ); - P( D, A, B, C, X[ 8], 9 ); - P( C, D, A, B, X[ 4], 11 ); - P( B, C, D, A, X[12], 15 ); - P( A, B, C, D, X[ 2], 3 ); - P( D, A, B, C, X[10], 9 ); - P( C, D, A, B, X[ 6], 11 ); - P( B, C, D, A, X[14], 15 ); - P( A, B, C, D, X[ 1], 3 ); - P( D, A, B, C, X[ 9], 9 ); - P( C, D, A, B, X[ 5], 11 ); - P( B, C, D, A, X[13], 15 ); - P( A, B, C, D, X[ 3], 3 ); - P( D, A, B, C, X[11], 9 ); - P( C, D, A, B, X[ 7], 11 ); - P( B, C, D, A, X[15], 15 ); - -#undef F -#undef P - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; -} - -/* - * MD4 process buffer - */ -void md4_update( md4_context *ctx, const unsigned char *input, int ilen ) -{ - int fill; - unsigned long left; - - if( ilen <= 0 ) - return; - - left = ctx->total[0] & 0x3F; - fill = 64 - left; - - ctx->total[0] += ilen; - ctx->total[0] &= 0xFFFFFFFF; - - if( ctx->total[0] < (unsigned long) ilen ) - ctx->total[1]++; - - if( left && ilen >= fill ) - { - MEMCPY( (void *) (ctx->buffer + left), - input, fill ); - md4_process( ctx, ctx->buffer ); - input += fill; - ilen -= fill; - left = 0; - } - - while( ilen >= 64 ) - { - md4_process( ctx, input ); - input += 64; - ilen -= 64; - } - - if( ilen > 0 ) - { - MEMCPY( (void *) (ctx->buffer + left), - input, ilen ); - } -} - -static const unsigned char md4_padding[64] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* - * MD4 final digest - */ -void md4_finish( md4_context *ctx, unsigned char output[16] ) -{ - unsigned long last, padn; - unsigned long high, low; - unsigned char msglen[8]; - - high = ( ctx->total[0] >> 29 ) - | ( ctx->total[1] << 3 ); - low = ( ctx->total[0] << 3 ); - - PUT_ULONG_LE( low, msglen, 0 ); - PUT_ULONG_LE( high, msglen, 4 ); - - last = ctx->total[0] & 0x3F; - padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); - - md4_update( ctx, md4_padding, padn ); - md4_update( ctx, msglen, 8 ); - - PUT_ULONG_LE( ctx->state[0], output, 0 ); - PUT_ULONG_LE( ctx->state[1], output, 4 ); - PUT_ULONG_LE( ctx->state[2], output, 8 ); - PUT_ULONG_LE( ctx->state[3], output, 12 ); -} - -/* - * output = MD4( input buffer ) - */ -void md4( unsigned char *input, int ilen, unsigned char output[16] ) -{ - md4_context ctx; - - md4_starts( &ctx ); - md4_update( &ctx, input, ilen ); - md4_finish( &ctx, output ); -} - -#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD4 */ diff --git a/ext/lwip/src/netif/ppp/polarssl/md5.c b/ext/lwip/src/netif/ppp/polarssl/md5.c deleted file mode 100644 index 1ec4d81..0000000 --- a/ext/lwip/src/netif/ppp/polarssl/md5.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * RFC 1321 compliant MD5 implementation - * - * 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. - */ -/* - * The MD5 algorithm was designed by Ron Rivest in 1991. - * - * http://www.ietf.org/rfc/rfc1321.txt - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD5 - -#include "netif/ppp/polarssl/md5.h" - -#include - -/* - * 32-bit integer manipulation macros (little endian) - */ -#ifndef GET_ULONG_LE -#define GET_ULONG_LE(n,b,i) \ -{ \ - (n) = ( (unsigned long) (b)[(i) ] ) \ - | ( (unsigned long) (b)[(i) + 1] << 8 ) \ - | ( (unsigned long) (b)[(i) + 2] << 16 ) \ - | ( (unsigned long) (b)[(i) + 3] << 24 ); \ -} -#endif - -#ifndef PUT_ULONG_LE -#define PUT_ULONG_LE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ -} -#endif - -/* - * MD5 context setup - */ -void md5_starts( md5_context *ctx ) -{ - ctx->total[0] = 0; - ctx->total[1] = 0; - - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xEFCDAB89; - ctx->state[2] = 0x98BADCFE; - ctx->state[3] = 0x10325476; -} - -static void md5_process( md5_context *ctx, const unsigned char data[64] ) -{ - unsigned long X[16], A, B, C, D; - - GET_ULONG_LE( X[ 0], data, 0 ); - GET_ULONG_LE( X[ 1], data, 4 ); - GET_ULONG_LE( X[ 2], data, 8 ); - GET_ULONG_LE( X[ 3], data, 12 ); - GET_ULONG_LE( X[ 4], data, 16 ); - GET_ULONG_LE( X[ 5], data, 20 ); - GET_ULONG_LE( X[ 6], data, 24 ); - GET_ULONG_LE( X[ 7], data, 28 ); - GET_ULONG_LE( X[ 8], data, 32 ); - GET_ULONG_LE( X[ 9], data, 36 ); - GET_ULONG_LE( X[10], data, 40 ); - GET_ULONG_LE( X[11], data, 44 ); - GET_ULONG_LE( X[12], data, 48 ); - GET_ULONG_LE( X[13], data, 52 ); - GET_ULONG_LE( X[14], data, 56 ); - GET_ULONG_LE( X[15], data, 60 ); - -#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) - -#define P(a,b,c,d,k,s,t) \ -{ \ - a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ -} - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - -#define F(x,y,z) (z ^ (x & (y ^ z))) - - P( A, B, C, D, 0, 7, 0xD76AA478 ); - P( D, A, B, C, 1, 12, 0xE8C7B756 ); - P( C, D, A, B, 2, 17, 0x242070DB ); - P( B, C, D, A, 3, 22, 0xC1BDCEEE ); - P( A, B, C, D, 4, 7, 0xF57C0FAF ); - P( D, A, B, C, 5, 12, 0x4787C62A ); - P( C, D, A, B, 6, 17, 0xA8304613 ); - P( B, C, D, A, 7, 22, 0xFD469501 ); - P( A, B, C, D, 8, 7, 0x698098D8 ); - P( D, A, B, C, 9, 12, 0x8B44F7AF ); - P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); - P( B, C, D, A, 11, 22, 0x895CD7BE ); - P( A, B, C, D, 12, 7, 0x6B901122 ); - P( D, A, B, C, 13, 12, 0xFD987193 ); - P( C, D, A, B, 14, 17, 0xA679438E ); - P( B, C, D, A, 15, 22, 0x49B40821 ); - -#undef F - -#define F(x,y,z) (y ^ (z & (x ^ y))) - - P( A, B, C, D, 1, 5, 0xF61E2562 ); - P( D, A, B, C, 6, 9, 0xC040B340 ); - P( C, D, A, B, 11, 14, 0x265E5A51 ); - P( B, C, D, A, 0, 20, 0xE9B6C7AA ); - P( A, B, C, D, 5, 5, 0xD62F105D ); - P( D, A, B, C, 10, 9, 0x02441453 ); - P( C, D, A, B, 15, 14, 0xD8A1E681 ); - P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); - P( A, B, C, D, 9, 5, 0x21E1CDE6 ); - P( D, A, B, C, 14, 9, 0xC33707D6 ); - P( C, D, A, B, 3, 14, 0xF4D50D87 ); - P( B, C, D, A, 8, 20, 0x455A14ED ); - P( A, B, C, D, 13, 5, 0xA9E3E905 ); - P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); - P( C, D, A, B, 7, 14, 0x676F02D9 ); - P( B, C, D, A, 12, 20, 0x8D2A4C8A ); - -#undef F - -#define F(x,y,z) (x ^ y ^ z) - - P( A, B, C, D, 5, 4, 0xFFFA3942 ); - P( D, A, B, C, 8, 11, 0x8771F681 ); - P( C, D, A, B, 11, 16, 0x6D9D6122 ); - P( B, C, D, A, 14, 23, 0xFDE5380C ); - P( A, B, C, D, 1, 4, 0xA4BEEA44 ); - P( D, A, B, C, 4, 11, 0x4BDECFA9 ); - P( C, D, A, B, 7, 16, 0xF6BB4B60 ); - P( B, C, D, A, 10, 23, 0xBEBFBC70 ); - P( A, B, C, D, 13, 4, 0x289B7EC6 ); - P( D, A, B, C, 0, 11, 0xEAA127FA ); - P( C, D, A, B, 3, 16, 0xD4EF3085 ); - P( B, C, D, A, 6, 23, 0x04881D05 ); - P( A, B, C, D, 9, 4, 0xD9D4D039 ); - P( D, A, B, C, 12, 11, 0xE6DB99E5 ); - P( C, D, A, B, 15, 16, 0x1FA27CF8 ); - P( B, C, D, A, 2, 23, 0xC4AC5665 ); - -#undef F - -#define F(x,y,z) (y ^ (x | ~z)) - - P( A, B, C, D, 0, 6, 0xF4292244 ); - P( D, A, B, C, 7, 10, 0x432AFF97 ); - P( C, D, A, B, 14, 15, 0xAB9423A7 ); - P( B, C, D, A, 5, 21, 0xFC93A039 ); - P( A, B, C, D, 12, 6, 0x655B59C3 ); - P( D, A, B, C, 3, 10, 0x8F0CCC92 ); - P( C, D, A, B, 10, 15, 0xFFEFF47D ); - P( B, C, D, A, 1, 21, 0x85845DD1 ); - P( A, B, C, D, 8, 6, 0x6FA87E4F ); - P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); - P( C, D, A, B, 6, 15, 0xA3014314 ); - P( B, C, D, A, 13, 21, 0x4E0811A1 ); - P( A, B, C, D, 4, 6, 0xF7537E82 ); - P( D, A, B, C, 11, 10, 0xBD3AF235 ); - P( C, D, A, B, 2, 15, 0x2AD7D2BB ); - P( B, C, D, A, 9, 21, 0xEB86D391 ); - -#undef F - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; -} - -/* - * MD5 process buffer - */ -void md5_update( md5_context *ctx, const unsigned char *input, int ilen ) -{ - int fill; - unsigned long left; - - if( ilen <= 0 ) - return; - - left = ctx->total[0] & 0x3F; - fill = 64 - left; - - ctx->total[0] += ilen; - ctx->total[0] &= 0xFFFFFFFF; - - if( ctx->total[0] < (unsigned long) ilen ) - ctx->total[1]++; - - if( left && ilen >= fill ) - { - MEMCPY( (void *) (ctx->buffer + left), - input, fill ); - md5_process( ctx, ctx->buffer ); - input += fill; - ilen -= fill; - left = 0; - } - - while( ilen >= 64 ) - { - md5_process( ctx, input ); - input += 64; - ilen -= 64; - } - - if( ilen > 0 ) - { - MEMCPY( (void *) (ctx->buffer + left), - input, ilen ); - } -} - -static const unsigned char md5_padding[64] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* - * MD5 final digest - */ -void md5_finish( md5_context *ctx, unsigned char output[16] ) -{ - unsigned long last, padn; - unsigned long high, low; - unsigned char msglen[8]; - - high = ( ctx->total[0] >> 29 ) - | ( ctx->total[1] << 3 ); - low = ( ctx->total[0] << 3 ); - - PUT_ULONG_LE( low, msglen, 0 ); - PUT_ULONG_LE( high, msglen, 4 ); - - last = ctx->total[0] & 0x3F; - padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); - - md5_update( ctx, md5_padding, padn ); - md5_update( ctx, msglen, 8 ); - - PUT_ULONG_LE( ctx->state[0], output, 0 ); - PUT_ULONG_LE( ctx->state[1], output, 4 ); - PUT_ULONG_LE( ctx->state[2], output, 8 ); - PUT_ULONG_LE( ctx->state[3], output, 12 ); -} - -/* - * output = MD5( input buffer ) - */ -void md5( unsigned char *input, int ilen, unsigned char output[16] ) -{ - md5_context ctx; - - md5_starts( &ctx ); - md5_update( &ctx, input, ilen ); - md5_finish( &ctx, output ); -} - -#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD5 */ diff --git a/ext/lwip/src/netif/ppp/polarssl/sha1.c b/ext/lwip/src/netif/ppp/polarssl/sha1.c deleted file mode 100644 index c2192ea..0000000 --- a/ext/lwip/src/netif/ppp/polarssl/sha1.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * FIPS-180-1 compliant SHA-1 implementation - * - * 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. - */ -/* - * The SHA-1 standard was published by NIST in 1993. - * - * http://www.itl.nist.gov/fipspubs/fip180-1.htm - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_SHA1 - -#include "netif/ppp/polarssl/sha1.h" - -#include - -/* - * 32-bit integer manipulation macros (big endian) - */ -#ifndef GET_ULONG_BE -#define GET_ULONG_BE(n,b,i) \ -{ \ - (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ - | ( (unsigned long) (b)[(i) + 1] << 16 ) \ - | ( (unsigned long) (b)[(i) + 2] << 8 ) \ - | ( (unsigned long) (b)[(i) + 3] ); \ -} -#endif - -#ifndef PUT_ULONG_BE -#define PUT_ULONG_BE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) ); \ -} -#endif - -/* - * SHA-1 context setup - */ -void sha1_starts( sha1_context *ctx ) -{ - ctx->total[0] = 0; - ctx->total[1] = 0; - - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xEFCDAB89; - ctx->state[2] = 0x98BADCFE; - ctx->state[3] = 0x10325476; - ctx->state[4] = 0xC3D2E1F0; -} - -static void sha1_process( sha1_context *ctx, const unsigned char data[64] ) -{ - unsigned long temp, W[16], A, B, C, D, E; - - GET_ULONG_BE( W[ 0], data, 0 ); - GET_ULONG_BE( W[ 1], data, 4 ); - GET_ULONG_BE( W[ 2], data, 8 ); - GET_ULONG_BE( W[ 3], data, 12 ); - GET_ULONG_BE( W[ 4], data, 16 ); - GET_ULONG_BE( W[ 5], data, 20 ); - GET_ULONG_BE( W[ 6], data, 24 ); - GET_ULONG_BE( W[ 7], data, 28 ); - GET_ULONG_BE( W[ 8], data, 32 ); - GET_ULONG_BE( W[ 9], data, 36 ); - GET_ULONG_BE( W[10], data, 40 ); - GET_ULONG_BE( W[11], data, 44 ); - GET_ULONG_BE( W[12], data, 48 ); - GET_ULONG_BE( W[13], data, 52 ); - GET_ULONG_BE( W[14], data, 56 ); - GET_ULONG_BE( W[15], data, 60 ); - -#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) - -#define R(t) \ -( \ - temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ - W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ - ( W[t & 0x0F] = S(temp,1) ) \ -) - -#define P(a,b,c,d,e,x) \ -{ \ - e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ -} - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - E = ctx->state[4]; - -#define F(x,y,z) (z ^ (x & (y ^ z))) -#define K 0x5A827999 - - P( A, B, C, D, E, W[0] ); - P( E, A, B, C, D, W[1] ); - P( D, E, A, B, C, W[2] ); - P( C, D, E, A, B, W[3] ); - P( B, C, D, E, A, W[4] ); - P( A, B, C, D, E, W[5] ); - P( E, A, B, C, D, W[6] ); - P( D, E, A, B, C, W[7] ); - P( C, D, E, A, B, W[8] ); - P( B, C, D, E, A, W[9] ); - P( A, B, C, D, E, W[10] ); - P( E, A, B, C, D, W[11] ); - P( D, E, A, B, C, W[12] ); - P( C, D, E, A, B, W[13] ); - P( B, C, D, E, A, W[14] ); - P( A, B, C, D, E, W[15] ); - P( E, A, B, C, D, R(16) ); - P( D, E, A, B, C, R(17) ); - P( C, D, E, A, B, R(18) ); - P( B, C, D, E, A, R(19) ); - -#undef K -#undef F - -#define F(x,y,z) (x ^ y ^ z) -#define K 0x6ED9EBA1 - - P( A, B, C, D, E, R(20) ); - P( E, A, B, C, D, R(21) ); - P( D, E, A, B, C, R(22) ); - P( C, D, E, A, B, R(23) ); - P( B, C, D, E, A, R(24) ); - P( A, B, C, D, E, R(25) ); - P( E, A, B, C, D, R(26) ); - P( D, E, A, B, C, R(27) ); - P( C, D, E, A, B, R(28) ); - P( B, C, D, E, A, R(29) ); - P( A, B, C, D, E, R(30) ); - P( E, A, B, C, D, R(31) ); - P( D, E, A, B, C, R(32) ); - P( C, D, E, A, B, R(33) ); - P( B, C, D, E, A, R(34) ); - P( A, B, C, D, E, R(35) ); - P( E, A, B, C, D, R(36) ); - P( D, E, A, B, C, R(37) ); - P( C, D, E, A, B, R(38) ); - P( B, C, D, E, A, R(39) ); - -#undef K -#undef F - -#define F(x,y,z) ((x & y) | (z & (x | y))) -#define K 0x8F1BBCDC - - P( A, B, C, D, E, R(40) ); - P( E, A, B, C, D, R(41) ); - P( D, E, A, B, C, R(42) ); - P( C, D, E, A, B, R(43) ); - P( B, C, D, E, A, R(44) ); - P( A, B, C, D, E, R(45) ); - P( E, A, B, C, D, R(46) ); - P( D, E, A, B, C, R(47) ); - P( C, D, E, A, B, R(48) ); - P( B, C, D, E, A, R(49) ); - P( A, B, C, D, E, R(50) ); - P( E, A, B, C, D, R(51) ); - P( D, E, A, B, C, R(52) ); - P( C, D, E, A, B, R(53) ); - P( B, C, D, E, A, R(54) ); - P( A, B, C, D, E, R(55) ); - P( E, A, B, C, D, R(56) ); - P( D, E, A, B, C, R(57) ); - P( C, D, E, A, B, R(58) ); - P( B, C, D, E, A, R(59) ); - -#undef K -#undef F - -#define F(x,y,z) (x ^ y ^ z) -#define K 0xCA62C1D6 - - P( A, B, C, D, E, R(60) ); - P( E, A, B, C, D, R(61) ); - P( D, E, A, B, C, R(62) ); - P( C, D, E, A, B, R(63) ); - P( B, C, D, E, A, R(64) ); - P( A, B, C, D, E, R(65) ); - P( E, A, B, C, D, R(66) ); - P( D, E, A, B, C, R(67) ); - P( C, D, E, A, B, R(68) ); - P( B, C, D, E, A, R(69) ); - P( A, B, C, D, E, R(70) ); - P( E, A, B, C, D, R(71) ); - P( D, E, A, B, C, R(72) ); - P( C, D, E, A, B, R(73) ); - P( B, C, D, E, A, R(74) ); - P( A, B, C, D, E, R(75) ); - P( E, A, B, C, D, R(76) ); - P( D, E, A, B, C, R(77) ); - P( C, D, E, A, B, R(78) ); - P( B, C, D, E, A, R(79) ); - -#undef K -#undef F - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; - ctx->state[4] += E; -} - -/* - * SHA-1 process buffer - */ -void sha1_update( sha1_context *ctx, const unsigned char *input, int ilen ) -{ - int fill; - unsigned long left; - - if( ilen <= 0 ) - return; - - left = ctx->total[0] & 0x3F; - fill = 64 - left; - - ctx->total[0] += ilen; - ctx->total[0] &= 0xFFFFFFFF; - - if( ctx->total[0] < (unsigned long) ilen ) - ctx->total[1]++; - - if( left && ilen >= fill ) - { - MEMCPY( (void *) (ctx->buffer + left), - input, fill ); - sha1_process( ctx, ctx->buffer ); - input += fill; - ilen -= fill; - left = 0; - } - - while( ilen >= 64 ) - { - sha1_process( ctx, input ); - input += 64; - ilen -= 64; - } - - if( ilen > 0 ) - { - MEMCPY( (void *) (ctx->buffer + left), - input, ilen ); - } -} - -static const unsigned char sha1_padding[64] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* - * SHA-1 final digest - */ -void sha1_finish( sha1_context *ctx, unsigned char output[20] ) -{ - unsigned long last, padn; - unsigned long high, low; - unsigned char msglen[8]; - - high = ( ctx->total[0] >> 29 ) - | ( ctx->total[1] << 3 ); - low = ( ctx->total[0] << 3 ); - - PUT_ULONG_BE( high, msglen, 0 ); - PUT_ULONG_BE( low, msglen, 4 ); - - last = ctx->total[0] & 0x3F; - padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); - - sha1_update( ctx, sha1_padding, padn ); - sha1_update( ctx, msglen, 8 ); - - PUT_ULONG_BE( ctx->state[0], output, 0 ); - PUT_ULONG_BE( ctx->state[1], output, 4 ); - PUT_ULONG_BE( ctx->state[2], output, 8 ); - PUT_ULONG_BE( ctx->state[3], output, 12 ); - PUT_ULONG_BE( ctx->state[4], output, 16 ); -} - -/* - * output = SHA-1( input buffer ) - */ -void sha1( unsigned char *input, int ilen, unsigned char output[20] ) -{ - sha1_context ctx; - - sha1_starts( &ctx ); - sha1_update( &ctx, input, ilen ); - sha1_finish( &ctx, output ); -} - -#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_SHA1 */ diff --git a/ext/lwip/src/netif/ppp/ppp.c b/ext/lwip/src/netif/ppp/ppp.c deleted file mode 100644 index d5e317c..0000000 --- a/ext/lwip/src/netif/ppp/ppp.c +++ /dev/null @@ -1,1640 +0,0 @@ -/***************************************************************************** -* ppp.c - Network Point to Point Protocol program file. -* -* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. -* portions Copyright (c) 1997 by 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. -*****************************************************************************/ - -/* - * ppp_defs.h - PPP definitions. - * - * if_pppvar.h - private structures and declarations for PPP. - * - * Copyright (c) 1994 The Australian National University. - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation is hereby granted, provided that the above copyright - * notice appears in all copies. This software is provided without any - * warranty, express or implied. The Australian National University - * makes no representations about the suitability of this software for - * any purpose. - * - * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, - * OR MODIFICATIONS. - */ - -/* - * if_ppp.h - Point-to-Point Protocol definitions. - * - * Copyright (c) 1989 Carnegie Mellon University. - * 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 Carnegie Mellon University. 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -/** - * @defgroup ppp PPP netif - * @ingroup addons - * @verbinclude "ppp.txt" - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/pbuf.h" -#include "lwip/stats.h" -#include "lwip/sys.h" -#include "lwip/tcpip.h" -#include "lwip/api.h" -#include "lwip/snmp.h" -#include "lwip/sys.h" -#include "lwip/ip4.h" /* for ip4_input() */ -#if PPP_IPV6_SUPPORT -#include "lwip/ip6.h" /* for ip6_input() */ -#endif /* PPP_IPV6_SUPPORT */ -#include "lwip/dns.h" - -#include "netif/ppp/ppp_impl.h" -#include "netif/ppp/pppos.h" - -#include "netif/ppp/fsm.h" -#include "netif/ppp/lcp.h" -#include "netif/ppp/magic.h" - -#if PAP_SUPPORT -#include "netif/ppp/upap.h" -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT -#include "netif/ppp/chap-new.h" -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT -#include "netif/ppp/eap.h" -#endif /* EAP_SUPPORT */ -#if CCP_SUPPORT -#include "netif/ppp/ccp.h" -#endif /* CCP_SUPPORT */ -#if MPPE_SUPPORT -#include "netif/ppp/mppe.h" -#endif /* MPPE_SUPPORT */ -#if ECP_SUPPORT -#include "netif/ppp/ecp.h" -#endif /* EAP_SUPPORT */ -#if VJ_SUPPORT -#include "netif/ppp/vj.h" -#endif /* VJ_SUPPORT */ -#if PPP_IPV4_SUPPORT -#include "netif/ppp/ipcp.h" -#endif /* PPP_IPV4_SUPPORT */ -#if PPP_IPV6_SUPPORT -#include "netif/ppp/ipv6cp.h" -#endif /* PPP_IPV6_SUPPORT */ - -/*************************/ -/*** LOCAL DEFINITIONS ***/ -/*************************/ - -/* Memory pools */ -#if PPPOS_SUPPORT -LWIP_MEMPOOL_PROTOTYPE(PPPOS_PCB); -#endif -#if PPPOE_SUPPORT -LWIP_MEMPOOL_PROTOTYPE(PPPOE_IF); -#endif -#if PPPOL2TP_SUPPORT -LWIP_MEMPOOL_PROTOTYPE(PPPOL2TP_PCB); -#endif -#if LWIP_PPP_API && LWIP_MPU_COMPATIBLE -LWIP_MEMPOOL_PROTOTYPE(PPPAPI_MSG); -#endif -LWIP_MEMPOOL_DECLARE(PPP_PCB, MEMP_NUM_PPP_PCB, sizeof(ppp_pcb), "PPP_PCB") - -/* FIXME: add stats per PPP session */ -#if PPP_STATS_SUPPORT -static struct timeval start_time; /* Time when link was started. */ -static struct pppd_stats old_link_stats; -struct pppd_stats link_stats; -unsigned link_connect_time; -int link_stats_valid; -#endif /* PPP_STATS_SUPPORT */ - -/* - * PPP Data Link Layer "protocol" table. - * One entry per supported protocol. - * The last entry must be NULL. - */ -const struct protent* const protocols[] = { - &lcp_protent, -#if PAP_SUPPORT - &pap_protent, -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - &chap_protent, -#endif /* CHAP_SUPPORT */ -#if CBCP_SUPPORT - &cbcp_protent, -#endif /* CBCP_SUPPORT */ -#if PPP_IPV4_SUPPORT - &ipcp_protent, -#endif /* PPP_IPV4_SUPPORT */ -#if PPP_IPV6_SUPPORT - &ipv6cp_protent, -#endif /* PPP_IPV6_SUPPORT */ -#if CCP_SUPPORT - &ccp_protent, -#endif /* CCP_SUPPORT */ -#if ECP_SUPPORT - &ecp_protent, -#endif /* ECP_SUPPORT */ -#ifdef AT_CHANGE - &atcp_protent, -#endif /* AT_CHANGE */ -#if EAP_SUPPORT - &eap_protent, -#endif /* EAP_SUPPORT */ - NULL -}; - -/* Prototypes for procedures local to this file. */ -static void ppp_do_connect(void *arg); -static err_t ppp_netif_init_cb(struct netif *netif); -#if LWIP_IPV4 -static err_t ppp_netif_output_ip4(struct netif *netif, struct pbuf *pb, const ip4_addr_t *ipaddr); -#endif /* LWIP_IPV4 */ -#if PPP_IPV6_SUPPORT -static err_t ppp_netif_output_ip6(struct netif *netif, struct pbuf *pb, const ip6_addr_t *ipaddr); -#endif /* PPP_IPV6_SUPPORT */ -static err_t ppp_netif_output(struct netif *netif, struct pbuf *pb, u16_t protocol); - -/***********************************/ -/*** PUBLIC FUNCTION DEFINITIONS ***/ -/***********************************/ -#if PPP_AUTH_SUPPORT -void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *passwd) { -#if PAP_SUPPORT - pcb->settings.refuse_pap = !(authtype & PPPAUTHTYPE_PAP); -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - pcb->settings.refuse_chap = !(authtype & PPPAUTHTYPE_CHAP); -#if MSCHAP_SUPPORT - pcb->settings.refuse_mschap = !(authtype & PPPAUTHTYPE_MSCHAP); - pcb->settings.refuse_mschap_v2 = !(authtype & PPPAUTHTYPE_MSCHAP_V2); -#endif /* MSCHAP_SUPPORT */ -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - pcb->settings.refuse_eap = !(authtype & PPPAUTHTYPE_EAP); -#endif /* EAP_SUPPORT */ - pcb->settings.user = user; - pcb->settings.passwd = passwd; -} -#endif /* PPP_AUTH_SUPPORT */ - -#if MPPE_SUPPORT -/* Set MPPE configuration */ -void ppp_set_mppe(ppp_pcb *pcb, u8_t flags) { - if (flags == PPP_MPPE_DISABLE) { - pcb->settings.require_mppe = 0; - return; - } - - pcb->settings.require_mppe = 1; - pcb->settings.refuse_mppe_stateful = !(flags & PPP_MPPE_ALLOW_STATEFUL); - pcb->settings.refuse_mppe_40 = !!(flags & PPP_MPPE_REFUSE_40); - pcb->settings.refuse_mppe_128 = !!(flags & PPP_MPPE_REFUSE_128); -} -#endif /* MPPE_SUPPORT */ - -#if PPP_NOTIFY_PHASE -void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb) { - pcb->notify_phase_cb = notify_phase_cb; - notify_phase_cb(pcb, pcb->phase, pcb->ctx_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 (pcb->phase != PPP_PHASE_DEAD) { - return ERR_ALREADY; - } - - PPPDEBUG(LOG_DEBUG, ("ppp_connect[%d]: holdoff=%d\n", pcb->netif->num, holdoff)); - - if (holdoff == 0) { - return pcb->link_cb->connect(pcb, pcb->link_ctx_cb); - } - - new_phase(pcb, PPP_PHASE_HOLDOFF); - sys_timeout((u32_t)(holdoff*1000), ppp_do_connect, pcb); - return ERR_OK; -} - -#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) { - if (pcb->phase != PPP_PHASE_DEAD) { - return ERR_ALREADY; - } - - PPPDEBUG(LOG_DEBUG, ("ppp_listen[%d]\n", pcb->netif->num)); - - if (pcb->link_cb->listen) { - return pcb->link_cb->listen(pcb, pcb->link_ctx_cb); - } - return ERR_IF; -} -#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) -{ - pcb->err_code = PPPERR_USER; - - /* holdoff phase, cancel the reconnection */ - if (pcb->phase == PPP_PHASE_HOLDOFF) { - sys_untimeout(ppp_do_connect, pcb); - new_phase(pcb, PPP_PHASE_DEAD); - } - - /* dead phase, nothing to do, call the status callback to be consistent */ - if (pcb->phase == PPP_PHASE_DEAD) { - pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); - return ERR_OK; - } - - /* - * Only accept carrier lost signal on the stable running phase in order - * to prevent changing the PPP phase FSM in transition phases. - * - * Always using nocarrier = 0 is still recommended, this is going to - * take a little longer time, but is a safer choice from FSM point of view. - */ - if (nocarrier && pcb->phase == PPP_PHASE_RUNNING) { - PPPDEBUG(LOG_DEBUG, ("ppp_close[%d]: carrier lost -> lcp_lowerdown\n", pcb->netif->num)); - lcp_lowerdown(pcb); - /* forced link termination, this will leave us at PPP_PHASE_DEAD. */ - link_terminated(pcb); - return ERR_OK; - } - - /* Disconnect */ - PPPDEBUG(LOG_DEBUG, ("ppp_close[%d]: kill_link -> lcp_close\n", pcb->netif->num)); - /* LCP close request, this will leave us at PPP_PHASE_DEAD. */ - lcp_close(pcb, "User request"); - return ERR_OK; -} - -/* - * 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) { - err_t err; - if (pcb->phase != PPP_PHASE_DEAD) { - return ERR_CONN; - } - - PPPDEBUG(LOG_DEBUG, ("ppp_free[%d]\n", pcb->netif->num)); - - netif_remove(pcb->netif); - - err = pcb->link_cb->free(pcb, pcb->link_ctx_cb); - - LWIP_MEMPOOL_FREE(PPP_PCB, pcb); - return err; -} - -/* 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) -{ - if (pcb == NULL) { - return ERR_VAL; - } - - switch(cmd) { - case PPPCTLG_UPSTATUS: /* Get the PPP up status. */ - if (!arg) { - goto fail; - } - *(int *)arg = (int)(0 -#if PPP_IPV4_SUPPORT - || pcb->if4_up -#endif /* PPP_IPV4_SUPPORT */ -#if PPP_IPV6_SUPPORT - || pcb->if6_up -#endif /* PPP_IPV6_SUPPORT */ - ); - return ERR_OK; - - case PPPCTLG_ERRCODE: /* Get the PPP error code. */ - if (!arg) { - goto fail; - } - *(int *)arg = (int)(pcb->err_code); - return ERR_OK; - - default: - goto fail; - } - -fail: - return ERR_VAL; -} - - -/**********************************/ -/*** LOCAL FUNCTION DEFINITIONS ***/ -/**********************************/ - -static void ppp_do_connect(void *arg) { - ppp_pcb *pcb = (ppp_pcb*)arg; - - LWIP_ASSERT("pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF", pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF); - - pcb->link_cb->connect(pcb, pcb->link_ctx_cb); -} - -/* - * ppp_netif_init_cb - netif init callback - */ -static err_t ppp_netif_init_cb(struct netif *netif) { - netif->name[0] = 'p'; - netif->name[1] = 'p'; -#if LWIP_IPV4 - /* FIXME: change that when netif_null_output_ip4() will materialize */ - netif->output = ppp_netif_output_ip4; -#endif /* LWIP_IPV4 */ -#if PPP_IPV6_SUPPORT - netif->output_ip6 = ppp_netif_output_ip6; -#endif /* PPP_IPV6_SUPPORT */ - netif->flags = NETIF_FLAG_UP; -#if LWIP_NETIF_HOSTNAME - /* @todo: Initialize interface hostname */ - /* netif_set_hostname(netif, "lwip"); */ -#endif /* LWIP_NETIF_HOSTNAME */ - return ERR_OK; -} - -#if LWIP_IPV4 -/* - * Send an IPv4 packet on the given connection. - */ -static err_t ppp_netif_output_ip4(struct netif *netif, struct pbuf *pb, const ip4_addr_t *ipaddr) { - LWIP_UNUSED_ARG(ipaddr); -#if PPP_IPV4_SUPPORT - return ppp_netif_output(netif, pb, PPP_IP); -#else /* PPP_IPV4_SUPPORT */ - LWIP_UNUSED_ARG(netif); - LWIP_UNUSED_ARG(pb); - return ERR_IF; -#endif /* PPP_IPV4_SUPPORT */ -} -#endif /* LWIP_IPV4 */ - -#if PPP_IPV6_SUPPORT -/* - * Send an IPv6 packet on the given connection. - */ -static err_t ppp_netif_output_ip6(struct netif *netif, struct pbuf *pb, const ip6_addr_t *ipaddr) { - LWIP_UNUSED_ARG(ipaddr); - return ppp_netif_output(netif, pb, PPP_IPV6); -} -#endif /* PPP_IPV6_SUPPORT */ - -static err_t ppp_netif_output(struct netif *netif, struct pbuf *pb, u16_t protocol) { - ppp_pcb *pcb = (ppp_pcb*)netif->state; - err_t err; - struct pbuf *fpb = NULL; - - /* Check that the link is up. */ - if (0 -#if PPP_IPV4_SUPPORT - || (protocol == PPP_IP && !pcb->if4_up) -#endif /* PPP_IPV4_SUPPORT */ -#if PPP_IPV6_SUPPORT - || (protocol == PPP_IPV6 && !pcb->if6_up) -#endif /* PPP_IPV6_SUPPORT */ - ) { - PPPDEBUG(LOG_ERR, ("ppp_netif_output[%d]: link not up\n", pcb->netif->num)); - goto err_rte_drop; - } - -#if MPPE_SUPPORT - /* If MPPE is required, refuse any IP packet until we are able to crypt them. */ - if (pcb->settings.require_mppe && pcb->ccp_transmit_method != CI_MPPE) { - PPPDEBUG(LOG_ERR, ("ppp_netif_output[%d]: MPPE required, not up\n", pcb->netif->num)); - goto err_rte_drop; - } -#endif /* MPPE_SUPPORT */ - -#if VJ_SUPPORT && LWIP_TCP - /* - * Attempt Van Jacobson header compression if VJ is configured and - * this is an IP packet. - */ - if (protocol == PPP_IP && pcb->vj_enabled) { - switch (vj_compress_tcp(&pcb->vj_comp, &pb)) { - case TYPE_IP: - /* No change... - protocol = PPP_IP; */ - break; - case TYPE_COMPRESSED_TCP: - /* vj_compress_tcp() returns a new allocated pbuf, indicate we should free - * our duplicated pbuf later */ - fpb = pb; - protocol = PPP_VJC_COMP; - break; - case TYPE_UNCOMPRESSED_TCP: - /* vj_compress_tcp() returns a new allocated pbuf, indicate we should free - * our duplicated pbuf later */ - fpb = pb; - protocol = PPP_VJC_UNCOMP; - break; - default: - PPPDEBUG(LOG_WARNING, ("ppp_netif_output[%d]: bad IP packet\n", pcb->netif->num)); - LINK_STATS_INC(link.proterr); - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(pcb->netif, ifoutdiscards); - return ERR_VAL; - } - } -#endif /* VJ_SUPPORT && LWIP_TCP */ - -#if CCP_SUPPORT - switch (pcb->ccp_transmit_method) { - case 0: - break; /* Don't compress */ -#if MPPE_SUPPORT - case CI_MPPE: - if ((err = mppe_compress(pcb, &pcb->mppe_comp, &pb, protocol)) != ERR_OK) { - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(netif, ifoutdiscards); - goto err; - } - /* if VJ compressor returned a new allocated pbuf, free it */ - if (fpb) { - pbuf_free(fpb); - } - /* mppe_compress() returns a new allocated pbuf, indicate we should free - * our duplicated pbuf later */ - fpb = pb; - protocol = PPP_COMP; - break; -#endif /* MPPE_SUPPORT */ - default: - PPPDEBUG(LOG_ERR, ("ppp_netif_output[%d]: bad CCP transmit method\n", pcb->netif->num)); - goto err_rte_drop; /* Cannot really happen, we only negotiate what we are able to do */ - } -#endif /* CCP_SUPPORT */ - - err = pcb->link_cb->netif_output(pcb, pcb->link_ctx_cb, pb, protocol); - goto err; - -err_rte_drop: - err = ERR_RTE; - LINK_STATS_INC(link.rterr); - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(netif, ifoutdiscards); -err: - if (fpb) { - pbuf_free(fpb); - } - return err; -} - -/************************************/ -/*** PRIVATE FUNCTION DEFINITIONS ***/ -/************************************/ - -/* Initialize the PPP subsystem. */ -int ppp_init(void) -{ -#if PPPOS_SUPPORT - LWIP_MEMPOOL_INIT(PPPOS_PCB); -#endif -#if PPPOE_SUPPORT - LWIP_MEMPOOL_INIT(PPPOE_IF); -#endif -#if PPPOL2TP_SUPPORT - LWIP_MEMPOOL_INIT(PPPOL2TP_PCB); -#endif -#if LWIP_PPP_API && LWIP_MPU_COMPATIBLE - LWIP_MEMPOOL_INIT(PPPAPI_MSG); -#endif - - LWIP_MEMPOOL_INIT(PPP_PCB); - - /* - * Initialize magic number generator now so that protocols may - * use magic numbers in initialization. - */ - magic_init(); - - return 0; -} - -/* - * Create a new PPP control block. - * - * This initializes the PPP control block but does not - * attempt to negotiate the LCP session. - * - * Return a new PPP connection control block pointer - * on success or a null pointer on failure. - */ -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) { - ppp_pcb *pcb; - const struct protent *protp; - int i; - - /* PPP is single-threaded: without a callback, - * there is no way to know when the link is up. */ - if (link_status_cb == NULL) { - return NULL; - } - - pcb = (ppp_pcb*)LWIP_MEMPOOL_ALLOC(PPP_PCB); - if (pcb == NULL) { - return NULL; - } - - memset(pcb, 0, sizeof(ppp_pcb)); - - /* default configuration */ -#if PAP_SUPPORT - pcb->settings.pap_timeout_time = UPAP_DEFTIMEOUT; - pcb->settings.pap_max_transmits = UPAP_DEFTRANSMITS; -#if PPP_SERVER - pcb->settings.pap_req_timeout = UPAP_DEFREQTIME; -#endif /* PPP_SERVER */ -#endif /* PAP_SUPPORT */ - -#if CHAP_SUPPORT - pcb->settings.chap_timeout_time = CHAP_DEFTIMEOUT; - pcb->settings.chap_max_transmits = CHAP_DEFTRANSMITS; -#if PPP_SERVER - pcb->settings.chap_rechallenge_time = CHAP_DEFRECHALLENGETIME; -#endif /* PPP_SERVER */ -#endif /* CHAP_SUPPPORT */ - -#if EAP_SUPPORT - pcb->settings.eap_req_time = EAP_DEFREQTIME; - pcb->settings.eap_allow_req = EAP_DEFALLOWREQ; -#if PPP_SERVER - pcb->settings.eap_timeout_time = EAP_DEFTIMEOUT; - pcb->settings.eap_max_transmits = EAP_DEFTRANSMITS; -#endif /* PPP_SERVER */ -#endif /* EAP_SUPPORT */ - - pcb->settings.lcp_loopbackfail = LCP_DEFLOOPBACKFAIL; - pcb->settings.lcp_echo_interval = LCP_ECHOINTERVAL; - pcb->settings.lcp_echo_fails = LCP_MAXECHOFAILS; - - pcb->settings.fsm_timeout_time = FSM_DEFTIMEOUT; - pcb->settings.fsm_max_conf_req_transmits = FSM_DEFMAXCONFREQS; - pcb->settings.fsm_max_term_transmits = FSM_DEFMAXTERMREQS; - pcb->settings.fsm_max_nak_loops = FSM_DEFMAXNAKLOOPS; - - pcb->netif = pppif; - MIB2_INIT_NETIF(pppif, snmp_ifType_ppp, 0); - if (!netif_add(pcb->netif, -#if LWIP_IPV4 - IP4_ADDR_ANY, IP4_ADDR_BROADCAST, IP4_ADDR_ANY, -#endif /* LWIP_IPV4 */ - (void *)pcb, ppp_netif_init_cb, NULL)) { - LWIP_MEMPOOL_FREE(PPP_PCB, pcb); - PPPDEBUG(LOG_ERR, ("ppp_new: netif_add failed\n")); - return NULL; - } - - pcb->link_cb = callbacks; - pcb->link_ctx_cb = link_ctx_cb; - pcb->link_status_cb = link_status_cb; - pcb->ctx_cb = ctx_cb; - - /* - * Initialize each protocol. - */ - for (i = 0; (protp = protocols[i]) != NULL; ++i) { - (*protp->init)(pcb); - } - - new_phase(pcb, PPP_PHASE_DEAD); - return pcb; -} - -/** Called when link is starting */ -void ppp_link_start(ppp_pcb *pcb) { - LWIP_ASSERT("pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF", pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF); - PPPDEBUG(LOG_DEBUG, ("ppp_link_start[%d]\n", pcb->netif->num)); - new_phase(pcb, PPP_PHASE_INITIALIZE); -} - -/** Initiate LCP open request */ -void ppp_start(ppp_pcb *pcb) { - PPPDEBUG(LOG_DEBUG, ("ppp_start[%d]\n", pcb->netif->num)); - - /* Clean data not taken care by anything else, mostly shared data. */ -#if PPP_STATS_SUPPORT - link_stats_valid = 0; -#endif /* PPP_STATS_SUPPORT */ -#if MPPE_SUPPORT - pcb->mppe_keys_set = 0; - memset(&pcb->mppe_comp, 0, sizeof(pcb->mppe_comp)); - memset(&pcb->mppe_decomp, 0, sizeof(pcb->mppe_decomp)); -#endif /* MPPE_SUPPORT */ -#if VJ_SUPPORT && LWIP_TCP - vj_compress_init(&pcb->vj_comp); -#endif /* VJ_SUPPORT && LWIP_TCP */ - - /* Start protocol */ - lcp_open(pcb); - lcp_lowerup(pcb); - PPPDEBUG(LOG_DEBUG, ("ppp_start[%d]: finished\n", pcb->netif->num)); -} - -/** Called when link failed to setup */ -void ppp_link_failed(ppp_pcb *pcb) { - PPPDEBUG(LOG_DEBUG, ("ppp_link_failed[%d]\n", pcb->netif->num)); - new_phase(pcb, PPP_PHASE_DEAD); - pcb->err_code = PPPERR_OPEN; - pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); -} - -/** Called when link is normally down (i.e. it was asked to end) */ -void ppp_link_end(ppp_pcb *pcb) { - PPPDEBUG(LOG_DEBUG, ("ppp_link_end[%d]\n", pcb->netif->num)); - if (pcb->err_code == PPPERR_NONE) { - pcb->err_code = PPPERR_CONNECT; - } - pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); -} - -/* - * Pass the processed input packet to the appropriate handler. - * This function and all handlers run in the context of the tcpip_thread - */ -void ppp_input(ppp_pcb *pcb, struct pbuf *pb) { - u16_t protocol; -#if PPP_DEBUG && PPP_PROTOCOLNAME - const char *pname; -#endif /* PPP_DEBUG && PPP_PROTOCOLNAME */ - - magic_randomize(); - - if (pb->len < 2) { - PPPDEBUG(LOG_ERR, ("ppp_input[%d]: packet too short\n", pcb->netif->num)); - goto drop; - } - protocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1]; - -#if PRINTPKT_SUPPORT - ppp_dump_packet("rcvd", (unsigned char *)pb->payload, pb->len); -#endif /* PRINTPKT_SUPPORT */ - - pbuf_header(pb, -(s16_t)sizeof(protocol)); - - LINK_STATS_INC(link.recv); - MIB2_STATS_NETIF_INC(pcb->netif, ifinucastpkts); - MIB2_STATS_NETIF_ADD(pcb->netif, ifinoctets, pb->tot_len); - - /* - * Toss all non-LCP packets unless LCP is OPEN. - */ - if (protocol != PPP_LCP && pcb->lcp_fsm.state != PPP_FSM_OPENED) { - ppp_dbglog("Discarded non-LCP packet when LCP not open"); - goto drop; - } - - /* - * Until we get past the authentication phase, toss all packets - * except LCP, LQR and authentication packets. - */ - if (pcb->phase <= PPP_PHASE_AUTHENTICATE - && !(protocol == PPP_LCP -#if LQR_SUPPORT - || protocol == PPP_LQR -#endif /* LQR_SUPPORT */ -#if PAP_SUPPORT - || protocol == PPP_PAP -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - || protocol == PPP_CHAP -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - || protocol == PPP_EAP -#endif /* EAP_SUPPORT */ - )) { - ppp_dbglog("discarding proto 0x%x in phase %d", protocol, pcb->phase); - goto drop; - } - -#if CCP_SUPPORT -#if MPPE_SUPPORT - /* - * MPPE is required and unencrypted data has arrived (this - * should never happen!). We should probably drop the link if - * the protocol is in the range of what should be encrypted. - * At the least, we drop this packet. - */ - if (pcb->settings.require_mppe && protocol != PPP_COMP && protocol < 0x8000) { - PPPDEBUG(LOG_ERR, ("ppp_input[%d]: MPPE required, received unencrypted data!\n", pcb->netif->num)); - goto drop; - } -#endif /* MPPE_SUPPORT */ - - if (protocol == PPP_COMP) { - u8_t *pl; - - switch (pcb->ccp_receive_method) { -#if MPPE_SUPPORT - case CI_MPPE: - if (mppe_decompress(pcb, &pcb->mppe_decomp, &pb) != ERR_OK) { - goto drop; - } - break; -#endif /* MPPE_SUPPORT */ - default: - PPPDEBUG(LOG_ERR, ("ppp_input[%d]: bad CCP receive method\n", pcb->netif->num)); - goto drop; /* Cannot really happen, we only negotiate what we are able to do */ - } - - /* Assume no PFC */ - if (pb->len < 2) { - goto drop; - } - - /* Extract and hide protocol (do PFC decompression if necessary) */ - pl = (u8_t*)pb->payload; - if (pl[0] & 0x01) { - protocol = pl[0]; - pbuf_header(pb, -(s16_t)1); - } else { - protocol = (pl[0] << 8) | pl[1]; - pbuf_header(pb, -(s16_t)2); - } - } -#endif /* CCP_SUPPORT */ - - switch(protocol) { - -#if PPP_IPV4_SUPPORT - case PPP_IP: /* Internet Protocol */ - PPPDEBUG(LOG_INFO, ("ppp_input[%d]: ip in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); - ip4_input(pb, pcb->netif); - return; -#endif /* PPP_IPV4_SUPPORT */ - -#if PPP_IPV6_SUPPORT - case PPP_IPV6: /* Internet Protocol Version 6 */ - PPPDEBUG(LOG_INFO, ("ppp_input[%d]: ip6 in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); - ip6_input(pb, pcb->netif); - return; -#endif /* PPP_IPV6_SUPPORT */ - -#if VJ_SUPPORT && LWIP_TCP - case PPP_VJC_COMP: /* VJ compressed TCP */ - /* - * Clip off the VJ header and prepend the rebuilt TCP/IP header and - * pass the result to IP. - */ - PPPDEBUG(LOG_INFO, ("ppp_input[%d]: vj_comp in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); - if (pcb->vj_enabled && vj_uncompress_tcp(&pb, &pcb->vj_comp) >= 0) { - ip4_input(pb, pcb->netif); - return; - } - /* Something's wrong so drop it. */ - PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping VJ compressed\n", pcb->netif->num)); - break; - - case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */ - /* - * Process the TCP/IP header for VJ header compression and then pass - * the packet to IP. - */ - PPPDEBUG(LOG_INFO, ("ppp_input[%d]: vj_un in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); - if (pcb->vj_enabled && vj_uncompress_uncomp(pb, &pcb->vj_comp) >= 0) { - ip4_input(pb, pcb->netif); - return; - } - /* Something's wrong so drop it. */ - PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping VJ uncompressed\n", pcb->netif->num)); - break; -#endif /* VJ_SUPPORT && LWIP_TCP */ - - default: { - int i; - const struct protent *protp; - - /* - * Upcall the proper protocol input routine. - */ - for (i = 0; (protp = protocols[i]) != NULL; ++i) { - if (protp->protocol == protocol) { - pb = ppp_singlebuf(pb); - (*protp->input)(pcb, (u8_t*)pb->payload, pb->len); - goto out; - } -#if 0 /* UNUSED - * - * This is actually a (hacked?) way for the Linux kernel to pass a data - * packet to pppd. pppd in normal condition only do signaling - * (LCP, PAP, CHAP, IPCP, ...) and does not handle any data packet at all. - * - * We don't even need this interface, which is only there because of PPP - * interface limitation between Linux kernel and pppd. For MPPE, which uses - * CCP to negotiate although it is not really a (de)compressor, we added - * ccp_resetrequest() in CCP and MPPE input data flow is calling either - * ccp_resetrequest() or lcp_close() if the issue is, respectively, non-fatal - * or fatal, this is what ccp_datainput() really do. - */ - if (protocol == (protp->protocol & ~0x8000) - && protp->datainput != NULL) { - (*protp->datainput)(pcb, pb->payload, pb->len); - goto out; - } -#endif /* UNUSED */ - } - -#if PPP_DEBUG -#if PPP_PROTOCOLNAME - pname = protocol_name(protocol); - if (pname != NULL) { - ppp_warn("Unsupported protocol '%s' (0x%x) received", pname, protocol); - } else -#endif /* PPP_PROTOCOLNAME */ - ppp_warn("Unsupported protocol 0x%x received", protocol); -#endif /* PPP_DEBUG */ - pbuf_header(pb, (s16_t)sizeof(protocol)); - lcp_sprotrej(pcb, (u8_t*)pb->payload, pb->len); - } - break; - } - -drop: - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(pcb->netif, ifindiscards); - -out: - pbuf_free(pb); -} - -/* merge a pbuf chain into one pbuf */ -struct pbuf *ppp_singlebuf(struct pbuf *p) { - struct pbuf *q, *b; - u8_t *pl; - - if(p->tot_len == p->len) { - return p; - } - - q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if(!q) { - PPPDEBUG(LOG_ERR, - ("ppp_singlebuf: unable to alloc new buf (%d)\n", p->tot_len)); - return p; /* live dangerously */ - } - - for(b = p, pl = (u8_t*)q->payload; b != NULL; b = b->next) { - MEMCPY(pl, b->payload, b->len); - pl += b->len; - } - - pbuf_free(p); - - return q; -} - -/* - * Write a pbuf to a ppp link, only used from PPP functions - * to send PPP packets. - * - * IPv4 and IPv6 packets from lwIP are sent, respectively, - * with ppp_netif_output_ip4() and ppp_netif_output_ip6() - * functions (which are callbacks of the netif PPP interface). - * - * RETURN: >= 0 Number of characters written - * -1 Failed to write to device - */ -err_t ppp_write(ppp_pcb *pcb, struct pbuf *p) { -#if PRINTPKT_SUPPORT - ppp_dump_packet("sent", (unsigned char *)p->payload+2, p->len-2); -#endif /* PRINTPKT_SUPPORT */ - return pcb->link_cb->write(pcb, pcb->link_ctx_cb, p); -} - -void ppp_link_terminated(ppp_pcb *pcb) { - PPPDEBUG(LOG_DEBUG, ("ppp_link_terminated[%d]\n", pcb->netif->num)); - pcb->link_cb->disconnect(pcb, pcb->link_ctx_cb); - PPPDEBUG(LOG_DEBUG, ("ppp_link_terminated[%d]: finished.\n", pcb->netif->num)); -} - - -/************************************************************************ - * Functions called by various PPP subsystems to configure - * the PPP interface or change the PPP phase. - */ - -/* - * new_phase - signal the start of a new phase of pppd's operation. - */ -void new_phase(ppp_pcb *pcb, int p) { - pcb->phase = p; - PPPDEBUG(LOG_DEBUG, ("ppp phase changed[%d]: phase=%d\n", pcb->netif->num, pcb->phase)); -#if PPP_NOTIFY_PHASE - if (pcb->notify_phase_cb != NULL) { - pcb->notify_phase_cb(pcb, p, pcb->ctx_cb); - } -#endif /* PPP_NOTIFY_PHASE */ -} - -/* - * ppp_send_config - configure the transmit-side characteristics of - * the ppp interface. - */ -int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp) { - LWIP_UNUSED_ARG(mtu); - /* pcb->mtu = mtu; -- set correctly with netif_set_mtu */ - - if (pcb->link_cb->send_config) { - pcb->link_cb->send_config(pcb, pcb->link_ctx_cb, accm, pcomp, accomp); - } - - PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]\n", pcb->netif->num) ); - return 0; -} - -/* - * ppp_recv_config - configure the receive-side characteristics of - * the ppp interface. - */ -int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp) { - LWIP_UNUSED_ARG(mru); - - if (pcb->link_cb->recv_config) { - pcb->link_cb->recv_config(pcb, pcb->link_ctx_cb, accm, pcomp, accomp); - } - - PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]\n", pcb->netif->num)); - return 0; -} - -#if PPP_IPV4_SUPPORT -/* - * sifaddr - Config the interface IP addresses and netmask. - */ -int sifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr, u32_t netmask) { - ip4_addr_t ip, nm, gw; - - ip4_addr_set_u32(&ip, our_adr); - ip4_addr_set_u32(&nm, netmask); - ip4_addr_set_u32(&gw, his_adr); - netif_set_addr(pcb->netif, &ip, &nm, &gw); - return 1; -} - -/******************************************************************** - * - * cifaddr - Clear the interface IP addresses, and delete routes - * through the interface if possible. - */ -int cifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr) { - LWIP_UNUSED_ARG(our_adr); - LWIP_UNUSED_ARG(his_adr); - - netif_set_addr(pcb->netif, IP4_ADDR_ANY, IP4_ADDR_BROADCAST, IP4_ADDR_ANY); - return 1; -} - -#if 0 /* UNUSED - PROXY ARP */ -/******************************************************************** - * - * sifproxyarp - Make a proxy ARP entry for the peer. - */ - -int sifproxyarp(ppp_pcb *pcb, u32_t his_adr) { - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(his_adr); - return 0; -} - -/******************************************************************** - * - * cifproxyarp - Delete the proxy ARP entry for the peer. - */ - -int cifproxyarp(ppp_pcb *pcb, u32_t his_adr) { - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(his_adr); - return 0; -} -#endif /* UNUSED - PROXY ARP */ - -#if LWIP_DNS -/* - * sdns - Config the DNS servers - */ -int sdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) { - ip_addr_t ns; - LWIP_UNUSED_ARG(pcb); - - ip_addr_set_ip4_u32(&ns, ns1); - dns_setserver(0, &ns); - ip_addr_set_ip4_u32(&ns, ns2); - dns_setserver(1, &ns); - return 1; -} - -/******************************************************************** - * - * cdns - Clear the DNS servers - */ -int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) { - const ip_addr_t *nsa; - ip_addr_t nsb; - LWIP_UNUSED_ARG(pcb); - - nsa = dns_getserver(0); - ip_addr_set_ip4_u32(&nsb, ns1); - if (ip_addr_cmp(nsa, &nsb)) { - dns_setserver(0, IP_ADDR_ANY); - } - nsa = dns_getserver(1); - ip_addr_set_ip4_u32(&nsb, ns2); - if (ip_addr_cmp(nsa, &nsb)) { - dns_setserver(1, IP_ADDR_ANY); - } - return 1; -} -#endif /* LWIP_DNS */ - -#if VJ_SUPPORT -/******************************************************************** - * - * sifvjcomp - config tcp header compression - */ -int sifvjcomp(ppp_pcb *pcb, int vjcomp, int cidcomp, int maxcid) { - pcb->vj_enabled = vjcomp; - pcb->vj_comp.compressSlot = cidcomp; - pcb->vj_comp.maxSlotIndex = maxcid; - PPPDEBUG(LOG_INFO, ("sifvjcomp[%d]: VJ compress enable=%d slot=%d max slot=%d\n", - pcb->netif->num, vjcomp, cidcomp, maxcid)); - return 0; -} -#endif /* VJ_SUPPORT */ - -/* - * sifup - Config the interface up and enable IP packets to pass. - */ -int sifup(ppp_pcb *pcb) { - pcb->if4_up = 1; - pcb->err_code = PPPERR_NONE; - netif_set_link_up(pcb->netif); - - PPPDEBUG(LOG_DEBUG, ("sifup[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); - pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); - return 1; -} - -/******************************************************************** - * - * sifdown - Disable the indicated protocol and config the interface - * down if there are no remaining protocols. - */ -int sifdown(ppp_pcb *pcb) { - - pcb->if4_up = 0; - - if (1 -#if PPP_IPV6_SUPPORT - /* set the interface down if IPv6 is down as well */ - && !pcb->if6_up -#endif /* PPP_IPV6_SUPPORT */ - ) { - /* make sure the netif link callback is called */ - netif_set_link_down(pcb->netif); - } - PPPDEBUG(LOG_DEBUG, ("sifdown[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); - return 1; -} - -/******************************************************************** - * - * Return user specified netmask, modified by any mask we might determine - * for address `addr' (in network byte order). - * Here we scan through the system's list of interfaces, looking for - * any non-point-to-point interfaces which might appear to be on the same - * network as `addr'. If we find any, we OR in their netmask to the - * user-specified netmask. - */ -u32_t get_mask(u32_t addr) { -#if 0 - u32_t mask, nmask; - - addr = htonl(addr); - if (IP_CLASSA(addr)) { /* determine network mask for address class */ - nmask = IP_CLASSA_NET; - } else if (IP_CLASSB(addr)) { - nmask = IP_CLASSB_NET; - } else { - nmask = IP_CLASSC_NET; - } - - /* class D nets are disallowed by bad_ip_adrs */ - mask = PP_HTONL(0xffffff00UL) | htonl(nmask); - - /* XXX - * Scan through the system's network interfaces. - * Get each netmask and OR them into our mask. - */ - /* return mask; */ - return mask; -#endif /* 0 */ - LWIP_UNUSED_ARG(addr); - return IPADDR_BROADCAST; -} -#endif /* PPP_IPV4_SUPPORT */ - -#if PPP_IPV6_SUPPORT -#define IN6_LLADDR_FROM_EUI64(ip6, eui64) do { \ - ip6.addr[0] = PP_HTONL(0xfe800000); \ - ip6.addr[1] = 0; \ - eui64_copy(eui64, ip6.addr[2]); \ - } while (0) - -/******************************************************************** - * - * sif6addr - Config the interface with an IPv6 link-local address - */ -int sif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64) { - ip6_addr_t ip6; - LWIP_UNUSED_ARG(his_eui64); - - IN6_LLADDR_FROM_EUI64(ip6, our_eui64); - netif_ip6_addr_set(pcb->netif, 0, &ip6); - netif_ip6_addr_set_state(pcb->netif, 0, IP6_ADDR_PREFERRED); - /* FIXME: should we add an IPv6 static neighbor using his_eui64 ? */ - return 1; -} - -/******************************************************************** - * - * cif6addr - Remove IPv6 address from interface - */ -int cif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64) { - LWIP_UNUSED_ARG(our_eui64); - LWIP_UNUSED_ARG(his_eui64); - - netif_ip6_addr_set(pcb->netif, 0, IP6_ADDR_ANY6); - netif_ip6_addr_set_state(pcb->netif, 0, IP6_ADDR_INVALID); - return 1; -} - -/* - * sif6up - Config the interface up and enable IPv6 packets to pass. - */ -int sif6up(ppp_pcb *pcb) { - - pcb->if6_up = 1; - pcb->err_code = PPPERR_NONE; - netif_set_link_up(pcb->netif); - - PPPDEBUG(LOG_DEBUG, ("sif6up[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); - pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); - return 1; -} - -/******************************************************************** - * - * sif6down - Disable the indicated protocol and config the interface - * down if there are no remaining protocols. - */ -int sif6down(ppp_pcb *pcb) { - - pcb->if6_up = 0; - - if (1 -#if PPP_IPV4_SUPPORT - /* set the interface down if IPv4 is down as well */ - && !pcb->if4_up -#endif /* PPP_IPV4_SUPPORT */ - ) { - /* make sure the netif link callback is called */ - netif_set_link_down(pcb->netif); - } - PPPDEBUG(LOG_DEBUG, ("sif6down[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); - return 1; -} -#endif /* PPP_IPV6_SUPPORT */ - -#if DEMAND_SUPPORT -/* - * sifnpmode - Set the mode for handling packets for a given NP. - */ -int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode) { - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(proto); - LWIP_UNUSED_ARG(mode); - return 0; -} -#endif /* DEMAND_SUPPORT */ - -/* - * netif_set_mtu - set the MTU on the PPP network interface. - */ -void netif_set_mtu(ppp_pcb *pcb, int mtu) { - - pcb->netif->mtu = mtu; - PPPDEBUG(LOG_INFO, ("netif_set_mtu[%d]: mtu=%d\n", pcb->netif->num, mtu)); -} - -/* - * netif_get_mtu - get PPP interface MTU - */ -int netif_get_mtu(ppp_pcb *pcb) { - - return pcb->netif->mtu; -} - -#if CCP_SUPPORT -#if 0 /* unused */ -/* - * ccp_test - whether a given compression method is acceptable for use. - */ -int -ccp_test(ppp_pcb *pcb, u_char *opt_ptr, int opt_len, int for_transmit) -{ - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(opt_ptr); - LWIP_UNUSED_ARG(opt_len); - LWIP_UNUSED_ARG(for_transmit); - return -1; -} -#endif /* unused */ - -/* - * ccp_set - inform about the current state of CCP. - */ -void -ccp_set(ppp_pcb *pcb, u8_t isopen, u8_t isup, u8_t receive_method, u8_t transmit_method) -{ - LWIP_UNUSED_ARG(isopen); - LWIP_UNUSED_ARG(isup); - pcb->ccp_receive_method = receive_method; - pcb->ccp_transmit_method = transmit_method; - PPPDEBUG(LOG_DEBUG, ("ccp_set[%d]: is_open=%d, is_up=%d, receive_method=%u, transmit_method=%u\n", - pcb->netif->num, isopen, isup, receive_method, transmit_method)); -} - -void -ccp_reset_comp(ppp_pcb *pcb) -{ - switch (pcb->ccp_transmit_method) { -#if MPPE_SUPPORT - case CI_MPPE: - mppe_comp_reset(pcb, &pcb->mppe_comp); - break; -#endif /* MPPE_SUPPORT */ - default: - break; - } -} - -void -ccp_reset_decomp(ppp_pcb *pcb) -{ - switch (pcb->ccp_receive_method) { -#if MPPE_SUPPORT - case CI_MPPE: - mppe_decomp_reset(pcb, &pcb->mppe_decomp); - break; -#endif /* MPPE_SUPPORT */ - default: - break; - } -} - -#if 0 /* unused */ -/* - * ccp_fatal_error - returns 1 if decompression was disabled as a - * result of an error detected after decompression of a packet, - * 0 otherwise. This is necessary because of patent nonsense. - */ -int -ccp_fatal_error(ppp_pcb *pcb) -{ - LWIP_UNUSED_ARG(pcb); - return 1; -} -#endif /* unused */ -#endif /* CCP_SUPPORT */ - -#if PPP_IDLETIMELIMIT -/******************************************************************** - * - * get_idle_time - return how long the link has been idle. - */ -int get_idle_time(ppp_pcb *pcb, struct ppp_idle *ip) { - /* FIXME: add idle time support and make it optional */ - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(ip); - return 1; -} -#endif /* PPP_IDLETIMELIMIT */ - -#if DEMAND_SUPPORT -/******************************************************************** - * - * get_loop_output - get outgoing packets from the ppp device, - * and detect when we want to bring the real link up. - * Return value is 1 if we need to bring up the link, 0 otherwise. - */ -int get_loop_output(void) { - return 0; -} -#endif /* DEMAND_SUPPORT */ - -#if PPP_PROTOCOLNAME -/* List of protocol names, to make our messages a little more informative. */ -struct protocol_list { - u_short proto; - const char *name; -} protocol_list[] = { - { 0x21, "IP" }, - { 0x23, "OSI Network Layer" }, - { 0x25, "Xerox NS IDP" }, - { 0x27, "DECnet Phase IV" }, - { 0x29, "Appletalk" }, - { 0x2b, "Novell IPX" }, - { 0x2d, "VJ compressed TCP/IP" }, - { 0x2f, "VJ uncompressed TCP/IP" }, - { 0x31, "Bridging PDU" }, - { 0x33, "Stream Protocol ST-II" }, - { 0x35, "Banyan Vines" }, - { 0x39, "AppleTalk EDDP" }, - { 0x3b, "AppleTalk SmartBuffered" }, - { 0x3d, "Multi-Link" }, - { 0x3f, "NETBIOS Framing" }, - { 0x41, "Cisco Systems" }, - { 0x43, "Ascom Timeplex" }, - { 0x45, "Fujitsu Link Backup and Load Balancing (LBLB)" }, - { 0x47, "DCA Remote Lan" }, - { 0x49, "Serial Data Transport Protocol (PPP-SDTP)" }, - { 0x4b, "SNA over 802.2" }, - { 0x4d, "SNA" }, - { 0x4f, "IP6 Header Compression" }, - { 0x51, "KNX Bridging Data" }, - { 0x53, "Encryption" }, - { 0x55, "Individual Link Encryption" }, - { 0x57, "IPv6" }, - { 0x59, "PPP Muxing" }, - { 0x5b, "Vendor-Specific Network Protocol" }, - { 0x61, "RTP IPHC Full Header" }, - { 0x63, "RTP IPHC Compressed TCP" }, - { 0x65, "RTP IPHC Compressed non-TCP" }, - { 0x67, "RTP IPHC Compressed UDP 8" }, - { 0x69, "RTP IPHC Compressed RTP 8" }, - { 0x6f, "Stampede Bridging" }, - { 0x73, "MP+" }, - { 0xc1, "NTCITS IPI" }, - { 0xfb, "single-link compression" }, - { 0xfd, "Compressed Datagram" }, - { 0x0201, "802.1d Hello Packets" }, - { 0x0203, "IBM Source Routing BPDU" }, - { 0x0205, "DEC LANBridge100 Spanning Tree" }, - { 0x0207, "Cisco Discovery Protocol" }, - { 0x0209, "Netcs Twin Routing" }, - { 0x020b, "STP - Scheduled Transfer Protocol" }, - { 0x020d, "EDP - Extreme Discovery Protocol" }, - { 0x0211, "Optical Supervisory Channel Protocol" }, - { 0x0213, "Optical Supervisory Channel Protocol" }, - { 0x0231, "Luxcom" }, - { 0x0233, "Sigma Network Systems" }, - { 0x0235, "Apple Client Server Protocol" }, - { 0x0281, "MPLS Unicast" }, - { 0x0283, "MPLS Multicast" }, - { 0x0285, "IEEE p1284.4 standard - data packets" }, - { 0x0287, "ETSI TETRA Network Protocol Type 1" }, - { 0x0289, "Multichannel Flow Treatment Protocol" }, - { 0x2063, "RTP IPHC Compressed TCP No Delta" }, - { 0x2065, "RTP IPHC Context State" }, - { 0x2067, "RTP IPHC Compressed UDP 16" }, - { 0x2069, "RTP IPHC Compressed RTP 16" }, - { 0x4001, "Cray Communications Control Protocol" }, - { 0x4003, "CDPD Mobile Network Registration Protocol" }, - { 0x4005, "Expand accelerator protocol" }, - { 0x4007, "ODSICP NCP" }, - { 0x4009, "DOCSIS DLL" }, - { 0x400B, "Cetacean Network Detection Protocol" }, - { 0x4021, "Stacker LZS" }, - { 0x4023, "RefTek Protocol" }, - { 0x4025, "Fibre Channel" }, - { 0x4027, "EMIT Protocols" }, - { 0x405b, "Vendor-Specific Protocol (VSP)" }, - { 0x8021, "Internet Protocol Control Protocol" }, - { 0x8023, "OSI Network Layer Control Protocol" }, - { 0x8025, "Xerox NS IDP Control Protocol" }, - { 0x8027, "DECnet Phase IV Control Protocol" }, - { 0x8029, "Appletalk Control Protocol" }, - { 0x802b, "Novell IPX Control Protocol" }, - { 0x8031, "Bridging NCP" }, - { 0x8033, "Stream Protocol Control Protocol" }, - { 0x8035, "Banyan Vines Control Protocol" }, - { 0x803d, "Multi-Link Control Protocol" }, - { 0x803f, "NETBIOS Framing Control Protocol" }, - { 0x8041, "Cisco Systems Control Protocol" }, - { 0x8043, "Ascom Timeplex" }, - { 0x8045, "Fujitsu LBLB Control Protocol" }, - { 0x8047, "DCA Remote Lan Network Control Protocol (RLNCP)" }, - { 0x8049, "Serial Data Control Protocol (PPP-SDCP)" }, - { 0x804b, "SNA over 802.2 Control Protocol" }, - { 0x804d, "SNA Control Protocol" }, - { 0x804f, "IP6 Header Compression Control Protocol" }, - { 0x8051, "KNX Bridging Control Protocol" }, - { 0x8053, "Encryption Control Protocol" }, - { 0x8055, "Individual Link Encryption Control Protocol" }, - { 0x8057, "IPv6 Control Protocol" }, - { 0x8059, "PPP Muxing Control Protocol" }, - { 0x805b, "Vendor-Specific Network Control Protocol (VSNCP)" }, - { 0x806f, "Stampede Bridging Control Protocol" }, - { 0x8073, "MP+ Control Protocol" }, - { 0x80c1, "NTCITS IPI Control Protocol" }, - { 0x80fb, "Single Link Compression Control Protocol" }, - { 0x80fd, "Compression Control Protocol" }, - { 0x8207, "Cisco Discovery Protocol Control" }, - { 0x8209, "Netcs Twin Routing" }, - { 0x820b, "STP - Control Protocol" }, - { 0x820d, "EDPCP - Extreme Discovery Protocol Ctrl Prtcl" }, - { 0x8235, "Apple Client Server Protocol Control" }, - { 0x8281, "MPLSCP" }, - { 0x8285, "IEEE p1284.4 standard - Protocol Control" }, - { 0x8287, "ETSI TETRA TNP1 Control Protocol" }, - { 0x8289, "Multichannel Flow Treatment Protocol" }, - { 0xc021, "Link Control Protocol" }, - { 0xc023, "Password Authentication Protocol" }, - { 0xc025, "Link Quality Report" }, - { 0xc027, "Shiva Password Authentication Protocol" }, - { 0xc029, "CallBack Control Protocol (CBCP)" }, - { 0xc02b, "BACP Bandwidth Allocation Control Protocol" }, - { 0xc02d, "BAP" }, - { 0xc05b, "Vendor-Specific Authentication Protocol (VSAP)" }, - { 0xc081, "Container Control Protocol" }, - { 0xc223, "Challenge Handshake Authentication Protocol" }, - { 0xc225, "RSA Authentication Protocol" }, - { 0xc227, "Extensible Authentication Protocol" }, - { 0xc229, "Mitsubishi Security Info Exch Ptcl (SIEP)" }, - { 0xc26f, "Stampede Bridging Authorization Protocol" }, - { 0xc281, "Proprietary Authentication Protocol" }, - { 0xc283, "Proprietary Authentication Protocol" }, - { 0xc481, "Proprietary Node ID Authentication Protocol" }, - { 0, NULL }, -}; - -/* - * protocol_name - find a name for a PPP protocol. - */ -const char * protocol_name(int proto) { - struct protocol_list *lp; - - for (lp = protocol_list; lp->proto != 0; ++lp) { - if (proto == lp->proto) { - return lp->name; - } - } - return NULL; -} -#endif /* PPP_PROTOCOLNAME */ - -#if PPP_STATS_SUPPORT - -/* ---- Note on PPP Stats support ---- - * - * The one willing link stats support should add the get_ppp_stats() - * to fetch statistics from lwIP. - */ - -/* - * reset_link_stats - "reset" stats when link goes up. - */ -void reset_link_stats(int u) { - if (!get_ppp_stats(u, &old_link_stats)) { - return; - } - gettimeofday(&start_time, NULL); -} - -/* - * update_link_stats - get stats at link termination. - */ -void update_link_stats(int u) { - struct timeval now; - char numbuf[32]; - - if (!get_ppp_stats(u, &link_stats) || gettimeofday(&now, NULL) < 0) { - return; - } - link_connect_time = now.tv_sec - start_time.tv_sec; - link_stats_valid = 1; - - link_stats.bytes_in -= old_link_stats.bytes_in; - link_stats.bytes_out -= old_link_stats.bytes_out; - link_stats.pkts_in -= old_link_stats.pkts_in; - link_stats.pkts_out -= old_link_stats.pkts_out; -} - -void print_link_stats() { - /* - * Print connect time and statistics. - */ - if (link_stats_valid) { - int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */ - info("Connect time %d.%d minutes.", t/10, t%10); - info("Sent %u bytes, received %u bytes.", link_stats.bytes_out, link_stats.bytes_in); - link_stats_valid = 0; - } -} -#endif /* PPP_STATS_SUPPORT */ - -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/pppapi.c b/ext/lwip/src/netif/ppp/pppapi.c deleted file mode 100644 index e2bedc7..0000000 --- a/ext/lwip/src/netif/ppp/pppapi.c +++ /dev/null @@ -1,422 +0,0 @@ -/** - * @file - * Point To Point Protocol Sequential API module - * - */ - -/* - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - */ - -#include "netif/ppp/ppp_opts.h" - -#if LWIP_PPP_API /* don't build if not configured for use in lwipopts.h */ - -#include "netif/ppp/pppapi.h" -#include "lwip/priv/tcpip_priv.h" -#include "netif/ppp/pppoe.h" -#include "netif/ppp/pppol2tp.h" -#include "netif/ppp/pppos.h" - -#if LWIP_MPU_COMPATIBLE -LWIP_MEMPOOL_DECLARE(PPPAPI_MSG, MEMP_NUM_PPP_API_MSG, sizeof(struct pppapi_msg), "PPPAPI_MSG") -#endif - -#define PPPAPI_VAR_REF(name) API_VAR_REF(name) -#define PPPAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct pppapi_msg, name) -#define PPPAPI_VAR_ALLOC(name) API_VAR_ALLOC_POOL(struct pppapi_msg, PPPAPI_MSG, name, ERR_MEM) -#define PPPAPI_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC_POOL(struct pppapi_msg, PPPAPI_MSG, name, NULL) -#define PPPAPI_VAR_FREE(name) API_VAR_FREE_POOL(PPPAPI_MSG, name) - -/** - * Call ppp_set_default() inside the tcpip_thread context. - */ -static err_t -pppapi_do_ppp_set_default(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct pppapi_msg */ - struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; - - ppp_set_default(msg->msg.ppp); - return ERR_OK; -} - -/** - * Call ppp_set_default() in a thread-safe way by running that function inside the - * tcpip_thread context. - */ -err_t -pppapi_set_default(ppp_pcb *pcb) -{ - err_t err; - PPPAPI_VAR_DECLARE(msg); - PPPAPI_VAR_ALLOC(msg); - - PPPAPI_VAR_REF(msg).msg.ppp = pcb; - err = tcpip_api_call(pppapi_do_ppp_set_default, &PPPAPI_VAR_REF(msg).call); - PPPAPI_VAR_FREE(msg); - return err; -} - - -#if PPP_NOTIFY_PHASE -/** - * Call ppp_set_notify_phase_callback() inside the tcpip_thread context. - */ -static err_t -pppapi_do_ppp_set_notify_phase_callback(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct pppapi_msg */ - struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; - - ppp_set_notify_phase_callback(msg->msg.ppp, msg->msg.msg.setnotifyphasecb.notify_phase_cb); - return ERR_OK; -} - -/** - * Call ppp_set_notify_phase_callback() in a thread-safe way by running that function inside the - * tcpip_thread context. - */ -err_t -pppapi_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb) -{ - err_t err; - PPPAPI_VAR_DECLARE(msg); - PPPAPI_VAR_ALLOC(msg); - - PPPAPI_VAR_REF(msg).msg.ppp = pcb; - PPPAPI_VAR_REF(msg).msg.msg.setnotifyphasecb.notify_phase_cb = notify_phase_cb; - err = tcpip_api_call(pppapi_do_ppp_set_notify_phase_callback, &PPPAPI_VAR_REF(msg).call); - PPPAPI_VAR_FREE(msg); - return err; -} -#endif /* PPP_NOTIFY_PHASE */ - - -#if PPPOS_SUPPORT -/** - * Call pppos_create() inside the tcpip_thread context. - */ -static err_t -pppapi_do_pppos_create(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct pppapi_msg */ - struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; - - msg->msg.ppp = pppos_create(msg->msg.msg.serialcreate.pppif, msg->msg.msg.serialcreate.output_cb, - msg->msg.msg.serialcreate.link_status_cb, msg->msg.msg.serialcreate.ctx_cb); - return ERR_OK; -} - -/** - * Call pppos_create() in a thread-safe way by running that function inside the - * tcpip_thread context. - */ -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) -{ - ppp_pcb* result; - PPPAPI_VAR_DECLARE(msg); - PPPAPI_VAR_ALLOC_RETURN_NULL(msg); - - PPPAPI_VAR_REF(msg).msg.ppp = NULL; - PPPAPI_VAR_REF(msg).msg.msg.serialcreate.pppif = pppif; - PPPAPI_VAR_REF(msg).msg.msg.serialcreate.output_cb = output_cb; - PPPAPI_VAR_REF(msg).msg.msg.serialcreate.link_status_cb = link_status_cb; - PPPAPI_VAR_REF(msg).msg.msg.serialcreate.ctx_cb = ctx_cb; - tcpip_api_call(pppapi_do_pppos_create, &PPPAPI_VAR_REF(msg).call); - result = PPPAPI_VAR_REF(msg).msg.ppp; - PPPAPI_VAR_FREE(msg); - return result; -} -#endif /* PPPOS_SUPPORT */ - - -#if PPPOE_SUPPORT -/** - * Call pppoe_create() inside the tcpip_thread context. - */ -static err_t -pppapi_do_pppoe_create(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct pppapi_msg */ - struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; - - msg->msg.ppp = pppoe_create(msg->msg.msg.ethernetcreate.pppif, msg->msg.msg.ethernetcreate.ethif, - msg->msg.msg.ethernetcreate.service_name, msg->msg.msg.ethernetcreate.concentrator_name, - msg->msg.msg.ethernetcreate.link_status_cb, msg->msg.msg.ethernetcreate.ctx_cb); - return ERR_OK; -} - -/** - * Call pppoe_create() in a thread-safe way by running that function inside the - * tcpip_thread context. - */ -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) -{ - ppp_pcb* result; - PPPAPI_VAR_DECLARE(msg); - PPPAPI_VAR_ALLOC_RETURN_NULL(msg); - - PPPAPI_VAR_REF(msg).msg.ppp = NULL; - PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.pppif = pppif; - PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.ethif = ethif; - PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.service_name = service_name; - PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.concentrator_name = concentrator_name; - PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.link_status_cb = link_status_cb; - PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.ctx_cb = ctx_cb; - tcpip_api_call(pppapi_do_pppoe_create, &PPPAPI_VAR_REF(msg).call); - result = PPPAPI_VAR_REF(msg).msg.ppp; - PPPAPI_VAR_FREE(msg); - return result; -} -#endif /* PPPOE_SUPPORT */ - - -#if PPPOL2TP_SUPPORT -/** - * Call pppol2tp_create() inside the tcpip_thread context. - */ -static err_t -pppapi_do_pppol2tp_create(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct pppapi_msg */ - struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; - - msg->msg.ppp = pppol2tp_create(msg->msg.msg.l2tpcreate.pppif, - msg->msg.msg.l2tpcreate.netif, API_EXPR_REF(msg->msg.msg.l2tpcreate.ipaddr), msg->msg.msg.l2tpcreate.port, -#if PPPOL2TP_AUTH_SUPPORT - msg->msg.msg.l2tpcreate.secret, - msg->msg.msg.l2tpcreate.secret_len, -#else /* PPPOL2TP_AUTH_SUPPORT */ - NULL, -#endif /* PPPOL2TP_AUTH_SUPPORT */ - msg->msg.msg.l2tpcreate.link_status_cb, msg->msg.msg.l2tpcreate.ctx_cb); - return ERR_OK; -} - -/** - * Call pppol2tp_create() in a thread-safe way by running that function inside the - * tcpip_thread context. - */ -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) -{ - ppp_pcb* result; - PPPAPI_VAR_DECLARE(msg); - PPPAPI_VAR_ALLOC_RETURN_NULL(msg); - - PPPAPI_VAR_REF(msg).msg.ppp = NULL; - PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.pppif = pppif; - PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.netif = netif; - PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.ipaddr = PPPAPI_VAR_REF(ipaddr); - PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.port = port; -#if PPPOL2TP_AUTH_SUPPORT - PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.secret = secret; - PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.secret_len = secret_len; -#endif /* PPPOL2TP_AUTH_SUPPORT */ - PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.link_status_cb = link_status_cb; - PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.ctx_cb = ctx_cb; - tcpip_api_call(pppapi_do_pppol2tp_create, &PPPAPI_VAR_REF(msg).call); - result = PPPAPI_VAR_REF(msg).msg.ppp; - PPPAPI_VAR_FREE(msg); - return result; -} -#endif /* PPPOL2TP_SUPPORT */ - - -/** - * Call ppp_connect() inside the tcpip_thread context. - */ -static err_t -pppapi_do_ppp_connect(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct pppapi_msg */ - struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; - - return ppp_connect(msg->msg.ppp, msg->msg.msg.connect.holdoff); -} - -/** - * Call ppp_connect() in a thread-safe way by running that function inside the - * tcpip_thread context. - */ -err_t -pppapi_connect(ppp_pcb *pcb, u16_t holdoff) -{ - err_t err; - PPPAPI_VAR_DECLARE(msg); - PPPAPI_VAR_ALLOC(msg); - - PPPAPI_VAR_REF(msg).msg.ppp = pcb; - PPPAPI_VAR_REF(msg).msg.msg.connect.holdoff = holdoff; - err = tcpip_api_call(pppapi_do_ppp_connect, &PPPAPI_VAR_REF(msg).call); - PPPAPI_VAR_FREE(msg); - return err; -} - - -#if PPP_SERVER -/** - * Call ppp_listen() inside the tcpip_thread context. - */ -static err_t -pppapi_do_ppp_listen(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct pppapi_msg */ - struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; - - return ppp_listen(msg->msg.ppp); -} - -/** - * Call ppp_listen() in a thread-safe way by running that function inside the - * tcpip_thread context. - */ -err_t -pppapi_listen(ppp_pcb *pcb) -{ - err_t err; - PPPAPI_VAR_DECLARE(msg); - PPPAPI_VAR_ALLOC(msg); - - PPPAPI_VAR_REF(msg).msg.ppp = pcb; - err = tcpip_api_call(pppapi_do_ppp_listen, &PPPAPI_VAR_REF(msg).call); - PPPAPI_VAR_FREE(msg); - return err; -} -#endif /* PPP_SERVER */ - - -/** - * Call ppp_close() inside the tcpip_thread context. - */ -static err_t -pppapi_do_ppp_close(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct pppapi_msg */ - struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; - - return ppp_close(msg->msg.ppp, msg->msg.msg.close.nocarrier); -} - -/** - * Call ppp_close() in a thread-safe way by running that function inside the - * tcpip_thread context. - */ -err_t -pppapi_close(ppp_pcb *pcb, u8_t nocarrier) -{ - err_t err; - PPPAPI_VAR_DECLARE(msg); - PPPAPI_VAR_ALLOC(msg); - - PPPAPI_VAR_REF(msg).msg.ppp = pcb; - PPPAPI_VAR_REF(msg).msg.msg.close.nocarrier = nocarrier; - err = tcpip_api_call(pppapi_do_ppp_close, &PPPAPI_VAR_REF(msg).call); - PPPAPI_VAR_FREE(msg); - return err; -} - - -/** - * Call ppp_free() inside the tcpip_thread context. - */ -static err_t -pppapi_do_ppp_free(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct pppapi_msg */ - struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; - - return ppp_free(msg->msg.ppp); -} - -/** - * Call ppp_free() in a thread-safe way by running that function inside the - * tcpip_thread context. - */ -err_t -pppapi_free(ppp_pcb *pcb) -{ - err_t err; - PPPAPI_VAR_DECLARE(msg); - PPPAPI_VAR_ALLOC(msg); - - PPPAPI_VAR_REF(msg).msg.ppp = pcb; - err = tcpip_api_call(pppapi_do_ppp_free, &PPPAPI_VAR_REF(msg).call); - PPPAPI_VAR_FREE(msg); - return err; -} - - -/** - * Call ppp_ioctl() inside the tcpip_thread context. - */ -static err_t -pppapi_do_ppp_ioctl(struct tcpip_api_call_data *m) -{ - /* cast through void* to silence alignment warnings. - * We know it works because the structs have been instantiated as struct pppapi_msg */ - struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; - - return ppp_ioctl(msg->msg.ppp, msg->msg.msg.ioctl.cmd, msg->msg.msg.ioctl.arg); -} - -/** - * Call ppp_ioctl() in a thread-safe way by running that function inside the - * tcpip_thread context. - */ -err_t -pppapi_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg) -{ - err_t err; - PPPAPI_VAR_DECLARE(msg); - PPPAPI_VAR_ALLOC(msg); - - PPPAPI_VAR_REF(msg).msg.ppp = pcb; - PPPAPI_VAR_REF(msg).msg.msg.ioctl.cmd = cmd; - PPPAPI_VAR_REF(msg).msg.msg.ioctl.arg = arg; - err = tcpip_api_call(pppapi_do_ppp_ioctl, &PPPAPI_VAR_REF(msg).call); - PPPAPI_VAR_FREE(msg); - return err; -} - -#endif /* LWIP_PPP_API */ diff --git a/ext/lwip/src/netif/ppp/pppcrypt.c b/ext/lwip/src/netif/ppp/pppcrypt.c deleted file mode 100644 index 82d78c1..0000000 --- a/ext/lwip/src/netif/ppp/pppcrypt.c +++ /dev/null @@ -1,66 +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 && MSCHAP_SUPPORT /* don't build if not necessary */ - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/pppcrypt.h" - - -static u_char pppcrypt_get_7bits(u_char *input, int startBit) { - unsigned int word; - - word = (unsigned)input[startBit / 8] << 8; - word |= (unsigned)input[startBit / 8 + 1]; - - word >>= 15 - (startBit % 8 + 7); - - return word & 0xFE; -} - -/* IN 56 bit DES key missing parity bits - * OUT 64 bit DES key with parity bits added - */ -void pppcrypt_56_to_64_bit_key(u_char *key, u_char * des_key) { - des_key[0] = pppcrypt_get_7bits(key, 0); - des_key[1] = pppcrypt_get_7bits(key, 7); - des_key[2] = pppcrypt_get_7bits(key, 14); - des_key[3] = pppcrypt_get_7bits(key, 21); - des_key[4] = pppcrypt_get_7bits(key, 28); - des_key[5] = pppcrypt_get_7bits(key, 35); - des_key[6] = pppcrypt_get_7bits(key, 42); - des_key[7] = pppcrypt_get_7bits(key, 49); -} - -#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/pppoe.c b/ext/lwip/src/netif/ppp/pppoe.c deleted file mode 100644 index 348129a..0000000 --- a/ext/lwip/src/netif/ppp/pppoe.c +++ /dev/null @@ -1,1259 +0,0 @@ -/***************************************************************************** -* pppoe.c - 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 */ - -#if 0 /* UNUSED */ -#include -#include -#endif /* UNUSED */ - -#include "lwip/timeouts.h" -#include "lwip/memp.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" - -#include "netif/ppp/ppp_impl.h" -#include "netif/ppp/lcp.h" -#include "netif/ppp/ipcp.h" -#include "netif/ppp/pppoe.h" - -/* Memory pool */ -LWIP_MEMPOOL_DECLARE(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") - -/* Add a 16 bit unsigned value to a buffer pointed to by PTR */ -#define PPPOE_ADD_16(PTR, VAL) \ - *(PTR)++ = (u8_t)((VAL) / 256); \ - *(PTR)++ = (u8_t)((VAL) % 256) - -/* Add a complete PPPoE header to the buffer pointed to by PTR */ -#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN) \ - *(PTR)++ = PPPOE_VERTYPE; \ - *(PTR)++ = (CODE); \ - PPPOE_ADD_16(PTR, SESS); \ - PPPOE_ADD_16(PTR, LEN) - -#define PPPOE_DISC_TIMEOUT (5*1000) /* base for quick timeout calculation */ -#define PPPOE_SLOW_RETRY (60*1000) /* persistent retry interval */ -#define PPPOE_DISC_MAXPADI 4 /* retry PADI four times (quickly) */ -#define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */ - -#ifdef PPPOE_SERVER -#error "PPPOE_SERVER is not yet supported under lwIP!" -/* from if_spppsubr.c */ -#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ -#endif - -#define PPPOE_ERRORSTRING_LEN 64 - - -/* callbacks called from PPP core */ -static err_t pppoe_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); -static err_t pppoe_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol); -static err_t pppoe_connect(ppp_pcb *ppp, void *ctx); -static void pppoe_disconnect(ppp_pcb *ppp, void *ctx); -static err_t pppoe_destroy(ppp_pcb *ppp, void *ctx); - -/* management routines */ -static void pppoe_abort_connect(struct pppoe_softc *); -#if 0 /* UNUSED */ -static void pppoe_clear_softc(struct pppoe_softc *, const char *); -#endif /* UNUSED */ - -/* internal timeout handling */ -static void pppoe_timeout(void *); - -/* sending actual protocol controll packets */ -static err_t pppoe_send_padi(struct pppoe_softc *); -static err_t pppoe_send_padr(struct pppoe_softc *); -#ifdef PPPOE_SERVER -static err_t pppoe_send_pado(struct pppoe_softc *); -static err_t pppoe_send_pads(struct pppoe_softc *); -#endif -static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *); - -/* internal helper functions */ -static err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); -static struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif); -static struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif); - -/** linked list of created pppoe interfaces */ -static struct pppoe_softc *pppoe_softc_list; - -/* Callbacks structure for PPP core */ -static const struct link_callbacks pppoe_callbacks = { - pppoe_connect, -#if PPP_SERVER - NULL, -#endif /* PPP_SERVER */ - pppoe_disconnect, - pppoe_destroy, - pppoe_write, - pppoe_netif_output, - NULL, - NULL -}; - -/* - * Create a new PPP Over Ethernet (PPPoE) connection. - * - * Return 0 on success, an error code on failure. - */ -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) -{ - ppp_pcb *ppp; - struct pppoe_softc *sc; - LWIP_UNUSED_ARG(service_name); - LWIP_UNUSED_ARG(concentrator_name); - - sc = (struct pppoe_softc *)LWIP_MEMPOOL_ALLOC(PPPOE_IF); - if (sc == NULL) { - return NULL; - } - - ppp = ppp_new(pppif, &pppoe_callbacks, sc, link_status_cb, ctx_cb); - if (ppp == NULL) { - LWIP_MEMPOOL_FREE(PPPOE_IF, sc); - return NULL; - } - - memset(sc, 0, sizeof(struct pppoe_softc)); - /* changed to real address later */ - MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); - sc->pcb = ppp; - sc->sc_ethif = ethif; - /* put the new interface at the head of the list */ - sc->next = pppoe_softc_list; - pppoe_softc_list = sc; - return ppp; -} - -/* Called by PPP core */ -static err_t pppoe_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) { - struct pppoe_softc *sc = (struct pppoe_softc *)ctx; - struct pbuf *ph; /* Ethernet + PPPoE header */ - err_t ret; -#if MIB2_STATS - u16_t tot_len; -#else /* MIB2_STATS */ - LWIP_UNUSED_ARG(ppp); -#endif /* MIB2_STATS */ - - /* skip address & flags */ - pbuf_header(p, -(s16_t)2); - - ph = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN), PBUF_RAM); - if(!ph) { - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.proterr); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - pbuf_free(p); - return ERR_MEM; - } - - pbuf_header(ph, -(s16_t)PPPOE_HEADERLEN); /* hide PPPoE header */ - pbuf_cat(ph, p); -#if MIB2_STATS - tot_len = ph->tot_len; -#endif /* MIB2_STATS */ - - ret = pppoe_xmit(sc, ph); - if (ret != ERR_OK) { - LINK_STATS_INC(link.err); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - return ret; - } - - MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, (u16_t)tot_len); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); - LINK_STATS_INC(link.xmit); - return ERR_OK; -} - -/* Called by PPP core */ -static err_t pppoe_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol) { - struct pppoe_softc *sc = (struct pppoe_softc *)ctx; - struct pbuf *pb; - u8_t *pl; - err_t err; -#if MIB2_STATS - u16_t tot_len; -#else /* MIB2_STATS */ - LWIP_UNUSED_ARG(ppp); -#endif /* MIB2_STATS */ - - /* @todo: try to use pbuf_header() here! */ - pb = pbuf_alloc(PBUF_LINK, PPPOE_HEADERLEN + sizeof(protocol), PBUF_RAM); - if(!pb) { - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.proterr); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - return ERR_MEM; - } - - pbuf_header(pb, -(s16_t)PPPOE_HEADERLEN); - - pl = (u8_t*)pb->payload; - PUTSHORT(protocol, pl); - - pbuf_chain(pb, p); -#if MIB2_STATS - tot_len = pb->tot_len; -#endif /* MIB2_STATS */ - - if( (err = pppoe_xmit(sc, pb)) != ERR_OK) { - LINK_STATS_INC(link.err); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - return err; - } - - MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, tot_len); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); - LINK_STATS_INC(link.xmit); - return ERR_OK; -} - -static err_t -pppoe_destroy(ppp_pcb *ppp, void *ctx) -{ - struct pppoe_softc *sc = (struct pppoe_softc *)ctx; - struct pppoe_softc **copp, *freep; - LWIP_UNUSED_ARG(ppp); - - sys_untimeout(pppoe_timeout, sc); - - /* remove interface from list */ - for (copp = &pppoe_softc_list; (freep = *copp); copp = &freep->next) { - if (freep == sc) { - *copp = freep->next; - break; - } - } - -#ifdef PPPOE_TODO - if (sc->sc_concentrator_name) { - mem_free(sc->sc_concentrator_name); - } - if (sc->sc_service_name) { - mem_free(sc->sc_service_name); - } -#endif /* PPPOE_TODO */ - LWIP_MEMPOOL_FREE(PPPOE_IF, sc); - - return ERR_OK; -} - -/* - * Find the interface handling the specified session. - * Note: O(number of sessions open), this is a client-side only, mean - * and lean implementation, so number of open sessions typically should - * be 1. - */ -static struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif) { - struct pppoe_softc *sc; - - if (session == 0) { - return NULL; - } - - for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { - if (sc->sc_state == PPPOE_STATE_SESSION - && sc->sc_session == session - && sc->sc_ethif == rcvif) { - return sc; - } - } - return NULL; -} - -/* Check host unique token passed and return appropriate softc pointer, - * or NULL if token is bogus. */ -static struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) { - struct pppoe_softc *sc, *t; - - if (pppoe_softc_list == NULL) { - return NULL; - } - - if (len != sizeof sc) { - return NULL; - } - MEMCPY(&t, token, len); - - for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { - if (sc == t) { - break; - } - } - - if (sc == NULL) { - PPPDEBUG(LOG_DEBUG, ("pppoe: alien host unique tag, no session found\n")); - return NULL; - } - - /* should be safe to access *sc now */ - if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) { - PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n", - sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state)); - return NULL; - } - if (sc->sc_ethif != rcvif) { - PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": wrong interface, not accepting host unique\n", - sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); - return NULL; - } - return sc; -} - -/* analyze and handle a single received packet while not in session state */ -void -pppoe_disc_input(struct netif *netif, struct pbuf *pb) -{ - u16_t tag, len; - u16_t session, plen; - struct pppoe_softc *sc; -#if PPP_DEBUG - const char *err_msg = NULL; -#endif /* PPP_DEBUG */ - u8_t *ac_cookie; - u16_t ac_cookie_len; -#ifdef PPPOE_SERVER - u8_t *hunique; - size_t hunique_len; -#endif - struct pppoehdr *ph; - struct pppoetag pt; - int off, err; - struct eth_hdr *ethhdr; - - /* don't do anything if there is not a single PPPoE instance */ - if (pppoe_softc_list == NULL) { - pbuf_free(pb); - return; - } - - pb = ppp_singlebuf(pb); - - if (pb->len < sizeof(*ethhdr)) { - goto done; - } - ethhdr = (struct eth_hdr *)pb->payload; - off = sizeof(*ethhdr); - - ac_cookie = NULL; - ac_cookie_len = 0; -#ifdef PPPOE_SERVER - hunique = NULL; - hunique_len = 0; -#endif - session = 0; - if (pb->len - off < (u16_t)PPPOE_HEADERLEN) { - PPPDEBUG(LOG_DEBUG, ("pppoe: packet too short: %d\n", pb->len)); - goto done; - } - - ph = (struct pppoehdr *) (ethhdr + 1); - if (ph->vertype != PPPOE_VERTYPE) { - PPPDEBUG(LOG_DEBUG, ("pppoe: unknown version/type packet: 0x%x\n", ph->vertype)); - goto done; - } - session = ntohs(ph->session); - plen = ntohs(ph->plen); - off += sizeof(*ph); - - if (plen + off > pb->len) { - PPPDEBUG(LOG_DEBUG, ("pppoe: packet content does not fit: data available = %d, packet size = %u\n", - pb->len - off, plen)); - goto done; - } - if(pb->tot_len == pb->len) { - pb->tot_len = pb->len = (u16_t)off + plen; /* ignore trailing garbage */ - } - tag = 0; - len = 0; - sc = NULL; - while (off + sizeof(pt) <= pb->len) { - MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt)); - tag = ntohs(pt.tag); - len = ntohs(pt.len); - if (off + sizeof(pt) + len > pb->len) { - PPPDEBUG(LOG_DEBUG, ("pppoe: tag 0x%x len 0x%x is too long\n", tag, len)); - goto done; - } - switch (tag) { - case PPPOE_TAG_EOL: - goto breakbreak; - case PPPOE_TAG_SNAME: - break; /* ignored */ - case PPPOE_TAG_ACNAME: - break; /* ignored */ - case PPPOE_TAG_HUNIQUE: - if (sc != NULL) { - break; - } -#ifdef PPPOE_SERVER - hunique = (u8_t*)pb->payload + off + sizeof(pt); - hunique_len = len; -#endif - sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif); - break; - case PPPOE_TAG_ACCOOKIE: - if (ac_cookie == NULL) { - if (len > PPPOE_MAX_AC_COOKIE_LEN) { - PPPDEBUG(LOG_DEBUG, ("pppoe: AC cookie is too long: len = %d, max = %d\n", len, PPPOE_MAX_AC_COOKIE_LEN)); - goto done; - } - ac_cookie = (u8_t*)pb->payload + off + sizeof(pt); - ac_cookie_len = len; - } - break; -#if PPP_DEBUG - case PPPOE_TAG_SNAME_ERR: - err_msg = "SERVICE NAME ERROR"; - break; - case PPPOE_TAG_ACSYS_ERR: - err_msg = "AC SYSTEM ERROR"; - break; - case PPPOE_TAG_GENERIC_ERR: - err_msg = "GENERIC ERROR"; - break; -#endif /* PPP_DEBUG */ - default: - break; - } -#if PPP_DEBUG - if (err_msg != NULL) { - char error_tmp[PPPOE_ERRORSTRING_LEN]; - u16_t error_len = LWIP_MIN(len, sizeof(error_tmp)-1); - strncpy(error_tmp, (char*)pb->payload + off + sizeof(pt), error_len); - error_tmp[error_len] = '\0'; - if (sc) { - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": %s: %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err_msg, error_tmp)); - } else { - PPPDEBUG(LOG_DEBUG, ("pppoe: %s: %s\n", err_msg, error_tmp)); - } - } -#endif /* PPP_DEBUG */ - off += sizeof(pt) + len; - } - -breakbreak:; - switch (ph->code) { - case PPPOE_CODE_PADI: -#ifdef PPPOE_SERVER - /* - * got service name, concentrator name, and/or host unique. - * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP. - */ - if (LIST_EMPTY(&pppoe_softc_list)) { - goto done; - } - LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { - if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) { - continue; - } - if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { - continue; - } - if (sc->sc_state == PPPOE_STATE_INITIAL) { - break; - } - } - if (sc == NULL) { - /* PPPDEBUG(LOG_DEBUG, ("pppoe: free passive interface is not found\n")); */ - goto done; - } - if (hunique) { - if (sc->sc_hunique) { - mem_free(sc->sc_hunique); - } - sc->sc_hunique = mem_malloc(hunique_len); - if (sc->sc_hunique == NULL) { - goto done; - } - sc->sc_hunique_len = hunique_len; - MEMCPY(sc->sc_hunique, hunique, hunique_len); - } - MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest); - sc->sc_state = PPPOE_STATE_PADO_SENT; - pppoe_send_pado(sc); - break; -#endif /* PPPOE_SERVER */ - case PPPOE_CODE_PADR: -#ifdef PPPOE_SERVER - /* - * get sc from ac_cookie if IFF_PASSIVE - */ - if (ac_cookie == NULL) { - /* be quiet if there is not a single pppoe instance */ - PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but not includes ac_cookie\n")); - goto done; - } - sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif); - if (sc == NULL) { - /* be quiet if there is not a single pppoe instance */ - if (!LIST_EMPTY(&pppoe_softc_list)) { - PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but could not find request for it\n")); - } - goto done; - } - if (sc->sc_state != PPPOE_STATE_PADO_SENT) { - PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); - goto done; - } - if (hunique) { - if (sc->sc_hunique) { - mem_free(sc->sc_hunique); - } - sc->sc_hunique = mem_malloc(hunique_len); - if (sc->sc_hunique == NULL) { - goto done; - } - sc->sc_hunique_len = hunique_len; - MEMCPY(sc->sc_hunique, hunique, hunique_len); - } - pppoe_send_pads(sc); - sc->sc_state = PPPOE_STATE_SESSION; - ppp_start(sc->pcb); /* notify upper layers */ - break; -#else - /* ignore, we are no access concentrator */ - goto done; -#endif /* PPPOE_SERVER */ - case PPPOE_CODE_PADO: - if (sc == NULL) { - /* be quiet if there is not a single pppoe instance */ - if (pppoe_softc_list != NULL) { - PPPDEBUG(LOG_DEBUG, ("pppoe: received PADO but could not find request for it\n")); - } - goto done; - } - if (sc->sc_state != PPPOE_STATE_PADI_SENT) { - PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); - goto done; - } - if (ac_cookie) { - sc->sc_ac_cookie_len = ac_cookie_len; - MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len); - } - MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr)); - sys_untimeout(pppoe_timeout, sc); - sc->sc_padr_retried = 0; - sc->sc_state = PPPOE_STATE_PADR_SENT; - if ((err = pppoe_send_padr(sc)) != 0) { - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); - } - sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); - break; - case PPPOE_CODE_PADS: - if (sc == NULL) { - goto done; - } - sc->sc_session = session; - sys_untimeout(pppoe_timeout, sc); - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session)); - sc->sc_state = PPPOE_STATE_SESSION; - ppp_start(sc->pcb); /* notify upper layers */ - break; - case PPPOE_CODE_PADT: - /* Don't disconnect here, we let the LCP Echo/Reply find the fact - * that PPP session is down. Asking the PPP stack to end the session - * require strict checking about the PPP phase to prevent endless - * disconnection loops. - */ -#if 0 /* UNUSED */ - if (sc == NULL) { /* PADT frames are rarely sent with a hunique tag, this is actually almost always true */ - goto done; - } - pppoe_clear_softc(sc, "received PADT"); -#endif /* UNUSED */ - break; - default: - if(sc) { - PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": unknown code (0x%"X16_F") session = 0x%"X16_F"\n", - sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, - (u16_t)ph->code, session)); - } else { - PPPDEBUG(LOG_DEBUG, ("pppoe: unknown code (0x%"X16_F") session = 0x%"X16_F"\n", (u16_t)ph->code, session)); - } - break; - } - -done: - pbuf_free(pb); - return; -} - -void -pppoe_data_input(struct netif *netif, struct pbuf *pb) -{ - u16_t session, plen; - struct pppoe_softc *sc; - struct pppoehdr *ph; -#ifdef PPPOE_TERM_UNKNOWN_SESSIONS - u8_t shost[ETHER_ADDR_LEN]; -#endif - -#ifdef PPPOE_TERM_UNKNOWN_SESSIONS - MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost)); -#endif - if (pbuf_header(pb, -(s16_t)sizeof(struct eth_hdr)) != 0) { - /* bail out */ - PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header failed\n")); - LINK_STATS_INC(link.lenerr); - goto drop; - } - - if (pb->len < sizeof(*ph)) { - PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: could not get PPPoE header\n")); - goto drop; - } - ph = (struct pppoehdr *)pb->payload; - - if (ph->vertype != PPPOE_VERTYPE) { - PPPDEBUG(LOG_DEBUG, ("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype)); - goto drop; - } - if (ph->code != 0) { - goto drop; - } - - session = ntohs(ph->session); - sc = pppoe_find_softc_by_session(session, netif); - if (sc == NULL) { -#ifdef PPPOE_TERM_UNKNOWN_SESSIONS - PPPDEBUG(LOG_DEBUG, ("pppoe: input for unknown session 0x%x, sending PADT\n", session)); - pppoe_send_padt(netif, session, shost); -#endif - goto drop; - } - - plen = ntohs(ph->plen); - - if (pbuf_header(pb, -(s16_t)(PPPOE_HEADERLEN)) != 0) { - /* bail out */ - PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n")); - LINK_STATS_INC(link.lenerr); - goto drop; - } - - PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n", - sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, - pb->len, plen)); - - if (pb->tot_len < plen) { - goto drop; - } - - /* Dispatch the packet thereby consuming it. */ - ppp_input(sc->pcb, pb); - return; - -drop: - pbuf_free(pb); -} - -static err_t -pppoe_output(struct pppoe_softc *sc, struct pbuf *pb) -{ - struct eth_hdr *ethhdr; - u16_t etype; - err_t res; - - if (!sc->sc_ethif) { - pbuf_free(pb); - return ERR_IF; - } - - /* make room for Ethernet header - should not fail */ - if (pbuf_header(pb, (s16_t)(sizeof(struct eth_hdr))) != 0) { - /* bail out */ - PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_output: could not allocate room for Ethernet header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); - LINK_STATS_INC(link.lenerr); - pbuf_free(pb); - return ERR_BUF; - } - ethhdr = (struct eth_hdr *)pb->payload; - etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC; - ethhdr->type = htons(etype); - MEMCPY(ðhdr->dest.addr, &sc->sc_dest.addr, sizeof(ethhdr->dest.addr)); - MEMCPY(ðhdr->src.addr, &sc->sc_ethif->hwaddr, sizeof(ethhdr->src.addr)); - - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n", - sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype, - sc->sc_state, sc->sc_session, - sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5], - pb->tot_len)); - - res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb); - - pbuf_free(pb); - - return res; -} - -static err_t -pppoe_send_padi(struct pppoe_softc *sc) -{ - struct pbuf *pb; - u8_t *p; - int len; -#ifdef PPPOE_TODO - int l1 = 0, l2 = 0; /* XXX: gcc */ -#endif /* PPPOE_TODO */ - - if (sc->sc_state >PPPOE_STATE_PADI_SENT) { - PPPDEBUG(LOG_ERR, ("ERROR: pppoe_send_padi in state %d", sc->sc_state)); - } - - /* calculate length of frame (excluding ethernet header + pppoe header) */ - len = 2 + 2 + 2 + 2 + sizeof sc; /* service name tag is required, host unique is send too */ -#ifdef PPPOE_TODO - if (sc->sc_service_name != NULL) { - l1 = (int)strlen(sc->sc_service_name); - len += l1; - } - if (sc->sc_concentrator_name != NULL) { - l2 = (int)strlen(sc->sc_concentrator_name); - len += 2 + 2 + l2; - } -#endif /* PPPOE_TODO */ - LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", - sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); - - /* allocate a buffer */ - pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); - if (!pb) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - - p = (u8_t*)pb->payload; - /* fill in pkt */ - PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, (u16_t)len); - PPPOE_ADD_16(p, PPPOE_TAG_SNAME); -#ifdef PPPOE_TODO - if (sc->sc_service_name != NULL) { - PPPOE_ADD_16(p, l1); - MEMCPY(p, sc->sc_service_name, l1); - p += l1; - } else -#endif /* PPPOE_TODO */ - { - PPPOE_ADD_16(p, 0); - } -#ifdef PPPOE_TODO - if (sc->sc_concentrator_name != NULL) { - PPPOE_ADD_16(p, PPPOE_TAG_ACNAME); - PPPOE_ADD_16(p, l2); - MEMCPY(p, sc->sc_concentrator_name, l2); - p += l2; - } -#endif /* PPPOE_TODO */ - PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); - PPPOE_ADD_16(p, sizeof(sc)); - MEMCPY(p, &sc, sizeof sc); - - /* send pkt */ - return pppoe_output(sc, pb); -} - -static void -pppoe_timeout(void *arg) -{ - u32_t retry_wait; - int err; - struct pppoe_softc *sc = (struct pppoe_softc*)arg; - - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); - - switch (sc->sc_state) { - case PPPOE_STATE_PADI_SENT: - /* - * We have two basic ways of retrying: - * - Quick retry mode: try a few times in short sequence - * - Slow retry mode: we already had a connection successfully - * established and will try infinitely (without user - * intervention) - * We only enter slow retry mode if IFF_LINK1 (aka autodial) - * is not set. - */ - if (sc->sc_padi_retried < 0xff) { - sc->sc_padi_retried++; - } - if (!sc->pcb->settings.persist && sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) { -#if 0 - if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) { - /* slow retry mode */ - retry_wait = PPPOE_SLOW_RETRY; - } else -#endif - { - pppoe_abort_connect(sc); - return; - } - } - /* initialize for quick retry mode */ - retry_wait = LWIP_MIN(PPPOE_DISC_TIMEOUT * sc->sc_padi_retried, PPPOE_SLOW_RETRY); - if ((err = pppoe_send_padi(sc)) != 0) { - sc->sc_padi_retried--; - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); - } - sys_timeout(retry_wait, pppoe_timeout, sc); - break; - - case PPPOE_STATE_PADR_SENT: - sc->sc_padr_retried++; - if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) { - MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); - sc->sc_state = PPPOE_STATE_PADI_SENT; - sc->sc_padr_retried = 0; - if ((err = pppoe_send_padi(sc)) != 0) { - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); - } - sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc); - return; - } - if ((err = pppoe_send_padr(sc)) != 0) { - sc->sc_padr_retried--; - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); - } - sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); - break; - default: - return; /* all done, work in peace */ - } -} - -/* Start a connection (i.e. initiate discovery phase) */ -static err_t -pppoe_connect(ppp_pcb *ppp, void *ctx) -{ - int err; - struct pppoe_softc *sc = (struct pppoe_softc *)ctx; - lcp_options *lcp_wo; - lcp_options *lcp_ao; -#if PPP_IPV4_SUPPORT && VJ_SUPPORT - ipcp_options *ipcp_wo; - ipcp_options *ipcp_ao; -#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ - - if (sc->sc_state != PPPOE_STATE_INITIAL) { - return EBUSY; - } - - /* stop any timer */ - sys_untimeout(pppoe_timeout, sc); - sc->sc_session = 0; - sc->sc_padi_retried = 0; - sc->sc_padr_retried = 0; -#ifdef PPPOE_SERVER - /* wait PADI if IFF_PASSIVE */ - if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { - return 0; - } -#endif - - ppp_link_start(ppp); - - lcp_wo = &ppp->lcp_wantoptions; - lcp_wo->mru = sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */ - lcp_wo->neg_asyncmap = 0; - lcp_wo->neg_pcompression = 0; - lcp_wo->neg_accompression = 0; - lcp_wo->passive = 0; - lcp_wo->silent = 0; - - lcp_ao = &ppp->lcp_allowoptions; - lcp_ao->mru = sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */ - lcp_ao->neg_asyncmap = 0; - lcp_ao->neg_pcompression = 0; - lcp_ao->neg_accompression = 0; - -#if PPP_IPV4_SUPPORT && VJ_SUPPORT - ipcp_wo = &ppp->ipcp_wantoptions; - ipcp_wo->neg_vj = 0; - ipcp_wo->old_vj = 0; - - ipcp_ao = &ppp->ipcp_allowoptions; - ipcp_ao->neg_vj = 0; - ipcp_ao->old_vj = 0; -#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ - - /* save state, in case we fail to send PADI */ - sc->sc_state = PPPOE_STATE_PADI_SENT; - if ((err = pppoe_send_padi(sc)) != 0) { - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); - } - sys_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc); - return err; -} - -/* disconnect */ -static void -pppoe_disconnect(ppp_pcb *ppp, void *ctx) -{ - struct pppoe_softc *sc = (struct pppoe_softc *)ctx; - - if (sc->sc_state < PPPOE_STATE_SESSION) { - return; - } - - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); - pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest); - - /* cleanup softc */ - sc->sc_state = PPPOE_STATE_INITIAL; - MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); - sc->sc_ac_cookie_len = 0; -#ifdef PPPOE_SERVER - if (sc->sc_hunique) { - mem_free(sc->sc_hunique); - sc->sc_hunique = NULL; - } - sc->sc_hunique_len = 0; -#endif - sc->sc_session = 0; - sc->sc_padi_retried = 0; - sc->sc_padr_retried = 0; - - ppp_link_end(ppp); /* notify upper layers */ - return; -} - -/* Connection attempt aborted */ -static void -pppoe_abort_connect(struct pppoe_softc *sc) -{ - PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); - - /* clear connection state */ - sc->sc_state = PPPOE_STATE_INITIAL; - MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); - sc->sc_ac_cookie_len = 0; - sc->sc_session = 0; - sc->sc_padi_retried = 0; - sc->sc_padr_retried = 0; - - ppp_link_failed(sc->pcb); /* notify upper layers */ -} - -/* Send a PADR packet */ -static err_t -pppoe_send_padr(struct pppoe_softc *sc) -{ - struct pbuf *pb; - u8_t *p; - size_t len; -#ifdef PPPOE_TODO - size_t l1 = 0; /* XXX: gcc */ -#endif /* PPPOE_TODO */ - - if (sc->sc_state != PPPOE_STATE_PADR_SENT) { - return ERR_CONN; - } - - len = 2 + 2 + 2 + 2 + sizeof(sc); /* service name, host unique */ -#ifdef PPPOE_TODO - if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ - l1 = strlen(sc->sc_service_name); - len += l1; - } -#endif /* PPPOE_TODO */ - if (sc->sc_ac_cookie_len > 0) { - len += 2 + 2 + sc->sc_ac_cookie_len; /* AC cookie */ - } - LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", - sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); - pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); - if (!pb) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - p = (u8_t*)pb->payload; - PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len); - PPPOE_ADD_16(p, PPPOE_TAG_SNAME); -#ifdef PPPOE_TODO - if (sc->sc_service_name != NULL) { - PPPOE_ADD_16(p, l1); - MEMCPY(p, sc->sc_service_name, l1); - p += l1; - } else -#endif /* PPPOE_TODO */ - { - PPPOE_ADD_16(p, 0); - } - if (sc->sc_ac_cookie_len > 0) { - PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); - PPPOE_ADD_16(p, sc->sc_ac_cookie_len); - MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len); - p += sc->sc_ac_cookie_len; - } - PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); - PPPOE_ADD_16(p, sizeof(sc)); - MEMCPY(p, &sc, sizeof sc); - - return pppoe_output(sc, pb); -} - -/* send a PADT packet */ -static err_t -pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest) -{ - struct pbuf *pb; - struct eth_hdr *ethhdr; - err_t res; - u8_t *p; - - pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN), PBUF_RAM); - if (!pb) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - - pbuf_header(pb, (s16_t)sizeof(struct eth_hdr)); - ethhdr = (struct eth_hdr *)pb->payload; - ethhdr->type = PP_HTONS(ETHTYPE_PPPOEDISC); - MEMCPY(ðhdr->dest.addr, dest, sizeof(ethhdr->dest.addr)); - MEMCPY(ðhdr->src.addr, &outgoing_if->hwaddr, sizeof(ethhdr->src.addr)); - - p = (u8_t*)(ethhdr + 1); - PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0); - - res = outgoing_if->linkoutput(outgoing_if, pb); - - pbuf_free(pb); - - return res; -} - -#ifdef PPPOE_SERVER -static err_t -pppoe_send_pado(struct pppoe_softc *sc) -{ - struct pbuf *pb; - u8_t *p; - size_t len; - - if (sc->sc_state != PPPOE_STATE_PADO_SENT) { - return ERR_CONN; - } - - /* calc length */ - len = 0; - /* include ac_cookie */ - len += 2 + 2 + sizeof(sc); - /* include hunique */ - len += 2 + 2 + sc->sc_hunique_len; - pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); - if (!pb) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - p = (u8_t*)pb->payload; - PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len); - PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); - PPPOE_ADD_16(p, sizeof(sc)); - MEMCPY(p, &sc, sizeof(sc)); - p += sizeof(sc); - PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); - PPPOE_ADD_16(p, sc->sc_hunique_len); - MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); - return pppoe_output(sc, pb); -} - -static err_t -pppoe_send_pads(struct pppoe_softc *sc) -{ - struct pbuf *pb; - u8_t *p; - size_t len, l1 = 0; /* XXX: gcc */ - - if (sc->sc_state != PPPOE_STATE_PADO_SENT) { - return ERR_CONN; - } - - sc->sc_session = mono_time.tv_sec % 0xff + 1; - /* calc length */ - len = 0; - /* include hunique */ - len += 2 + 2 + 2 + 2 + sc->sc_hunique_len; /* service name, host unique*/ - if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ - l1 = strlen(sc->sc_service_name); - len += l1; - } - pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); - if (!pb) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - p = (u8_t*)pb->payload; - PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len); - PPPOE_ADD_16(p, PPPOE_TAG_SNAME); - if (sc->sc_service_name != NULL) { - PPPOE_ADD_16(p, l1); - MEMCPY(p, sc->sc_service_name, l1); - p += l1; - } else { - PPPOE_ADD_16(p, 0); - } - PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); - PPPOE_ADD_16(p, sc->sc_hunique_len); - MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); - return pppoe_output(sc, pb); -} -#endif - -static err_t -pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb) -{ - u8_t *p; - size_t len; - - /* are we ready to process data yet? */ - if (sc->sc_state < PPPOE_STATE_SESSION) { - /*sppp_flush(&sc->sc_sppp.pp_if);*/ - pbuf_free(pb); - return ERR_CONN; - } - - len = pb->tot_len; - - /* make room for PPPoE header - should not fail */ - if (pbuf_header(pb, (s16_t)(PPPOE_HEADERLEN)) != 0) { - /* bail out */ - PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for PPPoE header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); - LINK_STATS_INC(link.lenerr); - pbuf_free(pb); - return ERR_BUF; - } - - p = (u8_t*)pb->payload; - PPPOE_ADD_HEADER(p, 0, sc->sc_session, len); - - return pppoe_output(sc, pb); -} - -#if 0 /*def PFIL_HOOKS*/ -static int -pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir) -{ - struct pppoe_softc *sc; - int s; - - if (mp != (struct pbuf **)PFIL_IFNET_DETACH) { - return 0; - } - - LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { - if (sc->sc_ethif != ifp) { - continue; - } - if (sc->sc_sppp.pp_if.if_flags & IFF_UP) { - sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING); - PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": ethernet interface detached, going down\n", - sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); - } - sc->sc_ethif = NULL; - pppoe_clear_softc(sc, "ethernet interface detached"); - } - - return 0; -} -#endif - -#if 0 /* UNUSED */ -static void -pppoe_clear_softc(struct pppoe_softc *sc, const char *message) -{ - LWIP_UNUSED_ARG(message); - - /* stop timer */ - sys_untimeout(pppoe_timeout, sc); - PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message)); - /* fix our state */ - sc->sc_state = PPPOE_STATE_INITIAL; - - /* notify upper layers */ - ppp_link_end(sc->pcb); /* /!\ dangerous /!\ */ - - /* clean up softc */ - MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); - sc->sc_ac_cookie_len = 0; - sc->sc_session = 0; - sc->sc_padi_retried = 0; - sc->sc_padr_retried = 0; -} -#endif /* UNUSED */ -#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/pppol2tp.c b/ext/lwip/src/netif/ppp/pppol2tp.c deleted file mode 100644 index ae5be76..0000000 --- a/ext/lwip/src/netif/ppp/pppol2tp.c +++ /dev/null @@ -1,1150 +0,0 @@ -/** - * @file - * Network Point to Point Protocol over Layer 2 Tunneling Protocol program 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. - * - */ - -/* - * L2TP Support status: - * - * Supported: - * - L2TPv2 (PPP over L2TP, a.k.a. UDP tunnels) - * - LAC - * - * Not supported: - * - LNS (require PPP server support) - * - L2TPv3 ethernet pseudowires - * - L2TPv3 VLAN pseudowire - * - L2TPv3 PPP pseudowires - * - L2TPv3 IP encapsulation - * - L2TPv3 IP pseudowire - * - L2TP tunnel switching - http://tools.ietf.org/html/draft-ietf-l2tpext-tunnel-switching-08 - * - Multiple tunnels per UDP socket, as well as multiple sessions per tunnel - * - Hidden AVPs - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PPPOL2TP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/err.h" -#include "lwip/memp.h" -#include "lwip/netif.h" -#include "lwip/udp.h" -#include "lwip/snmp.h" - -#include "netif/ppp/ppp_impl.h" -#include "netif/ppp/lcp.h" -#include "netif/ppp/ipcp.h" -#include "netif/ppp/pppol2tp.h" -#include "netif/ppp/pppcrypt.h" -#include "netif/ppp/magic.h" - -/* Memory pool */ -LWIP_MEMPOOL_DECLARE(PPPOL2TP_PCB, MEMP_NUM_PPPOL2TP_INTERFACES, sizeof(pppol2tp_pcb), "PPPOL2TP_PCB") - -/* callbacks called from PPP core */ -static err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); -static err_t pppol2tp_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol); -static err_t pppol2tp_destroy(ppp_pcb *ppp, void *ctx); /* Destroy a L2TP control block */ -static err_t pppol2tp_connect(ppp_pcb *ppp, void *ctx); /* Be a LAC, connect to a LNS. */ -static void pppol2tp_disconnect(ppp_pcb *ppp, void *ctx); /* Disconnect */ - - /* Prototypes for procedures local to this file. */ -static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); -static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, struct pbuf *p, u16_t ns, u16_t nr); -static void pppol2tp_timeout(void *arg); -static void pppol2tp_abort_connect(pppol2tp_pcb *l2tp); -static void pppol2tp_clear(pppol2tp_pcb *l2tp); -static err_t pppol2tp_send_sccrq(pppol2tp_pcb *l2tp); -static err_t pppol2tp_send_scccn(pppol2tp_pcb *l2tp, u16_t ns); -static err_t pppol2tp_send_icrq(pppol2tp_pcb *l2tp, u16_t ns); -static err_t pppol2tp_send_iccn(pppol2tp_pcb *l2tp, u16_t ns); -static err_t pppol2tp_send_zlb(pppol2tp_pcb *l2tp, u16_t ns); -static err_t pppol2tp_send_stopccn(pppol2tp_pcb *l2tp, u16_t ns); -static err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb); -static err_t pppol2tp_udp_send(pppol2tp_pcb *l2tp, struct pbuf *pb); - -/* Callbacks structure for PPP core */ -static const struct link_callbacks pppol2tp_callbacks = { - pppol2tp_connect, -#if PPP_SERVER - NULL, -#endif /* PPP_SERVER */ - pppol2tp_disconnect, - pppol2tp_destroy, - pppol2tp_write, - pppol2tp_netif_output, - NULL, - NULL -}; - - -/* 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) { - ppp_pcb *ppp; - pppol2tp_pcb *l2tp; - struct udp_pcb *udp; - - if (ipaddr == NULL) { - goto ipaddr_check_failed; - } - - l2tp = (pppol2tp_pcb *)LWIP_MEMPOOL_ALLOC(PPPOL2TP_PCB); - if (l2tp == NULL) { - goto memp_malloc_l2tp_failed; - } - - udp = udp_new_ip_type(IP_GET_TYPE(ipaddr)); - if (udp == NULL) { - goto udp_new_failed; - } - udp_recv(udp, pppol2tp_input, l2tp); - - ppp = ppp_new(pppif, &pppol2tp_callbacks, l2tp, link_status_cb, ctx_cb); - if (ppp == NULL) { - goto ppp_new_failed; - } - - memset(l2tp, 0, sizeof(pppol2tp_pcb)); - l2tp->phase = PPPOL2TP_STATE_INITIAL; - l2tp->ppp = ppp; - l2tp->udp = udp; - l2tp->netif = netif; - ip_addr_copy(l2tp->remote_ip, *ipaddr); - l2tp->remote_port = port; -#if PPPOL2TP_AUTH_SUPPORT - l2tp->secret = secret; - l2tp->secret_len = secret_len; -#endif /* PPPOL2TP_AUTH_SUPPORT */ - - return ppp; - -ppp_new_failed: - udp_remove(udp); -udp_new_failed: - LWIP_MEMPOOL_FREE(PPPOL2TP_PCB, l2tp); -memp_malloc_l2tp_failed: -ipaddr_check_failed: - return NULL; -} - -/* Called by PPP core */ -static err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) { - pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; - struct pbuf *ph; /* UDP + L2TP header */ - err_t ret; -#if MIB2_STATS - u16_t tot_len; -#else /* MIB2_STATS */ - LWIP_UNUSED_ARG(ppp); -#endif /* MIB2_STATS */ - - ph = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(PPPOL2TP_OUTPUT_DATA_HEADER_LEN), PBUF_RAM); - if(!ph) { - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.proterr); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - pbuf_free(p); - return ERR_MEM; - } - - pbuf_header(ph, -(s16_t)PPPOL2TP_OUTPUT_DATA_HEADER_LEN); /* hide L2TP header */ - pbuf_cat(ph, p); -#if MIB2_STATS - tot_len = ph->tot_len; -#endif /* MIB2_STATS */ - - ret = pppol2tp_xmit(l2tp, ph); - if (ret != ERR_OK) { - LINK_STATS_INC(link.err); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - return ret; - } - - MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, (u16_t)tot_len); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); - LINK_STATS_INC(link.xmit); - return ERR_OK; -} - -/* Called by PPP core */ -static err_t pppol2tp_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol) { - pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; - struct pbuf *pb; - u8_t *pl; - err_t err; -#if MIB2_STATS - u16_t tot_len; -#else /* MIB2_STATS */ - LWIP_UNUSED_ARG(ppp); -#endif /* MIB2_STATS */ - - /* @todo: try to use pbuf_header() here! */ - pb = pbuf_alloc(PBUF_TRANSPORT, PPPOL2TP_OUTPUT_DATA_HEADER_LEN + sizeof(protocol), PBUF_RAM); - if(!pb) { - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.proterr); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - return ERR_MEM; - } - - pbuf_header(pb, -(s16_t)PPPOL2TP_OUTPUT_DATA_HEADER_LEN); - - pl = (u8_t*)pb->payload; - PUTSHORT(protocol, pl); - - pbuf_chain(pb, p); -#if MIB2_STATS - tot_len = pb->tot_len; -#endif /* MIB2_STATS */ - - if( (err = pppol2tp_xmit(l2tp, pb)) != ERR_OK) { - LINK_STATS_INC(link.err); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - return err; - } - - MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, tot_len); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); - LINK_STATS_INC(link.xmit); - return ERR_OK; -} - -/* Destroy a L2TP control block */ -static err_t pppol2tp_destroy(ppp_pcb *ppp, void *ctx) { - pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; - LWIP_UNUSED_ARG(ppp); - - sys_untimeout(pppol2tp_timeout, l2tp); - udp_remove(l2tp->udp); - LWIP_MEMPOOL_FREE(PPPOL2TP_PCB, l2tp); - return ERR_OK; -} - -/* Be a LAC, connect to a LNS. */ -static err_t pppol2tp_connect(ppp_pcb *ppp, void *ctx) { - err_t err; - pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; - lcp_options *lcp_wo; - lcp_options *lcp_ao; -#if PPP_IPV4_SUPPORT && VJ_SUPPORT - ipcp_options *ipcp_wo; - ipcp_options *ipcp_ao; -#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ - - if (l2tp->phase != PPPOL2TP_STATE_INITIAL) { - return ERR_VAL; - } - - pppol2tp_clear(l2tp); - - ppp_link_start(ppp); - - lcp_wo = &ppp->lcp_wantoptions; - lcp_wo->mru = PPPOL2TP_DEFMRU; - lcp_wo->neg_asyncmap = 0; - lcp_wo->neg_pcompression = 0; - lcp_wo->neg_accompression = 0; - lcp_wo->passive = 0; - lcp_wo->silent = 0; - - lcp_ao = &ppp->lcp_allowoptions; - lcp_ao->mru = PPPOL2TP_DEFMRU; - lcp_ao->neg_asyncmap = 0; - lcp_ao->neg_pcompression = 0; - lcp_ao->neg_accompression = 0; - -#if PPP_IPV4_SUPPORT && VJ_SUPPORT - ipcp_wo = &ppp->ipcp_wantoptions; - ipcp_wo->neg_vj = 0; - ipcp_wo->old_vj = 0; - - ipcp_ao = &ppp->ipcp_allowoptions; - ipcp_ao->neg_vj = 0; - ipcp_ao->old_vj = 0; -#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ - - /* Listen to a random source port, we need to do that instead of using udp_connect() - * because the L2TP LNS might answer with its own random source port (!= 1701) - */ -#if LWIP_IPV6 - if (IP_IS_V6_VAL(l2tp->udp->local_ip)) { - udp_bind(l2tp->udp, IP6_ADDR_ANY, 0); - } else -#endif /* LWIP_IPV6 */ - udp_bind(l2tp->udp, IP_ADDR_ANY, 0); - -#if PPPOL2TP_AUTH_SUPPORT - /* Generate random vector */ - if (l2tp->secret != NULL) { - magic_random_bytes(l2tp->secret_rv, sizeof(l2tp->secret_rv)); - } -#endif /* PPPOL2TP_AUTH_SUPPORT */ - - do { - l2tp->remote_tunnel_id = magic(); - } while(l2tp->remote_tunnel_id == 0); - /* save state, in case we fail to send SCCRQ */ - l2tp->sccrq_retried = 0; - l2tp->phase = PPPOL2TP_STATE_SCCRQ_SENT; - if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); - } - sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); - return err; -} - -/* Disconnect */ -static void pppol2tp_disconnect(ppp_pcb *ppp, void *ctx) { - pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; - - if (l2tp->phase < PPPOL2TP_STATE_DATA) { - return; - } - - l2tp->our_ns++; - pppol2tp_send_stopccn(l2tp, l2tp->our_ns); - - pppol2tp_clear(l2tp); - ppp_link_end(ppp); /* notify upper layers */ -} - -/* UDP Callback for incoming IPv4 L2TP frames */ -static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { - pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; - u16_t hflags, hlen, len=0, tunnel_id=0, session_id=0, ns=0, nr=0, offset=0; - u8_t *inp; - LWIP_UNUSED_ARG(pcb); - - if (l2tp->phase < PPPOL2TP_STATE_SCCRQ_SENT) { - goto free_and_return; - } - - if (!ip_addr_cmp(&l2tp->remote_ip, addr)) { - goto free_and_return; - } - - /* discard packet if port mismatch, but only if we received a SCCRP */ - if (l2tp->phase > PPPOL2TP_STATE_SCCRQ_SENT && l2tp->tunnel_port != port) { - goto free_and_return; - } - - /* printf("-----------\nL2TP INPUT, %d\n", p->len); */ - - /* L2TP header */ - if (p->len < sizeof(hflags) + sizeof(tunnel_id) + sizeof(session_id) ) { - goto packet_too_short; - } - - inp = (u8_t*)p->payload; - GETSHORT(hflags, inp); - - if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { - /* check mandatory flags for a control packet */ - if ( (hflags & PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY) != PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY ) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: mandatory header flags for control packet not set\n")); - goto free_and_return; - } - /* check forbidden flags for a control packet */ - if (hflags & PPPOL2TP_HEADERFLAG_CONTROL_FORBIDDEN) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: forbidden header flags for control packet found\n")); - goto free_and_return; - } - } else { - /* check mandatory flags for a data packet */ - if ( (hflags & PPPOL2TP_HEADERFLAG_DATA_MANDATORY) != PPPOL2TP_HEADERFLAG_DATA_MANDATORY) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: mandatory header flags for data packet not set\n")); - goto free_and_return; - } - } - - /* Expected header size */ - hlen = sizeof(hflags) + sizeof(tunnel_id) + sizeof(session_id); - if (hflags & PPPOL2TP_HEADERFLAG_LENGTH) { - hlen += sizeof(len); - } - if (hflags & PPPOL2TP_HEADERFLAG_SEQUENCE) { - hlen += sizeof(ns) + sizeof(nr); - } - if (hflags & PPPOL2TP_HEADERFLAG_OFFSET) { - hlen += sizeof(offset); - } - if (p->len < hlen) { - goto packet_too_short; - } - - if (hflags & PPPOL2TP_HEADERFLAG_LENGTH) { - GETSHORT(len, inp); - if (p->len < len || len < hlen) { - goto packet_too_short; - } - } - GETSHORT(tunnel_id, inp); - GETSHORT(session_id, inp); - if (hflags & PPPOL2TP_HEADERFLAG_SEQUENCE) { - GETSHORT(ns, inp); - GETSHORT(nr, inp); - } - if (hflags & PPPOL2TP_HEADERFLAG_OFFSET) { - GETSHORT(offset, inp) - if (offset > 4096) { /* don't be fooled with large offset which might overflow hlen */ - PPPDEBUG(LOG_DEBUG, ("pppol2tp: strange packet received, offset=%d\n", offset)); - goto free_and_return; - } - hlen += offset; - if (p->len < hlen) { - goto packet_too_short; - } - INCPTR(offset, inp); - } - - /* printf("HLEN = %d\n", hlen); */ - - /* skip L2TP header */ - if (pbuf_header(p, -(s16_t)hlen) != 0) { - goto free_and_return; - } - - /* printf("LEN=%d, TUNNEL_ID=%d, SESSION_ID=%d, NS=%d, NR=%d, OFFSET=%d\n", len, tunnel_id, session_id, ns, nr, offset); */ - PPPDEBUG(LOG_DEBUG, ("pppol2tp: input packet, len=%"U16_F", tunnel=%"U16_F", session=%"U16_F", ns=%"U16_F", nr=%"U16_F"\n", - len, tunnel_id, session_id, ns, nr)); - - /* Control packet */ - if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { - pppol2tp_dispatch_control_packet(l2tp, port, p, ns, nr); - goto free_and_return; - } - - /* Data packet */ - if(l2tp->phase != PPPOL2TP_STATE_DATA) { - goto free_and_return; - } - if(tunnel_id != l2tp->remote_tunnel_id) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: tunnel ID mismatch, assigned=%d, received=%d\n", l2tp->remote_tunnel_id, tunnel_id)); - goto free_and_return; - } - if(session_id != l2tp->remote_session_id) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: session ID mismatch, assigned=%d, received=%d\n", l2tp->remote_session_id, session_id)); - goto free_and_return; - } - /* - * skip address & flags if necessary - * - * RFC 2661 does not specify whether the PPP frame in the L2TP payload should - * have a HDLC header or not. We handle both cases for compatibility. - */ - if (p->len >= 2) { - GETSHORT(hflags, inp); - if (hflags == 0xff03) { - pbuf_header(p, -(s16_t)2); - } - } - /* Dispatch the packet thereby consuming it. */ - ppp_input(l2tp->ppp, p); - return; - -packet_too_short: - PPPDEBUG(LOG_DEBUG, ("pppol2tp: packet too short: %d\n", p->len)); -free_and_return: - pbuf_free(p); -} - -/* L2TP Control packet entry point */ -static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, struct pbuf *p, u16_t ns, u16_t nr) { - u8_t *inp; - u16_t avplen, avpflags, vendorid, attributetype, messagetype=0; - err_t err; -#if PPPOL2TP_AUTH_SUPPORT - lwip_md5_context md5_ctx; - u8_t md5_hash[16]; - u8_t challenge_id = 0; -#endif /* PPPOL2TP_AUTH_SUPPORT */ - - l2tp->peer_nr = nr; - l2tp->peer_ns = ns; - /* printf("L2TP CTRL INPUT, ns=%d, nr=%d, len=%d\n", ns, nr, p->len); */ - - /* Handle the special case of the ICCN acknowledge */ - if (l2tp->phase == PPPOL2TP_STATE_ICCN_SENT && l2tp->peer_nr > l2tp->our_ns) { - l2tp->phase = PPPOL2TP_STATE_DATA; - } - - /* ZLB packets */ - if (p->tot_len == 0) { - return; - } - - p = ppp_singlebuf(p); - inp = (u8_t*)p->payload; - /* Decode AVPs */ - while (p->len > 0) { - if (p->len < sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype) ) { - goto packet_too_short; - } - GETSHORT(avpflags, inp); - avplen = avpflags & PPPOL2TP_AVPHEADERFLAG_LENGTHMASK; - /* printf("AVPLEN = %d\n", avplen); */ - if (p->len < avplen || avplen < sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype)) { - goto packet_too_short; - } - GETSHORT(vendorid, inp); - GETSHORT(attributetype, inp); - avplen -= sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype); - - /* Message type must be the first AVP */ - if (messagetype == 0) { - if (attributetype != 0 || vendorid != 0 || avplen != sizeof(messagetype) ) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: message type must be the first AVP\n")); - return; - } - GETSHORT(messagetype, inp); - /* printf("Message type = %d\n", messagetype); */ - switch(messagetype) { - /* Start Control Connection Reply */ - case PPPOL2TP_MESSAGETYPE_SCCRP: - /* Only accept SCCRP packet if we sent a SCCRQ */ - if (l2tp->phase != PPPOL2TP_STATE_SCCRQ_SENT) { - goto send_zlb; - } - break; - /* Incoming Call Reply */ - case PPPOL2TP_MESSAGETYPE_ICRP: - /* Only accept ICRP packet if we sent a IRCQ */ - if (l2tp->phase != PPPOL2TP_STATE_ICRQ_SENT) { - goto send_zlb; - } - break; - /* Stop Control Connection Notification */ - case PPPOL2TP_MESSAGETYPE_STOPCCN: - pppol2tp_send_zlb(l2tp, l2tp->our_ns); /* Ack the StopCCN before we switch to down state */ - if (l2tp->phase < PPPOL2TP_STATE_DATA) { - pppol2tp_abort_connect(l2tp); - } else if (l2tp->phase == PPPOL2TP_STATE_DATA) { - /* Don't disconnect here, we let the LCP Echo/Reply find the fact - * that PPP session is down. Asking the PPP stack to end the session - * require strict checking about the PPP phase to prevent endless - * disconnection loops. - */ - } - return; - default: - break; - } - goto nextavp; - } - - /* Skip proprietary L2TP extensions */ - if (vendorid != 0) { - goto skipavp; - } - - switch (messagetype) { - /* Start Control Connection Reply */ - case PPPOL2TP_MESSAGETYPE_SCCRP: - switch (attributetype) { - case PPPOL2TP_AVPTYPE_TUNNELID: - if (avplen != sizeof(l2tp->source_tunnel_id) ) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Assign tunnel ID length check failed\n")); - return; - } - GETSHORT(l2tp->source_tunnel_id, inp); - PPPDEBUG(LOG_DEBUG, ("pppol2tp: Assigned tunnel ID %"U16_F"\n", l2tp->source_tunnel_id)); - goto nextavp; -#if PPPOL2TP_AUTH_SUPPORT - case PPPOL2TP_AVPTYPE_CHALLENGE: - if (avplen == 0) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: Challenge length check failed\n")); - return; - } - if (l2tp->secret == NULL) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: Received challenge from peer and no secret key available\n")); - pppol2tp_abort_connect(l2tp); - return; - } - /* Generate hash of ID, secret, challenge */ - lwip_md5_init(&md5_ctx); - lwip_md5_starts(&md5_ctx); - challenge_id = PPPOL2TP_MESSAGETYPE_SCCCN; - lwip_md5_update(&md5_ctx, &challenge_id, 1); - lwip_md5_update(&md5_ctx, l2tp->secret, l2tp->secret_len); - lwip_md5_update(&md5_ctx, inp, avplen); - lwip_md5_finish(&md5_ctx, l2tp->challenge_hash); - lwip_md5_free(&md5_ctx); - l2tp->send_challenge = 1; - goto skipavp; - case PPPOL2TP_AVPTYPE_CHALLENGERESPONSE: - if (avplen != PPPOL2TP_AVPTYPE_CHALLENGERESPONSE_SIZE) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Challenge Response length check failed\n")); - return; - } - /* Generate hash of ID, secret, challenge */ - lwip_md5_init(&md5_ctx); - lwip_md5_starts(&md5_ctx); - challenge_id = PPPOL2TP_MESSAGETYPE_SCCRP; - lwip_md5_update(&md5_ctx, &challenge_id, 1); - lwip_md5_update(&md5_ctx, l2tp->secret, l2tp->secret_len); - lwip_md5_update(&md5_ctx, l2tp->secret_rv, sizeof(l2tp->secret_rv)); - lwip_md5_finish(&md5_ctx, md5_hash); - lwip_md5_free(&md5_ctx); - if ( memcmp(inp, md5_hash, sizeof(md5_hash)) ) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: Received challenge response from peer and secret key do not match\n")); - pppol2tp_abort_connect(l2tp); - return; - } - goto skipavp; -#endif /* PPPOL2TP_AUTH_SUPPORT */ - default: - break; - } - break; - /* Incoming Call Reply */ - case PPPOL2TP_MESSAGETYPE_ICRP: - switch (attributetype) { - case PPPOL2TP_AVPTYPE_SESSIONID: - if (avplen != sizeof(l2tp->source_session_id) ) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Assign session ID length check failed\n")); - return; - } - GETSHORT(l2tp->source_session_id, inp); - PPPDEBUG(LOG_DEBUG, ("pppol2tp: Assigned session ID %"U16_F"\n", l2tp->source_session_id)); - goto nextavp; - default: - break; - } - break; - default: - break; - } - -skipavp: - INCPTR(avplen, inp); -nextavp: - /* printf("AVP Found, vendor=%d, attribute=%d, len=%d\n", vendorid, attributetype, avplen); */ - /* next AVP */ - if (pbuf_header(p, -(s16_t)(avplen + sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype)) ) != 0) { - return; - } - } - - switch(messagetype) { - /* Start Control Connection Reply */ - case PPPOL2TP_MESSAGETYPE_SCCRP: - do { - l2tp->remote_session_id = magic(); - } while(l2tp->remote_session_id == 0); - l2tp->tunnel_port = port; /* LNS server might have chosen its own local port */ - l2tp->icrq_retried = 0; - l2tp->phase = PPPOL2TP_STATE_ICRQ_SENT; - l2tp->our_ns++; - if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns)) != 0) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); - } - l2tp->our_ns++; - if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); - } - sys_untimeout(pppol2tp_timeout, l2tp); - sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); - break; - /* Incoming Call Reply */ - case PPPOL2TP_MESSAGETYPE_ICRP: - l2tp->iccn_retried = 0; - l2tp->phase = PPPOL2TP_STATE_ICCN_SENT; - l2tp->our_ns++; - ppp_start(l2tp->ppp); /* notify upper layers */ - if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); - } - sys_untimeout(pppol2tp_timeout, l2tp); - sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); - break; - /* Unhandled packet, send ZLB ACK */ - default: - goto send_zlb; - } - return; - -send_zlb: - pppol2tp_send_zlb(l2tp, l2tp->our_ns); - return; -packet_too_short: - PPPDEBUG(LOG_DEBUG, ("pppol2tp: packet too short: %d\n", p->len)); -} - -/* L2TP Timeout handler */ -static void pppol2tp_timeout(void *arg) { - pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; - err_t err; - u32_t retry_wait; - - PPPDEBUG(LOG_DEBUG, ("pppol2tp: timeout\n")); - - switch (l2tp->phase) { - case PPPOL2TP_STATE_SCCRQ_SENT: - /* backoff wait */ - if (l2tp->sccrq_retried < 0xff) { - l2tp->sccrq_retried++; - } - if (!l2tp->ppp->settings.persist && l2tp->sccrq_retried >= PPPOL2TP_MAXSCCRQ) { - pppol2tp_abort_connect(l2tp); - return; - } - retry_wait = LWIP_MIN(PPPOL2TP_CONTROL_TIMEOUT * l2tp->sccrq_retried, PPPOL2TP_SLOW_RETRY); - PPPDEBUG(LOG_DEBUG, ("pppol2tp: sccrq_retried=%d\n", l2tp->sccrq_retried)); - if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { - l2tp->sccrq_retried--; - PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); - } - sys_timeout(retry_wait, pppol2tp_timeout, l2tp); - break; - - case PPPOL2TP_STATE_ICRQ_SENT: - l2tp->icrq_retried++; - if (l2tp->icrq_retried >= PPPOL2TP_MAXICRQ) { - pppol2tp_abort_connect(l2tp); - return; - } - PPPDEBUG(LOG_DEBUG, ("pppol2tp: icrq_retried=%d\n", l2tp->icrq_retried)); - if (l2tp->peer_nr <= l2tp->our_ns -1) { /* the SCCCN was not acknowledged */ - if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns -1)) != 0) { - l2tp->icrq_retried--; - PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); - sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); - break; - } - } - if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { - l2tp->icrq_retried--; - PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); - } - sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); - break; - - case PPPOL2TP_STATE_ICCN_SENT: - l2tp->iccn_retried++; - if (l2tp->iccn_retried >= PPPOL2TP_MAXICCN) { - pppol2tp_abort_connect(l2tp); - return; - } - PPPDEBUG(LOG_DEBUG, ("pppol2tp: iccn_retried=%d\n", l2tp->iccn_retried)); - if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { - l2tp->iccn_retried--; - PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); - } - sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); - break; - - default: - return; /* all done, work in peace */ - } -} - -/* Connection attempt aborted */ -static void pppol2tp_abort_connect(pppol2tp_pcb *l2tp) { - PPPDEBUG(LOG_DEBUG, ("pppol2tp: could not establish connection\n")); - pppol2tp_clear(l2tp); - ppp_link_failed(l2tp->ppp); /* notify upper layers */ -} - -/* Reset L2TP control block to its initial state */ -static void pppol2tp_clear(pppol2tp_pcb *l2tp) { - /* stop any timer */ - sys_untimeout(pppol2tp_timeout, l2tp); - l2tp->phase = PPPOL2TP_STATE_INITIAL; - l2tp->tunnel_port = l2tp->remote_port; - l2tp->our_ns = 0; - l2tp->peer_nr = 0; - l2tp->peer_ns = 0; - l2tp->source_tunnel_id = 0; - l2tp->remote_tunnel_id = 0; - l2tp->source_session_id = 0; - l2tp->remote_session_id = 0; - /* l2tp->*_retried are cleared when used */ -} - -/* Initiate a new tunnel */ -static err_t pppol2tp_send_sccrq(pppol2tp_pcb *l2tp) { - struct pbuf *pb; - u8_t *p; - u16_t len; - - /* calculate UDP packet length */ - len = 12 +8 +8 +10 +10 +6+sizeof(PPPOL2TP_HOSTNAME)-1 +6+sizeof(PPPOL2TP_VENDORNAME)-1 +8 +8; -#if PPPOL2TP_AUTH_SUPPORT - if (l2tp->secret != NULL) { - len += 6 + sizeof(l2tp->secret_rv); - } -#endif /* PPPOL2TP_AUTH_SUPPORT */ - - /* allocate a buffer */ - pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - if (pb == NULL) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - - p = (u8_t*)pb->payload; - /* fill in pkt */ - /* L2TP control header */ - PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); - PUTSHORT(len, p); /* Length */ - PUTSHORT(0, p); /* Tunnel Id */ - PUTSHORT(0, p); /* Session Id */ - PUTSHORT(0, p); /* NS Sequence number - to peer */ - PUTSHORT(0, p); /* NR Sequence number - expected for peer */ - - /* AVP - Message type */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ - PUTSHORT(PPPOL2TP_MESSAGETYPE_SCCRQ, p); /* Attribute value: Message type: SCCRQ */ - - /* AVP - L2TP Version */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_VERSION, p); /* Attribute type: Version */ - PUTSHORT(PPPOL2TP_VERSION, p); /* Attribute value: L2TP Version */ - - /* AVP - Framing capabilities */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_FRAMINGCAPABILITIES, p); /* Attribute type: Framing capabilities */ - PUTLONG(PPPOL2TP_FRAMINGCAPABILITIES, p); /* Attribute value: Framing capabilities */ - - /* AVP - Bearer capabilities */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_BEARERCAPABILITIES, p); /* Attribute type: Bearer capabilities */ - PUTLONG(PPPOL2TP_BEARERCAPABILITIES, p); /* Attribute value: Bearer capabilities */ - - /* AVP - Host name */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6+sizeof(PPPOL2TP_HOSTNAME)-1, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_HOSTNAME, p); /* Attribute type: Hostname */ - MEMCPY(p, PPPOL2TP_HOSTNAME, sizeof(PPPOL2TP_HOSTNAME)-1); /* Attribute value: Hostname */ - INCPTR(sizeof(PPPOL2TP_HOSTNAME)-1, p); - - /* AVP - Vendor name */ - PUTSHORT(6+sizeof(PPPOL2TP_VENDORNAME)-1, p); /* len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_VENDORNAME, p); /* Attribute type: Vendor name */ - MEMCPY(p, PPPOL2TP_VENDORNAME, sizeof(PPPOL2TP_VENDORNAME)-1); /* Attribute value: Vendor name */ - INCPTR(sizeof(PPPOL2TP_VENDORNAME)-1, p); - - /* AVP - Assign tunnel ID */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_TUNNELID, p); /* Attribute type: Tunnel ID */ - PUTSHORT(l2tp->remote_tunnel_id, p); /* Attribute value: Tunnel ID */ - - /* AVP - Receive window size */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_RECEIVEWINDOWSIZE, p); /* Attribute type: Receive window size */ - PUTSHORT(PPPOL2TP_RECEIVEWINDOWSIZE, p); /* Attribute value: Receive window size */ - -#if PPPOL2TP_AUTH_SUPPORT - /* AVP - Challenge */ - if (l2tp->secret != NULL) { - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6 + sizeof(l2tp->secret_rv), p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_CHALLENGE, p); /* Attribute type: Challenge */ - MEMCPY(p, l2tp->secret_rv, sizeof(l2tp->secret_rv)); /* Attribute value: Random vector */ - INCPTR(sizeof(l2tp->secret_rv), p); - } -#endif /* PPPOL2TP_AUTH_SUPPORT */ - - return pppol2tp_udp_send(l2tp, pb); -} - -/* Complete tunnel establishment */ -static err_t pppol2tp_send_scccn(pppol2tp_pcb *l2tp, u16_t ns) { - struct pbuf *pb; - u8_t *p; - u16_t len; - - /* calculate UDP packet length */ - len = 12 +8; -#if PPPOL2TP_AUTH_SUPPORT - if (l2tp->send_challenge) { - len += 6 + sizeof(l2tp->challenge_hash); - } -#endif /* PPPOL2TP_AUTH_SUPPORT */ - - /* allocate a buffer */ - pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - if (pb == NULL) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - - p = (u8_t*)pb->payload; - /* fill in pkt */ - /* L2TP control header */ - PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); - PUTSHORT(len, p); /* Length */ - PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ - PUTSHORT(0, p); /* Session Id */ - PUTSHORT(ns, p); /* NS Sequence number - to peer */ - PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ - - /* AVP - Message type */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ - PUTSHORT(PPPOL2TP_MESSAGETYPE_SCCCN, p); /* Attribute value: Message type: SCCCN */ - -#if PPPOL2TP_AUTH_SUPPORT - /* AVP - Challenge response */ - if (l2tp->send_challenge) { - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6 + sizeof(l2tp->challenge_hash), p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_CHALLENGERESPONSE, p); /* Attribute type: Challenge response */ - MEMCPY(p, l2tp->challenge_hash, sizeof(l2tp->challenge_hash)); /* Attribute value: Computed challenge */ - INCPTR(sizeof(l2tp->challenge_hash), p); - } -#endif /* PPPOL2TP_AUTH_SUPPORT */ - - return pppol2tp_udp_send(l2tp, pb); -} - -/* Initiate a new session */ -static err_t pppol2tp_send_icrq(pppol2tp_pcb *l2tp, u16_t ns) { - struct pbuf *pb; - u8_t *p; - u16_t len; - u32_t serialnumber; - - /* calculate UDP packet length */ - len = 12 +8 +8 +10; - - /* allocate a buffer */ - pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - if (pb == NULL) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - - p = (u8_t*)pb->payload; - /* fill in pkt */ - /* L2TP control header */ - PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); - PUTSHORT(len, p); /* Length */ - PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ - PUTSHORT(0, p); /* Session Id */ - PUTSHORT(ns, p); /* NS Sequence number - to peer */ - PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ - - /* AVP - Message type */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ - PUTSHORT(PPPOL2TP_MESSAGETYPE_ICRQ, p); /* Attribute value: Message type: ICRQ */ - - /* AVP - Assign session ID */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_SESSIONID, p); /* Attribute type: Session ID */ - PUTSHORT(l2tp->remote_session_id, p); /* Attribute value: Session ID */ - - /* AVP - Call Serial Number */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_CALLSERIALNUMBER, p); /* Attribute type: Serial number */ - serialnumber = magic(); - PUTLONG(serialnumber, p); /* Attribute value: Serial number */ - - return pppol2tp_udp_send(l2tp, pb); -} - -/* Complete tunnel establishment */ -static err_t pppol2tp_send_iccn(pppol2tp_pcb *l2tp, u16_t ns) { - struct pbuf *pb; - u8_t *p; - u16_t len; - - /* calculate UDP packet length */ - len = 12 +8 +10 +10; - - /* allocate a buffer */ - pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - if (pb == NULL) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - - p = (u8_t*)pb->payload; - /* fill in pkt */ - /* L2TP control header */ - PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); - PUTSHORT(len, p); /* Length */ - PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ - PUTSHORT(l2tp->source_session_id, p); /* Session Id */ - PUTSHORT(ns, p); /* NS Sequence number - to peer */ - PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ - - /* AVP - Message type */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ - PUTSHORT(PPPOL2TP_MESSAGETYPE_ICCN, p); /* Attribute value: Message type: ICCN */ - - /* AVP - Framing type */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_FRAMINGTYPE, p); /* Attribute type: Framing type */ - PUTLONG(PPPOL2TP_FRAMINGTYPE, p); /* Attribute value: Framing type */ - - /* AVP - TX Connect speed */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_TXCONNECTSPEED, p); /* Attribute type: TX Connect speed */ - PUTLONG(PPPOL2TP_TXCONNECTSPEED, p); /* Attribute value: TX Connect speed */ - - return pppol2tp_udp_send(l2tp, pb); -} - -/* Send a ZLB ACK packet */ -static err_t pppol2tp_send_zlb(pppol2tp_pcb *l2tp, u16_t ns) { - struct pbuf *pb; - u8_t *p; - u16_t len; - - /* calculate UDP packet length */ - len = 12; - - /* allocate a buffer */ - pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - if (pb == NULL) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - - p = (u8_t*)pb->payload; - /* fill in pkt */ - /* L2TP control header */ - PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); - PUTSHORT(len, p); /* Length */ - PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ - PUTSHORT(0, p); /* Session Id */ - PUTSHORT(ns, p); /* NS Sequence number - to peer */ - PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ - - return pppol2tp_udp_send(l2tp, pb); -} - -/* Send a StopCCN packet */ -static err_t pppol2tp_send_stopccn(pppol2tp_pcb *l2tp, u16_t ns) { - struct pbuf *pb; - u8_t *p; - u16_t len; - - /* calculate UDP packet length */ - len = 12 +8 +8 +8; - - /* allocate a buffer */ - pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - if (pb == NULL) { - return ERR_MEM; - } - LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); - - p = (u8_t*)pb->payload; - /* fill in pkt */ - /* L2TP control header */ - PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); - PUTSHORT(len, p); /* Length */ - PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ - PUTSHORT(0, p); /* Session Id */ - PUTSHORT(ns, p); /* NS Sequence number - to peer */ - PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ - - /* AVP - Message type */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ - PUTSHORT(PPPOL2TP_MESSAGETYPE_STOPCCN, p); /* Attribute value: Message type: StopCCN */ - - /* AVP - Assign tunnel ID */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_TUNNELID, p); /* Attribute type: Tunnel ID */ - PUTSHORT(l2tp->remote_tunnel_id, p); /* Attribute value: Tunnel ID */ - - /* AVP - Result code */ - PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ - PUTSHORT(0, p); /* Vendor ID */ - PUTSHORT(PPPOL2TP_AVPTYPE_RESULTCODE, p); /* Attribute type: Result code */ - PUTSHORT(PPPOL2TP_RESULTCODE, p); /* Attribute value: Result code */ - - return pppol2tp_udp_send(l2tp, pb); -} - -static err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb) { - u8_t *p; - - /* are we ready to process data yet? */ - if (l2tp->phase < PPPOL2TP_STATE_DATA) { - pbuf_free(pb); - return ERR_CONN; - } - - /* make room for L2TP header - should not fail */ - if (pbuf_header(pb, (s16_t)PPPOL2TP_OUTPUT_DATA_HEADER_LEN) != 0) { - /* bail out */ - PPPDEBUG(LOG_ERR, ("pppol2tp: pppol2tp_pcb: could not allocate room for L2TP header\n")); - LINK_STATS_INC(link.lenerr); - pbuf_free(pb); - return ERR_BUF; - } - - p = (u8_t*)pb->payload; - PUTSHORT(PPPOL2TP_HEADERFLAG_DATA_MANDATORY, p); - PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ - PUTSHORT(l2tp->source_session_id, p); /* Session Id */ - - return pppol2tp_udp_send(l2tp, pb); -} - -static err_t pppol2tp_udp_send(pppol2tp_pcb *l2tp, struct pbuf *pb) { - err_t err; - if (l2tp->netif) { - err = udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->tunnel_port, l2tp->netif); - } else { - err = udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->tunnel_port); - } - pbuf_free(pb); - return err; -} - -#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/pppos.c b/ext/lwip/src/netif/ppp/pppos.c deleted file mode 100644 index 006971d..0000000 --- a/ext/lwip/src/netif/ppp/pppos.c +++ /dev/null @@ -1,877 +0,0 @@ -/** - * @file - * Network Point to Point Protocol over Serial 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 */ - -#include -#include - -#include "lwip/err.h" -#include "lwip/pbuf.h" -#include "lwip/sys.h" -#include "lwip/memp.h" -#include "lwip/netif.h" -#include "lwip/snmp.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/api.h" -#include "lwip/ip4.h" /* for ip4_input() */ - -#include "netif/ppp/ppp_impl.h" -#include "netif/ppp/pppos.h" -#include "netif/ppp/vj.h" - -/* Memory pool */ -LWIP_MEMPOOL_DECLARE(PPPOS_PCB, MEMP_NUM_PPPOS_INTERFACES, sizeof(pppos_pcb), "PPPOS_PCB") - -/* callbacks called from PPP core */ -static err_t pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); -static err_t pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol); -static err_t pppos_connect(ppp_pcb *ppp, void *ctx); -#if PPP_SERVER -static err_t pppos_listen(ppp_pcb *ppp, void *ctx); -#endif /* PPP_SERVER */ -static void pppos_disconnect(ppp_pcb *ppp, void *ctx); -static err_t pppos_destroy(ppp_pcb *ppp, void *ctx); -static void pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp); -static void pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp); - -/* Prototypes for procedures local to this file. */ -#if PPP_INPROC_IRQ_SAFE -static void pppos_input_callback(void *arg); -#endif /* PPP_INPROC_IRQ_SAFE */ -static void pppos_input_free_current_packet(pppos_pcb *pppos); -static void pppos_input_drop(pppos_pcb *pppos); -static err_t pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs); -static err_t pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs); - -/* Callbacks structure for PPP core */ -static const struct link_callbacks pppos_callbacks = { - pppos_connect, -#if PPP_SERVER - pppos_listen, -#endif /* PPP_SERVER */ - pppos_disconnect, - pppos_destroy, - pppos_write, - pppos_netif_output, - pppos_send_config, - pppos_recv_config -}; - -/* PPP's Asynchronous-Control-Character-Map. The mask array is used - * to select the specific bit for a character. */ -#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & 1 << (c & 0x07)) - -#if PPP_FCS_TABLE -/* - * FCS lookup table as calculated by genfcstab. - */ -static const u16_t fcstab[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; -#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) -#else /* PPP_FCS_TABLE */ -/* The HDLC polynomial: X**0 + X**5 + X**12 + X**16 (0x8408) */ -#define PPP_FCS_POLYNOMIAL 0x8408 -static u16_t -ppp_get_fcs(u8_t byte) -{ - unsigned int octet; - int bit; - octet = byte; - for (bit = 8; bit-- > 0; ) { - octet = (octet & 0x01) ? ((octet >> 1) ^ PPP_FCS_POLYNOMIAL) : (octet >> 1); - } - return octet & 0xffff; -} -#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_get_fcs(((fcs) ^ (c)) & 0xff)) -#endif /* PPP_FCS_TABLE */ - -/* - * Values for FCS calculations. - */ -#define PPP_INITFCS 0xffff /* Initial FCS value */ -#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ - -#if PPP_INPROC_IRQ_SAFE -#define PPPOS_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) -#define PPPOS_PROTECT(lev) SYS_ARCH_PROTECT(lev) -#define PPPOS_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) -#else -#define PPPOS_DECL_PROTECT(lev) -#define PPPOS_PROTECT(lev) -#define PPPOS_UNPROTECT(lev) -#endif /* PPP_INPROC_IRQ_SAFE */ - - -/* - * Create a new PPP connection using the given serial I/O device. - * - * Return 0 on success, an error code on failure. - */ -ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, - ppp_link_status_cb_fn link_status_cb, void *ctx_cb) -{ - pppos_pcb *pppos; - ppp_pcb *ppp; - - pppos = (pppos_pcb *)LWIP_MEMPOOL_ALLOC(PPPOS_PCB); - if (pppos == NULL) { - return NULL; - } - - ppp = ppp_new(pppif, &pppos_callbacks, pppos, link_status_cb, ctx_cb); - if (ppp == NULL) { - LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos); - return NULL; - } - - memset(pppos, 0, sizeof(pppos_pcb)); - pppos->ppp = ppp; - pppos->output_cb = output_cb; - return ppp; -} - -/* Called by PPP core */ -static err_t -pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) -{ - pppos_pcb *pppos = (pppos_pcb *)ctx; - u8_t *s; - struct pbuf *nb; - u16_t n; - u16_t fcs_out; - err_t err; - LWIP_UNUSED_ARG(ppp); - - /* Grab an output buffer. */ - nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); - if (nb == NULL) { - PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num)); - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - pbuf_free(p); - return ERR_MEM; - } - - /* If the link has been idle, we'll send a fresh flag character to - * flush any noise. */ - err = ERR_OK; - if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) { - err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); - } - - /* Load output buffer. */ - fcs_out = PPP_INITFCS; - s = (u8_t*)p->payload; - n = p->len; - while (n-- > 0) { - err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out); - } - - err = pppos_output_last(pppos, err, nb, &fcs_out); - if (err == ERR_OK) { - PPPDEBUG(LOG_INFO, ("pppos_write[%d]: len=%d\n", ppp->netif->num, p->len)); - } else { - PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: output failed len=%d\n", ppp->netif->num, p->len)); - } - pbuf_free(p); - return err; -} - -/* Called by PPP core */ -static err_t -pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol) -{ - pppos_pcb *pppos = (pppos_pcb *)ctx; - struct pbuf *nb, *p; - u16_t fcs_out; - err_t err; - LWIP_UNUSED_ARG(ppp); - - /* Grab an output buffer. */ - nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); - if (nb == NULL) { - PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num)); - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - return ERR_MEM; - } - - /* If the link has been idle, we'll send a fresh flag character to - * flush any noise. */ - err = ERR_OK; - if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) { - err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); - } - - fcs_out = PPP_INITFCS; - if (!pppos->accomp) { - err = pppos_output_append(pppos, err, nb, PPP_ALLSTATIONS, 1, &fcs_out); - err = pppos_output_append(pppos, err, nb, PPP_UI, 1, &fcs_out); - } - if (!pppos->pcomp || protocol > 0xFF) { - err = pppos_output_append(pppos, err, nb, (protocol >> 8) & 0xFF, 1, &fcs_out); - } - err = pppos_output_append(pppos, err, nb, protocol & 0xFF, 1, &fcs_out); - - /* Load packet. */ - for(p = pb; p; p = p->next) { - u16_t n = p->len; - u8_t *s = (u8_t*)p->payload; - - while (n-- > 0) { - err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out); - } - } - - err = pppos_output_last(pppos, err, nb, &fcs_out); - if (err == ERR_OK) { - PPPDEBUG(LOG_INFO, ("pppos_netif_output[%d]: proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len)); - } else { - PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: output failed proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len)); - } - return err; -} - -static err_t -pppos_connect(ppp_pcb *ppp, void *ctx) -{ - pppos_pcb *pppos = (pppos_pcb *)ctx; - PPPOS_DECL_PROTECT(lev); - -#if PPP_INPROC_IRQ_SAFE - /* input pbuf left over from last session? */ - pppos_input_free_current_packet(pppos); -#endif /* PPP_INPROC_IRQ_SAFE */ - - ppp_link_start(ppp); - /* reset PPPoS control block to its initial state */ - memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit)); - - /* - * Default the in and out accm so that escape and flag characters - * are always escaped. - */ - pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */ - pppos->out_accm[15] = 0x60; - PPPOS_PROTECT(lev); - pppos->open = 1; - PPPOS_UNPROTECT(lev); - - /* - * Start the connection and handle incoming events (packet or timeout). - */ - PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num)); - ppp_start(ppp); /* notify upper layers */ - return ERR_OK; -} - -#if PPP_SERVER -static err_t -pppos_listen(ppp_pcb *ppp, void *ctx) -{ - pppos_pcb *pppos = (pppos_pcb *)ctx; - PPPOS_DECL_PROTECT(lev); - -#if PPP_INPROC_IRQ_SAFE - /* input pbuf left over from last session? */ - pppos_input_free_current_packet(pppos); -#endif /* PPP_INPROC_IRQ_SAFE */ - - ppp_link_start(ppp); - /* reset PPPoS control block to its initial state */ - memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit)); - - /* - * Default the in and out accm so that escape and flag characters - * are always escaped. - */ - pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */ - pppos->out_accm[15] = 0x60; - PPPOS_PROTECT(lev); - pppos->open = 1; - PPPOS_UNPROTECT(lev); - - /* - * Wait for something to happen. - */ - PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num)); - ppp_start(ppp); /* notify upper layers */ - return ERR_OK; -} -#endif /* PPP_SERVER */ - -static void -pppos_disconnect(ppp_pcb *ppp, void *ctx) -{ - pppos_pcb *pppos = (pppos_pcb *)ctx; - PPPOS_DECL_PROTECT(lev); - - PPPOS_PROTECT(lev); - pppos->open = 0; - PPPOS_UNPROTECT(lev); - - /* If PPP_INPROC_IRQ_SAFE is used we cannot call - * pppos_input_free_current_packet() here because - * rx IRQ might still call pppos_input(). - */ -#if !PPP_INPROC_IRQ_SAFE - /* input pbuf left ? */ - pppos_input_free_current_packet(pppos); -#endif /* !PPP_INPROC_IRQ_SAFE */ - - ppp_link_end(ppp); /* notify upper layers */ -} - -static err_t -pppos_destroy(ppp_pcb *ppp, void *ctx) -{ - pppos_pcb *pppos = (pppos_pcb *)ctx; - LWIP_UNUSED_ARG(ppp); - -#if PPP_INPROC_IRQ_SAFE - /* input pbuf left ? */ - pppos_input_free_current_packet(pppos); -#endif /* PPP_INPROC_IRQ_SAFE */ - - LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos); - return ERR_OK; -} - -#if !NO_SYS && !PPP_INPROC_IRQ_SAFE -/** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread. - * - * @param pcb PPP descriptor index, returned by pppos_create() - * @param data received data - * @param len length of received data - */ -err_t -pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l) -{ - struct pbuf *p; - err_t err; - - p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL); - if (!p) { - return ERR_MEM; - } - pbuf_take(p, s, l); - - err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys); - if (err != ERR_OK) { - pbuf_free(p); - } - return err; -} - -/* called from TCPIP thread */ -err_t pppos_input_sys(struct pbuf *p, struct netif *inp) { - ppp_pcb *ppp = (ppp_pcb*)inp->state; - struct pbuf *n; - - for (n = p; n; n = n->next) { - pppos_input(ppp, (u8_t*)n->payload, n->len); - } - pbuf_free(p); - return ERR_OK; -} -#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ - -/** PPPoS input helper struct, must be packed since it is stored - * to pbuf->payload, which might be unaligned. */ -#if PPP_INPROC_IRQ_SAFE -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct pppos_input_header { - PACK_STRUCT_FIELD(ppp_pcb *ppp); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#endif /* PPP_INPROC_IRQ_SAFE */ - -/** Pass received raw characters to PPPoS to be decoded. - * - * @param pcb PPP descriptor index, returned by pppos_create() - * @param data received data - * @param len length of received data - */ -void -pppos_input(ppp_pcb *ppp, u8_t *s, int l) -{ - pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb; - struct pbuf *next_pbuf; - u8_t cur_char; - u8_t escaped; - PPPOS_DECL_PROTECT(lev); - - PPPOS_PROTECT(lev); - if (!pppos->open) { - PPPOS_UNPROTECT(lev); - return; - } - PPPOS_UNPROTECT(lev); - - PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l)); - while (l-- > 0) { - cur_char = *s++; - - PPPOS_PROTECT(lev); - escaped = ESCAPE_P(pppos->in_accm, cur_char); - PPPOS_UNPROTECT(lev); - /* Handle special characters. */ - if (escaped) { - /* Check for escape sequences. */ - /* XXX Note that this does not handle an escaped 0x5d character which - * would appear as an escape character. Since this is an ASCII ']' - * and there is no reason that I know of to escape it, I won't complicate - * the code to handle this case. GLL */ - if (cur_char == PPP_ESCAPE) { - pppos->in_escaped = 1; - /* Check for the flag character. */ - } else if (cur_char == PPP_FLAG) { - /* If this is just an extra flag character, ignore it. */ - if (pppos->in_state <= PDADDRESS) { - /* ignore it */; - /* If we haven't received the packet header, drop what has come in. */ - } else if (pppos->in_state < PDDATA) { - PPPDEBUG(LOG_WARNING, - ("pppos_input[%d]: Dropping incomplete packet %d\n", - ppp->netif->num, pppos->in_state)); - LINK_STATS_INC(link.lenerr); - pppos_input_drop(pppos); - /* If the fcs is invalid, drop the packet. */ - } else if (pppos->in_fcs != PPP_GOODFCS) { - PPPDEBUG(LOG_INFO, - ("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n", - ppp->netif->num, pppos->in_fcs, pppos->in_protocol)); - /* Note: If you get lots of these, check for UART frame errors or try different baud rate */ - LINK_STATS_INC(link.chkerr); - pppos_input_drop(pppos); - /* Otherwise it's a good packet so pass it on. */ - } else { - struct pbuf *inp; - /* Trim off the checksum. */ - if(pppos->in_tail->len > 2) { - pppos->in_tail->len -= 2; - - pppos->in_tail->tot_len = pppos->in_tail->len; - if (pppos->in_tail != pppos->in_head) { - pbuf_cat(pppos->in_head, pppos->in_tail); - } - } else { - pppos->in_tail->tot_len = pppos->in_tail->len; - if (pppos->in_tail != pppos->in_head) { - pbuf_cat(pppos->in_head, pppos->in_tail); - } - - pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2); - } - - /* Dispatch the packet thereby consuming it. */ - inp = pppos->in_head; - /* Packet consumed, release our references. */ - pppos->in_head = NULL; - pppos->in_tail = NULL; -#if IP_FORWARD || LWIP_IPV6_FORWARD - /* hide the room for Ethernet forwarding header */ - pbuf_header(inp, -(s16_t)(PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN)); -#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ -#if PPP_INPROC_IRQ_SAFE - if(tcpip_callback_with_block(pppos_input_callback, inp, 0) != ERR_OK) { - PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num)); - pbuf_free(inp); - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards); - } -#else /* PPP_INPROC_IRQ_SAFE */ - ppp_input(ppp, inp); -#endif /* PPP_INPROC_IRQ_SAFE */ - } - - /* Prepare for a new packet. */ - pppos->in_fcs = PPP_INITFCS; - pppos->in_state = PDADDRESS; - pppos->in_escaped = 0; - /* Other characters are usually control characters that may have - * been inserted by the physical layer so here we just drop them. */ - } else { - PPPDEBUG(LOG_WARNING, - ("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char)); - } - /* Process other characters. */ - } else { - /* Unencode escaped characters. */ - if (pppos->in_escaped) { - pppos->in_escaped = 0; - cur_char ^= PPP_TRANS; - } - - /* Process character relative to current state. */ - switch(pppos->in_state) { - case PDIDLE: /* Idle state - waiting. */ - /* Drop the character if it's not 0xff - * we would have processed a flag character above. */ - if (cur_char != PPP_ALLSTATIONS) { - break; - } - /* no break */ - /* Fall through */ - - case PDSTART: /* Process start flag. */ - /* Prepare for a new packet. */ - pppos->in_fcs = PPP_INITFCS; - /* no break */ - /* Fall through */ - - case PDADDRESS: /* Process address field. */ - if (cur_char == PPP_ALLSTATIONS) { - pppos->in_state = PDCONTROL; - break; - } - /* no break */ - - /* Else assume compressed address and control fields so - * fall through to get the protocol... */ - case PDCONTROL: /* Process control field. */ - /* If we don't get a valid control code, restart. */ - if (cur_char == PPP_UI) { - pppos->in_state = PDPROTOCOL1; - break; - } - /* no break */ - -#if 0 - else { - PPPDEBUG(LOG_WARNING, - ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char)); - pppos->in_state = PDSTART; - } -#endif - case PDPROTOCOL1: /* Process protocol field 1. */ - /* If the lower bit is set, this is the end of the protocol - * field. */ - if (cur_char & 1) { - pppos->in_protocol = cur_char; - pppos->in_state = PDDATA; - } else { - pppos->in_protocol = (u16_t)cur_char << 8; - pppos->in_state = PDPROTOCOL2; - } - break; - case PDPROTOCOL2: /* Process protocol field 2. */ - pppos->in_protocol |= cur_char; - pppos->in_state = PDDATA; - break; - case PDDATA: /* Process data byte. */ - /* Make space to receive processed data. */ - if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) { - u16_t pbuf_alloc_len; - if (pppos->in_tail != NULL) { - pppos->in_tail->tot_len = pppos->in_tail->len; - if (pppos->in_tail != pppos->in_head) { - pbuf_cat(pppos->in_head, pppos->in_tail); - /* give up the in_tail reference now */ - pppos->in_tail = NULL; - } - } - /* If we haven't started a packet, we need a packet header. */ - pbuf_alloc_len = 0; -#if IP_FORWARD || LWIP_IPV6_FORWARD - /* If IP forwarding is enabled we are reserving PBUF_LINK_ENCAPSULATION_HLEN - * + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header - * space to be forwarded (to Ethernet for example). - */ - if (pppos->in_head == NULL) { - pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; - } -#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ - next_pbuf = pbuf_alloc(PBUF_RAW, pbuf_alloc_len, PBUF_POOL); - if (next_pbuf == NULL) { - /* No free buffers. Drop the input packet and let the - * higher layers deal with it. Continue processing - * the received pbuf chain in case a new packet starts. */ - PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num)); - LINK_STATS_INC(link.memerr); - pppos_input_drop(pppos); - pppos->in_state = PDSTART; /* Wait for flag sequence. */ - break; - } - if (pppos->in_head == NULL) { - u8_t *payload = ((u8_t*)next_pbuf->payload) + pbuf_alloc_len; -#if PPP_INPROC_IRQ_SAFE - ((struct pppos_input_header*)payload)->ppp = ppp; - payload += sizeof(struct pppos_input_header); - next_pbuf->len += sizeof(struct pppos_input_header); -#endif /* PPP_INPROC_IRQ_SAFE */ - next_pbuf->len += sizeof(pppos->in_protocol); - *(payload++) = pppos->in_protocol >> 8; - *(payload) = pppos->in_protocol & 0xFF; - pppos->in_head = next_pbuf; - } - pppos->in_tail = next_pbuf; - } - /* Load character into buffer. */ - ((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char; - break; - default: - break; - } - - /* update the frame check sequence number. */ - pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char); - } - } /* while (l-- > 0), all bytes processed */ -} - -#if PPP_INPROC_IRQ_SAFE -/* PPPoS input callback using one input pointer - */ -static void pppos_input_callback(void *arg) { - struct pbuf *pb = (struct pbuf*)arg; - ppp_pcb *ppp; - - ppp = ((struct pppos_input_header*)pb->payload)->ppp; - if(pbuf_header(pb, -(s16_t)sizeof(struct pppos_input_header))) { - LWIP_ASSERT("pbuf_header failed\n", 0); - goto drop; - } - - /* Dispatch the packet thereby consuming it. */ - ppp_input(ppp, pb); - return; - -drop: - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards); - pbuf_free(pb); -} -#endif /* PPP_INPROC_IRQ_SAFE */ - -static void -pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp) -{ - int i; - pppos_pcb *pppos = (pppos_pcb *)ctx; - LWIP_UNUSED_ARG(ppp); - - pppos->pcomp = pcomp; - pppos->accomp = accomp; - - /* Load the ACCM bits for the 32 control codes. */ - for (i = 0; i < 32/8; i++) { - pppos->out_accm[i] = (u8_t)((accm >> (8 * i)) & 0xFF); - } - - PPPDEBUG(LOG_INFO, ("pppos_send_config[%d]: out_accm=%X %X %X %X\n", - pppos->ppp->netif->num, - pppos->out_accm[0], pppos->out_accm[1], pppos->out_accm[2], pppos->out_accm[3])); -} - -static void -pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp) -{ - int i; - pppos_pcb *pppos = (pppos_pcb *)ctx; - PPPOS_DECL_PROTECT(lev); - LWIP_UNUSED_ARG(ppp); - LWIP_UNUSED_ARG(pcomp); - LWIP_UNUSED_ARG(accomp); - - /* Load the ACCM bits for the 32 control codes. */ - PPPOS_PROTECT(lev); - for (i = 0; i < 32 / 8; i++) { - pppos->in_accm[i] = (u8_t)(accm >> (i * 8)); - } - PPPOS_UNPROTECT(lev); - - PPPDEBUG(LOG_INFO, ("pppos_recv_config[%d]: in_accm=%X %X %X %X\n", - pppos->ppp->netif->num, - pppos->in_accm[0], pppos->in_accm[1], pppos->in_accm[2], pppos->in_accm[3])); -} - -/* - * Drop the input packet. - */ -static void -pppos_input_free_current_packet(pppos_pcb *pppos) -{ - if (pppos->in_head != NULL) { - if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) { - pbuf_free(pppos->in_tail); - } - pbuf_free(pppos->in_head); - pppos->in_head = NULL; - } - pppos->in_tail = NULL; -} - -/* - * Drop the input packet and increase error counters. - */ -static void -pppos_input_drop(pppos_pcb *pppos) -{ - if (pppos->in_head != NULL) { -#if 0 - PPPDEBUG(LOG_INFO, ("pppos_input_drop: %d:%.*H\n", pppos->in_head->len, min(60, pppos->in_head->len * 2), pppos->in_head->payload)); -#endif - PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head)); - } - pppos_input_free_current_packet(pppos); -#if VJ_SUPPORT && LWIP_TCP - vj_uncompress_err(&pppos->ppp->vj_comp); -#endif /* VJ_SUPPORT && LWIP_TCP */ - - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards); -} - -/* - * pppos_output_append - append given character to end of given pbuf. - * If out_accm is not 0 and the character needs to be escaped, do so. - * If pbuf is full, send the pbuf and reuse it. - * Return the current pbuf. - */ -static err_t -pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs) -{ - if (err != ERR_OK) { - return err; - } - - /* Make sure there is room for the character and an escape code. - * Sure we don't quite fill the buffer if the character doesn't - * get escaped but is one character worth complicating this? */ - if ((PBUF_POOL_BUFSIZE - nb->len) < 2) { - u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb); - if (l != nb->len) { - return ERR_IF; - } - nb->len = 0; - } - - /* Update FCS before checking for special characters. */ - if (fcs) { - *fcs = PPP_FCS(*fcs, c); - } - - /* Copy to output buffer escaping special characters. */ - if (accm && ESCAPE_P(pppos->out_accm, c)) { - *((u8_t*)nb->payload + nb->len++) = PPP_ESCAPE; - *((u8_t*)nb->payload + nb->len++) = c ^ PPP_TRANS; - } else { - *((u8_t*)nb->payload + nb->len++) = c; - } - - return ERR_OK; -} - -static err_t -pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs) -{ - ppp_pcb *ppp = pppos->ppp; - - /* Add FCS and trailing flag. */ - err = pppos_output_append(pppos, err, nb, ~(*fcs) & 0xFF, 1, NULL); - err = pppos_output_append(pppos, err, nb, (~(*fcs) >> 8) & 0xFF, 1, NULL); - err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); - - if (err != ERR_OK) { - goto failed; - } - - /* Send remaining buffer if not empty */ - if (nb->len > 0) { - u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb); - if (l != nb->len) { - err = ERR_IF; - goto failed; - } - } - - pppos->last_xmit = sys_now(); - MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, nb->tot_len); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); - LINK_STATS_INC(link.xmit); - pbuf_free(nb); - return ERR_OK; - -failed: - pppos->last_xmit = 0; /* prepend PPP_FLAG to next packet */ - LINK_STATS_INC(link.err); - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); - pbuf_free(nb); - return err; -} - -#endif /* PPP_SUPPORT && PPPOS_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/upap.c b/ext/lwip/src/netif/ppp/upap.c deleted file mode 100644 index d00c2d7..0000000 --- a/ext/lwip/src/netif/ppp/upap.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * upap.c - User/Password Authentication Protocol. - * - * 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -/* - * @todo: - */ - -#if 0 /* UNUSED */ -#include -#include -#endif /* UNUSED */ - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/upap.h" - -#if PPP_OPTIONS -/* - * Command-line options. - */ -static option_t pap_option_list[] = { - { "hide-password", o_bool, &hide_password, - "Don't output passwords to log", OPT_PRIO | 1 }, - { "show-password", o_bool, &hide_password, - "Show password string in debug log messages", OPT_PRIOSUB | 0 }, - - { "pap-restart", o_int, &upap[0].us_timeouttime, - "Set retransmit timeout for PAP", OPT_PRIO }, - { "pap-max-authreq", o_int, &upap[0].us_maxtransmits, - "Set max number of transmissions for auth-reqs", OPT_PRIO }, - { "pap-timeout", o_int, &upap[0].us_reqtimeout, - "Set time limit for peer PAP authentication", OPT_PRIO }, - - { NULL } -}; -#endif /* PPP_OPTIONS */ - -/* - * Protocol entry points. - */ -static void upap_init(ppp_pcb *pcb); -static void upap_lowerup(ppp_pcb *pcb); -static void upap_lowerdown(ppp_pcb *pcb); -static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l); -static void upap_protrej(ppp_pcb *pcb); -#if PRINTPKT_SUPPORT -static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg); -#endif /* PRINTPKT_SUPPORT */ - -const struct protent pap_protent = { - PPP_PAP, - upap_init, - upap_input, - upap_protrej, - upap_lowerup, - upap_lowerdown, - NULL, - NULL, -#if PRINTPKT_SUPPORT - upap_printpkt, -#endif /* PRINTPKT_SUPPORT */ -#if PPP_DATAINPUT - NULL, -#endif /* PPP_DATAINPUT */ -#if PRINTPKT_SUPPORT - "PAP", - NULL, -#endif /* PRINTPKT_SUPPORT */ -#if PPP_OPTIONS - pap_option_list, - NULL, -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT - NULL, - NULL -#endif /* DEMAND_SUPPORT */ -}; - -static void upap_timeout(void *arg); -#if PPP_SERVER -static void upap_reqtimeout(void *arg); -static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len); -#endif /* PPP_SERVER */ -static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len); -static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len); -static void upap_sauthreq(ppp_pcb *pcb); -#if PPP_SERVER -static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen); -#endif /* PPP_SERVER */ - - -/* - * upap_init - Initialize a UPAP unit. - */ -static void upap_init(ppp_pcb *pcb) { - pcb->upap.us_user = NULL; - pcb->upap.us_userlen = 0; - pcb->upap.us_passwd = NULL; - pcb->upap.us_passwdlen = 0; - pcb->upap.us_clientstate = UPAPCS_INITIAL; -#if PPP_SERVER - pcb->upap.us_serverstate = UPAPSS_INITIAL; -#endif /* PPP_SERVER */ - pcb->upap.us_id = 0; -} - - -/* - * upap_authwithpeer - Authenticate us with our peer (start client). - * - * Set new state and send authenticate's. - */ -void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password) { - - if(!user || !password) - return; - - /* Save the username and password we're given */ - pcb->upap.us_user = user; - pcb->upap.us_userlen = LWIP_MIN(strlen(user), 0xff); - pcb->upap.us_passwd = password; - pcb->upap.us_passwdlen = LWIP_MIN(strlen(password), 0xff); - pcb->upap.us_transmits = 0; - - /* Lower layer up yet? */ - if (pcb->upap.us_clientstate == UPAPCS_INITIAL || - pcb->upap.us_clientstate == UPAPCS_PENDING) { - pcb->upap.us_clientstate = UPAPCS_PENDING; - return; - } - - upap_sauthreq(pcb); /* Start protocol */ -} - -#if PPP_SERVER -/* - * upap_authpeer - Authenticate our peer (start server). - * - * Set new state. - */ -void upap_authpeer(ppp_pcb *pcb) { - - /* Lower layer up yet? */ - if (pcb->upap.us_serverstate == UPAPSS_INITIAL || - pcb->upap.us_serverstate == UPAPSS_PENDING) { - pcb->upap.us_serverstate = UPAPSS_PENDING; - return; - } - - pcb->upap.us_serverstate = UPAPSS_LISTEN; - if (pcb->settings.pap_req_timeout > 0) - TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout); -} -#endif /* PPP_SERVER */ - -/* - * upap_timeout - Retransmission timer for sending auth-reqs expired. - */ -static void upap_timeout(void *arg) { - ppp_pcb *pcb = (ppp_pcb*)arg; - - if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) - return; - - if (pcb->upap.us_transmits >= pcb->settings.pap_max_transmits) { - /* give up in disgust */ - ppp_error("No response to PAP authenticate-requests"); - pcb->upap.us_clientstate = UPAPCS_BADAUTH; - auth_withpeer_fail(pcb, PPP_PAP); - return; - } - - upap_sauthreq(pcb); /* Send Authenticate-Request */ -} - - -#if PPP_SERVER -/* - * upap_reqtimeout - Give up waiting for the peer to send an auth-req. - */ -static void upap_reqtimeout(void *arg) { - ppp_pcb *pcb = (ppp_pcb*)arg; - - if (pcb->upap.us_serverstate != UPAPSS_LISTEN) - return; /* huh?? */ - - auth_peer_fail(pcb, PPP_PAP); - pcb->upap.us_serverstate = UPAPSS_BADAUTH; -} -#endif /* PPP_SERVER */ - - -/* - * upap_lowerup - The lower layer is up. - * - * Start authenticating if pending. - */ -static void upap_lowerup(ppp_pcb *pcb) { - - if (pcb->upap.us_clientstate == UPAPCS_INITIAL) - pcb->upap.us_clientstate = UPAPCS_CLOSED; - else if (pcb->upap.us_clientstate == UPAPCS_PENDING) { - upap_sauthreq(pcb); /* send an auth-request */ - } - -#if PPP_SERVER - if (pcb->upap.us_serverstate == UPAPSS_INITIAL) - pcb->upap.us_serverstate = UPAPSS_CLOSED; - else if (pcb->upap.us_serverstate == UPAPSS_PENDING) { - pcb->upap.us_serverstate = UPAPSS_LISTEN; - if (pcb->settings.pap_req_timeout > 0) - TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout); - } -#endif /* PPP_SERVER */ -} - - -/* - * upap_lowerdown - The lower layer is down. - * - * Cancel all timeouts. - */ -static void upap_lowerdown(ppp_pcb *pcb) { - - if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */ - UNTIMEOUT(upap_timeout, pcb); /* Cancel timeout */ -#if PPP_SERVER - if (pcb->upap.us_serverstate == UPAPSS_LISTEN && pcb->settings.pap_req_timeout > 0) - UNTIMEOUT(upap_reqtimeout, pcb); -#endif /* PPP_SERVER */ - - pcb->upap.us_clientstate = UPAPCS_INITIAL; -#if PPP_SERVER - pcb->upap.us_serverstate = UPAPSS_INITIAL; -#endif /* PPP_SERVER */ -} - - -/* - * upap_protrej - Peer doesn't speak this protocol. - * - * This shouldn't happen. In any case, pretend lower layer went down. - */ -static void upap_protrej(ppp_pcb *pcb) { - - if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) { - ppp_error("PAP authentication failed due to protocol-reject"); - auth_withpeer_fail(pcb, PPP_PAP); - } -#if PPP_SERVER - if (pcb->upap.us_serverstate == UPAPSS_LISTEN) { - ppp_error("PAP authentication of peer failed (protocol-reject)"); - auth_peer_fail(pcb, PPP_PAP); - } -#endif /* PPP_SERVER */ - upap_lowerdown(pcb); -} - - -/* - * upap_input - Input UPAP packet. - */ -static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l) { - u_char *inp; - u_char code, id; - int len; - - /* - * Parse header (code, id and length). - * If packet too short, drop it. - */ - inp = inpacket; - if (l < UPAP_HEADERLEN) { - UPAPDEBUG(("pap_input: rcvd short header.")); - return; - } - GETCHAR(code, inp); - GETCHAR(id, inp); - GETSHORT(len, inp); - if (len < UPAP_HEADERLEN) { - UPAPDEBUG(("pap_input: rcvd illegal length.")); - return; - } - if (len > l) { - UPAPDEBUG(("pap_input: rcvd short packet.")); - return; - } - len -= UPAP_HEADERLEN; - - /* - * Action depends on code. - */ - switch (code) { - case UPAP_AUTHREQ: -#if PPP_SERVER - upap_rauthreq(pcb, inp, id, len); -#endif /* PPP_SERVER */ - break; - - case UPAP_AUTHACK: - upap_rauthack(pcb, inp, id, len); - break; - - case UPAP_AUTHNAK: - upap_rauthnak(pcb, inp, id, len); - break; - - default: /* XXX Need code reject */ - break; - } -} - -#if PPP_SERVER -/* - * upap_rauth - Receive Authenticate. - */ -static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len) { - u_char ruserlen, rpasswdlen; - char *ruser; - char *rpasswd; - char rhostname[256]; - int retcode; - const char *msg; - int msglen; - - if (pcb->upap.us_serverstate < UPAPSS_LISTEN) - return; - - /* - * If we receive a duplicate authenticate-request, we are - * supposed to return the same status as for the first request. - */ - if (pcb->upap.us_serverstate == UPAPSS_OPEN) { - upap_sresp(pcb, UPAP_AUTHACK, id, "", 0); /* return auth-ack */ - return; - } - if (pcb->upap.us_serverstate == UPAPSS_BADAUTH) { - upap_sresp(pcb, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */ - return; - } - - /* - * Parse user/passwd. - */ - if (len < 1) { - UPAPDEBUG(("pap_rauth: rcvd short packet.")); - return; - } - GETCHAR(ruserlen, inp); - len -= sizeof (u_char) + ruserlen + sizeof (u_char); - if (len < 0) { - UPAPDEBUG(("pap_rauth: rcvd short packet.")); - return; - } - ruser = (char *) inp; - INCPTR(ruserlen, inp); - GETCHAR(rpasswdlen, inp); - if (len < rpasswdlen) { - UPAPDEBUG(("pap_rauth: rcvd short packet.")); - return; - } - - rpasswd = (char *) inp; - - /* - * Check the username and password given. - */ - retcode = UPAP_AUTHNAK; - if (auth_check_passwd(pcb, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen)) { - retcode = UPAP_AUTHACK; - } - BZERO(rpasswd, rpasswdlen); - -#if 0 /* UNUSED */ - /* - * Check remote number authorization. A plugin may have filled in - * the remote number or added an allowed number, and rather than - * return an authenticate failure, is leaving it for us to verify. - */ - if (retcode == UPAP_AUTHACK) { - if (!auth_number()) { - /* We do not want to leak info about the pap result. */ - retcode = UPAP_AUTHNAK; /* XXX exit value will be "wrong" */ - warn("calling number %q is not authorized", remote_number); - } - } - - msglen = strlen(msg); - if (msglen > 255) - msglen = 255; -#endif /* UNUSED */ - - upap_sresp(pcb, retcode, id, msg, msglen); - - /* Null terminate and clean remote name. */ - ppp_slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser); - - if (retcode == UPAP_AUTHACK) { - pcb->upap.us_serverstate = UPAPSS_OPEN; - ppp_notice("PAP peer authentication succeeded for %q", rhostname); - auth_peer_success(pcb, PPP_PAP, 0, ruser, ruserlen); - } else { - pcb->upap.us_serverstate = UPAPSS_BADAUTH; - ppp_warn("PAP peer authentication failed for %q", rhostname); - auth_peer_fail(pcb, PPP_PAP); - } - - if (pcb->settings.pap_req_timeout > 0) - UNTIMEOUT(upap_reqtimeout, pcb); -} -#endif /* PPP_SERVER */ - -/* - * upap_rauthack - Receive Authenticate-Ack. - */ -static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len) { - u_char msglen; - char *msg; - LWIP_UNUSED_ARG(id); - - if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */ - return; - - /* - * Parse message. - */ - if (len < 1) { - UPAPDEBUG(("pap_rauthack: ignoring missing msg-length.")); - } else { - GETCHAR(msglen, inp); - if (msglen > 0) { - len -= sizeof (u_char); - if (len < msglen) { - UPAPDEBUG(("pap_rauthack: rcvd short packet.")); - return; - } - msg = (char *) inp; - PRINTMSG(msg, msglen); - } - } - - pcb->upap.us_clientstate = UPAPCS_OPEN; - - auth_withpeer_success(pcb, PPP_PAP, 0); -} - - -/* - * upap_rauthnak - Receive Authenticate-Nak. - */ -static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len) { - u_char msglen; - char *msg; - LWIP_UNUSED_ARG(id); - - if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */ - return; - - /* - * Parse message. - */ - if (len < 1) { - UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length.")); - } else { - GETCHAR(msglen, inp); - if (msglen > 0) { - len -= sizeof (u_char); - if (len < msglen) { - UPAPDEBUG(("pap_rauthnak: rcvd short packet.")); - return; - } - msg = (char *) inp; - PRINTMSG(msg, msglen); - } - } - - pcb->upap.us_clientstate = UPAPCS_BADAUTH; - - ppp_error("PAP authentication failed"); - auth_withpeer_fail(pcb, PPP_PAP); -} - - -/* - * upap_sauthreq - Send an Authenticate-Request. - */ -static void upap_sauthreq(ppp_pcb *pcb) { - struct pbuf *p; - u_char *outp; - int outlen; - - outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + - pcb->upap.us_userlen + pcb->upap.us_passwdlen; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = (u_char*)p->payload; - MAKEHEADER(outp, PPP_PAP); - - PUTCHAR(UPAP_AUTHREQ, outp); - PUTCHAR(++pcb->upap.us_id, outp); - PUTSHORT(outlen, outp); - PUTCHAR(pcb->upap.us_userlen, outp); - MEMCPY(outp, pcb->upap.us_user, pcb->upap.us_userlen); - INCPTR(pcb->upap.us_userlen, outp); - PUTCHAR(pcb->upap.us_passwdlen, outp); - MEMCPY(outp, pcb->upap.us_passwd, pcb->upap.us_passwdlen); - - ppp_write(pcb, p); - - TIMEOUT(upap_timeout, pcb, pcb->settings.pap_timeout_time); - ++pcb->upap.us_transmits; - pcb->upap.us_clientstate = UPAPCS_AUTHREQ; -} - -#if PPP_SERVER -/* - * upap_sresp - Send a response (ack or nak). - */ -static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen) { - struct pbuf *p; - u_char *outp; - int outlen; - - outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; - p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE); - if(NULL == p) - return; - if(p->tot_len != p->len) { - pbuf_free(p); - return; - } - - outp = (u_char*)p->payload; - MAKEHEADER(outp, PPP_PAP); - - PUTCHAR(code, outp); - PUTCHAR(id, outp); - PUTSHORT(outlen, outp); - PUTCHAR(msglen, outp); - MEMCPY(outp, msg, msglen); - - ppp_write(pcb, p); -} -#endif /* PPP_SERVER */ - -#if PRINTPKT_SUPPORT -/* - * upap_printpkt - print the contents of a PAP packet. - */ -static const char* const upap_codenames[] = { - "AuthReq", "AuthAck", "AuthNak" -}; - -static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg) { - int code, id, len; - int mlen, ulen, wlen; - const u_char *user, *pwd, *msg; - const u_char *pstart; - - if (plen < UPAP_HEADERLEN) - return 0; - pstart = p; - GETCHAR(code, p); - GETCHAR(id, p); - GETSHORT(len, p); - if (len < UPAP_HEADERLEN || len > plen) - return 0; - - if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(upap_codenames)) - printer(arg, " %s", upap_codenames[code-1]); - else - printer(arg, " code=0x%x", code); - printer(arg, " id=0x%x", id); - len -= UPAP_HEADERLEN; - switch (code) { - case UPAP_AUTHREQ: - if (len < 1) - break; - ulen = p[0]; - if (len < ulen + 2) - break; - wlen = p[ulen + 1]; - if (len < ulen + wlen + 2) - break; - user = (const u_char *) (p + 1); - pwd = (const u_char *) (p + ulen + 2); - p += ulen + wlen + 2; - len -= ulen + wlen + 2; - printer(arg, " user="); - ppp_print_string(user, ulen, printer, arg); - printer(arg, " password="); -/* FIXME: require ppp_pcb struct as printpkt() argument */ -#if 0 - if (!pcb->settings.hide_password) -#endif - ppp_print_string(pwd, wlen, printer, arg); -#if 0 - else - printer(arg, ""); -#endif - break; - case UPAP_AUTHACK: - case UPAP_AUTHNAK: - if (len < 1) - break; - mlen = p[0]; - if (len < mlen + 1) - break; - msg = (const u_char *) (p + 1); - p += mlen + 1; - len -= mlen + 1; - printer(arg, " "); - ppp_print_string(msg, mlen, printer, arg); - break; - default: - break; - } - - /* print the rest of the bytes in the packet */ - for (; len > 0; --len) { - GETCHAR(code, p); - printer(arg, " %.2x", code); - } - - return p - pstart; -} -#endif /* PRINTPKT_SUPPORT */ - -#endif /* PPP_SUPPORT && PAP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/utils.c b/ext/lwip/src/netif/ppp/utils.c deleted file mode 100644 index 5b14ac5..0000000 --- a/ext/lwip/src/netif/ppp/utils.c +++ /dev/null @@ -1,961 +0,0 @@ -/* - * utils.c - various utility functions used in pppd. - * - * Copyright (c) 1999-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. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#if 0 /* UNUSED */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef SVR4 -#include -#endif -#endif /* UNUSED */ - -#include /* isdigit() */ - -#include "netif/ppp/ppp_impl.h" - -#include "netif/ppp/fsm.h" -#include "netif/ppp/lcp.h" - -#if defined(SUNOS4) -extern char *strerror(); -#endif - -static void ppp_logit(int level, const char *fmt, va_list args); -static void ppp_log_write(int level, char *buf); -#if PRINTPKT_SUPPORT -static void ppp_vslp_printer(void *arg, const char *fmt, ...); -static void ppp_format_packet(const u_char *p, int len, - void (*printer) (void *, const char *, ...), void *arg); - -struct buffer_info { - char *ptr; - int len; -}; -#endif /* PRINTPKT_SUPPORT */ - -/* - * ppp_strlcpy - like strcpy/strncpy, doesn't overflow destination buffer, - * always leaves destination null-terminated (for len > 0). - */ -size_t ppp_strlcpy(char *dest, const char *src, size_t len) { - size_t ret = strlen(src); - - if (len != 0) { - if (ret < len) - strcpy(dest, src); - else { - strncpy(dest, src, len - 1); - dest[len-1] = 0; - } - } - return ret; -} - -/* - * ppp_strlcat - like strcat/strncat, doesn't overflow destination buffer, - * always leaves destination null-terminated (for len > 0). - */ -size_t ppp_strlcat(char *dest, const char *src, size_t len) { - size_t dlen = strlen(dest); - - return dlen + ppp_strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0)); -} - - -/* - * ppp_slprintf - format a message into a buffer. Like sprintf except we - * also specify the length of the output buffer, and we handle - * %m (error message), %v (visible string), - * %q (quoted string), %t (current time) and %I (IP address) formats. - * Doesn't do floating-point formats. - * Returns the number of chars put into buf. - */ -int ppp_slprintf(char *buf, int buflen, const char *fmt, ...) { - va_list args; - int n; - - va_start(args, fmt); - n = ppp_vslprintf(buf, buflen, fmt, args); - va_end(args); - return n; -} - -/* - * ppp_vslprintf - like ppp_slprintf, takes a va_list instead of a list of args. - */ -#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) - -int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args) { - int c, i, n; - int width, prec, fillch; - int base, len, neg, quoted; - unsigned long val = 0; - const char *f; - char *str, *buf0; - const unsigned char *p; - char num[32]; -#if 0 /* need port */ - time_t t; -#endif /* need port */ - u32_t ip; - static char hexchars[] = "0123456789abcdef"; -#if PRINTPKT_SUPPORT - struct buffer_info bufinfo; -#endif /* PRINTPKT_SUPPORT */ - - buf0 = buf; - --buflen; - while (buflen > 0) { - for (f = fmt; *f != '%' && *f != 0; ++f) - ; - if (f > fmt) { - len = f - fmt; - if (len > buflen) - len = buflen; - memcpy(buf, fmt, len); - buf += len; - buflen -= len; - fmt = f; - } - if (*fmt == 0) - break; - c = *++fmt; - width = 0; - prec = -1; - fillch = ' '; - if (c == '0') { - fillch = '0'; - c = *++fmt; - } - if (c == '*') { - width = va_arg(args, int); - c = *++fmt; - } else { - while (isdigit(c)) { - width = width * 10 + c - '0'; - c = *++fmt; - } - } - if (c == '.') { - c = *++fmt; - if (c == '*') { - prec = va_arg(args, int); - c = *++fmt; - } else { - prec = 0; - while (isdigit(c)) { - prec = prec * 10 + c - '0'; - c = *++fmt; - } - } - } - str = 0; - base = 0; - neg = 0; - ++fmt; - switch (c) { - case 'l': - c = *fmt++; - switch (c) { - case 'd': - val = va_arg(args, long); - if ((long)val < 0) { - neg = 1; - val = (unsigned long)-(long)val; - } - base = 10; - break; - case 'u': - val = va_arg(args, unsigned long); - base = 10; - break; - default: - OUTCHAR('%'); - OUTCHAR('l'); - --fmt; /* so %lz outputs %lz etc. */ - continue; - } - break; - case 'd': - i = va_arg(args, int); - if (i < 0) { - neg = 1; - val = -i; - } else - val = i; - base = 10; - break; - case 'u': - val = va_arg(args, unsigned int); - base = 10; - break; - case 'o': - val = va_arg(args, unsigned int); - base = 8; - break; - case 'x': - case 'X': - val = va_arg(args, unsigned int); - base = 16; - break; - case 'p': - val = (unsigned long) va_arg(args, void *); - base = 16; - neg = 2; - break; - case 's': - str = va_arg(args, char *); - break; - case 'c': - num[0] = va_arg(args, int); - num[1] = 0; - str = num; - break; -#if 0 /* do we always have strerror() in embedded ? */ - case 'm': - str = strerror(errno); - break; -#endif /* do we always have strerror() in embedded ? */ - case 'I': - ip = va_arg(args, u32_t); - ip = ntohl(ip); - ppp_slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff, - (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); - str = num; - break; -#if 0 /* need port */ - case 't': - time(&t); - str = ctime(&t); - str += 4; /* chop off the day name */ - str[15] = 0; /* chop off year and newline */ - break; -#endif /* need port */ - case 'v': /* "visible" string */ - case 'q': /* quoted string */ - quoted = c == 'q'; - p = va_arg(args, unsigned char *); - if (p == NULL) - p = (const unsigned char *)""; - if (fillch == '0' && prec >= 0) { - n = prec; - } else { - n = strlen((const char *)p); - if (prec >= 0 && n > prec) - n = prec; - } - while (n > 0 && buflen > 0) { - c = *p++; - --n; - if (!quoted && c >= 0x80) { - OUTCHAR('M'); - OUTCHAR('-'); - c -= 0x80; - } - if (quoted && (c == '"' || c == '\\')) - OUTCHAR('\\'); - if (c < 0x20 || (0x7f <= c && c < 0xa0)) { - if (quoted) { - OUTCHAR('\\'); - switch (c) { - case '\t': OUTCHAR('t'); break; - case '\n': OUTCHAR('n'); break; - case '\b': OUTCHAR('b'); break; - case '\f': OUTCHAR('f'); break; - default: - OUTCHAR('x'); - OUTCHAR(hexchars[c >> 4]); - OUTCHAR(hexchars[c & 0xf]); - } - } else { - if (c == '\t') - OUTCHAR(c); - else { - OUTCHAR('^'); - OUTCHAR(c ^ 0x40); - } - } - } else - OUTCHAR(c); - } - continue; -#if PRINTPKT_SUPPORT - case 'P': /* print PPP packet */ - bufinfo.ptr = buf; - bufinfo.len = buflen + 1; - p = va_arg(args, unsigned char *); - n = va_arg(args, int); - ppp_format_packet(p, n, ppp_vslp_printer, &bufinfo); - buf = bufinfo.ptr; - buflen = bufinfo.len - 1; - continue; -#endif /* PRINTPKT_SUPPORT */ - case 'B': - p = va_arg(args, unsigned char *); - for (n = prec; n > 0; --n) { - c = *p++; - if (fillch == ' ') - OUTCHAR(' '); - OUTCHAR(hexchars[(c >> 4) & 0xf]); - OUTCHAR(hexchars[c & 0xf]); - } - continue; - default: - *buf++ = '%'; - if (c != '%') - --fmt; /* so %z outputs %z etc. */ - --buflen; - continue; - } - if (base != 0) { - str = num + sizeof(num); - *--str = 0; - while (str > num + neg) { - *--str = hexchars[val % base]; - val = val / base; - if (--prec <= 0 && val == 0) - break; - } - switch (neg) { - case 1: - *--str = '-'; - break; - case 2: - *--str = 'x'; - *--str = '0'; - break; - default: - break; - } - len = num + sizeof(num) - 1 - str; - } else { - len = strlen(str); - if (prec >= 0 && len > prec) - len = prec; - } - if (width > 0) { - if (width > buflen) - width = buflen; - if ((n = width - len) > 0) { - buflen -= n; - for (; n > 0; --n) - *buf++ = fillch; - } - } - if (len > buflen) - len = buflen; - memcpy(buf, str, len); - buf += len; - buflen -= len; - } - *buf = 0; - return buf - buf0; -} - -#if PRINTPKT_SUPPORT -/* - * vslp_printer - used in processing a %P format - */ -static void ppp_vslp_printer(void *arg, const char *fmt, ...) { - int n; - va_list pvar; - struct buffer_info *bi; - - va_start(pvar, fmt); - bi = (struct buffer_info *) arg; - n = ppp_vslprintf(bi->ptr, bi->len, fmt, pvar); - va_end(pvar); - - bi->ptr += n; - bi->len -= n; -} -#endif /* PRINTPKT_SUPPORT */ - -#if 0 /* UNUSED */ -/* - * log_packet - format a packet and log it. - */ - -void -log_packet(p, len, prefix, level) - u_char *p; - int len; - char *prefix; - int level; -{ - init_pr_log(prefix, level); - ppp_format_packet(p, len, pr_log, &level); - end_pr_log(); -} -#endif /* UNUSED */ - -#if PRINTPKT_SUPPORT -/* - * ppp_format_packet - make a readable representation of a packet, - * calling `printer(arg, format, ...)' to output it. - */ -static void ppp_format_packet(const u_char *p, int len, - void (*printer) (void *, const char *, ...), void *arg) { - int i, n; - u_short proto; - const struct protent *protp; - - if (len >= 2) { - GETSHORT(proto, p); - len -= 2; - for (i = 0; (protp = protocols[i]) != NULL; ++i) - if (proto == protp->protocol) - break; - if (protp != NULL) { - printer(arg, "[%s", protp->name); - n = (*protp->printpkt)(p, len, printer, arg); - printer(arg, "]"); - p += n; - len -= n; - } else { - for (i = 0; (protp = protocols[i]) != NULL; ++i) - if (proto == (protp->protocol & ~0x8000)) - break; - if (protp != 0 && protp->data_name != 0) { - printer(arg, "[%s data]", protp->data_name); - if (len > 8) - printer(arg, "%.8B ...", p); - else - printer(arg, "%.*B", len, p); - len = 0; - } else - printer(arg, "[proto=0x%x]", proto); - } - } - - if (len > 32) - printer(arg, "%.32B ...", p); - else - printer(arg, "%.*B", len, p); -} -#endif /* PRINTPKT_SUPPORT */ - -#if 0 /* UNUSED */ -/* - * init_pr_log, end_pr_log - initialize and finish use of pr_log. - */ - -static char line[256]; /* line to be logged accumulated here */ -static char *linep; /* current pointer within line */ -static int llevel; /* level for logging */ - -void -init_pr_log(prefix, level) - const char *prefix; - int level; -{ - linep = line; - if (prefix != NULL) { - ppp_strlcpy(line, prefix, sizeof(line)); - linep = line + strlen(line); - } - llevel = level; -} - -void -end_pr_log() -{ - if (linep != line) { - *linep = 0; - ppp_log_write(llevel, line); - } -} - -/* - * pr_log - printer routine for outputting to log - */ -void -pr_log (void *arg, const char *fmt, ...) -{ - int l, n; - va_list pvar; - char *p, *eol; - char buf[256]; - - va_start(pvar, fmt); - n = ppp_vslprintf(buf, sizeof(buf), fmt, pvar); - va_end(pvar); - - p = buf; - eol = strchr(buf, '\n'); - if (linep != line) { - l = (eol == NULL)? n: eol - buf; - if (linep + l < line + sizeof(line)) { - if (l > 0) { - memcpy(linep, buf, l); - linep += l; - } - if (eol == NULL) - return; - p = eol + 1; - eol = strchr(p, '\n'); - } - *linep = 0; - ppp_log_write(llevel, line); - linep = line; - } - - while (eol != NULL) { - *eol = 0; - ppp_log_write(llevel, p); - p = eol + 1; - eol = strchr(p, '\n'); - } - - /* assumes sizeof(buf) <= sizeof(line) */ - l = buf + n - p; - if (l > 0) { - memcpy(line, p, n); - linep = line + l; - } -} -#endif /* UNUSED */ - -/* - * ppp_print_string - print a readable representation of a string using - * printer. - */ -void ppp_print_string(const u_char *p, int len, void (*printer) (void *, const char *, ...), void *arg) { - int c; - - printer(arg, "\""); - for (; len > 0; --len) { - c = *p++; - if (' ' <= c && c <= '~') { - if (c == '\\' || c == '"') - printer(arg, "\\"); - printer(arg, "%c", c); - } else { - switch (c) { - case '\n': - printer(arg, "\\n"); - break; - case '\r': - printer(arg, "\\r"); - break; - case '\t': - printer(arg, "\\t"); - break; - default: - printer(arg, "\\%.3o", (u8_t)c); - /* no break */ - } - } - } - printer(arg, "\""); -} - -/* - * ppp_logit - does the hard work for fatal et al. - */ -static void ppp_logit(int level, const char *fmt, va_list args) { - char buf[1024]; - - ppp_vslprintf(buf, sizeof(buf), fmt, args); - ppp_log_write(level, buf); -} - -static void ppp_log_write(int level, char *buf) { - LWIP_UNUSED_ARG(level); /* necessary if PPPDEBUG is defined to an empty function */ - LWIP_UNUSED_ARG(buf); - PPPDEBUG(level, ("%s\n", buf) ); -#if 0 - if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) { - int n = strlen(buf); - - if (n > 0 && buf[n-1] == '\n') - --n; - if (write(log_to_fd, buf, n) != n - || write(log_to_fd, "\n", 1) != 1) - log_to_fd = -1; - } -#endif -} - -/* - * ppp_fatal - log an error message and die horribly. - */ -void ppp_fatal(const char *fmt, ...) { - va_list pvar; - - va_start(pvar, fmt); - ppp_logit(LOG_ERR, fmt, pvar); - va_end(pvar); - - LWIP_ASSERT("ppp_fatal", 0); /* as promised */ -} - -/* - * ppp_error - log an error message. - */ -void ppp_error(const char *fmt, ...) { - va_list pvar; - - va_start(pvar, fmt); - ppp_logit(LOG_ERR, fmt, pvar); - va_end(pvar); -#if 0 /* UNUSED */ - ++error_count; -#endif /* UNUSED */ -} - -/* - * ppp_warn - log a warning message. - */ -void ppp_warn(const char *fmt, ...) { - va_list pvar; - - va_start(pvar, fmt); - ppp_logit(LOG_WARNING, fmt, pvar); - va_end(pvar); -} - -/* - * ppp_notice - log a notice-level message. - */ -void ppp_notice(const char *fmt, ...) { - va_list pvar; - - va_start(pvar, fmt); - ppp_logit(LOG_NOTICE, fmt, pvar); - va_end(pvar); -} - -/* - * ppp_info - log an informational message. - */ -void ppp_info(const char *fmt, ...) { - va_list pvar; - - va_start(pvar, fmt); - ppp_logit(LOG_INFO, fmt, pvar); - va_end(pvar); -} - -/* - * ppp_dbglog - log a debug message. - */ -void ppp_dbglog(const char *fmt, ...) { - va_list pvar; - - va_start(pvar, fmt); - ppp_logit(LOG_DEBUG, fmt, pvar); - va_end(pvar); -} - -#if PRINTPKT_SUPPORT -/* - * ppp_dump_packet - print out a packet in readable form if it is interesting. - * Assumes len >= PPP_HDRLEN. - */ -void ppp_dump_packet(const char *tag, unsigned char *p, int len) { - int proto; - - /* - * don't print IPv4 and IPv6 packets. - */ - proto = (p[0] << 8) + p[1]; - if (proto == PPP_IP) - return; -#if PPP_IPV6_SUPPORT - if (proto == PPP_IPV6) - return; -#endif - - /* - * don't print LCP echo request/reply packets if the link is up. - */ - if (proto == PPP_LCP && len >= 2 + HEADERLEN) { - unsigned char *lcp = p + 2; - int l = (lcp[2] << 8) + lcp[3]; - - if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP) - && l >= HEADERLEN && l <= len - 2) - return; - } - - ppp_dbglog("%s %P", tag, p, len); -} -#endif /* PRINTPKT_SUPPORT */ - -#if 0 /* Unused */ - -/* - * complete_read - read a full `count' bytes from fd, - * unless end-of-file or an error other than EINTR is encountered. - */ -ssize_t -complete_read(int fd, void *buf, size_t count) -{ - size_t done; - ssize_t nb; - char *ptr = buf; - - for (done = 0; done < count; ) { - nb = read(fd, ptr, count - done); - if (nb < 0) { - if (errno == EINTR) - continue; - return -1; - } - if (nb == 0) - break; - done += nb; - ptr += nb; - } - return done; -} - -/* Procedures for locking the serial device using a lock file. */ -#ifndef LOCK_DIR -#ifdef __linux__ -#define LOCK_DIR "/var/lock" -#else -#ifdef SVR4 -#define LOCK_DIR "/var/spool/locks" -#else -#define LOCK_DIR "/var/spool/lock" -#endif -#endif -#endif /* LOCK_DIR */ - -static char lock_file[MAXPATHLEN]; - -/* - * lock - create a lock file for the named device - */ -int -lock(dev) - char *dev; -{ -#ifdef LOCKLIB - int result; - - result = mklock (dev, (void *) 0); - if (result == 0) { - ppp_strlcpy(lock_file, dev, sizeof(lock_file)); - return 0; - } - - if (result > 0) - ppp_notice("Device %s is locked by pid %d", dev, result); - else - ppp_error("Can't create lock file %s", lock_file); - return -1; - -#else /* LOCKLIB */ - - char lock_buffer[12]; - int fd, pid, n; - -#ifdef SVR4 - struct stat sbuf; - - if (stat(dev, &sbuf) < 0) { - ppp_error("Can't get device number for %s: %m", dev); - return -1; - } - if ((sbuf.st_mode & S_IFMT) != S_IFCHR) { - ppp_error("Can't lock %s: not a character device", dev); - return -1; - } - ppp_slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d", - LOCK_DIR, major(sbuf.st_dev), - major(sbuf.st_rdev), minor(sbuf.st_rdev)); -#else - char *p; - char lockdev[MAXPATHLEN]; - - if ((p = strstr(dev, "dev/")) != NULL) { - dev = p + 4; - strncpy(lockdev, dev, MAXPATHLEN-1); - lockdev[MAXPATHLEN-1] = 0; - while ((p = strrchr(lockdev, '/')) != NULL) { - *p = '_'; - } - dev = lockdev; - } else - if ((p = strrchr(dev, '/')) != NULL) - dev = p + 1; - - ppp_slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev); -#endif - - while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { - if (errno != EEXIST) { - ppp_error("Can't create lock file %s: %m", lock_file); - break; - } - - /* Read the lock file to find out who has the device locked. */ - fd = open(lock_file, O_RDONLY, 0); - if (fd < 0) { - if (errno == ENOENT) /* This is just a timing problem. */ - continue; - ppp_error("Can't open existing lock file %s: %m", lock_file); - break; - } -#ifndef LOCK_BINARY - n = read(fd, lock_buffer, 11); -#else - n = read(fd, &pid, sizeof(pid)); -#endif /* LOCK_BINARY */ - close(fd); - fd = -1; - if (n <= 0) { - ppp_error("Can't read pid from lock file %s", lock_file); - break; - } - - /* See if the process still exists. */ -#ifndef LOCK_BINARY - lock_buffer[n] = 0; - pid = atoi(lock_buffer); -#endif /* LOCK_BINARY */ - if (pid == getpid()) - return 1; /* somebody else locked it for us */ - if (pid == 0 - || (kill(pid, 0) == -1 && errno == ESRCH)) { - if (unlink (lock_file) == 0) { - ppp_notice("Removed stale lock on %s (pid %d)", dev, pid); - continue; - } - ppp_warn("Couldn't remove stale lock on %s", dev); - } else - ppp_notice("Device %s is locked by pid %d", dev, pid); - break; - } - - if (fd < 0) { - lock_file[0] = 0; - return -1; - } - - pid = getpid(); -#ifndef LOCK_BINARY - ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid); - write (fd, lock_buffer, 11); -#else - write(fd, &pid, sizeof (pid)); -#endif - close(fd); - return 0; - -#endif -} - -/* - * relock - called to update our lockfile when we are about to detach, - * thus changing our pid (we fork, the child carries on, and the parent dies). - * Note that this is called by the parent, with pid equal to the pid - * of the child. This avoids a potential race which would exist if - * we had the child rewrite the lockfile (the parent might die first, - * and another process could think the lock was stale if it checked - * between when the parent died and the child rewrote the lockfile). - */ -int -relock(pid) - int pid; -{ -#ifdef LOCKLIB - /* XXX is there a way to do this? */ - return -1; -#else /* LOCKLIB */ - - int fd; - char lock_buffer[12]; - - if (lock_file[0] == 0) - return -1; - fd = open(lock_file, O_WRONLY, 0); - if (fd < 0) { - ppp_error("Couldn't reopen lock file %s: %m", lock_file); - lock_file[0] = 0; - return -1; - } - -#ifndef LOCK_BINARY - ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid); - write (fd, lock_buffer, 11); -#else - write(fd, &pid, sizeof(pid)); -#endif /* LOCK_BINARY */ - close(fd); - return 0; - -#endif /* LOCKLIB */ -} - -/* - * unlock - remove our lockfile - */ -void -unlock() -{ - if (lock_file[0]) { -#ifdef LOCKLIB - (void) rmlock(lock_file, (void *) 0); -#else - unlink(lock_file); -#endif - lock_file[0] = 0; - } -} - -#endif /* Unused */ - -#endif /* PPP_SUPPORT */ diff --git a/ext/lwip/src/netif/ppp/vj.c b/ext/lwip/src/netif/ppp/vj.c deleted file mode 100644 index b297c78..0000000 --- a/ext/lwip/src/netif/ppp/vj.c +++ /dev/null @@ -1,695 +0,0 @@ -/* - * Routines to compress and uncompess tcp packets (for transmission - * over low speed serial lines. - * - * 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. - * - * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au, - * so that the entire packet being decompressed doesn't have - * to be in contiguous memory (just the compressed header). - * - * Modified March 1998 by Guy Lancaster, glanca@gesn.com, - * for a 16 bit processor. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && VJ_SUPPORT && LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "netif/ppp/ppp_impl.h" -#include "netif/ppp/pppdebug.h" - -#include "netif/ppp/vj.h" - -#include - -#if LINK_STATS -#define INCR(counter) ++comp->stats.counter -#else -#define INCR(counter) -#endif - -void -vj_compress_init(struct vjcompress *comp) -{ - u8_t i; - struct cstate *tstate = comp->tstate; - -#if MAX_SLOTS == 0 - memset((char *)comp, 0, sizeof(*comp)); -#endif - comp->maxSlotIndex = MAX_SLOTS - 1; - comp->compressSlot = 0; /* Disable slot ID compression by default. */ - for (i = MAX_SLOTS - 1; i > 0; --i) { - tstate[i].cs_id = i; - tstate[i].cs_next = &tstate[i - 1]; - } - tstate[0].cs_next = &tstate[MAX_SLOTS - 1]; - tstate[0].cs_id = 0; - comp->last_cs = &tstate[0]; - comp->last_recv = 255; - comp->last_xmit = 255; - comp->flags = VJF_TOSS; -} - - -/* ENCODE encodes a number that is known to be non-zero. ENCODEZ - * checks for zero (since zero has to be encoded in the long, 3 byte - * form). - */ -#define ENCODE(n) { \ - if ((u16_t)(n) >= 256) { \ - *cp++ = 0; \ - cp[1] = (u8_t)(n); \ - cp[0] = (u8_t)((n) >> 8); \ - cp += 2; \ - } else { \ - *cp++ = (u8_t)(n); \ - } \ -} -#define ENCODEZ(n) { \ - if ((u16_t)(n) >= 256 || (u16_t)(n) == 0) { \ - *cp++ = 0; \ - cp[1] = (u8_t)(n); \ - cp[0] = (u8_t)((n) >> 8); \ - cp += 2; \ - } else { \ - *cp++ = (u8_t)(n); \ - } \ -} - -#define DECODEL(f) { \ - if (*cp == 0) {\ - u32_t tmp_ = ntohl(f) + ((cp[1] << 8) | cp[2]); \ - (f) = htonl(tmp_); \ - cp += 3; \ - } else { \ - u32_t tmp_ = ntohl(f) + (u32_t)*cp++; \ - (f) = htonl(tmp_); \ - } \ -} - -#define DECODES(f) { \ - if (*cp == 0) {\ - u16_t tmp_ = ntohs(f) + (((u16_t)cp[1] << 8) | cp[2]); \ - (f) = htons(tmp_); \ - cp += 3; \ - } else { \ - u16_t tmp_ = ntohs(f) + (u16_t)*cp++; \ - (f) = htons(tmp_); \ - } \ -} - -#define DECODEU(f) { \ - if (*cp == 0) {\ - (f) = htons(((u16_t)cp[1] << 8) | cp[2]); \ - cp += 3; \ - } else { \ - (f) = htons((u16_t)*cp++); \ - } \ -} - -/* Helper structures for unaligned *u32_t and *u16_t accesses */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct vj_u32_t { - PACK_STRUCT_FIELD(u32_t v); -} 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 vj_u16_t { - PACK_STRUCT_FIELD(u16_t v); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/* - * vj_compress_tcp - Attempt to do Van Jacobson header compression on a - * packet. This assumes that nb and comp are not null and that the first - * buffer of the chain contains a valid IP header. - * Return the VJ type code indicating whether or not the packet was - * compressed. - */ -u8_t -vj_compress_tcp(struct vjcompress *comp, struct pbuf **pb) -{ - struct pbuf *np = *pb; - struct ip_hdr *ip = (struct ip_hdr *)np->payload; - struct cstate *cs = comp->last_cs->cs_next; - u16_t ilen = IPH_HL(ip); - u16_t hlen; - struct tcp_hdr *oth; - struct tcp_hdr *th; - u16_t deltaS, deltaA = 0; - u32_t deltaL; - u32_t changes = 0; - u8_t new_seq[16]; - u8_t *cp = new_seq; - - /* - * Check that the packet is IP proto TCP. - */ - if (IPH_PROTO(ip) != IP_PROTO_TCP) { - return (TYPE_IP); - } - - /* - * Bail if this is an IP fragment or if the TCP packet isn't - * `compressible' (i.e., ACK isn't set or some other control bit is - * set). - */ - if ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || np->tot_len < 40) { - return (TYPE_IP); - } - th = (struct tcp_hdr *)&((struct vj_u32_t*)ip)[ilen]; - if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) { - return (TYPE_IP); - } - - /* Check that the TCP/IP headers are contained in the first buffer. */ - hlen = ilen + TCPH_HDRLEN(th); - hlen <<= 2; - if (np->len < hlen) { - PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen)); - return (TYPE_IP); - } - - /* TCP stack requires that we don't change the packet payload, therefore we copy - * the whole packet before compression. */ - np = pbuf_alloc(PBUF_RAW, np->tot_len, PBUF_POOL); - if (!np) { - return (TYPE_IP); - } - - if (pbuf_copy(np, *pb) != ERR_OK) { - pbuf_free(np); - return (TYPE_IP); - } - - *pb = np; - ip = (struct ip_hdr *)np->payload; - - /* - * Packet is compressible -- we're going to send either a - * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need - * to locate (or create) the connection state. Special case the - * most recently used connection since it's most likely to be used - * again & we don't have to do any reordering if it's used. - */ - INCR(vjs_packets); - if (!ip4_addr_cmp(&ip->src, &cs->cs_ip.src) - || !ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest) - || (*(struct vj_u32_t*)th).v != (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) { - /* - * Wasn't the first -- search for it. - * - * States are kept in a circularly linked list with - * last_cs pointing to the end of the list. The - * list is kept in lru order by moving a state to the - * head of the list whenever it is referenced. Since - * the list is short and, empirically, the connection - * we want is almost always near the front, we locate - * states via linear search. If we don't find a state - * for the datagram, the oldest state is (re-)used. - */ - struct cstate *lcs; - struct cstate *lastcs = comp->last_cs; - - do { - lcs = cs; cs = cs->cs_next; - INCR(vjs_searches); - if (ip4_addr_cmp(&ip->src, &cs->cs_ip.src) - && ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest) - && (*(struct vj_u32_t*)th).v == (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) { - goto found; - } - } while (cs != lastcs); - - /* - * Didn't find it -- re-use oldest cstate. Send an - * uncompressed packet that tells the other side what - * connection number we're using for this conversation. - * Note that since the state list is circular, the oldest - * state points to the newest and we only need to set - * last_cs to update the lru linkage. - */ - INCR(vjs_misses); - comp->last_cs = lcs; - goto uncompressed; - - found: - /* - * Found it -- move to the front on the connection list. - */ - if (cs == lastcs) { - comp->last_cs = lcs; - } else { - lcs->cs_next = cs->cs_next; - cs->cs_next = lastcs->cs_next; - lastcs->cs_next = cs; - } - } - - oth = (struct tcp_hdr *)&((struct vj_u32_t*)&cs->cs_ip)[ilen]; - deltaS = ilen; - - /* - * Make sure that only what we expect to change changed. The first - * line of the `if' checks the IP protocol version, header length & - * type of service. The 2nd line checks the "Don't fragment" bit. - * The 3rd line checks the time-to-live and protocol (the protocol - * check is unnecessary but costless). The 4th line checks the TCP - * header length. The 5th line checks IP options, if any. The 6th - * line checks TCP options, if any. If any of these things are - * different between the previous & current datagram, we send the - * current datagram `uncompressed'. - */ - if ((((struct vj_u16_t*)ip)[0]).v != (((struct vj_u16_t*)&cs->cs_ip)[0]).v - || (((struct vj_u16_t*)ip)[3]).v != (((struct vj_u16_t*)&cs->cs_ip)[3]).v - || (((struct vj_u16_t*)ip)[4]).v != (((struct vj_u16_t*)&cs->cs_ip)[4]).v - || TCPH_HDRLEN(th) != TCPH_HDRLEN(oth) - || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) - || (TCPH_HDRLEN(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_HDRLEN(th) - 5) << 2))) { - goto uncompressed; - } - - /* - * Figure out which of the changing fields changed. The - * receiver expects changes in the order: urgent, window, - * ack, seq (the order minimizes the number of temporaries - * needed in this section of code). - */ - if (TCPH_FLAGS(th) & TCP_URG) { - deltaS = ntohs(th->urgp); - ENCODEZ(deltaS); - changes |= NEW_U; - } else if (th->urgp != oth->urgp) { - /* argh! URG not set but urp changed -- a sensible - * implementation should never do this but RFC793 - * doesn't prohibit the change so we have to deal - * with it. */ - goto uncompressed; - } - - if ((deltaS = (u16_t)(ntohs(th->wnd) - ntohs(oth->wnd))) != 0) { - ENCODE(deltaS); - changes |= NEW_W; - } - - if ((deltaL = ntohl(th->ackno) - ntohl(oth->ackno)) != 0) { - if (deltaL > 0xffff) { - goto uncompressed; - } - deltaA = (u16_t)deltaL; - ENCODE(deltaA); - changes |= NEW_A; - } - - if ((deltaL = ntohl(th->seqno) - ntohl(oth->seqno)) != 0) { - if (deltaL > 0xffff) { - goto uncompressed; - } - deltaS = (u16_t)deltaL; - ENCODE(deltaS); - changes |= NEW_S; - } - - switch(changes) { - case 0: - /* - * Nothing changed. If this packet contains data and the - * last one didn't, this is probably a data packet following - * an ack (normal on an interactive connection) and we send - * it compressed. Otherwise it's probably a retransmit, - * retransmitted ack or window probe. Send it uncompressed - * in case the other side missed the compressed version. - */ - if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) && - ntohs(IPH_LEN(&cs->cs_ip)) == hlen) { - break; - } - /* no break */ - /* fall through */ - - case SPECIAL_I: - case SPECIAL_D: - /* - * actual changes match one of our special case encodings -- - * send packet uncompressed. - */ - goto uncompressed; - - case NEW_S|NEW_A: - if (deltaS == deltaA && deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { - /* special case for echoed terminal traffic */ - changes = SPECIAL_I; - cp = new_seq; - } - break; - - case NEW_S: - if (deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { - /* special case for data xfer */ - changes = SPECIAL_D; - cp = new_seq; - } - break; - default: - break; - } - - deltaS = (u16_t)(ntohs(IPH_ID(ip)) - ntohs(IPH_ID(&cs->cs_ip))); - if (deltaS != 1) { - ENCODEZ(deltaS); - changes |= NEW_I; - } - if (TCPH_FLAGS(th) & TCP_PSH) { - changes |= TCP_PUSH_BIT; - } - /* - * Grab the cksum before we overwrite it below. Then update our - * state with this packet's header. - */ - deltaA = ntohs(th->chksum); - MEMCPY(&cs->cs_ip, ip, hlen); - - /* - * We want to use the original packet as our compressed packet. - * (cp - new_seq) is the number of bytes we need for compressed - * sequence numbers. In addition we need one byte for the change - * mask, one for the connection id and two for the tcp checksum. - * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how - * many bytes of the original packet to toss so subtract the two to - * get the new packet size. - */ - deltaS = (u16_t)(cp - new_seq); - if (!comp->compressSlot || comp->last_xmit != cs->cs_id) { - comp->last_xmit = cs->cs_id; - hlen -= deltaS + 4; - if (pbuf_header(np, -(s16_t)hlen)){ - /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_header failed\n", 0); - } - cp = (u8_t*)np->payload; - *cp++ = (u8_t)(changes | NEW_C); - *cp++ = cs->cs_id; - } else { - hlen -= deltaS + 3; - if (pbuf_header(np, -(s16_t)hlen)) { - /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_header failed\n", 0); - } - cp = (u8_t*)np->payload; - *cp++ = (u8_t)changes; - } - *cp++ = (u8_t)(deltaA >> 8); - *cp++ = (u8_t)deltaA; - MEMCPY(cp, new_seq, deltaS); - INCR(vjs_compressed); - return (TYPE_COMPRESSED_TCP); - - /* - * Update connection state cs & send uncompressed packet (that is, - * a regular ip/tcp packet but with the 'conversation id' we hope - * to use on future compressed packets in the protocol field). - */ -uncompressed: - MEMCPY(&cs->cs_ip, ip, hlen); - IPH_PROTO_SET(ip, cs->cs_id); - comp->last_xmit = cs->cs_id; - return (TYPE_UNCOMPRESSED_TCP); -} - -/* - * Called when we may have missed a packet. - */ -void -vj_uncompress_err(struct vjcompress *comp) -{ - comp->flags |= VJF_TOSS; - INCR(vjs_errorin); -} - -/* - * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP. - * Return 0 on success, -1 on failure. - */ -int -vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp) -{ - u32_t hlen; - struct cstate *cs; - struct ip_hdr *ip; - - ip = (struct ip_hdr *)nb->payload; - hlen = IPH_HL(ip) << 2; - if (IPH_PROTO(ip) >= MAX_SLOTS - || hlen + sizeof(struct tcp_hdr) > nb->len - || (hlen += TCPH_HDRLEN(((struct tcp_hdr *)&((char *)ip)[hlen])) << 2) - > nb->len - || hlen > MAX_HDR) { - PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", - IPH_PROTO(ip), hlen, nb->len)); - comp->flags |= VJF_TOSS; - INCR(vjs_errorin); - return -1; - } - cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)]; - comp->flags &=~ VJF_TOSS; - IPH_PROTO_SET(ip, IP_PROTO_TCP); - MEMCPY(&cs->cs_ip, ip, hlen); - cs->cs_hlen = (u16_t)hlen; - INCR(vjs_uncompressedin); - return 0; -} - -/* - * Uncompress a packet of type TYPE_COMPRESSED_TCP. - * The packet is composed of a buffer chain and the first buffer - * must contain an accurate chain length. - * The first buffer must include the entire compressed TCP/IP header. - * This procedure replaces the compressed header with the uncompressed - * header and returns the length of the VJ header. - */ -int -vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) -{ - u8_t *cp; - struct tcp_hdr *th; - struct cstate *cs; - struct vj_u16_t *bp; - struct pbuf *n0 = *nb; - u32_t tmp; - u32_t vjlen, hlen, changes; - - INCR(vjs_compressedin); - cp = (u8_t*)n0->payload; - changes = *cp++; - if (changes & NEW_C) { - /* - * Make sure the state index is in range, then grab the state. - * If we have a good state index, clear the 'discard' flag. - */ - if (*cp >= MAX_SLOTS) { - PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp)); - goto bad; - } - - comp->flags &=~ VJF_TOSS; - comp->last_recv = *cp++; - } else { - /* - * this packet has an implicit state index. If we've - * had a line error since the last time we got an - * explicit state index, we have to toss the packet. - */ - if (comp->flags & VJF_TOSS) { - PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n")); - INCR(vjs_tossed); - return (-1); - } - } - cs = &comp->rstate[comp->last_recv]; - hlen = IPH_HL(&cs->cs_ip) << 2; - th = (struct tcp_hdr *)&((u8_t*)&cs->cs_ip)[hlen]; - th->chksum = htons((*cp << 8) | cp[1]); - cp += 2; - if (changes & TCP_PUSH_BIT) { - TCPH_SET_FLAG(th, TCP_PSH); - } else { - TCPH_UNSET_FLAG(th, TCP_PSH); - } - - switch (changes & SPECIALS_MASK) { - case SPECIAL_I: - { - u32_t i = ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; - /* some compilers can't nest inline assembler.. */ - tmp = ntohl(th->ackno) + i; - th->ackno = htonl(tmp); - tmp = ntohl(th->seqno) + i; - th->seqno = htonl(tmp); - } - break; - - case SPECIAL_D: - /* some compilers can't nest inline assembler.. */ - tmp = ntohl(th->seqno) + ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; - th->seqno = htonl(tmp); - break; - - default: - if (changes & NEW_U) { - TCPH_SET_FLAG(th, TCP_URG); - DECODEU(th->urgp); - } else { - TCPH_UNSET_FLAG(th, TCP_URG); - } - if (changes & NEW_W) { - DECODES(th->wnd); - } - if (changes & NEW_A) { - DECODEL(th->ackno); - } - if (changes & NEW_S) { - DECODEL(th->seqno); - } - break; - } - if (changes & NEW_I) { - DECODES(cs->cs_ip._id); - } else { - IPH_ID_SET(&cs->cs_ip, ntohs(IPH_ID(&cs->cs_ip)) + 1); - IPH_ID_SET(&cs->cs_ip, htons(IPH_ID(&cs->cs_ip))); - } - - /* - * At this point, cp points to the first byte of data in the - * packet. Fill in the IP total length and update the IP - * header checksum. - */ - vjlen = (u16_t)(cp - (u8_t*)n0->payload); - if (n0->len < vjlen) { - /* - * We must have dropped some characters (crc should detect - * this but the old slip framing won't) - */ - PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n", - n0->len, vjlen)); - goto bad; - } - -#if BYTE_ORDER == LITTLE_ENDIAN - tmp = n0->tot_len - vjlen + cs->cs_hlen; - IPH_LEN_SET(&cs->cs_ip, htons((u16_t)tmp)); -#else - IPH_LEN_SET(&cs->cs_ip, htons(n0->tot_len - vjlen + cs->cs_hlen)); -#endif - - /* recompute the ip header checksum */ - bp = (struct vj_u16_t*) &cs->cs_ip; - IPH_CHKSUM_SET(&cs->cs_ip, 0); - for (tmp = 0; hlen > 0; hlen -= 2) { - tmp += (*bp++).v; - } - tmp = (tmp & 0xffff) + (tmp >> 16); - tmp = (tmp & 0xffff) + (tmp >> 16); - IPH_CHKSUM_SET(&cs->cs_ip, (u16_t)(~tmp)); - - /* Remove the compressed header and prepend the uncompressed header. */ - if (pbuf_header(n0, -(s16_t)vjlen)) { - /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_header failed\n", 0); - goto bad; - } - - if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) { - struct pbuf *np, *q; - u8_t *bufptr; - -#if IP_FORWARD - /* If IP forwarding is enabled we are using a PBUF_LINK packet type so - * the packet is being allocated with enough header space to be - * forwarded (to Ethernet for example). - */ - np = pbuf_alloc(PBUF_LINK, n0->len + cs->cs_hlen, PBUF_POOL); -#else /* IP_FORWARD */ - np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL); -#endif /* IP_FORWARD */ - if(!np) { - PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n")); - goto bad; - } - - if (pbuf_header(np, -(s16_t)cs->cs_hlen)) { - /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_header failed\n", 0); - goto bad; - } - - bufptr = (u8_t*)n0->payload; - for(q = np; q != NULL; q = q->next) { - MEMCPY(q->payload, bufptr, q->len); - bufptr += q->len; - } - - if(n0->next) { - pbuf_chain(np, n0->next); - pbuf_dechain(n0); - } - pbuf_free(n0); - n0 = np; - } - - if (pbuf_header(n0, (s16_t)cs->cs_hlen)) { - struct pbuf *np; - - LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE); - np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL); - if(!np) { - PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n")); - goto bad; - } - pbuf_cat(np, n0); - n0 = np; - } - LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen); - MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen); - - *nb = n0; - - return vjlen; - -bad: - comp->flags |= VJF_TOSS; - INCR(vjs_errorin); - return (-1); -} - -#endif /* PPP_SUPPORT && VJ_SUPPORT && LWIP_TCP */ diff --git a/ext/lwip/src/netif/slipif.c b/ext/lwip/src/netif/slipif.c deleted file mode 100644 index f6c5d4b..0000000 --- a/ext/lwip/src/netif/slipif.c +++ /dev/null @@ -1,555 +0,0 @@ -/** - * @file - * SLIP Interface - * - */ - -/* - * 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. 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 built upon the file: src/arch/rtxc/netif/sioslip.c - * - * Author: Magnus Ivarsson - * Simon Goldschmidt - */ - - -/** - * @defgroup slipif SLIP netif - * @ingroup addons - * - * This is an arch independent SLIP netif. The specific serial hooks must be - * provided by another file. They are sio_open, sio_read/sio_tryread and sio_send - * - * Usage: This netif can be used in three ways:\n - * 1) For NO_SYS==0, an RX thread can be used which blocks on sio_read() - * until data is received.\n - * 2) In your main loop, call slipif_poll() to check for new RX bytes, - * completed packets are fed into netif->input().\n - * 3) Call slipif_received_byte[s]() from your serial RX ISR and - * slipif_process_rxqueue() from your main loop. ISR level decodes - * packets and puts completed packets on a queue which is fed into - * the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for - * pbuf_alloc to work on ISR level!). - * - */ - -#include "netif/slipif.h" -#include "lwip/opt.h" - -#include "lwip/def.h" -#include "lwip/pbuf.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "lwip/sys.h" -#include "lwip/sio.h" - -#define SLIP_END 0xC0 /* 0300: start and end of every packet */ -#define SLIP_ESC 0xDB /* 0333: escape start (one byte escaped data follows) */ -#define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */ -#define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */ - -/** Maximum packet size that is received by this netif */ -#ifndef SLIP_MAX_SIZE -#define SLIP_MAX_SIZE 1500 -#endif - -/** Define this to the interface speed for SNMP - * (sio_fd is the sio_fd_t returned by sio_open). - * The default value of zero means 'unknown'. - */ -#ifndef SLIP_SIO_SPEED -#define SLIP_SIO_SPEED(sio_fd) 0 -#endif - -enum slipif_recv_state { - SLIP_RECV_NORMAL, - SLIP_RECV_ESCAPE -}; - -struct slipif_priv { - sio_fd_t sd; - /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */ - struct pbuf *p, *q; - u8_t state; - u16_t i, recved; -#if SLIP_RX_FROM_ISR - struct pbuf *rxpackets; -#endif -}; - -/** - * Send a pbuf doing the necessary SLIP encapsulation - * - * Uses the serial layer's sio_send() - * - * @param netif the lwip network interface structure for this slipif - * @param p the pbuf chain packet to send - * @return always returns ERR_OK since the serial layer does not provide return values - */ -static err_t -slipif_output(struct netif *netif, struct pbuf *p) -{ - struct slipif_priv *priv; - struct pbuf *q; - u16_t i; - u8_t c; - - LWIP_ASSERT("netif != NULL", (netif != NULL)); - LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); - LWIP_ASSERT("p != NULL", (p != NULL)); - - LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output(%"U16_F"): sending %"U16_F" bytes\n", (u16_t)netif->num, p->tot_len)); - priv = (struct slipif_priv *)netif->state; - - /* Send pbuf out on the serial I/O device. */ - /* Start with packet delimiter. */ - sio_send(SLIP_END, priv->sd); - - for (q = p; q != NULL; q = q->next) { - for (i = 0; i < q->len; i++) { - c = ((u8_t *)q->payload)[i]; - switch (c) { - case SLIP_END: - /* need to escape this byte (0xC0 -> 0xDB, 0xDC) */ - sio_send(SLIP_ESC, priv->sd); - sio_send(SLIP_ESC_END, priv->sd); - break; - case SLIP_ESC: - /* need to escape this byte (0xDB -> 0xDB, 0xDD) */ - sio_send(SLIP_ESC, priv->sd); - sio_send(SLIP_ESC_ESC, priv->sd); - break; - default: - /* normal byte - no need for escaping */ - sio_send(c, priv->sd); - break; - } - } - } - /* End with packet delimiter. */ - sio_send(SLIP_END, priv->sd); - return ERR_OK; -} - -#if LWIP_IPV4 -/** - * Send a pbuf doing the necessary SLIP encapsulation - * - * Uses the serial layer's sio_send() - * - * @param netif the lwip network interface structure for this slipif - * @param p the pbuf chain packet to send - * @param ipaddr the ip address to send the packet to (not used for slipif) - * @return always returns ERR_OK since the serial layer does not provide return values - */ -static err_t -slipif_output_v4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) -{ - LWIP_UNUSED_ARG(ipaddr); - return slipif_output(netif, p); -} -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -/** - * Send a pbuf doing the necessary SLIP encapsulation - * - * Uses the serial layer's sio_send() - * - * @param netif the lwip network interface structure for this slipif - * @param p the pbuf chain packet to send - * @param ipaddr the ip address to send the packet to (not used for slipif) - * @return always returns ERR_OK since the serial layer does not provide return values - */ -static err_t -slipif_output_v6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) -{ - LWIP_UNUSED_ARG(ipaddr); - return slipif_output(netif, p); -} -#endif /* LWIP_IPV6 */ - -/** - * Handle the incoming SLIP stream character by character - * - * @param netif the lwip network interface structure for this slipif - * @param c received character (multiple calls to this function will - * return a complete packet, NULL is returned before - used for polling) - * @return The IP packet when SLIP_END is received - */ -static struct pbuf* -slipif_rxbyte(struct netif *netif, u8_t c) -{ - struct slipif_priv *priv; - struct pbuf *t; - - LWIP_ASSERT("netif != NULL", (netif != NULL)); - LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); - - priv = (struct slipif_priv *)netif->state; - - switch (priv->state) { - case SLIP_RECV_NORMAL: - switch (c) { - case SLIP_END: - if (priv->recved > 0) { - /* Received whole packet. */ - /* Trim the pbuf to the size of the received packet. */ - pbuf_realloc(priv->q, priv->recved); - - LINK_STATS_INC(link.recv); - - LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved)); - t = priv->q; - priv->p = priv->q = NULL; - priv->i = priv->recved = 0; - return t; - } - return NULL; - case SLIP_ESC: - priv->state = SLIP_RECV_ESCAPE; - return NULL; - default: - break; - } /* end switch (c) */ - break; - case SLIP_RECV_ESCAPE: - /* un-escape END or ESC bytes, leave other bytes - (although that would be a protocol error) */ - switch (c) { - case SLIP_ESC_END: - c = SLIP_END; - break; - case SLIP_ESC_ESC: - c = SLIP_ESC; - break; - default: - break; - } - priv->state = SLIP_RECV_NORMAL; - break; - default: - break; - } /* end switch (priv->state) */ - - /* byte received, packet not yet completely received */ - if (priv->p == NULL) { - /* allocate a new pbuf */ - LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n")); - priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - PBUF_LINK_ENCAPSULATION_HLEN), PBUF_POOL); - - if (priv->p == NULL) { - LINK_STATS_INC(link.drop); - LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); - /* don't process any further since we got no pbuf to receive to */ - return NULL; - } - - if (priv->q != NULL) { - /* 'chain' the pbuf to the existing chain */ - pbuf_cat(priv->q, priv->p); - } else { - /* p is the first pbuf in the chain */ - priv->q = priv->p; - } - } - - /* this automatically drops bytes if > SLIP_MAX_SIZE */ - if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) { - ((u8_t *)priv->p->payload)[priv->i] = c; - priv->recved++; - priv->i++; - if (priv->i >= priv->p->len) { - /* on to the next pbuf */ - priv->i = 0; - if (priv->p->next != NULL && priv->p->next->len > 0) { - /* p is a chain, on to the next in the chain */ - priv->p = priv->p->next; - } else { - /* p is a single pbuf, set it to NULL so next time a new - * pbuf is allocated */ - priv->p = NULL; - } - } - } - return NULL; -} - -/** Like slipif_rxbyte, but passes completed packets to netif->input - * - * @param netif The lwip network interface structure for this slipif - * @param data received character - */ -static void -slipif_rxbyte_input(struct netif *netif, u8_t c) -{ - struct pbuf *p; - p = slipif_rxbyte(netif, c); - if (p != NULL) { - if (netif->input(p, netif) != ERR_OK) { - pbuf_free(p); - } - } -} - -#if SLIP_USE_RX_THREAD -/** - * The SLIP input thread. - * - * Feed the IP layer with incoming packets - * - * @param nf the lwip network interface structure for this slipif - */ -static void -slipif_loop_thread(void *nf) -{ - u8_t c; - struct netif *netif = (struct netif *)nf; - struct slipif_priv *priv = (struct slipif_priv *)netif->state; - - while (1) { - if (sio_read(priv->sd, &c, 1) > 0) { - slipif_rxbyte_input(netif, c); - } - } -} -#endif /* SLIP_USE_RX_THREAD */ - -/** - * SLIP netif initialization - * - * Call the arch specific sio_open and remember - * the opened device in the state field of the netif. - * - * @param netif the lwip network interface structure for this slipif - * @return ERR_OK if serial line could be opened, - * ERR_MEM if no memory could be allocated, - * ERR_IF is serial line couldn't be opened - * - * @note netif->num must contain the number of the serial port to open - * (0 by default). If netif->state is != NULL, it is interpreted as an - * u8_t pointer pointing to the serial port number instead of netif->num. - * - */ -err_t -slipif_init(struct netif *netif) -{ - struct slipif_priv *priv; - u8_t sio_num; - - LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num)); - - /* Allocate private data */ - priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv)); - if (!priv) { - return ERR_MEM; - } - - netif->name[0] = 's'; - netif->name[1] = 'l'; -#if LWIP_IPV4 - netif->output = slipif_output_v4; -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 - netif->output_ip6 = slipif_output_v6; -#endif /* LWIP_IPV6 */ - netif->mtu = SLIP_MAX_SIZE; - - /* netif->state or netif->num contain the port number */ - if (netif->state != NULL) { - sio_num = *(u8_t*)netif->state; - } else { - sio_num = netif->num; - } - /* Try to open the serial port. */ - priv->sd = sio_open(sio_num); - if (!priv->sd) { - /* Opening the serial port failed. */ - mem_free(priv); - return ERR_IF; - } - - /* Initialize private data */ - priv->p = NULL; - priv->q = NULL; - priv->state = SLIP_RECV_NORMAL; - priv->i = 0; - priv->recved = 0; -#if SLIP_RX_FROM_ISR - priv->rxpackets = NULL; -#endif - - netif->state = priv; - - /* initialize the snmp variables and counters inside the struct netif */ - MIB2_INIT_NETIF(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd)); - -#if SLIP_USE_RX_THREAD - /* Create a thread to poll the serial line. */ - sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif, - SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO); -#endif /* SLIP_USE_RX_THREAD */ - return ERR_OK; -} - -/** - * Polls the serial device and feeds the IP layer with incoming packets. - * - * @param netif The lwip network interface structure for this slipif - */ -void -slipif_poll(struct netif *netif) -{ - u8_t c; - struct slipif_priv *priv; - - LWIP_ASSERT("netif != NULL", (netif != NULL)); - LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); - - priv = (struct slipif_priv *)netif->state; - - while (sio_tryread(priv->sd, &c, 1) > 0) { - slipif_rxbyte_input(netif, c); - } -} - -#if SLIP_RX_FROM_ISR -/** - * Feeds the IP layer with incoming packets that were receive - * - * @param netif The lwip network interface structure for this slipif - */ -void -slipif_process_rxqueue(struct netif *netif) -{ - struct slipif_priv *priv; - SYS_ARCH_DECL_PROTECT(old_level); - - LWIP_ASSERT("netif != NULL", (netif != NULL)); - LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); - - priv = (struct slipif_priv *)netif->state; - - SYS_ARCH_PROTECT(old_level); - while (priv->rxpackets != NULL) { - struct pbuf *p = priv->rxpackets; -#if SLIP_RX_QUEUE - /* dequeue packet */ - struct pbuf *q = p; - while ((q->len != q->tot_len) && (q->next != NULL)) { - q = q->next; - } - priv->rxpackets = q->next; - q->next = NULL; -#else /* SLIP_RX_QUEUE */ - priv->rxpackets = NULL; -#endif /* SLIP_RX_QUEUE */ - SYS_ARCH_UNPROTECT(old_level); - if (netif->input(p, netif) != ERR_OK) { - pbuf_free(p); - } - SYS_ARCH_PROTECT(old_level); - } -} - -/** Like slipif_rxbyte, but queues completed packets. - * - * @param netif The lwip network interface structure for this slipif - * @param data Received serial byte - */ -static void -slipif_rxbyte_enqueue(struct netif *netif, u8_t data) -{ - struct pbuf *p; - struct slipif_priv *priv = (struct slipif_priv *)netif->state; - SYS_ARCH_DECL_PROTECT(old_level); - - p = slipif_rxbyte(netif, data); - if (p != NULL) { - SYS_ARCH_PROTECT(old_level); - if (priv->rxpackets != NULL) { -#if SLIP_RX_QUEUE - /* queue multiple pbufs */ - struct pbuf *q = p; - while (q->next != NULL) { - q = q->next; - } - q->next = p; - } else { -#else /* SLIP_RX_QUEUE */ - pbuf_free(priv->rxpackets); - } - { -#endif /* SLIP_RX_QUEUE */ - priv->rxpackets = p; - } - SYS_ARCH_UNPROTECT(old_level); - } -} - -/** - * Process a received byte, completed packets are put on a queue that is - * fed into IP through slipif_process_rxqueue(). - * - * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. - * - * @param netif The lwip network interface structure for this slipif - * @param data received character - */ -void -slipif_received_byte(struct netif *netif, u8_t data) -{ - LWIP_ASSERT("netif != NULL", (netif != NULL)); - LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); - slipif_rxbyte_enqueue(netif, data); -} - -/** - * Process multiple received byte, completed packets are put on a queue that is - * fed into IP through slipif_process_rxqueue(). - * - * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. - * - * @param netif The lwip network interface structure for this slipif - * @param data received character - * @param len Number of received characters - */ -void -slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len) -{ - u8_t i; - u8_t *rxdata = data; - LWIP_ASSERT("netif != NULL", (netif != NULL)); - LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); - - for (i = 0; i < len; i++, rxdata++) { - slipif_rxbyte_enqueue(netif, *rxdata); - } -} -#endif /* SLIP_RX_FROM_ISR */ diff --git a/ext/lwip/test/unit/core/test_mem.c b/ext/lwip/test/unit/core/test_mem.c deleted file mode 100644 index 66b4877..0000000 --- a/ext/lwip/test/unit/core/test_mem.c +++ /dev/null @@ -1,121 +0,0 @@ -#include "test_mem.h" - -#include "lwip/mem.h" -#include "lwip/stats.h" - -#if !LWIP_STATS || !MEM_STATS -#error "This tests needs MEM-statistics enabled" -#endif -#if LWIP_DNS -#error "This test needs DNS turned off (as it mallocs on init)" -#endif - -/* Setups/teardown functions */ - -static void -mem_setup(void) -{ -} - -static void -mem_teardown(void) -{ -} - - -/* Test functions */ - -/** Call mem_malloc, mem_free and mem_trim and check stats */ -START_TEST(test_mem_one) -{ -#define SIZE1 16 -#define SIZE1_2 12 -#define SIZE2 16 - void *p1, *p2; - mem_size_t s1, s2; - LWIP_UNUSED_ARG(_i); - - fail_unless(lwip_stats.mem.used == 0); - - p1 = mem_malloc(SIZE1); - fail_unless(p1 != NULL); - fail_unless(lwip_stats.mem.used >= SIZE1); - s1 = lwip_stats.mem.used; - - p2 = mem_malloc(SIZE2); - fail_unless(p2 != NULL); - fail_unless(lwip_stats.mem.used >= SIZE2 + s1); - s2 = lwip_stats.mem.used; - - mem_trim(p1, SIZE1_2); - - mem_free(p2); - fail_unless(lwip_stats.mem.used <= s2 - SIZE2); - - mem_free(p1); - fail_unless(lwip_stats.mem.used == 0); -} -END_TEST - -static void malloc_keep_x(int x, int num, int size, int freestep) -{ - int i; - void* p[16]; - LWIP_ASSERT("invalid size", size >= 0 && size < (mem_size_t)-1); - memset(p, 0, sizeof(p)); - for(i = 0; i < num && i < 16; i++) { - p[i] = mem_malloc((mem_size_t)size); - fail_unless(p[i] != NULL); - } - for(i = 0; i < num && i < 16; i += freestep) { - if (i == x) { - continue; - } - mem_free(p[i]); - p[i] = NULL; - } - for(i = 0; i < num && i < 16; i++) { - if (i == x) { - continue; - } - if (p[i] != NULL) { - mem_free(p[i]); - p[i] = NULL; - } - } - fail_unless(p[x] != NULL); - mem_free(p[x]); -} - -START_TEST(test_mem_random) -{ - const int num = 16; - int x; - int size; - int freestep; - LWIP_UNUSED_ARG(_i); - - fail_unless(lwip_stats.mem.used == 0); - - for (x = 0; x < num; x++) { - for (size = 1; size < 32; size++) { - for (freestep = 1; freestep <= 3; freestep++) { - fail_unless(lwip_stats.mem.used == 0); - malloc_keep_x(x, num, size, freestep); - fail_unless(lwip_stats.mem.used == 0); - } - } - } -} -END_TEST - -/** Create the suite including all tests for this module */ -Suite * -mem_suite(void) -{ - testfunc tests[] = { - TESTFUNC(test_mem_one), - TESTFUNC(test_mem_random) - }; - return create_suite("MEM", tests, sizeof(tests)/sizeof(testfunc), mem_setup, mem_teardown); -} diff --git a/ext/lwip/test/unit/core/test_mem.h b/ext/lwip/test/unit/core/test_mem.h deleted file mode 100644 index a85bccb..0000000 --- a/ext/lwip/test/unit/core/test_mem.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LWIP_HDR_TEST_MEM_H__ -#define LWIP_HDR_TEST_MEM_H__ - -#include "../lwip_check.h" - -Suite *mem_suite(void); - -#endif diff --git a/ext/lwip/test/unit/core/test_pbuf.c b/ext/lwip/test/unit/core/test_pbuf.c deleted file mode 100644 index 9315c4c..0000000 --- a/ext/lwip/test/unit/core/test_pbuf.c +++ /dev/null @@ -1,239 +0,0 @@ -#include "test_pbuf.h" - -#include "lwip/pbuf.h" -#include "lwip/stats.h" - -#if !LWIP_STATS || !MEM_STATS ||!MEMP_STATS -#error "This tests needs MEM- and MEMP-statistics enabled" -#endif -#if LWIP_DNS -#error "This test needs DNS turned off (as it mallocs on init)" -#endif -#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !LWIP_WND_SCALE -#error "This test needs TCP OOSEQ queueing and window scaling enabled" -#endif - -/* Setups/teardown functions */ - -static void -pbuf_setup(void) -{ -} - -static void -pbuf_teardown(void) -{ -} - - -#define TESTBUFSIZE_1 65535 -#define TESTBUFSIZE_2 65530 -#define TESTBUFSIZE_3 50050 -static u8_t testbuf_1[TESTBUFSIZE_1]; -static u8_t testbuf_1a[TESTBUFSIZE_1]; -static u8_t testbuf_2[TESTBUFSIZE_2]; -static u8_t testbuf_2a[TESTBUFSIZE_2]; -static u8_t testbuf_3[TESTBUFSIZE_3]; -static u8_t testbuf_3a[TESTBUFSIZE_3]; - -/* Test functions */ - -/** Call pbuf_copy on a pbuf with zero length */ -START_TEST(test_pbuf_copy_zero_pbuf) -{ - struct pbuf *p1, *p2, *p3; - err_t err; - LWIP_UNUSED_ARG(_i); - - fail_unless(lwip_stats.mem.used == 0); - fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0); - - p1 = pbuf_alloc(PBUF_RAW, 1024, PBUF_RAM); - fail_unless(p1 != NULL); - fail_unless(p1->ref == 1); - - p2 = pbuf_alloc(PBUF_RAW, 2, PBUF_POOL); - fail_unless(p2 != NULL); - fail_unless(p2->ref == 1); - p2->len = p2->tot_len = 0; - - pbuf_cat(p1, p2); - fail_unless(p1->ref == 1); - fail_unless(p2->ref == 1); - - p3 = pbuf_alloc(PBUF_RAW, p1->tot_len, PBUF_POOL); - err = pbuf_copy(p3, p1); - fail_unless(err == ERR_VAL); - - pbuf_free(p1); - pbuf_free(p3); - fail_unless(lwip_stats.mem.used == 0); - - fail_unless(lwip_stats.mem.used == 0); - fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0); -} -END_TEST - -START_TEST(test_pbuf_split_64k_on_small_pbufs) -{ - struct pbuf *p, *rest=NULL; - LWIP_UNUSED_ARG(_i); - - p = pbuf_alloc(PBUF_RAW, 1, PBUF_POOL); - pbuf_split_64k(p, &rest); - fail_unless(p->tot_len == 1); - pbuf_free(p); -} -END_TEST - -START_TEST(test_pbuf_queueing_bigger_than_64k) -{ - int i; - err_t err; - struct pbuf *p1, *p2, *p3, *rest2=NULL, *rest3=NULL; - LWIP_UNUSED_ARG(_i); - - for(i = 0; i < TESTBUFSIZE_1; i++) { - testbuf_1[i] = (u8_t)rand(); - } - for(i = 0; i < TESTBUFSIZE_2; i++) { - testbuf_2[i] = (u8_t)rand(); - } - for(i = 0; i < TESTBUFSIZE_3; i++) { - testbuf_3[i] = (u8_t)rand(); - } - - p1 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_1, PBUF_POOL); - fail_unless(p1 != NULL); - p2 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_2, PBUF_POOL); - fail_unless(p2 != NULL); - p3 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_3, PBUF_POOL); - fail_unless(p3 != NULL); - err = pbuf_take(p1, testbuf_1, TESTBUFSIZE_1); - fail_unless(err == ERR_OK); - err = pbuf_take(p2, testbuf_2, TESTBUFSIZE_2); - fail_unless(err == ERR_OK); - err = pbuf_take(p3, testbuf_3, TESTBUFSIZE_3); - fail_unless(err == ERR_OK); - - pbuf_cat(p1, p2); - pbuf_cat(p1, p3); - - pbuf_split_64k(p1, &rest2); - fail_unless(p1->tot_len == TESTBUFSIZE_1); - fail_unless(rest2->tot_len == (u16_t)((TESTBUFSIZE_2+TESTBUFSIZE_3) & 0xFFFF)); - pbuf_split_64k(rest2, &rest3); - fail_unless(rest2->tot_len == TESTBUFSIZE_2); - fail_unless(rest3->tot_len == TESTBUFSIZE_3); - - pbuf_copy_partial(p1, testbuf_1a, TESTBUFSIZE_1, 0); - pbuf_copy_partial(rest2, testbuf_2a, TESTBUFSIZE_2, 0); - pbuf_copy_partial(rest3, testbuf_3a, TESTBUFSIZE_3, 0); - for(i = 0; i < TESTBUFSIZE_1; i++) - fail_unless(testbuf_1[i] == testbuf_1a[i]); - for(i = 0; i < TESTBUFSIZE_2; i++) - fail_unless(testbuf_2[i] == testbuf_2a[i]); - for(i = 0; i < TESTBUFSIZE_3; i++) - fail_unless(testbuf_3[i] == testbuf_3a[i]); - - pbuf_free(p1); - pbuf_free(rest2); - pbuf_free(rest3); -} -END_TEST - -/* Test for bug that writing with pbuf_take_at() did nothing - * and returned ERR_OK when writing at beginning of a pbuf - * in the chain. - */ -START_TEST(test_pbuf_take_at_edge) -{ - err_t res; - u8_t *out; - int i; - u8_t testdata[] = { 0x01, 0x08, 0x82, 0x02 }; - struct pbuf *p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL); - struct pbuf *q = p->next; - LWIP_UNUSED_ARG(_i); - /* alloc big enough to get a chain of pbufs */ - fail_if(p->tot_len == p->len); - memset(p->payload, 0, p->len); - memset(q->payload, 0, q->len); - - /* copy data to the beginning of first pbuf */ - res = pbuf_take_at(p, &testdata, sizeof(testdata), 0); - fail_unless(res == ERR_OK); - - out = (u8_t*)p->payload; - for (i = 0; i < (int)sizeof(testdata); i++) { - fail_unless(out[i] == testdata[i], - "Bad data at pos %d, was %02X, expected %02X", i, out[i], testdata[i]); - } - - /* copy data to the just before end of first pbuf */ - res = pbuf_take_at(p, &testdata, sizeof(testdata), p->len - 1); - fail_unless(res == ERR_OK); - - out = (u8_t*)p->payload; - fail_unless(out[p->len - 1] == testdata[0], - "Bad data at pos %d, was %02X, expected %02X", p->len - 1, out[p->len - 1], testdata[0]); - out = (u8_t*)q->payload; - for (i = 1; i < (int)sizeof(testdata); i++) { - fail_unless(out[i-1] == testdata[i], - "Bad data at pos %d, was %02X, expected %02X", p->len - 1 + i, out[i-1], testdata[i]); - } - - /* copy data to the beginning of second pbuf */ - res = pbuf_take_at(p, &testdata, sizeof(testdata), p->len); - fail_unless(res == ERR_OK); - - out = (u8_t*)p->payload; - for (i = 0; i < (int)sizeof(testdata); i++) { - fail_unless(out[i] == testdata[i], - "Bad data at pos %d, was %02X, expected %02X", p->len+i, out[i], testdata[i]); - } -} -END_TEST - -/* Verify pbuf_put_at()/pbuf_get_at() when using - * offsets equal to beginning of new pbuf in chain - */ -START_TEST(test_pbuf_get_put_at_edge) -{ - u8_t *out; - u8_t testdata = 0x01; - u8_t getdata; - struct pbuf *p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL); - struct pbuf *q = p->next; - LWIP_UNUSED_ARG(_i); - /* alloc big enough to get a chain of pbufs */ - fail_if(p->tot_len == p->len); - memset(p->payload, 0, p->len); - memset(q->payload, 0, q->len); - - /* put byte at the beginning of second pbuf */ - pbuf_put_at(p, p->len, testdata); - - out = (u8_t*)q->payload; - fail_unless(*out == testdata, - "Bad data at pos %d, was %02X, expected %02X", p->len, *out, testdata); - - getdata = pbuf_get_at(p, p->len); - fail_unless(*out == getdata, - "pbuf_get_at() returned bad data at pos %d, was %02X, expected %02X", p->len, getdata, *out); -} -END_TEST - -/** Create the suite including all tests for this module */ -Suite * -pbuf_suite(void) -{ - testfunc tests[] = { - TESTFUNC(test_pbuf_copy_zero_pbuf), - TESTFUNC(test_pbuf_split_64k_on_small_pbufs), - TESTFUNC(test_pbuf_queueing_bigger_than_64k), - TESTFUNC(test_pbuf_take_at_edge), - TESTFUNC(test_pbuf_get_put_at_edge) - }; - return create_suite("PBUF", tests, sizeof(tests)/sizeof(testfunc), pbuf_setup, pbuf_teardown); -} diff --git a/ext/lwip/test/unit/core/test_pbuf.h b/ext/lwip/test/unit/core/test_pbuf.h deleted file mode 100644 index 8253157..0000000 --- a/ext/lwip/test/unit/core/test_pbuf.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LWIP_HDR_TEST_PBUF_H__ -#define LWIP_HDR_TEST_PBUF_H__ - -#include "../lwip_check.h" - -Suite *pbuf_suite(void); - -#endif diff --git a/ext/lwip/test/unit/dhcp/test_dhcp.c b/ext/lwip/test/unit/dhcp/test_dhcp.c deleted file mode 100644 index 0d0e81a..0000000 --- a/ext/lwip/test/unit/dhcp/test_dhcp.c +++ /dev/null @@ -1,915 +0,0 @@ -#include "test_dhcp.h" - -#include "lwip/netif.h" -#include "lwip/dhcp.h" -#include "netif/etharp.h" - -struct netif net_test; - -static const u8_t broadcast[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - -static const u8_t magic_cookie[] = { 0x63, 0x82, 0x53, 0x63 }; - -static u8_t dhcp_offer[] = { - 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* To unit */ - 0x00, 0x0F, 0xEE, 0x30, 0xAB, 0x22, /* From Remote host */ - 0x08, 0x00, /* Protocol: IP */ - 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, /* IP header */ - 0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x00, 0x00, /* UDP header */ - - 0x02, /* Type == Boot reply */ - 0x01, 0x06, /* Hw Ethernet, 6 bytes addrlen */ - 0x00, /* 0 hops */ - 0xAA, 0xAA, 0xAA, 0xAA, /* Transaction id, will be overwritten */ - 0x00, 0x00, /* 0 seconds elapsed */ - 0x00, 0x00, /* Flags (unicast) */ - 0x00, 0x00, 0x00, 0x00, /* Client ip */ - 0xc3, 0xaa, 0xbd, 0xc8, /* Your IP */ - 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server ip */ - 0x00, 0x00, 0x00, 0x00, /* relay agent */ - 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MAC addr + padding */ - - /* Empty server name and boot file name */ - 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, 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, 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, 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, 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, - - 0x63, 0x82, 0x53, 0x63, /* Magic cookie */ - 0x35, 0x01, 0x02, /* Message type: Offer */ - 0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Server identifier (IP) */ - 0x33, 0x04, 0x00, 0x00, 0x00, 0x78, /* Lease time 2 minutes */ - 0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Router IP */ - 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, /* Subnet mask */ - 0xff, /* End option */ - 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, /* Padding */ -}; - -static u8_t dhcp_ack[] = { - 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* To unit */ - 0x00, 0x0f, 0xEE, 0x30, 0xAB, 0x22, /* From remote host */ - 0x08, 0x00, /* Proto IP */ - 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, /* IP header */ - 0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x00, 0x00, /* UDP header */ - 0x02, /* Bootp reply */ - 0x01, 0x06, /* Hw type Eth, len 6 */ - 0x00, /* 0 hops */ - 0xAA, 0xAA, 0xAA, 0xAA, - 0x00, 0x00, /* 0 seconds elapsed */ - 0x00, 0x00, /* Flags (unicast) */ - 0x00, 0x00, 0x00, 0x00, /* Client IP */ - 0xc3, 0xaa, 0xbd, 0xc8, /* Your IP */ - 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server IP */ - 0x00, 0x00, 0x00, 0x00, /* Relay agent */ - 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Macaddr + padding */ - - /* Empty server name and boot file name */ - 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, 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, 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, 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, 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, - - 0x63, 0x82, 0x53, 0x63, /* Magic cookie */ - 0x35, 0x01, 0x05, /* Dhcp message type ack */ - 0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server identifier */ - 0x33, 0x04, 0x00, 0x00, 0x00, 0x78, /* Lease time 2 minutes */ - 0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Router IP */ - 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, /* Netmask */ - 0xff, /* End marker */ - - 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, /* Padding */ -}; - -static const u8_t arpreply[] = { - 0x00, 0x23, 0xC1, 0xDE, 0xD0, 0x0D, /* dst mac */ - 0x00, 0x32, 0x44, 0x20, 0x01, 0x02, /* src mac */ - 0x08, 0x06, /* proto arp */ - 0x00, 0x01, /* hw eth */ - 0x08, 0x00, /* proto ip */ - 0x06, /* hw addr len 6 */ - 0x04, /* proto addr len 4 */ - 0x00, 0x02, /* arp reply */ - 0x00, 0x32, 0x44, 0x20, 0x01, 0x02, /* sender mac */ - 0xc3, 0xaa, 0xbd, 0xc8, /* sender ip */ - 0x00, 0x23, 0xC1, 0xDE, 0xD0, 0x0D, /* target mac */ - 0x00, 0x00, 0x00, 0x00, /* target ip */ -}; - -static int txpacket; -static enum tcase { - TEST_LWIP_DHCP, - TEST_LWIP_DHCP_NAK, - TEST_LWIP_DHCP_RELAY, - TEST_LWIP_DHCP_NAK_NO_ENDMARKER -} tcase; - -static int debug = 0; -static void setdebug(int a) {debug = a;} - -static int tick = 0; -static void tick_lwip(void) -{ - tick++; - if (tick % 5 == 0) { - dhcp_fine_tmr(); - } - if (tick % 600 == 0) { - dhcp_coarse_tmr(); - } -} - -static void send_pkt(struct netif *netif, const u8_t *data, size_t len) -{ - struct pbuf *p, *q; - LWIP_ASSERT("pkt too big", len <= 0xFFFF); - p = pbuf_alloc(PBUF_RAW, (u16_t)len, PBUF_POOL); - - if (debug) { - /* Dump data */ - u32_t i; - printf("RX data (len %d)", p->tot_len); - for (i = 0; i < len; i++) { - printf(" %02X", data[i]); - } - printf("\n"); - } - - fail_unless(p != NULL); - for(q = p; q != NULL; q = q->next) { - memcpy(q->payload, data, q->len); - data += q->len; - } - netif->input(p, netif); -} - -static err_t lwip_tx_func(struct netif *netif, struct pbuf *p); - -static err_t testif_init(struct netif *netif) -{ - netif->name[0] = 'c'; - netif->name[1] = 'h'; - netif->output = etharp_output; - netif->linkoutput = lwip_tx_func; - netif->mtu = 1500; - netif->hwaddr_len = 6; - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; - - netif->hwaddr[0] = 0x00; - netif->hwaddr[1] = 0x23; - netif->hwaddr[2] = 0xC1; - netif->hwaddr[3] = 0xDE; - netif->hwaddr[4] = 0xD0; - netif->hwaddr[5] = 0x0D; - - return ERR_OK; -} - -static void dhcp_setup(void) -{ - txpacket = 0; -} - -static void dhcp_teardown(void) -{ -} - -static void check_pkt(struct pbuf *p, u32_t pos, const u8_t *mem, u32_t len) -{ - u8_t *data; - - fail_if((pos + len) > p->tot_len); - while (pos > p->len && p->next) { - pos -= p->len; - p = p->next; - } - fail_if(p == NULL); - fail_unless(pos + len <= p->len); /* All data we seek within same pbuf */ - - data = (u8_t*)p->payload; - fail_if(memcmp(&data[pos], mem, len), "data at pos %d, len %d in packet %d did not match", pos, len, txpacket); -} - -static void check_pkt_fuzzy(struct pbuf *p, u32_t startpos, const u8_t *mem, u32_t len) -{ - int found; - u32_t i; - u8_t *data; - - fail_if((startpos + len) > p->tot_len); - while (startpos > p->len && p->next) { - startpos -= p->len; - p = p->next; - } - fail_if(p == NULL); - fail_unless(startpos + len <= p->len); /* All data we seek within same pbuf */ - - found = 0; - data = (u8_t*)p->payload; - for (i = startpos; i <= (p->len - len); i++) { - if (memcmp(&data[i], mem, len) == 0) { - found = 1; - break; - } - } - fail_unless(found); -} - -static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) -{ - fail_unless(netif == &net_test); - txpacket++; - - if (debug) { - struct pbuf *pp = p; - /* Dump data */ - printf("TX data (pkt %d, len %d, tick %d)", txpacket, p->tot_len, tick); - do { - int i; - for (i = 0; i < pp->len; i++) { - printf(" %02X", ((u8_t *) pp->payload)[i]); - } - if (pp->next) { - pp = pp->next; - } - } while (pp->next); - printf("\n"); - } - - switch (tcase) { - case TEST_LWIP_DHCP: - switch (txpacket) { - case 1: - case 2: - { - const u8_t ipproto[] = { 0x08, 0x00 }; - const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ - const u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ - check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ - - check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ - - check_pkt(p, 42, bootp_start, sizeof(bootp_start)); - - check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); - - check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ - - check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); - - /* Check dchp message type, can be at different positions */ - if (txpacket == 1) { - u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 }; - check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt)); - } else if (txpacket == 2) { - u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; - u8_t requested_ipaddr[] = { 0x32, 0x04, 0xc3, 0xaa, 0xbd, 0xc8 }; /* Ask for offered IP */ - - check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); - check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); - } - break; - } - case 3: - case 4: - case 5: - { - const u8_t arpproto[] = { 0x08, 0x06 }; - - check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ - check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ - - check_pkt(p, 12, arpproto, sizeof(arpproto)); /* eth level proto: ip */ - break; - } - default: - fail(); - break; - } - break; - - case TEST_LWIP_DHCP_NAK: - { - const u8_t ipproto[] = { 0x08, 0x00 }; - const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ - const u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - const u8_t dhcp_nak_opt[] = { 0x35, 0x01, 0x04 }; - const u8_t requested_ipaddr[] = { 0x32, 0x04, 0xc3, 0xaa, 0xbd, 0xc8 }; /* offered IP */ - - fail_unless(txpacket == 4); - check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ - check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ - - check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ - - check_pkt(p, 42, bootp_start, sizeof(bootp_start)); - - check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); - - check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ - - check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); - - check_pkt_fuzzy(p, 282, dhcp_nak_opt, sizeof(dhcp_nak_opt)); /* NAK the ack */ - - check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); - break; - } - - case TEST_LWIP_DHCP_RELAY: - switch (txpacket) { - case 1: - case 2: - { - const u8_t ipproto[] = { 0x08, 0x00 }; - const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ - const u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ - check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ - - check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ - - check_pkt(p, 42, bootp_start, sizeof(bootp_start)); - - check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); - - check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ - - check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); - - /* Check dchp message type, can be at different positions */ - if (txpacket == 1) { - u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 }; - check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt)); - } else if (txpacket == 2) { - u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; - u8_t requested_ipaddr[] = { 0x32, 0x04, 0x4f, 0x8a, 0x33, 0x05 }; /* Ask for offered IP */ - - check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); - check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); - } - break; - } - case 3: - case 4: - case 5: - case 6: - { - const u8_t arpproto[] = { 0x08, 0x06 }; - - check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ - check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ - - check_pkt(p, 12, arpproto, sizeof(arpproto)); /* eth level proto: ip */ - break; - } - case 7: - { - const u8_t fake_arp[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab }; - const u8_t ipproto[] = { 0x08, 0x00 }; - const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ - const u8_t ipaddrs[] = { 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - const u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; - - check_pkt(p, 0, fake_arp, 6); /* eth level dest: broadcast */ - check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ - - check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ - - check_pkt(p, 42, bootp_start, sizeof(bootp_start)); - - check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); - - check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ - - check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); - - /* Check dchp message type, can be at different positions */ - check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); - break; - } - default: - fail(); - break; - } - break; - - default: - break; - } - - return ERR_OK; -} - -/* - * Test basic happy flow DHCP session. - * Validate that xid is checked. - */ -START_TEST(test_dhcp) -{ - ip4_addr_t addr; - ip4_addr_t netmask; - ip4_addr_t gw; - int i; - u32_t xid; - LWIP_UNUSED_ARG(_i); - - tcase = TEST_LWIP_DHCP; - setdebug(0); - - IP4_ADDR(&addr, 0, 0, 0, 0); - IP4_ADDR(&netmask, 0, 0, 0, 0); - IP4_ADDR(&gw, 0, 0, 0, 0); - - netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); - netif_set_up(&net_test); - - dhcp_start(&net_test); - - fail_unless(txpacket == 1); /* DHCP discover sent */ - xid = net_test.dhcp->xid; /* Write bad xid, not using htonl! */ - memcpy(&dhcp_offer[46], &xid, 4); - send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); - - /* IP addresses should be zero */ - fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); - fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); - fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); - - fail_unless(txpacket == 1, "TX %d packets, expected 1", txpacket); /* Nothing more sent */ - xid = htonl(net_test.dhcp->xid); - memcpy(&dhcp_offer[46], &xid, 4); /* insert correct transaction id */ - send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); - - fail_unless(txpacket == 2, "TX %d packets, expected 2", txpacket); /* DHCP request sent */ - xid = net_test.dhcp->xid; /* Write bad xid, not using htonl! */ - memcpy(&dhcp_ack[46], &xid, 4); - send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); - - fail_unless(txpacket == 2, "TX %d packets, still expected 2", txpacket); /* No more sent */ - xid = htonl(net_test.dhcp->xid); /* xid updated */ - memcpy(&dhcp_ack[46], &xid, 4); /* insert transaction id */ - send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); - - for (i = 0; i < 20; i++) { - tick_lwip(); - } - fail_unless(txpacket == 5, "TX %d packets, expected 5", txpacket); /* ARP requests sent */ - - /* Interface up */ - fail_unless(netif_is_up(&net_test)); - - /* Now it should have taken the IP */ - IP4_ADDR(&addr, 195, 170, 189, 200); - IP4_ADDR(&netmask, 255, 255, 255, 0); - IP4_ADDR(&gw, 195, 170, 189, 171); - fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); - fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); - fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); - - netif_remove(&net_test); -} -END_TEST - -/* - * Test that IP address is not taken and NAK is sent if someone - * replies to ARP requests for the offered address. - */ -START_TEST(test_dhcp_nak) -{ - ip4_addr_t addr; - ip4_addr_t netmask; - ip4_addr_t gw; - u32_t xid; - LWIP_UNUSED_ARG(_i); - - tcase = TEST_LWIP_DHCP; - setdebug(0); - - IP4_ADDR(&addr, 0, 0, 0, 0); - IP4_ADDR(&netmask, 0, 0, 0, 0); - IP4_ADDR(&gw, 0, 0, 0, 0); - - netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); - netif_set_up(&net_test); - - dhcp_start(&net_test); - - fail_unless(txpacket == 1); /* DHCP discover sent */ - xid = net_test.dhcp->xid; /* Write bad xid, not using htonl! */ - memcpy(&dhcp_offer[46], &xid, 4); - send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); - - /* IP addresses should be zero */ - fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); - fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); - fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); - - fail_unless(txpacket == 1); /* Nothing more sent */ - xid = htonl(net_test.dhcp->xid); - memcpy(&dhcp_offer[46], &xid, 4); /* insert correct transaction id */ - send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); - - fail_unless(txpacket == 2); /* DHCP request sent */ - xid = net_test.dhcp->xid; /* Write bad xid, not using htonl! */ - memcpy(&dhcp_ack[46], &xid, 4); - send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); - - fail_unless(txpacket == 2); /* No more sent */ - xid = htonl(net_test.dhcp->xid); /* xid updated */ - memcpy(&dhcp_ack[46], &xid, 4); /* insert transaction id */ - send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); - - fail_unless(txpacket == 3); /* ARP request sent */ - - tcase = TEST_LWIP_DHCP_NAK; /* Switch testcase */ - - /* Send arp reply, mark offered IP as taken */ - send_pkt(&net_test, arpreply, sizeof(arpreply)); - - fail_unless(txpacket == 4); /* DHCP nak sent */ - - netif_remove(&net_test); -} -END_TEST - -/* - * Test case based on captured data where - * replies are sent from a different IP than the - * one the client unicasted to. - */ -START_TEST(test_dhcp_relayed) -{ - u8_t relay_offer[] = { - 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, - 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, - 0x08, 0x00, 0x45, 0x00, - 0x01, 0x38, 0xfd, 0x53, 0x00, 0x00, 0x40, 0x11, - 0x78, 0x46, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, - 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, - 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x51, 0x35, - 0xb6, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, - 0xc1, 0xde, 0xd0, 0x0d, 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, 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, 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, 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, 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, 0x00, 0x00, 0x63, 0x82, - 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, - 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, - 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, - 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, - 0x00, 0x00, 0x54, 0x49, 0x35, 0x01, 0x02, 0x36, - 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff - }; - - u8_t relay_ack1[] = { - 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x22, - 0x93, 0x5a, 0xf7, 0x60, 0x08, 0x00, 0x45, 0x00, - 0x01, 0x38, 0xfd, 0x55, 0x00, 0x00, 0x40, 0x11, - 0x78, 0x44, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, - 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, - 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x51, 0x35, - 0xb6, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, - 0xc1, 0xde, 0xd0, 0x0d, 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, 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, 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, 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, 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, 0x00, 0x00, 0x63, 0x82, - 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, - 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, - 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, - 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, - 0x00, 0x00, 0x54, 0x49, 0x35, 0x01, 0x05, 0x36, - 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff - }; - - u8_t relay_ack2[] = { - 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, - 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, - 0x08, 0x00, 0x45, 0x00, - 0x01, 0x38, 0xfa, 0x18, 0x00, 0x00, 0x40, 0x11, - 0x7b, 0x81, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, - 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, - 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x49, 0x8b, - 0x6e, 0xab, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x8a, - 0x33, 0x05, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, - 0xc1, 0xde, 0xd0, 0x0d, 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, 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, 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, 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, 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, 0x00, 0x00, 0x63, 0x82, - 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, - 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, - 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, - 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, - 0x00, 0x00, 0x54, 0x60, 0x35, 0x01, 0x05, 0x36, - 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff }; - - const u8_t arp_resp[] = { - 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* DEST */ - 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, /* SRC */ - 0x08, 0x06, /* Type: ARP */ - 0x00, 0x01, /* HW: Ethernet */ - 0x08, 0x00, /* PROTO: IP */ - 0x06, /* HW size */ - 0x04, /* PROTO size */ - 0x00, 0x02, /* OPCODE: Reply */ - - 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab, /* Target MAC */ - 0x4f, 0x8a, 0x32, 0x01, /* Target IP */ - - 0x00, 0x23, 0xc1, 0x00, 0x06, 0x50, /* src mac */ - 0x4f, 0x8a, 0x33, 0x05, /* src ip */ - - /* Padding follows.. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - - ip4_addr_t addr; - ip4_addr_t netmask; - ip4_addr_t gw; - int i; - u32_t xid; - LWIP_UNUSED_ARG(_i); - - tcase = TEST_LWIP_DHCP_RELAY; - setdebug(0); - - IP4_ADDR(&addr, 0, 0, 0, 0); - IP4_ADDR(&netmask, 0, 0, 0, 0); - IP4_ADDR(&gw, 0, 0, 0, 0); - - netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); - netif_set_up(&net_test); - - dhcp_start(&net_test); - - fail_unless(txpacket == 1); /* DHCP discover sent */ - - /* IP addresses should be zero */ - fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); - fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); - fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); - - fail_unless(txpacket == 1); /* Nothing more sent */ - xid = htonl(net_test.dhcp->xid); - memcpy(&relay_offer[46], &xid, 4); /* insert correct transaction id */ - send_pkt(&net_test, relay_offer, sizeof(relay_offer)); - - /* request sent? */ - fail_unless(txpacket == 2, "txpkt = %d, should be 2", txpacket); - xid = htonl(net_test.dhcp->xid); /* xid updated */ - memcpy(&relay_ack1[46], &xid, 4); /* insert transaction id */ - send_pkt(&net_test, relay_ack1, sizeof(relay_ack1)); - - for (i = 0; i < 25; i++) { - tick_lwip(); - } - fail_unless(txpacket == 5, "txpkt should be 5, is %d", txpacket); /* ARP requests sent */ - - /* Interface up */ - fail_unless(netif_is_up(&net_test)); - - /* Now it should have taken the IP */ - IP4_ADDR(&addr, 79, 138, 51, 5); - IP4_ADDR(&netmask, 255, 255, 254, 0); - IP4_ADDR(&gw, 79, 138, 50, 1); - fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); - fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); - fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); - - fail_unless(txpacket == 5, "txpacket = %d", txpacket); - - for (i = 0; i < 108000 - 25; i++) { - tick_lwip(); - } - - fail_unless(netif_is_up(&net_test)); - fail_unless(txpacket == 6, "txpacket = %d", txpacket); - - /* We need to send arp response here.. */ - - send_pkt(&net_test, arp_resp, sizeof(arp_resp)); - - fail_unless(txpacket == 7, "txpacket = %d", txpacket); - fail_unless(netif_is_up(&net_test)); - - xid = htonl(net_test.dhcp->xid); /* xid updated */ - memcpy(&relay_ack2[46], &xid, 4); /* insert transaction id */ - send_pkt(&net_test, relay_ack2, sizeof(relay_ack2)); - - for (i = 0; i < 100000; i++) { - tick_lwip(); - } - - fail_unless(txpacket == 7, "txpacket = %d", txpacket); - - netif_remove(&net_test); - -} -END_TEST - -START_TEST(test_dhcp_nak_no_endmarker) -{ - ip4_addr_t addr; - ip4_addr_t netmask; - ip4_addr_t gw; - - u8_t dhcp_nack_no_endmarker[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x54, 0x75, - 0xd0, 0x26, 0xd0, 0x0d, 0x08, 0x00, 0x45, 0x00, - 0x01, 0x15, 0x38, 0x86, 0x00, 0x00, 0xff, 0x11, - 0xc0, 0xa8, 0xc0, 0xa8, 0x01, 0x01, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x43, 0x00, 0x44, 0x01, 0x01, - 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x7a, 0xcb, - 0xba, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, - 0xc1, 0xde, 0xd0, 0x0d, 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, 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, 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, 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, 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, 0x00, 0x00, 0x63, 0x82, - 0x53, 0x63, 0x35, 0x01, 0x06, 0x36, 0x04, 0xc0, - 0xa8, 0x01, 0x01, 0x31, 0xef, 0xad, 0x72, 0x31, - 0x43, 0x4e, 0x44, 0x30, 0x32, 0x35, 0x30, 0x43, - 0x52, 0x47, 0x44, 0x38, 0x35, 0x36, 0x3c, 0x08, - 0x4d, 0x53, 0x46, 0x54, 0x20, 0x35, 0x2e, 0x30, - 0x37, 0x0d, 0x01, 0x0f, 0x03, 0x06, 0x2c, 0x2e, - 0x2f, 0x1f, 0x21, 0x79, 0xf9, 0x2b, 0xfc, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x71, - 0xf3, 0x5b, 0xe2, 0x71, 0x2e, 0x01, 0x08, 0x03, - 0x04, 0xc0, 0xa8, 0x01, 0x01, 0xff, 0xeb, 0x1e, - 0x44, 0xec, 0xeb, 0x1e, 0x30, 0x37, 0x0c, 0x01, - 0x0f, 0x03, 0x06, 0x2c, 0x2e, 0x2f, 0x1f, 0x21, - 0x79, 0xf9, 0x2b, 0xff, 0x25, 0xc0, 0x09, 0xd6, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - u32_t xid; - LWIP_UNUSED_ARG(_i); - - tcase = TEST_LWIP_DHCP_NAK_NO_ENDMARKER; - setdebug(0); - - IP4_ADDR(&addr, 0, 0, 0, 0); - IP4_ADDR(&netmask, 0, 0, 0, 0); - IP4_ADDR(&gw, 0, 0, 0, 0); - - netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); - netif_set_up(&net_test); - - dhcp_start(&net_test); - - fail_unless(txpacket == 1); /* DHCP discover sent */ - xid = net_test.dhcp->xid; /* Write bad xid, not using htonl! */ - memcpy(&dhcp_offer[46], &xid, 4); - send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); - - /* IP addresses should be zero */ - fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); - fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); - fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); - - fail_unless(txpacket == 1); /* Nothing more sent */ - xid = htonl(net_test.dhcp->xid); - memcpy(&dhcp_offer[46], &xid, 4); /* insert correct transaction id */ - send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); - - fail_unless(net_test.dhcp->state == DHCP_STATE_REQUESTING); - - fail_unless(txpacket == 2); /* No more sent */ - xid = htonl(net_test.dhcp->xid); /* xid updated */ - memcpy(&dhcp_nack_no_endmarker[46], &xid, 4); /* insert transaction id */ - send_pkt(&net_test, dhcp_nack_no_endmarker, sizeof(dhcp_nack_no_endmarker)); - - /* NAK should put us in another state for a while, no other way detecting it */ - fail_unless(net_test.dhcp->state != DHCP_STATE_REQUESTING); - - netif_remove(&net_test); -} -END_TEST - - -/** Create the suite including all tests for this module */ -Suite * -dhcp_suite(void) -{ - testfunc tests[] = { - TESTFUNC(test_dhcp), - TESTFUNC(test_dhcp_nak), - TESTFUNC(test_dhcp_relayed), - TESTFUNC(test_dhcp_nak_no_endmarker) - }; - return create_suite("DHCP", tests, sizeof(tests)/sizeof(testfunc), dhcp_setup, dhcp_teardown); -} diff --git a/ext/lwip/test/unit/dhcp/test_dhcp.h b/ext/lwip/test/unit/dhcp/test_dhcp.h deleted file mode 100644 index 480aab9..0000000 --- a/ext/lwip/test/unit/dhcp/test_dhcp.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LWIP_HDR_TEST_DHCP_H__ -#define LWIP_HDR_TEST_DHCP_H__ - -#include "../lwip_check.h" - -Suite* dhcp_suite(void); - -#endif diff --git a/ext/lwip/test/unit/etharp/test_etharp.c b/ext/lwip/test/unit/etharp/test_etharp.c deleted file mode 100644 index ba9a40d..0000000 --- a/ext/lwip/test/unit/etharp/test_etharp.c +++ /dev/null @@ -1,268 +0,0 @@ -#include "test_etharp.h" - -#include "lwip/udp.h" -#include "netif/etharp.h" -#include "lwip/stats.h" - -#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS || !ETHARP_STATS -#error "This tests needs UDP-, MEMP- and ETHARP-statistics enabled" -#endif -#if !ETHARP_SUPPORT_STATIC_ENTRIES -#error "This test needs ETHARP_SUPPORT_STATIC_ENTRIES enabled" -#endif - -static struct netif test_netif; -static ip4_addr_t test_ipaddr, test_netmask, test_gw; -struct eth_addr test_ethaddr = {{1,1,1,1,1,1}}; -struct eth_addr test_ethaddr2 = {{1,1,1,1,1,2}}; -struct eth_addr test_ethaddr3 = {{1,1,1,1,1,3}}; -struct eth_addr test_ethaddr4 = {{1,1,1,1,1,4}}; -static int linkoutput_ctr; - -/* Helper functions */ -static void -etharp_remove_all(void) -{ - int i; - /* call etharp_tmr often enough to have all entries cleaned */ - for(i = 0; i < 0xff; i++) { - etharp_tmr(); - } -} - -static err_t -default_netif_linkoutput(struct netif *netif, struct pbuf *p) -{ - fail_unless(netif == &test_netif); - fail_unless(p != NULL); - linkoutput_ctr++; - return ERR_OK; -} - -static err_t -default_netif_init(struct netif *netif) -{ - fail_unless(netif != NULL); - netif->linkoutput = default_netif_linkoutput; - netif->output = etharp_output; - netif->mtu = 1500; - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; - netif->hwaddr_len = ETHARP_HWADDR_LEN; - return ERR_OK; -} - -static void -default_netif_add(void) -{ - IP4_ADDR(&test_gw, 192,168,0,1); - IP4_ADDR(&test_ipaddr, 192,168,0,1); - IP4_ADDR(&test_netmask, 255,255,0,0); - - fail_unless(netif_default == NULL); - netif_set_default(netif_add(&test_netif, &test_ipaddr, &test_netmask, - &test_gw, NULL, default_netif_init, NULL)); - netif_set_up(&test_netif); -} - -static void -default_netif_remove(void) -{ - fail_unless(netif_default == &test_netif); - netif_remove(&test_netif); -} - -static void -create_arp_response(ip4_addr_t *adr) -{ - int k; - struct eth_hdr *ethhdr; - struct etharp_hdr *etharphdr; - struct pbuf *p = pbuf_alloc(PBUF_RAW, sizeof(struct eth_hdr) + sizeof(struct etharp_hdr), PBUF_RAM); - if(p == NULL) { - FAIL_RET(); - } - ethhdr = (struct eth_hdr*)p->payload; - etharphdr = (struct etharp_hdr*)(ethhdr + 1); - - ethhdr->dest = test_ethaddr; - ethhdr->src = test_ethaddr2; - ethhdr->type = htons(ETHTYPE_ARP); - - etharphdr->hwtype = htons(/*HWTYPE_ETHERNET*/ 1); - etharphdr->proto = htons(ETHTYPE_IP); - etharphdr->hwlen = ETHARP_HWADDR_LEN; - etharphdr->protolen = sizeof(ip4_addr_t); - etharphdr->opcode = htons(ARP_REPLY); - - SMEMCPY(ðarphdr->sipaddr, adr, sizeof(ip4_addr_t)); - SMEMCPY(ðarphdr->dipaddr, &test_ipaddr, sizeof(ip4_addr_t)); - - k = 6; - while(k > 0) { - k--; - /* Write the ARP MAC-Addresses */ - etharphdr->shwaddr.addr[k] = test_ethaddr2.addr[k]; - etharphdr->dhwaddr.addr[k] = test_ethaddr.addr[k]; - /* Write the Ethernet MAC-Addresses */ - ethhdr->dest.addr[k] = test_ethaddr.addr[k]; - ethhdr->src.addr[k] = test_ethaddr2.addr[k]; - } - - ethernet_input(p, &test_netif); -} - -/* Setups/teardown functions */ - -static void -etharp_setup(void) -{ - etharp_remove_all(); - default_netif_add(); -} - -static void -etharp_teardown(void) -{ - etharp_remove_all(); - default_netif_remove(); -} - - -/* Test functions */ - -START_TEST(test_etharp_table) -{ -#if ETHARP_SUPPORT_STATIC_ENTRIES - err_t err; -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - s8_t idx; - const ip4_addr_t *unused_ipaddr; - struct eth_addr *unused_ethaddr; - struct udp_pcb* pcb; - LWIP_UNUSED_ARG(_i); - - if (netif_default != &test_netif) { - fail("This test needs a default netif"); - } - - linkoutput_ctr = 0; - - pcb = udp_new(); - fail_unless(pcb != NULL); - if (pcb != NULL) { - ip4_addr_t adrs[ARP_TABLE_SIZE + 2]; - int i; - for(i = 0; i < ARP_TABLE_SIZE + 2; i++) { - IP4_ADDR(&adrs[i], 192,168,0,i+2); - } - /* fill ARP-table with dynamic entries */ - for(i = 0; i < ARP_TABLE_SIZE; i++) { - struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM); - fail_unless(p != NULL); - if (p != NULL) { - err_t err2; - ip_addr_t dst; - ip_addr_copy_from_ip4(dst, adrs[i]); - err2 = udp_sendto(pcb, p, &dst, 123); - fail_unless(err2 == ERR_OK); - /* etharp request sent? */ - fail_unless(linkoutput_ctr == (2*i) + 1); - pbuf_free(p); - - /* create an ARP response */ - create_arp_response(&adrs[i]); - /* queued UDP packet sent? */ - fail_unless(linkoutput_ctr == (2*i) + 2); - - idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr); - fail_unless(idx == i); - etharp_tmr(); - } - } - linkoutput_ctr = 0; -#if ETHARP_SUPPORT_STATIC_ENTRIES - /* create one static entry */ - err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE], &test_ethaddr3); - fail_unless(err == ERR_OK); - idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); - fail_unless(idx == 0); - fail_unless(linkoutput_ctr == 0); -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - - linkoutput_ctr = 0; - /* fill ARP-table with dynamic entries */ - for(i = 0; i < ARP_TABLE_SIZE; i++) { - struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM); - fail_unless(p != NULL); - if (p != NULL) { - err_t err2; - ip_addr_t dst; - ip_addr_copy_from_ip4(dst, adrs[i]); - err2 = udp_sendto(pcb, p, &dst, 123); - fail_unless(err2 == ERR_OK); - /* etharp request sent? */ - fail_unless(linkoutput_ctr == (2*i) + 1); - pbuf_free(p); - - /* create an ARP response */ - create_arp_response(&adrs[i]); - /* queued UDP packet sent? */ - fail_unless(linkoutput_ctr == (2*i) + 2); - - idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr); - if (i < ARP_TABLE_SIZE - 1) { - fail_unless(idx == i+1); - } else { - /* the last entry must not overwrite the static entry! */ - fail_unless(idx == 1); - } - etharp_tmr(); - } - } -#if ETHARP_SUPPORT_STATIC_ENTRIES - /* create a second static entry */ - err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE+1], &test_ethaddr4); - fail_unless(err == ERR_OK); - idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); - fail_unless(idx == 0); - idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr); - fail_unless(idx == 2); - /* and remove it again */ - err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE+1]); - fail_unless(err == ERR_OK); - idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); - fail_unless(idx == 0); - idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr); - fail_unless(idx == -1); -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - - /* check that static entries don't time out */ - etharp_remove_all(); - idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); - fail_unless(idx == 0); - -#if ETHARP_SUPPORT_STATIC_ENTRIES - /* remove the first static entry */ - err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE]); - fail_unless(err == ERR_OK); - idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); - fail_unless(idx == -1); - idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr); - fail_unless(idx == -1); -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - - udp_remove(pcb); - } -} -END_TEST - - -/** Create the suite including all tests for this module */ -Suite * -etharp_suite(void) -{ - testfunc tests[] = { - TESTFUNC(test_etharp_table) - }; - return create_suite("ETHARP", tests, sizeof(tests)/sizeof(testfunc), etharp_setup, etharp_teardown); -} diff --git a/ext/lwip/test/unit/etharp/test_etharp.h b/ext/lwip/test/unit/etharp/test_etharp.h deleted file mode 100644 index fac7c9c..0000000 --- a/ext/lwip/test/unit/etharp/test_etharp.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LWIP_HDR_TEST_ETHARP_H__ -#define LWIP_HDR_TEST_ETHARP_H__ - -#include "../lwip_check.h" - -Suite* etharp_suite(void); - -#endif diff --git a/ext/lwip/test/unit/lwip_check.h b/ext/lwip/test/unit/lwip_check.h deleted file mode 100644 index 2126e2f..0000000 --- a/ext/lwip/test/unit/lwip_check.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef LWIP_HDR_LWIP_CHECK_H__ -#define LWIP_HDR_LWIP_CHECK_H__ - -/* Common header file for lwIP unit tests using the check framework */ - -#include -#include -#include - -#define FAIL_RET() do { fail(); return; } while(0) -#define EXPECT(x) fail_unless(x) -#define EXPECT_RET(x) do { fail_unless(x); if(!(x)) { return; }} while(0) -#define EXPECT_RETX(x, y) do { fail_unless(x); if(!(x)) { return y; }} while(0) -#define EXPECT_RETNULL(x) EXPECT_RETX(x, NULL) - -typedef struct { - TFun func; - const char *name; -} testfunc; - -#define TESTFUNC(x) {(x), "" # x "" } - -/* Modified function from check.h, supplying function name */ -#define tcase_add_named_test(tc,tf) \ - _tcase_add_test((tc),(tf).func,(tf).name,0, 0, 0, 1) - -/** typedef for a function returning a test suite */ -typedef Suite* (suite_getter_fn)(void); - -/** Create a test suite */ -Suite* create_suite(const char* name, testfunc *tests, size_t num_tests, SFun setup, SFun teardown); - -#ifdef LWIP_UNITTESTS_LIB -int lwip_unittests_run(void) -#endif - -#endif /* LWIP_HDR_LWIP_CHECK_H__ */ diff --git a/ext/lwip/test/unit/lwip_unittests.c b/ext/lwip/test/unit/lwip_unittests.c deleted file mode 100644 index b702884..0000000 --- a/ext/lwip/test/unit/lwip_unittests.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "lwip_check.h" - -#include "udp/test_udp.h" -#include "tcp/test_tcp.h" -#include "tcp/test_tcp_oos.h" -#include "core/test_mem.h" -#include "core/test_pbuf.h" -#include "etharp/test_etharp.h" -#include "dhcp/test_dhcp.h" - -#include "lwip/init.h" - -Suite* create_suite(const char* name, testfunc *tests, size_t num_tests, SFun setup, SFun teardown) -{ - size_t i; - Suite *s = suite_create(name); - - for(i = 0; i < num_tests; i++) { - TCase *tc_core = tcase_create(name); - if ((setup != NULL) || (teardown != NULL)) { - tcase_add_checked_fixture(tc_core, setup, teardown); - } - tcase_add_named_test(tc_core, tests[i]); - suite_add_tcase(s, tc_core); - } - return s; -} - -#ifdef LWIP_UNITTESTS_LIB -int lwip_unittests_run(void) -#else -int main(void) -#endif -{ - int number_failed; - SRunner *sr; - size_t i; - suite_getter_fn* suites[] = { - udp_suite, - tcp_suite, - tcp_oos_suite, - mem_suite, - pbuf_suite, - etharp_suite, - dhcp_suite - }; - size_t num = sizeof(suites)/sizeof(void*); - LWIP_ASSERT("No suites defined", num > 0); - - lwip_init(); - - sr = srunner_create((suites[0])()); - for(i = 1; i < num; i++) { - srunner_add_suite(sr, ((suite_getter_fn*)suites[i])()); - } - -#ifdef LWIP_UNITTESTS_NOFORK - srunner_set_fork_status(sr, CK_NOFORK); -#endif -#ifdef LWIP_UNITTESTS_FORK - srunner_set_fork_status(sr, CK_FORK); -#endif - - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/ext/lwip/test/unit/lwipopts.h b/ext/lwip/test/unit/lwipopts.h deleted file mode 100644 index 5cda431..0000000 --- a/ext/lwip/test/unit/lwipopts.h +++ /dev/null @@ -1,57 +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: Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_LWIPOPTS_H__ -#define LWIP_HDR_LWIPOPTS_H__ - -/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */ -#define NO_SYS 1 -#define SYS_LIGHTWEIGHT_PROT 0 -#define LWIP_NETCONN 0 -#define LWIP_SOCKET 0 - -/* Enable DHCP to test it, disable UDP checksum to easier inject packets */ -#define LWIP_DHCP 1 - -/* Minimal changes to opt.h required for tcp unit tests: */ -#define MEM_SIZE 16000 -#define TCP_SND_QUEUELEN 40 -#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN -#define TCP_SND_BUF (12 * TCP_MSS) -#define TCP_WND (10 * TCP_MSS) -#define LWIP_WND_SCALE 1 -#define TCP_RCV_SCALE 0 -#define PBUF_POOL_SIZE 400 /* pbuf tests need ~200KByte */ - -/* Minimal changes to opt.h required for etharp unit tests: */ -#define ETHARP_SUPPORT_STATIC_ENTRIES 1 - -#endif /* LWIP_HDR_LWIPOPTS_H__ */ diff --git a/ext/lwip/test/unit/tcp/tcp_helper.c b/ext/lwip/test/unit/tcp/tcp_helper.c deleted file mode 100644 index fc7e67f..0000000 --- a/ext/lwip/test/unit/tcp/tcp_helper.c +++ /dev/null @@ -1,305 +0,0 @@ -#include "tcp_helper.h" - -#include "lwip/priv/tcp_priv.h" -#include "lwip/stats.h" -#include "lwip/pbuf.h" -#include "lwip/inet_chksum.h" -#include "lwip/ip_addr.h" - -#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS -#error "This tests needs TCP- and MEMP-statistics enabled" -#endif - -/** Remove all pcbs on the given list. */ -static void -tcp_remove(struct tcp_pcb* pcb_list) -{ - struct tcp_pcb *pcb = pcb_list; - struct tcp_pcb *pcb2; - - while(pcb != NULL) { - pcb2 = pcb; - pcb = pcb->next; - tcp_abort(pcb2); - } -} - -/** Remove all pcbs on listen-, active- and time-wait-list (bound- isn't exported). */ -void -tcp_remove_all(void) -{ - tcp_remove(tcp_listen_pcbs.pcbs); - tcp_remove(tcp_active_pcbs); - tcp_remove(tcp_tw_pcbs); - fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); - fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) == 0); - fail_unless(MEMP_STATS_GET(used, MEMP_TCP_SEG) == 0); - fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0); -} - -/** Create a TCP segment usable for passing to tcp_input */ -static struct pbuf* -tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* dst_ip, - u16_t src_port, u16_t dst_port, void* data, size_t data_len, - u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd) -{ - struct pbuf *p, *q; - struct ip_hdr* iphdr; - struct tcp_hdr* tcphdr; - u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len); - LWIP_ASSERT("data_len too big", data_len <= 0xFFFF); - - p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL); - EXPECT_RETNULL(p != NULL); - /* first pbuf must be big enough to hold the headers */ - EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); - if (data_len > 0) { - /* first pbuf must be big enough to hold at least 1 data byte, too */ - EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); - } - - for(q = p; q != NULL; q = q->next) { - memset(q->payload, 0, q->len); - } - - iphdr = (struct ip_hdr*)p->payload; - /* fill IP header */ - iphdr->dest.addr = ip_2_ip4(dst_ip)->addr; - iphdr->src.addr = ip_2_ip4(src_ip)->addr; - IPH_VHL_SET(iphdr, 4, IP_HLEN / 4); - IPH_TOS_SET(iphdr, 0); - IPH_LEN_SET(iphdr, htons(p->tot_len)); - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); - - /* let p point to TCP header */ - pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); - - tcphdr = (struct tcp_hdr*)p->payload; - tcphdr->src = htons(src_port); - tcphdr->dest = htons(dst_port); - tcphdr->seqno = htonl(seqno); - tcphdr->ackno = htonl(ackno); - TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4); - TCPH_FLAGS_SET(tcphdr, headerflags); - tcphdr->wnd = htons(wnd); - - if (data_len > 0) { - /* let p point to TCP data */ - pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr)); - /* copy data */ - pbuf_take(p, data, (u16_t)data_len); - /* let p point to TCP header again */ - pbuf_header(p, sizeof(struct tcp_hdr)); - } - - /* calculate checksum */ - - tcphdr->chksum = ip_chksum_pseudo(p, - IP_PROTO_TCP, p->tot_len, src_ip, dst_ip); - - pbuf_header(p, sizeof(struct ip_hdr)); - - return p; -} - -/** Create a TCP segment usable for passing to tcp_input */ -struct pbuf* -tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, - u16_t src_port, u16_t dst_port, void* data, size_t data_len, - u32_t seqno, u32_t ackno, u8_t headerflags) -{ - return tcp_create_segment_wnd(src_ip, dst_ip, src_port, dst_port, data, - data_len, seqno, ackno, headerflags, TCP_WND); -} - -/** Create a TCP segment usable for passing to tcp_input - * - IP-addresses, ports, seqno and ackno are taken from pcb - * - seqno and ackno can be altered with an offset - */ -struct pbuf* -tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset, - u32_t ackno_offset, u8_t headerflags) -{ - return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, - data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags); -} - -/** Create a TCP segment usable for passing to tcp_input - * - IP-addresses, ports, seqno and ackno are taken from pcb - * - seqno and ackno can be altered with an offset - * - TCP window can be adjusted - */ -struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len, - u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd) -{ - return tcp_create_segment_wnd(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, - data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags, wnd); -} - -/** Safely bring a tcp_pcb into the requested state */ -void -tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip, - ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port) -{ - /* @todo: are these all states? */ - /* @todo: remove from previous list */ - pcb->state = state; - if (state == ESTABLISHED) { - TCP_REG(&tcp_active_pcbs, pcb); - pcb->local_ip.addr = local_ip->addr; - pcb->local_port = local_port; - pcb->remote_ip.addr = remote_ip->addr; - pcb->remote_port = remote_port; - } else if(state == LISTEN) { - TCP_REG(&tcp_listen_pcbs.pcbs, pcb); - pcb->local_ip.addr = local_ip->addr; - pcb->local_port = local_port; - } else if(state == TIME_WAIT) { - TCP_REG(&tcp_tw_pcbs, pcb); - pcb->local_ip.addr = local_ip->addr; - pcb->local_port = local_port; - pcb->remote_ip.addr = remote_ip->addr; - pcb->remote_port = remote_port; - } else { - fail(); - } -} - -void -test_tcp_counters_err(void* arg, err_t err) -{ - struct test_tcp_counters* counters = (struct test_tcp_counters*)arg; - EXPECT_RET(arg != NULL); - counters->err_calls++; - counters->last_err = err; -} - -static void -test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p) -{ - struct pbuf* q; - u32_t i, received; - if(counters->expected_data == NULL) { - /* no data to compare */ - return; - } - EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len); - received = counters->recved_bytes; - for(q = p; q != NULL; q = q->next) { - char *data = (char*)q->payload; - for(i = 0; i < q->len; i++) { - EXPECT_RET(data[i] == counters->expected_data[received]); - received++; - } - } - EXPECT(received == counters->recved_bytes + p->tot_len); -} - -err_t -test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) -{ - struct test_tcp_counters* counters = (struct test_tcp_counters*)arg; - EXPECT_RETX(arg != NULL, ERR_OK); - EXPECT_RETX(pcb != NULL, ERR_OK); - EXPECT_RETX(err == ERR_OK, ERR_OK); - - if (p != NULL) { - if (counters->close_calls == 0) { - counters->recv_calls++; - test_tcp_counters_check_rxdata(counters, p); - counters->recved_bytes += p->tot_len; - } else { - counters->recv_calls_after_close++; - counters->recved_bytes_after_close += p->tot_len; - } - pbuf_free(p); - } else { - counters->close_calls++; - } - EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0); - return ERR_OK; -} - -/** Allocate a pcb and set up the test_tcp_counters_* callbacks */ -struct tcp_pcb* -test_tcp_new_counters_pcb(struct test_tcp_counters* counters) -{ - struct tcp_pcb* pcb = tcp_new(); - if (pcb != NULL) { - /* set up args and callbacks */ - tcp_arg(pcb, counters); - tcp_recv(pcb, test_tcp_counters_recv); - tcp_err(pcb, test_tcp_counters_err); - pcb->snd_wnd = TCP_WND; - pcb->snd_wnd_max = TCP_WND; - } - return pcb; -} - -/** Calls tcp_input() after adjusting current_iphdr_dest */ -void test_tcp_input(struct pbuf *p, struct netif *inp) -{ - struct ip_hdr *iphdr = (struct ip_hdr*)p->payload; - /* these lines are a hack, don't use them as an example :-) */ - ip_addr_copy_from_ip4(*ip_current_dest_addr(), iphdr->dest); - ip_addr_copy_from_ip4(*ip_current_src_addr(), iphdr->src); - ip_current_netif() = inp; - ip_data.current_ip4_header = iphdr; - - /* since adding IPv6, p->payload must point to tcp header, not ip header */ - pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); - - tcp_input(p, inp); - - ip_addr_set_zero(ip_current_dest_addr()); - ip_addr_set_zero(ip_current_src_addr()); - ip_current_netif() = NULL; - ip_data.current_ip4_header = NULL; -} - -static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p, - const ip4_addr_t *ipaddr) -{ - struct test_tcp_txcounters *txcounters = (struct test_tcp_txcounters*)netif->state; - LWIP_UNUSED_ARG(ipaddr); - if (txcounters != NULL) - { - txcounters->num_tx_calls++; - txcounters->num_tx_bytes += p->tot_len; - if (txcounters->copy_tx_packets) { - struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); - err_t err; - EXPECT(p_copy != NULL); - err = pbuf_copy(p_copy, p); - EXPECT(err == ERR_OK); - if (txcounters->tx_packets == NULL) { - txcounters->tx_packets = p_copy; - } else { - pbuf_cat(txcounters->tx_packets, p_copy); - } - } - } - return ERR_OK; -} - -void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters, - ip_addr_t *ip_addr, ip_addr_t *netmask) -{ - struct netif *n; - memset(netif, 0, sizeof(struct netif)); - if (txcounters != NULL) { - memset(txcounters, 0, sizeof(struct test_tcp_txcounters)); - netif->state = txcounters; - } - netif->output = test_tcp_netif_output; - netif->flags |= NETIF_FLAG_UP | NETIF_FLAG_LINK_UP; - ip4_addr_copy(netif->netmask, *ip_2_ip4(netmask)); - ip4_addr_copy(netif->ip_addr, *ip_2_ip4(ip_addr)); - for (n = netif_list; n != NULL; n = n->next) { - if (n == netif) { - return; - } - } - netif->next = NULL; - netif_list = netif; -} diff --git a/ext/lwip/test/unit/tcp/tcp_helper.h b/ext/lwip/test/unit/tcp/tcp_helper.h deleted file mode 100644 index 4119f37..0000000 --- a/ext/lwip/test/unit/tcp/tcp_helper.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef LWIP_HDR_TCP_HELPER_H__ -#define LWIP_HDR_TCP_HELPER_H__ - -#include "../lwip_check.h" -#include "lwip/arch.h" -#include "lwip/tcp.h" -#include "lwip/netif.h" - -/* counters used for test_tcp_counters_* callback functions */ -struct test_tcp_counters { - u32_t recv_calls; - u32_t recved_bytes; - u32_t recv_calls_after_close; - u32_t recved_bytes_after_close; - u32_t close_calls; - u32_t err_calls; - err_t last_err; - char* expected_data; - u32_t expected_data_len; -}; - -struct test_tcp_txcounters { - u32_t num_tx_calls; - u32_t num_tx_bytes; - u8_t copy_tx_packets; - struct pbuf *tx_packets; -}; - -/* Helper functions */ -void tcp_remove_all(void); - -struct pbuf* tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, - u16_t src_port, u16_t dst_port, void* data, size_t data_len, - u32_t seqno, u32_t ackno, u8_t headerflags); -struct pbuf* tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, - u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags); -struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len, - u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd); -void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip, - ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port); -void test_tcp_counters_err(void* arg, err_t err); -err_t test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err); - -struct tcp_pcb* test_tcp_new_counters_pcb(struct test_tcp_counters* counters); - -void test_tcp_input(struct pbuf *p, struct netif *inp); - -void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters, - ip_addr_t *ip_addr, ip_addr_t *netmask); - - -#endif diff --git a/ext/lwip/test/unit/tcp/test_tcp.c b/ext/lwip/test/unit/tcp/test_tcp.c deleted file mode 100644 index 1b89f65..0000000 --- a/ext/lwip/test/unit/tcp/test_tcp.c +++ /dev/null @@ -1,742 +0,0 @@ -#include "test_tcp.h" - -#include "lwip/priv/tcp_priv.h" -#include "lwip/stats.h" -#include "tcp_helper.h" -#include "lwip/inet_chksum.h" - -#ifdef _MSC_VER -#pragma warning(disable: 4307) /* we explicitly wrap around TCP seqnos */ -#endif - -#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS -#error "This tests needs TCP- and MEMP-statistics enabled" -#endif -#if TCP_SND_BUF <= TCP_WND -#error "This tests needs TCP_SND_BUF to be > TCP_WND" -#endif - -static u8_t test_tcp_timer; - -/* our own version of tcp_tmr so we can reset fast/slow timer state */ -static void -test_tcp_tmr(void) -{ - tcp_fasttmr(); - if (++test_tcp_timer & 1) { - tcp_slowtmr(); - } -} - -/* Setups/teardown functions */ - -static void -tcp_setup(void) -{ - /* reset iss to default (6510) */ - tcp_ticks = 0; - tcp_ticks = 0 - (tcp_next_iss() - 6510); - tcp_next_iss(); - tcp_ticks = 0; - - test_tcp_timer = 0; - tcp_remove_all(); -} - -static void -tcp_teardown(void) -{ - tcp_remove_all(); - netif_list = NULL; - netif_default = NULL; -} - - -/* Test functions */ - -/** Call tcp_new() and tcp_abort() and test memp stats */ -START_TEST(test_tcp_new_abort) -{ - struct tcp_pcb* pcb; - LWIP_UNUSED_ARG(_i); - - fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); - - pcb = tcp_new(); - fail_unless(pcb != NULL); - if (pcb != NULL) { - fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); - } -} -END_TEST - -/** Create an ESTABLISHED pcb and check if receive callback is called */ -START_TEST(test_tcp_recv_inseq) -{ - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf* p; - char data[] = {1, 2, 3, 4}; - ip_addr_t remote_ip, local_ip, netmask; - u16_t data_len; - u16_t remote_port = 0x100, local_port = 0x101; - struct netif netif; - struct test_tcp_txcounters txcounters; - LWIP_UNUSED_ARG(_i); - - /* initialize local vars */ - memset(&netif, 0, sizeof(netif)); - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); - data_len = sizeof(data); - /* initialize counter struct */ - memset(&counters, 0, sizeof(counters)); - counters.expected_data_len = data_len; - counters.expected_data = data; - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - - /* create a segment */ - p = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0); - EXPECT(p != NULL); - if (p != NULL) { - /* pass the segment to tcp_input */ - test_tcp_input(p, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 1); - EXPECT(counters.recved_bytes == data_len); - EXPECT(counters.err_calls == 0); - } - - /* make sure the pcb is freed */ - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -} -END_TEST - -/** Check that we handle malformed tcp headers, and discard the pbuf(s) */ -START_TEST(test_tcp_malformed_header) -{ - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf* p; - char data[] = {1, 2, 3, 4}; - ip_addr_t remote_ip, local_ip, netmask; - u16_t data_len, chksum; - u16_t remote_port = 0x100, local_port = 0x101; - struct netif netif; - struct test_tcp_txcounters txcounters; - struct tcp_hdr *hdr; - LWIP_UNUSED_ARG(_i); - - /* initialize local vars */ - memset(&netif, 0, sizeof(netif)); - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); - data_len = sizeof(data); - /* initialize counter struct */ - memset(&counters, 0, sizeof(counters)); - counters.expected_data_len = data_len; - counters.expected_data = data; - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - - /* create a segment */ - p = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0); - - pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); - - hdr = (struct tcp_hdr *)p->payload; - TCPH_HDRLEN_FLAGS_SET(hdr, 15, 0x3d1); - - hdr->chksum = 0; - - chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - &remote_ip, &local_ip); - - hdr->chksum = chksum; - - pbuf_header(p, sizeof(struct ip_hdr)); - - EXPECT(p != NULL); - EXPECT(p->next == NULL); - if (p != NULL) { - /* pass the segment to tcp_input */ - test_tcp_input(p, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - } - - /* make sure the pcb is freed */ - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -} -END_TEST - - -/** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data. - * At the end, send more data. */ -START_TEST(test_tcp_fast_retx_recover) -{ - struct netif netif; - struct test_tcp_txcounters txcounters; - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf* p; - char data1[] = { 1, 2, 3, 4}; - char data2[] = { 5, 6, 7, 8}; - char data3[] = { 9, 10, 11, 12}; - char data4[] = {13, 14, 15, 16}; - char data5[] = {17, 18, 19, 20}; - char data6[] = {21, 22, 23, 24}; - ip_addr_t remote_ip, local_ip, netmask; - u16_t remote_port = 0x100, local_port = 0x101; - err_t err; - LWIP_UNUSED_ARG(_i); - - /* initialize local vars */ - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); - memset(&counters, 0, sizeof(counters)); - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - pcb->mss = TCP_MSS; - /* disable initial congestion window (we don't send a SYN here...) */ - pcb->cwnd = pcb->snd_wnd; - - /* send data1 */ - err = tcp_write(pcb, data1, sizeof(data1), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - EXPECT_RET(txcounters.num_tx_calls == 1); - EXPECT_RET(txcounters.num_tx_bytes == sizeof(data1) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr)); - memset(&txcounters, 0, sizeof(txcounters)); - /* "recv" ACK for data1 */ - p = tcp_create_rx_segment(pcb, NULL, 0, 0, 4, TCP_ACK); - EXPECT_RET(p != NULL); - test_tcp_input(p, &netif); - EXPECT_RET(txcounters.num_tx_calls == 0); - EXPECT_RET(pcb->unacked == NULL); - /* send data2 */ - err = tcp_write(pcb, data2, sizeof(data2), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - EXPECT_RET(txcounters.num_tx_calls == 1); - EXPECT_RET(txcounters.num_tx_bytes == sizeof(data2) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr)); - memset(&txcounters, 0, sizeof(txcounters)); - /* duplicate ACK for data1 (data2 is lost) */ - p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); - EXPECT_RET(p != NULL); - test_tcp_input(p, &netif); - EXPECT_RET(txcounters.num_tx_calls == 0); - EXPECT_RET(pcb->dupacks == 1); - /* send data3 */ - err = tcp_write(pcb, data3, sizeof(data3), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - /* nagle enabled, no tx calls */ - EXPECT_RET(txcounters.num_tx_calls == 0); - EXPECT_RET(txcounters.num_tx_bytes == 0); - memset(&txcounters, 0, sizeof(txcounters)); - /* 2nd duplicate ACK for data1 (data2 and data3 are lost) */ - p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); - EXPECT_RET(p != NULL); - test_tcp_input(p, &netif); - EXPECT_RET(txcounters.num_tx_calls == 0); - EXPECT_RET(pcb->dupacks == 2); - /* queue data4, don't send it (unsent-oversize is != 0) */ - err = tcp_write(pcb, data4, sizeof(data4), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - /* 3nd duplicate ACK for data1 (data2 and data3 are lost) -> fast retransmission */ - p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); - EXPECT_RET(p != NULL); - test_tcp_input(p, &netif); - /*EXPECT_RET(txcounters.num_tx_calls == 1);*/ - EXPECT_RET(pcb->dupacks == 3); - memset(&txcounters, 0, sizeof(txcounters)); - /* @todo: check expected data?*/ - - /* send data5, not output yet */ - err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - /*err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK);*/ - EXPECT_RET(txcounters.num_tx_calls == 0); - EXPECT_RET(txcounters.num_tx_bytes == 0); - memset(&txcounters, 0, sizeof(txcounters)); - { - int i = 0; - do - { - err = tcp_write(pcb, data6, TCP_MSS, TCP_WRITE_FLAG_COPY); - i++; - }while(err == ERR_OK); - EXPECT_RET(err != ERR_OK); - } - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - /*EXPECT_RET(txcounters.num_tx_calls == 0); - EXPECT_RET(txcounters.num_tx_bytes == 0);*/ - memset(&txcounters, 0, sizeof(txcounters)); - - /* send even more data */ - err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - /* ...and even more data */ - err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - /* ...and even more data */ - err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - /* ...and even more data */ - err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - - /* send ACKs for data2 and data3 */ - p = tcp_create_rx_segment(pcb, NULL, 0, 0, 12, TCP_ACK); - EXPECT_RET(p != NULL); - test_tcp_input(p, &netif); - /*EXPECT_RET(txcounters.num_tx_calls == 0);*/ - - /* ...and even more data */ - err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - /* ...and even more data */ - err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - -#if 0 - /* create expected segment */ - p1 = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0); - EXPECT_RET(p != NULL); - if (p != NULL) { - /* pass the segment to tcp_input */ - test_tcp_input(p, &netif); - /* check if counters are as expected */ - EXPECT_RET(counters.close_calls == 0); - EXPECT_RET(counters.recv_calls == 1); - EXPECT_RET(counters.recved_bytes == data_len); - EXPECT_RET(counters.err_calls == 0); - } -#endif - /* make sure the pcb is freed */ - EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -} -END_TEST - -static u8_t tx_data[TCP_WND*2]; - -static void -check_seqnos(struct tcp_seg *segs, int num_expected, u32_t *seqnos_expected) -{ - struct tcp_seg *s = segs; - int i; - for (i = 0; i < num_expected; i++, s = s->next) { - EXPECT_RET(s != NULL); - EXPECT(s->tcphdr->seqno == htonl(seqnos_expected[i])); - } - EXPECT(s == NULL); -} - -/** Send data with sequence numbers that wrap around the u32_t range. - * Then, provoke fast retransmission by duplicate ACKs and check that all - * segment lists are still properly sorted. */ -START_TEST(test_tcp_fast_rexmit_wraparound) -{ - struct netif netif; - struct test_tcp_txcounters txcounters; - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf* p; - ip_addr_t remote_ip, local_ip, netmask; - u16_t remote_port = 0x100, local_port = 0x101; - err_t err; -#define SEQNO1 (0xFFFFFF00 - TCP_MSS) -#define ISS 6510 - u16_t i, sent_total = 0; - u32_t seqnos[] = { - SEQNO1, - SEQNO1 + (1 * TCP_MSS), - SEQNO1 + (2 * TCP_MSS), - SEQNO1 + (3 * TCP_MSS), - SEQNO1 + (4 * TCP_MSS), - SEQNO1 + (5 * TCP_MSS)}; - LWIP_UNUSED_ARG(_i); - - for (i = 0; i < sizeof(tx_data); i++) { - tx_data[i] = (u8_t)i; - } - - /* initialize local vars */ - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); - memset(&counters, 0, sizeof(counters)); - - /* create and initialize the pcb */ - tcp_ticks = SEQNO1 - ISS; - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - EXPECT(pcb->lastack == SEQNO1); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - pcb->mss = TCP_MSS; - /* disable initial congestion window (we don't send a SYN here...) */ - pcb->cwnd = 2*TCP_MSS; - - /* send 6 mss-sized segments */ - for (i = 0; i < 6; i++) { - err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - sent_total += TCP_MSS; - } - check_seqnos(pcb->unsent, 6, seqnos); - EXPECT(pcb->unacked == NULL); - err = tcp_output(pcb); - EXPECT(txcounters.num_tx_calls == 2); - EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); - memset(&txcounters, 0, sizeof(txcounters)); - - check_seqnos(pcb->unacked, 2, seqnos); - check_seqnos(pcb->unsent, 4, &seqnos[2]); - - /* ACK the first segment */ - p = tcp_create_rx_segment(pcb, NULL, 0, 0, TCP_MSS, TCP_ACK); - test_tcp_input(p, &netif); - /* ensure this didn't trigger a retransmission */ - EXPECT(txcounters.num_tx_calls == 1); - EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); - memset(&txcounters, 0, sizeof(txcounters)); - check_seqnos(pcb->unacked, 2, &seqnos[1]); - check_seqnos(pcb->unsent, 3, &seqnos[3]); - - /* 3 dupacks */ - EXPECT(pcb->dupacks == 0); - p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); - test_tcp_input(p, &netif); - EXPECT(txcounters.num_tx_calls == 0); - EXPECT(pcb->dupacks == 1); - p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); - test_tcp_input(p, &netif); - EXPECT(txcounters.num_tx_calls == 0); - EXPECT(pcb->dupacks == 2); - /* 3rd dupack -> fast rexmit */ - p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); - test_tcp_input(p, &netif); - EXPECT(pcb->dupacks == 3); - EXPECT(txcounters.num_tx_calls == 4); - memset(&txcounters, 0, sizeof(txcounters)); - EXPECT(pcb->unsent == NULL); - check_seqnos(pcb->unacked, 5, &seqnos[1]); - - /* make sure the pcb is freed */ - EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -} -END_TEST - -/** Send data with sequence numbers that wrap around the u32_t range. - * Then, provoke RTO retransmission and check that all - * segment lists are still properly sorted. */ -START_TEST(test_tcp_rto_rexmit_wraparound) -{ - struct netif netif; - struct test_tcp_txcounters txcounters; - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - ip_addr_t remote_ip, local_ip, netmask; - u16_t remote_port = 0x100, local_port = 0x101; - err_t err; -#define SEQNO1 (0xFFFFFF00 - TCP_MSS) -#define ISS 6510 - u16_t i, sent_total = 0; - u32_t seqnos[] = { - SEQNO1, - SEQNO1 + (1 * TCP_MSS), - SEQNO1 + (2 * TCP_MSS), - SEQNO1 + (3 * TCP_MSS), - SEQNO1 + (4 * TCP_MSS), - SEQNO1 + (5 * TCP_MSS)}; - LWIP_UNUSED_ARG(_i); - - for (i = 0; i < sizeof(tx_data); i++) { - tx_data[i] = (u8_t)i; - } - - /* initialize local vars */ - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); - memset(&counters, 0, sizeof(counters)); - - /* create and initialize the pcb */ - tcp_ticks = 0; - tcp_ticks = 0 - tcp_next_iss(); - tcp_ticks = SEQNO1 - tcp_next_iss(); - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - EXPECT(pcb->lastack == SEQNO1); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - pcb->mss = TCP_MSS; - /* disable initial congestion window (we don't send a SYN here...) */ - pcb->cwnd = 2*TCP_MSS; - - /* send 6 mss-sized segments */ - for (i = 0; i < 6; i++) { - err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - sent_total += TCP_MSS; - } - check_seqnos(pcb->unsent, 6, seqnos); - EXPECT(pcb->unacked == NULL); - err = tcp_output(pcb); - EXPECT(txcounters.num_tx_calls == 2); - EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); - memset(&txcounters, 0, sizeof(txcounters)); - - check_seqnos(pcb->unacked, 2, seqnos); - check_seqnos(pcb->unsent, 4, &seqnos[2]); - - /* call the tcp timer some times */ - for (i = 0; i < 10; i++) { - test_tcp_tmr(); - EXPECT(txcounters.num_tx_calls == 0); - } - /* 11th call to tcp_tmr: RTO rexmit fires */ - test_tcp_tmr(); - EXPECT(txcounters.num_tx_calls == 1); - check_seqnos(pcb->unacked, 1, seqnos); - check_seqnos(pcb->unsent, 5, &seqnos[1]); - - /* fake greater cwnd */ - pcb->cwnd = pcb->snd_wnd; - /* send more data */ - err = tcp_output(pcb); - EXPECT(err == ERR_OK); - /* check queues are sorted */ - EXPECT(pcb->unsent == NULL); - check_seqnos(pcb->unacked, 6, seqnos); - - /* make sure the pcb is freed */ - EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -} -END_TEST - -/** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data. - * At the end, send more data. */ -static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent) -{ - struct netif netif; - struct test_tcp_txcounters txcounters; - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf *p; - ip_addr_t remote_ip, local_ip, netmask; - u16_t remote_port = 0x100, local_port = 0x101; - err_t err; - u16_t sent_total, i; - u8_t expected = 0xFE; - - for (i = 0; i < sizeof(tx_data); i++) { - u8_t d = (u8_t)i; - if (d == 0xFE) { - d = 0xF0; - } - tx_data[i] = d; - } - if (zero_window_probe_from_unsent) { - tx_data[TCP_WND] = expected; - } else { - tx_data[0] = expected; - } - - /* initialize local vars */ - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); - memset(&counters, 0, sizeof(counters)); - memset(&txcounters, 0, sizeof(txcounters)); - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - pcb->mss = TCP_MSS; - /* disable initial congestion window (we don't send a SYN here...) */ - pcb->cwnd = pcb->snd_wnd; - - /* send a full window (minus 1 packets) of TCP data in MSS-sized chunks */ - sent_total = 0; - if ((TCP_WND - TCP_MSS) % TCP_MSS != 0) { - u16_t initial_data_len = (TCP_WND - TCP_MSS) % TCP_MSS; - err = tcp_write(pcb, &tx_data[sent_total], initial_data_len, TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - EXPECT(txcounters.num_tx_calls == 1); - EXPECT(txcounters.num_tx_bytes == initial_data_len + 40U); - memset(&txcounters, 0, sizeof(txcounters)); - sent_total += initial_data_len; - } - for (; sent_total < (TCP_WND - TCP_MSS); sent_total += TCP_MSS) { - err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - EXPECT(txcounters.num_tx_calls == 1); - EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); - memset(&txcounters, 0, sizeof(txcounters)); - } - EXPECT(sent_total == (TCP_WND - TCP_MSS)); - - /* now ACK the packet before the first */ - p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); - test_tcp_input(p, &netif); - /* ensure this didn't trigger a retransmission */ - EXPECT(txcounters.num_tx_calls == 0); - EXPECT(txcounters.num_tx_bytes == 0); - - EXPECT(pcb->persist_backoff == 0); - /* send the last packet, now a complete window has been sent */ - err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); - sent_total += TCP_MSS; - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - EXPECT(txcounters.num_tx_calls == 1); - EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); - memset(&txcounters, 0, sizeof(txcounters)); - EXPECT(pcb->persist_backoff == 0); - - if (zero_window_probe_from_unsent) { - /* ACK all data but close the TX window */ - p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, TCP_WND, TCP_ACK, 0); - test_tcp_input(p, &netif); - /* ensure this didn't trigger any transmission */ - EXPECT(txcounters.num_tx_calls == 0); - EXPECT(txcounters.num_tx_bytes == 0); - EXPECT(pcb->persist_backoff == 1); - } - - /* send one byte more (out of window) -> persist timer starts */ - err = tcp_write(pcb, &tx_data[sent_total], 1, TCP_WRITE_FLAG_COPY); - EXPECT_RET(err == ERR_OK); - err = tcp_output(pcb); - EXPECT_RET(err == ERR_OK); - EXPECT(txcounters.num_tx_calls == 0); - EXPECT(txcounters.num_tx_bytes == 0); - memset(&txcounters, 0, sizeof(txcounters)); - if (!zero_window_probe_from_unsent) { - /* no persist timer unless a zero window announcement has been received */ - EXPECT(pcb->persist_backoff == 0); - } else { - EXPECT(pcb->persist_backoff == 1); - - /* call tcp_timer some more times to let persist timer count up */ - for (i = 0; i < 4; i++) { - test_tcp_tmr(); - EXPECT(txcounters.num_tx_calls == 0); - EXPECT(txcounters.num_tx_bytes == 0); - } - - /* this should trigger the zero-window-probe */ - txcounters.copy_tx_packets = 1; - test_tcp_tmr(); - txcounters.copy_tx_packets = 0; - EXPECT(txcounters.num_tx_calls == 1); - EXPECT(txcounters.num_tx_bytes == 1 + 40U); - EXPECT(txcounters.tx_packets != NULL); - if (txcounters.tx_packets != NULL) { - u8_t sent; - u16_t ret; - ret = pbuf_copy_partial(txcounters.tx_packets, &sent, 1, 40U); - EXPECT(ret == 1); - EXPECT(sent == expected); - } - if (txcounters.tx_packets != NULL) { - pbuf_free(txcounters.tx_packets); - txcounters.tx_packets = NULL; - } - } - - /* make sure the pcb is freed */ - EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -} - -START_TEST(test_tcp_tx_full_window_lost_from_unsent) -{ - LWIP_UNUSED_ARG(_i); - test_tcp_tx_full_window_lost(1); -} -END_TEST - -START_TEST(test_tcp_tx_full_window_lost_from_unacked) -{ - LWIP_UNUSED_ARG(_i); - test_tcp_tx_full_window_lost(0); -} -END_TEST - -/** Create the suite including all tests for this module */ -Suite * -tcp_suite(void) -{ - testfunc tests[] = { - TESTFUNC(test_tcp_new_abort), - TESTFUNC(test_tcp_recv_inseq), - TESTFUNC(test_tcp_malformed_header), - TESTFUNC(test_tcp_fast_retx_recover), - TESTFUNC(test_tcp_fast_rexmit_wraparound), - TESTFUNC(test_tcp_rto_rexmit_wraparound), - TESTFUNC(test_tcp_tx_full_window_lost_from_unacked), - TESTFUNC(test_tcp_tx_full_window_lost_from_unsent) - }; - return create_suite("TCP", tests, sizeof(tests)/sizeof(testfunc), tcp_setup, tcp_teardown); -} diff --git a/ext/lwip/test/unit/tcp/test_tcp.h b/ext/lwip/test/unit/tcp/test_tcp.h deleted file mode 100644 index ea739eb..0000000 --- a/ext/lwip/test/unit/tcp/test_tcp.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LWIP_HDR_TEST_TCP_H__ -#define LWIP_HDR_TEST_TCP_H__ - -#include "../lwip_check.h" - -Suite *tcp_suite(void); - -#endif diff --git a/ext/lwip/test/unit/tcp/test_tcp_oos.c b/ext/lwip/test/unit/tcp/test_tcp_oos.c deleted file mode 100644 index 98f7098..0000000 --- a/ext/lwip/test/unit/tcp/test_tcp_oos.c +++ /dev/null @@ -1,1049 +0,0 @@ -#include "test_tcp_oos.h" - -#include "lwip/priv/tcp_priv.h" -#include "lwip/stats.h" -#include "tcp_helper.h" - -#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS -#error "This tests needs TCP- and MEMP-statistics enabled" -#endif -#if !TCP_QUEUE_OOSEQ -#error "This tests needs TCP_QUEUE_OOSEQ enabled" -#endif - -/** CHECK_SEGMENTS_ON_OOSEQ: - * 1: check count, seqno and len of segments on pcb->ooseq (strict) - * 0: only check that bytes are received in correct order (less strict) */ -#define CHECK_SEGMENTS_ON_OOSEQ 1 - -#if CHECK_SEGMENTS_ON_OOSEQ -#define EXPECT_OOSEQ(x) EXPECT(x) -#else -#define EXPECT_OOSEQ(x) -#endif - -/* helper functions */ - -/** Get the numbers of segments on the ooseq list */ -static int tcp_oos_count(struct tcp_pcb* pcb) -{ - int num = 0; - struct tcp_seg* seg = pcb->ooseq; - while(seg != NULL) { - num++; - seg = seg->next; - } - return num; -} - -#if TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_PBUFS < ((TCP_WND / TCP_MSS) + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) -/** Get the numbers of pbufs on the ooseq list */ -static int tcp_oos_pbuf_count(struct tcp_pcb* pcb) -{ - int num = 0; - struct tcp_seg* seg = pcb->ooseq; - while(seg != NULL) { - num += pbuf_clen(seg->p); - seg = seg->next; - } - return num; -} -#endif - -/** Get the seqno of a segment (by index) on the ooseq list - * - * @param pcb the pcb to check for ooseq segments - * @param seg_index index of the segment on the ooseq list - * @return seqno of the segment - */ -static u32_t -tcp_oos_seg_seqno(struct tcp_pcb* pcb, int seg_index) -{ - int num = 0; - struct tcp_seg* seg = pcb->ooseq; - - /* then check the actual segment */ - while(seg != NULL) { - if(num == seg_index) { - return seg->tcphdr->seqno; - } - num++; - seg = seg->next; - } - fail(); - return 0; -} - -/** Get the tcplen (datalen + SYN/FIN) of a segment (by index) on the ooseq list - * - * @param pcb the pcb to check for ooseq segments - * @param seg_index index of the segment on the ooseq list - * @return tcplen of the segment - */ -static int -tcp_oos_seg_tcplen(struct tcp_pcb* pcb, int seg_index) -{ - int num = 0; - struct tcp_seg* seg = pcb->ooseq; - - /* then check the actual segment */ - while(seg != NULL) { - if(num == seg_index) { - return TCP_TCPLEN(seg); - } - num++; - seg = seg->next; - } - fail(); - return -1; -} - -/** Get the tcplen (datalen + SYN/FIN) of all segments on the ooseq list - * - * @param pcb the pcb to check for ooseq segments - * @return tcplen of all segment - */ -static int -tcp_oos_tcplen(struct tcp_pcb* pcb) -{ - int len = 0; - struct tcp_seg* seg = pcb->ooseq; - - /* then check the actual segment */ - while(seg != NULL) { - len += TCP_TCPLEN(seg); - seg = seg->next; - } - return len; -} - -/* Setup/teardown functions */ - -static void -tcp_oos_setup(void) -{ - tcp_remove_all(); -} - -static void -tcp_oos_teardown(void) -{ - tcp_remove_all(); - netif_list = NULL; - netif_default = NULL; -} - - - -/* Test functions */ - -/** create multiple segments and pass them to tcp_input in a wrong - * order to see if ooseq-caching works correctly - * FIN is received in out-of-sequence segments only */ -START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ) -{ - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf *p_8_9, *p_4_8, *p_4_10, *p_2_14, *p_fin, *pinseq; - char data[] = { - 1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16}; - ip_addr_t remote_ip, local_ip, netmask; - u16_t data_len; - u16_t remote_port = 0x100, local_port = 0x101; - struct netif netif; - LWIP_UNUSED_ARG(_i); - - /* initialize local vars */ - memset(&netif, 0, sizeof(netif)); - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); - data_len = sizeof(data); - /* initialize counter struct */ - memset(&counters, 0, sizeof(counters)); - counters.expected_data_len = data_len; - counters.expected_data = data; - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - - /* create segments */ - /* pinseq is sent as last segment! */ - pinseq = tcp_create_rx_segment(pcb, &data[0], 4, 0, 0, TCP_ACK); - /* p1: 8 bytes before FIN */ - /* seqno: 8..16 */ - p_8_9 = tcp_create_rx_segment(pcb, &data[8], 8, 8, 0, TCP_ACK|TCP_FIN); - /* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */ - /* seqno: 4..11 */ - p_4_8 = tcp_create_rx_segment(pcb, &data[4], 8, 4, 0, TCP_ACK); - /* p3: same as p2 but 2 bytes longer */ - /* seqno: 4..13 */ - p_4_10 = tcp_create_rx_segment(pcb, &data[4], 10, 4, 0, TCP_ACK); - /* p4: 14 bytes before FIN, includes data from p1 and p2, plus partly from pinseq */ - /* seqno: 2..15 */ - p_2_14 = tcp_create_rx_segment(pcb, &data[2], 14, 2, 0, TCP_ACK); - /* FIN, seqno 16 */ - p_fin = tcp_create_rx_segment(pcb, NULL, 0,16, 0, TCP_ACK|TCP_FIN); - EXPECT(pinseq != NULL); - EXPECT(p_8_9 != NULL); - EXPECT(p_4_8 != NULL); - EXPECT(p_4_10 != NULL); - EXPECT(p_2_14 != NULL); - EXPECT(p_fin != NULL); - if ((pinseq != NULL) && (p_8_9 != NULL) && (p_4_8 != NULL) && (p_4_10 != NULL) && (p_2_14 != NULL) && (p_fin != NULL)) { - /* pass the segment to tcp_input */ - test_tcp_input(p_8_9, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 8); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 9); /* includes FIN */ - - /* pass the segment to tcp_input */ - test_tcp_input(p_4_8, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 4); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 4); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */ - - /* pass the segment to tcp_input */ - test_tcp_input(p_4_10, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* ooseq queue: unchanged */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 4); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 4); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */ - - /* pass the segment to tcp_input */ - test_tcp_input(p_2_14, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 2); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 15); /* includes FIN */ - - /* pass the segment to tcp_input */ - test_tcp_input(p_fin, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* ooseq queue: unchanged */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 2); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 15); /* includes FIN */ - - /* pass the segment to tcp_input */ - test_tcp_input(pinseq, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 1); - EXPECT(counters.recv_calls == 1); - EXPECT(counters.recved_bytes == data_len); - EXPECT(counters.err_calls == 0); - EXPECT(pcb->ooseq == NULL); - } - - /* make sure the pcb is freed */ - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -} -END_TEST - - -/** create multiple segments and pass them to tcp_input in a wrong - * order to see if ooseq-caching works correctly - * FIN is received IN-SEQUENCE at the end */ -START_TEST(test_tcp_recv_ooseq_FIN_INSEQ) -{ - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf *p_1_2, *p_4_8, *p_3_11, *p_2_12, *p_15_1, *p_15_1a, *pinseq, *pinseqFIN; - char data[] = { - 1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16}; - ip_addr_t remote_ip, local_ip, netmask; - u16_t data_len; - u16_t remote_port = 0x100, local_port = 0x101; - struct netif netif; - LWIP_UNUSED_ARG(_i); - - /* initialize local vars */ - memset(&netif, 0, sizeof(netif)); - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); - data_len = sizeof(data); - /* initialize counter struct */ - memset(&counters, 0, sizeof(counters)); - counters.expected_data_len = data_len; - counters.expected_data = data; - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - - /* create segments */ - /* p1: 7 bytes - 2 before FIN */ - /* seqno: 1..2 */ - p_1_2 = tcp_create_rx_segment(pcb, &data[1], 2, 1, 0, TCP_ACK); - /* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */ - /* seqno: 4..11 */ - p_4_8 = tcp_create_rx_segment(pcb, &data[4], 8, 4, 0, TCP_ACK); - /* p3: same as p2 but 2 bytes longer and one byte more at the front */ - /* seqno: 3..13 */ - p_3_11 = tcp_create_rx_segment(pcb, &data[3], 11, 3, 0, TCP_ACK); - /* p4: 13 bytes - 2 before FIN - should be ignored as contained in p1 and p3 */ - /* seqno: 2..13 */ - p_2_12 = tcp_create_rx_segment(pcb, &data[2], 12, 2, 0, TCP_ACK); - /* pinseq is the first segment that is held back to create ooseq! */ - /* seqno: 0..3 */ - pinseq = tcp_create_rx_segment(pcb, &data[0], 4, 0, 0, TCP_ACK); - /* p5: last byte before FIN */ - /* seqno: 15 */ - p_15_1 = tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK); - /* p6: same as p5, should be ignored */ - p_15_1a= tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK); - /* pinseqFIN: last 2 bytes plus FIN */ - /* only segment containing seqno 14 and FIN */ - pinseqFIN = tcp_create_rx_segment(pcb, &data[14], 2, 14, 0, TCP_ACK|TCP_FIN); - EXPECT(pinseq != NULL); - EXPECT(p_1_2 != NULL); - EXPECT(p_4_8 != NULL); - EXPECT(p_3_11 != NULL); - EXPECT(p_2_12 != NULL); - EXPECT(p_15_1 != NULL); - EXPECT(p_15_1a != NULL); - EXPECT(pinseqFIN != NULL); - if ((pinseq != NULL) && (p_1_2 != NULL) && (p_4_8 != NULL) && (p_3_11 != NULL) && (p_2_12 != NULL) - && (p_15_1 != NULL) && (p_15_1a != NULL) && (pinseqFIN != NULL)) { - /* pass the segment to tcp_input */ - test_tcp_input(p_1_2, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2); - - /* pass the segment to tcp_input */ - test_tcp_input(p_4_8, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 4); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 8); - - /* pass the segment to tcp_input */ - test_tcp_input(p_3_11, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2); - /* p_3_11 has removed p_4_8 from ooseq */ - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 3); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 11); - - /* pass the segment to tcp_input */ - test_tcp_input(p_2_12, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 2); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 12); - - /* pass the segment to tcp_input */ - test_tcp_input(pinseq, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 1); - EXPECT(counters.recved_bytes == 14); - EXPECT(counters.err_calls == 0); - EXPECT(pcb->ooseq == NULL); - - /* pass the segment to tcp_input */ - test_tcp_input(p_15_1, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 1); - EXPECT(counters.recved_bytes == 14); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1); - - /* pass the segment to tcp_input */ - test_tcp_input(p_15_1a, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 1); - EXPECT(counters.recved_bytes == 14); - EXPECT(counters.err_calls == 0); - /* check ooseq queue: unchanged */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); - EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15); - EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1); - - /* pass the segment to tcp_input */ - test_tcp_input(pinseqFIN, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 1); - EXPECT(counters.recv_calls == 2); - EXPECT(counters.recved_bytes == data_len); - EXPECT(counters.err_calls == 0); - EXPECT(pcb->ooseq == NULL); - } - - /* make sure the pcb is freed */ - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -} -END_TEST - -static char data_full_wnd[TCP_WND]; - -/** create multiple segments and pass them to tcp_input with the first segment missing - * to simulate overruning the rxwin with ooseq queueing enabled */ -START_TEST(test_tcp_recv_ooseq_overrun_rxwin) -{ -#if !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS - int i, k; - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf *pinseq, *p_ovr; - ip_addr_t remote_ip, local_ip, netmask; - u16_t remote_port = 0x100, local_port = 0x101; - struct netif netif; - int datalen = 0; - int datalen2; - - for(i = 0; i < (int)sizeof(data_full_wnd); i++) { - data_full_wnd[i] = (char)i; - } - - /* initialize local vars */ - memset(&netif, 0, sizeof(netif)); - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); - /* initialize counter struct */ - memset(&counters, 0, sizeof(counters)); - counters.expected_data_len = TCP_WND; - counters.expected_data = data_full_wnd; - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - pcb->rcv_nxt = 0x8000; - - /* create segments */ - /* pinseq is sent as last segment! */ - pinseq = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK); - - for(i = TCP_MSS, k = 0; i < TCP_WND; i += TCP_MSS, k++) { - int count, expected_datalen; - struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], - TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); - EXPECT_RET(p != NULL); - /* pass the segment to tcp_input */ - test_tcp_input(p, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - count = tcp_oos_count(pcb); - EXPECT_OOSEQ(count == k+1); - datalen = tcp_oos_tcplen(pcb); - if (i + TCP_MSS < TCP_WND) { - expected_datalen = (k+1)*TCP_MSS; - } else { - expected_datalen = TCP_WND - TCP_MSS; - } - if (datalen != expected_datalen) { - EXPECT_OOSEQ(datalen == expected_datalen); - } - } - - /* pass in one more segment, cleary overrunning the rxwin */ - p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); - EXPECT_RET(p_ovr != NULL); - /* pass the segment to tcp_input */ - test_tcp_input(p_ovr, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == k); - datalen2 = tcp_oos_tcplen(pcb); - EXPECT_OOSEQ(datalen == datalen2); - - /* now pass inseq */ - test_tcp_input(pinseq, &netif); - EXPECT(pcb->ooseq == NULL); - - /* make sure the pcb is freed */ - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -#endif /* !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS */ - LWIP_UNUSED_ARG(_i); -} -END_TEST - -/** similar to above test, except seqno starts near the max rxwin */ -START_TEST(test_tcp_recv_ooseq_overrun_rxwin_edge) -{ -#if !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS - int i, k; - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf *pinseq, *p_ovr; - ip_addr_t remote_ip, local_ip, netmask; - u16_t remote_port = 0x100, local_port = 0x101; - struct netif netif; - int datalen = 0; - int datalen2; - - for(i = 0; i < (int)sizeof(data_full_wnd); i++) { - data_full_wnd[i] = (char)i; - } - - /* initialize local vars */ - memset(&netif, 0, sizeof(netif)); - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); - /* initialize counter struct */ - memset(&counters, 0, sizeof(counters)); - counters.expected_data_len = TCP_WND; - counters.expected_data = data_full_wnd; - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - pcb->rcv_nxt = 0xffffffff - (TCP_WND / 2); - - /* create segments */ - /* pinseq is sent as last segment! */ - pinseq = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK); - - for(i = TCP_MSS, k = 0; i < TCP_WND; i += TCP_MSS, k++) { - int count, expected_datalen; - struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], - TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); - EXPECT_RET(p != NULL); - /* pass the segment to tcp_input */ - test_tcp_input(p, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - count = tcp_oos_count(pcb); - EXPECT_OOSEQ(count == k+1); - datalen = tcp_oos_tcplen(pcb); - if (i + TCP_MSS < TCP_WND) { - expected_datalen = (k+1)*TCP_MSS; - } else { - expected_datalen = TCP_WND - TCP_MSS; - } - if (datalen != expected_datalen) { - EXPECT_OOSEQ(datalen == expected_datalen); - } - } - - /* pass in one more segment, cleary overrunning the rxwin */ - p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); - EXPECT_RET(p_ovr != NULL); - /* pass the segment to tcp_input */ - test_tcp_input(p_ovr, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == k); - datalen2 = tcp_oos_tcplen(pcb); - EXPECT_OOSEQ(datalen == datalen2); - - /* now pass inseq */ - test_tcp_input(pinseq, &netif); - EXPECT(pcb->ooseq == NULL); - - /* make sure the pcb is freed */ - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -#endif /* !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS */ - LWIP_UNUSED_ARG(_i); -} -END_TEST - -START_TEST(test_tcp_recv_ooseq_max_bytes) -{ -#if TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) - int i, k; - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf *p_ovr; - ip_addr_t remote_ip, local_ip, netmask; - u16_t remote_port = 0x100, local_port = 0x101; - struct netif netif; - int datalen = 0; - int datalen2; - - for(i = 0; i < sizeof(data_full_wnd); i++) { - data_full_wnd[i] = (char)i; - } - - /* initialize local vars */ - memset(&netif, 0, sizeof(netif)); - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); - /* initialize counter struct */ - memset(&counters, 0, sizeof(counters)); - counters.expected_data_len = TCP_WND; - counters.expected_data = data_full_wnd; - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - pcb->rcv_nxt = 0x8000; - - /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */ - - /* create segments and 'recv' them */ - for(k = 1, i = 1; k < TCP_OOSEQ_MAX_BYTES; k += TCP_MSS, i++) { - int count; - struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[k], - TCP_MSS, k, 0, TCP_ACK); - EXPECT_RET(p != NULL); - EXPECT_RET(p->next == NULL); - /* pass the segment to tcp_input */ - test_tcp_input(p, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - count = tcp_oos_pbuf_count(pcb); - EXPECT_OOSEQ(count == i); - datalen = tcp_oos_tcplen(pcb); - EXPECT_OOSEQ(datalen == (i * TCP_MSS)); - } - - /* pass in one more segment, overrunning the limit */ - p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[k+1], 1, k+1, 0, TCP_ACK); - EXPECT_RET(p_ovr != NULL); - /* pass the segment to tcp_input */ - test_tcp_input(p_ovr, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue (ensure the new segment was not accepted) */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1)); - datalen2 = tcp_oos_tcplen(pcb); - EXPECT_OOSEQ(datalen2 == ((i-1) * TCP_MSS)); - - /* make sure the pcb is freed */ - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -#endif /* TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */ - LWIP_UNUSED_ARG(_i); -} -END_TEST - -START_TEST(test_tcp_recv_ooseq_max_pbufs) -{ -#if TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_PBUFS < ((TCP_WND / TCP_MSS) + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) - int i; - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf *p_ovr; - ip_addr_t remote_ip, local_ip, netmask; - u16_t remote_port = 0x100, local_port = 0x101; - struct netif netif; - int datalen = 0; - int datalen2; - - for(i = 0; i < sizeof(data_full_wnd); i++) { - data_full_wnd[i] = (char)i; - } - - /* initialize local vars */ - memset(&netif, 0, sizeof(netif)); - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); - /* initialize counter struct */ - memset(&counters, 0, sizeof(counters)); - counters.expected_data_len = TCP_WND; - counters.expected_data = data_full_wnd; - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - pcb->rcv_nxt = 0x8000; - - /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */ - - /* create segments and 'recv' them */ - for(i = 1; i <= TCP_OOSEQ_MAX_PBUFS; i++) { - int count; - struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[i], - 1, i, 0, TCP_ACK); - EXPECT_RET(p != NULL); - EXPECT_RET(p->next == NULL); - /* pass the segment to tcp_input */ - test_tcp_input(p, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue */ - count = tcp_oos_pbuf_count(pcb); - EXPECT_OOSEQ(count == i); - datalen = tcp_oos_tcplen(pcb); - EXPECT_OOSEQ(datalen == i); - } - - /* pass in one more segment, overrunning the limit */ - p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[i+1], 1, i+1, 0, TCP_ACK); - EXPECT_RET(p_ovr != NULL); - /* pass the segment to tcp_input */ - test_tcp_input(p_ovr, &netif); - /* check if counters are as expected */ - EXPECT(counters.close_calls == 0); - EXPECT(counters.recv_calls == 0); - EXPECT(counters.recved_bytes == 0); - EXPECT(counters.err_calls == 0); - /* check ooseq queue (ensure the new segment was not accepted) */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1)); - datalen2 = tcp_oos_tcplen(pcb); - EXPECT_OOSEQ(datalen2 == (i-1)); - - /* make sure the pcb is freed */ - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -#endif /* TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */ - LWIP_UNUSED_ARG(_i); -} -END_TEST - -static void -check_rx_counters(struct tcp_pcb *pcb, struct test_tcp_counters *counters, u32_t exp_close_calls, u32_t exp_rx_calls, - u32_t exp_rx_bytes, u32_t exp_err_calls, int exp_oos_count, int exp_oos_len) -{ - int oos_len; - EXPECT(counters->close_calls == exp_close_calls); - EXPECT(counters->recv_calls == exp_rx_calls); - EXPECT(counters->recved_bytes == exp_rx_bytes); - EXPECT(counters->err_calls == exp_err_calls); - /* check that pbuf is queued in ooseq */ - EXPECT_OOSEQ(tcp_oos_count(pcb) == exp_oos_count); - oos_len = tcp_oos_tcplen(pcb); - EXPECT_OOSEQ(exp_oos_len == oos_len); -} - -/* this test uses 4 packets: - * - data (len=TCP_MSS) - * - FIN - * - data after FIN (len=1) (invalid) - * - 2nd FIN (invalid) - * - * the parameter 'delay_packet' is a bitmask that choses which on these packets is ooseq - */ -static void test_tcp_recv_ooseq_double_FINs(int delay_packet) -{ - int i, k; - struct test_tcp_counters counters; - struct tcp_pcb* pcb; - struct pbuf *p_normal_fin, *p_data_after_fin, *p, *p_2nd_fin_ooseq; - ip_addr_t remote_ip, local_ip, netmask; - u16_t remote_port = 0x100, local_port = 0x101; - struct netif netif; - u32_t exp_rx_calls = 0, exp_rx_bytes = 0, exp_close_calls = 0, exp_oos_pbufs = 0, exp_oos_tcplen = 0; - int first_dropped = 0xff; - - for(i = 0; i < (int)sizeof(data_full_wnd); i++) { - data_full_wnd[i] = (char)i; - } - - /* initialize local vars */ - memset(&netif, 0, sizeof(netif)); - IP_ADDR4(&local_ip, 192, 168, 1, 1); - IP_ADDR4(&remote_ip, 192, 168, 1, 2); - IP_ADDR4(&netmask, 255, 255, 255, 0); - test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); - /* initialize counter struct */ - memset(&counters, 0, sizeof(counters)); - counters.expected_data_len = TCP_WND; - counters.expected_data = data_full_wnd; - - /* create and initialize the pcb */ - pcb = test_tcp_new_counters_pcb(&counters); - EXPECT_RET(pcb != NULL); - tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); - pcb->rcv_nxt = 0x8000; - - /* create segments */ - p = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK); - p_normal_fin = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS, 0, TCP_ACK|TCP_FIN); - k = 1; - p_data_after_fin = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS+1], k, TCP_MSS+1, 0, TCP_ACK); - p_2nd_fin_ooseq = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS+1+k, 0, TCP_ACK|TCP_FIN); - - if(delay_packet & 1) { - /* drop normal data */ - first_dropped = 1; - } else { - /* send normal data */ - test_tcp_input(p, &netif); - exp_rx_calls++; - exp_rx_bytes += TCP_MSS; - } - /* check if counters are as expected */ - check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); - - if(delay_packet & 2) { - /* drop FIN */ - if(first_dropped > 2) { - first_dropped = 2; - } - } else { - /* send FIN */ - test_tcp_input(p_normal_fin, &netif); - if (first_dropped < 2) { - /* already dropped packets, this one is ooseq */ - exp_oos_pbufs++; - exp_oos_tcplen++; - } else { - /* inseq */ - exp_close_calls++; - } - } - /* check if counters are as expected */ - check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); - - if(delay_packet & 4) { - /* drop data-after-FIN */ - if(first_dropped > 3) { - first_dropped = 3; - } - } else { - /* send data-after-FIN */ - test_tcp_input(p_data_after_fin, &netif); - if (first_dropped < 3) { - /* already dropped packets, this one is ooseq */ - if (delay_packet & 2) { - /* correct FIN was ooseq */ - exp_oos_pbufs++; - exp_oos_tcplen += k; - } - } else { - /* inseq: no change */ - } - } - /* check if counters are as expected */ - check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); - - if(delay_packet & 8) { - /* drop 2nd-FIN */ - if(first_dropped > 4) { - first_dropped = 4; - } - } else { - /* send 2nd-FIN */ - test_tcp_input(p_2nd_fin_ooseq, &netif); - if (first_dropped < 3) { - /* already dropped packets, this one is ooseq */ - if (delay_packet & 2) { - /* correct FIN was ooseq */ - exp_oos_pbufs++; - exp_oos_tcplen++; - } - } else { - /* inseq: no change */ - } - } - /* check if counters are as expected */ - check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); - - if(delay_packet & 1) { - /* dropped normal data before */ - test_tcp_input(p, &netif); - exp_rx_calls++; - exp_rx_bytes += TCP_MSS; - if((delay_packet & 2) == 0) { - /* normal FIN was NOT delayed */ - exp_close_calls++; - exp_oos_pbufs = exp_oos_tcplen = 0; - } - } - /* check if counters are as expected */ - check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); - - if(delay_packet & 2) { - /* dropped normal FIN before */ - test_tcp_input(p_normal_fin, &netif); - exp_close_calls++; - exp_oos_pbufs = exp_oos_tcplen = 0; - } - /* check if counters are as expected */ - check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); - - if(delay_packet & 4) { - /* dropped data-after-FIN before */ - test_tcp_input(p_data_after_fin, &netif); - } - /* check if counters are as expected */ - check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); - - if(delay_packet & 8) { - /* dropped 2nd-FIN before */ - test_tcp_input(p_2nd_fin_ooseq, &netif); - } - /* check if counters are as expected */ - check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); - - /* check that ooseq data has been dumped */ - EXPECT(pcb->ooseq == NULL); - - /* make sure the pcb is freed */ - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); - tcp_abort(pcb); - EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); -} - -/** create multiple segments and pass them to tcp_input with the first segment missing - * to simulate overruning the rxwin with ooseq queueing enabled */ -#define FIN_TEST(name, num) \ - START_TEST(name) \ - { \ - LWIP_UNUSED_ARG(_i); \ - test_tcp_recv_ooseq_double_FINs(num); \ - } \ - END_TEST -FIN_TEST(test_tcp_recv_ooseq_double_FIN_0, 0) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_1, 1) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_2, 2) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_3, 3) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_4, 4) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_5, 5) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_6, 6) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_7, 7) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_8, 8) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_9, 9) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_10, 10) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_11, 11) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_12, 12) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_13, 13) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_14, 14) -FIN_TEST(test_tcp_recv_ooseq_double_FIN_15, 15) - - -/** Create the suite including all tests for this module */ -Suite * -tcp_oos_suite(void) -{ - testfunc tests[] = { - TESTFUNC(test_tcp_recv_ooseq_FIN_OOSEQ), - TESTFUNC(test_tcp_recv_ooseq_FIN_INSEQ), - TESTFUNC(test_tcp_recv_ooseq_overrun_rxwin), - TESTFUNC(test_tcp_recv_ooseq_overrun_rxwin_edge), - TESTFUNC(test_tcp_recv_ooseq_max_bytes), - TESTFUNC(test_tcp_recv_ooseq_max_pbufs), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_0), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_1), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_2), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_3), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_4), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_5), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_6), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_7), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_8), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_9), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_10), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_11), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_12), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_13), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_14), - TESTFUNC(test_tcp_recv_ooseq_double_FIN_15) - }; - return create_suite("TCP_OOS", tests, sizeof(tests)/sizeof(testfunc), tcp_oos_setup, tcp_oos_teardown); -} diff --git a/ext/lwip/test/unit/tcp/test_tcp_oos.h b/ext/lwip/test/unit/tcp/test_tcp_oos.h deleted file mode 100644 index 1cb8650..0000000 --- a/ext/lwip/test/unit/tcp/test_tcp_oos.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LWIP_HDR_TEST_TCP_OOS_H__ -#define LWIP_HDR_TEST_TCP_OOS_H__ - -#include "../lwip_check.h" - -Suite *tcp_oos_suite(void); - -#endif diff --git a/ext/lwip/test/unit/udp/test_udp.c b/ext/lwip/test/unit/udp/test_udp.c deleted file mode 100644 index 147822f..0000000 --- a/ext/lwip/test/unit/udp/test_udp.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "test_udp.h" - -#include "lwip/udp.h" -#include "lwip/stats.h" - -#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS -#error "This tests needs UDP- and MEMP-statistics enabled" -#endif - -/* Helper functions */ -static void -udp_remove_all(void) -{ - struct udp_pcb *pcb = udp_pcbs; - struct udp_pcb *pcb2; - - while(pcb != NULL) { - pcb2 = pcb; - pcb = pcb->next; - udp_remove(pcb2); - } - fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0); -} - -/* Setups/teardown functions */ - -static void -udp_setup(void) -{ - udp_remove_all(); -} - -static void -udp_teardown(void) -{ - udp_remove_all(); -} - - -/* Test functions */ - -START_TEST(test_udp_new_remove) -{ - struct udp_pcb* pcb; - LWIP_UNUSED_ARG(_i); - - fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0); - - pcb = udp_new(); - fail_unless(pcb != NULL); - if (pcb != NULL) { - fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 1); - udp_remove(pcb); - fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0); - } -} -END_TEST - - -/** Create the suite including all tests for this module */ -Suite * -udp_suite(void) -{ - testfunc tests[] = { - TESTFUNC(test_udp_new_remove), - }; - return create_suite("UDP", tests, sizeof(tests)/sizeof(testfunc), udp_setup, udp_teardown); -} diff --git a/ext/lwip/test/unit/udp/test_udp.h b/ext/lwip/test/unit/udp/test_udp.h deleted file mode 100644 index eb14354..0000000 --- a/ext/lwip/test/unit/udp/test_udp.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LWIP_HDR_TEST_UDP_H__ -#define LWIP_HDR_TEST_UDP_H__ - -#include "../lwip_check.h" - -Suite* udp_suite(void); - -#endif diff --git a/ext/lwipopts.h b/ext/lwipopts.h deleted file mode 100644 index f5df284..0000000 --- a/ext/lwipopts.h +++ /dev/null @@ -1,2 +0,0 @@ -// Refers to the actual lwIP stack driver location -#include "../src/stack_drivers/lwip/lwipopts.h" \ No newline at end of file diff --git a/ext/picotcp/.gitignore b/ext/picotcp/.gitignore deleted file mode 100644 index 88593da..0000000 --- a/ext/picotcp/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -*.d -*.o -*.a -*.out -*.swp -tags -build -UNIT_* -core -core.* -.DS_Store -cscope.files -cscope.out -*.so -*.aux -*.pdf -*.toc -*.gz -*.log -*.pyc -*.elf -*.gcov -*.gcda -*.gcno diff --git a/ext/picotcp/.travis.yml b/ext/picotcp/.travis.yml deleted file mode 100644 index 0a87dd4..0000000 --- a/ext/picotcp/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -before_install: - - sudo apt-get update -qq - - sudo apt-get install -y vde2 check libvdeplug2-dev libpcap-dev psmisc - - sudo pip install cpp-coveralls - - make clean - - rm -f *.gc* - -install: make GCOV=1 && make units ARCH=faulty GCOV=1 && make test GCOV=1 -language: c -script: - - ./test/coverage.sh -after_success: - - coveralls --exclude test/ --exclude modules/ptsocket --exclude build --exclude modules/pico_dev_mock.c --exclude modules/pico_dev_null.c --exclude modules/pico_dev_pcap.c --exclude modules/pico_dev_tap_windows.c --exclude modules/pico_dev_tun.c --gcov-options='\-lp' diff --git a/ext/picotcp/COPYING b/ext/picotcp/COPYING deleted file mode 100644 index 8a5fe4b..0000000 --- a/ext/picotcp/COPYING +++ /dev/null @@ -1,8 +0,0 @@ -PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. - -Released under the GNU General Public License, version 2. -See LICENSE for details. - -Different licensing models may exist, at the sole discretion of -the Copyright holders. - diff --git a/ext/picotcp/LICENSE b/ext/picotcp/LICENSE deleted file mode 100644 index d159169..0000000 --- a/ext/picotcp/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/ext/picotcp/MODTREE b/ext/picotcp/MODTREE deleted file mode 100644 index 6e343a9..0000000 --- a/ext/picotcp/MODTREE +++ /dev/null @@ -1,23 +0,0 @@ -RTOS: -IPV4: -IPV6: -DEVLOOP: -CRC: -ETH: IPV4 -TCP: IPV4 -UDP: IPV4 -IPV4FRAG: IPV4 -NAT: IPV4 UDP -ICMP4: IPV4 -MCAST: UDP -PING: ICMP4 -DHCP_CLIENT: UDP -DHCP_SERVER: UDP -DNS_CLIENT: UDP -IPFILTER: IPV4 -OLSR: MCAST -SLAACV4: IPV4 -SNTP_CLIENT: DNS_CLIENT -TFTP: UDP -MDNS: MCAST -DNS_SD: MDNS diff --git a/ext/picotcp/Makefile b/ext/picotcp/Makefile deleted file mode 100644 index 8ce14e6..0000000 --- a/ext/picotcp/Makefile +++ /dev/null @@ -1,423 +0,0 @@ --include ../../config.mk --include ../../tools/kconfig/.config - -CC:=$(CROSS_COMPILE)gcc -LD:=$(CROSS_COMPILE)ld -AR:=$(CROSS_COMPILE)ar -RANLIB:=$(CROSS_COMPILE)ranlib -SIZE:=$(CROSS_COMPILE)size -STRIP_BIN:=$(CROSS_COMPILE)strip -TEST_LDFLAGS=-pthread $(PREFIX)/modules/*.o $(PREFIX)/lib/*.o -lvdeplug -LIBNAME:="libpicotcp.a" - -PREFIX?=$(PWD)/build -DEBUG?=1 -PROFILE?=0 -PERF?=0 -ENDIAN?=little -STRIP?=0 -RTOS?=0 -GENERIC?=0 -PTHREAD?=0 -ADDRESS_SANITIZER?=1 - -# Default compiled-in protocols -# -TCP?=1 -UDP?=1 -ETH?=1 -IPV4?=1 -IPV4FRAG?=1 -IPV6FRAG?=0 -NAT?=1 -ICMP4?=1 -MCAST?=1 -DEVLOOP?=1 -PING?=1 -DHCP_CLIENT?=1 -DHCP_SERVER?=1 -DNS_CLIENT?=1 -MDNS?=1 -DNS_SD?=1 -SNTP_CLIENT?=1 -IPFILTER?=1 -CRC?=1 -OLSR?=0 -SLAACV4?=1 -TFTP?=1 -AODV?=1 -MEMORY_MANAGER?=0 -MEMORY_MANAGER_PROFILING?=0 -TUN?=0 -TAP?=0 -PCAP?=0 -PPP?=1 -CYASSL?=0 -WOLFSSL?=0 -POLARSSL?=0 - -#IPv6 related -IPV6?=1 - -EXTRA_CFLAGS+=-DPICO_COMPILE_TIME=`date +%s` -EXTRA_CFLAGS+=$(PLATFORM_CFLAGS) - -CFLAGS=-I$(PREFIX)/include -Iinclude -Imodules -Wall -Wdeclaration-after-statement -W -Wextra -Wshadow -Wcast-qual -Wwrite-strings -Wunused-variable -Wundef -Wunused-function $(EXTRA_CFLAGS) -# extra flags recommanded by TIOBE TICS framework to score an A on compiler warnings -CFLAGS+= -Wconversion -# request from Toon -CFLAGS+= -Wcast-align -CFLAGS+= -Wmissing-prototypes -CFLAGS+= -Wno-missing-field-initializers - - -ifeq ($(DEBUG),1) - CFLAGS+=-ggdb -else - ifeq ($(PERF), 1) - CFLAGS+=-O3 - else - CFLAGS+=-Os - endif -endif - -ifeq ($(PROFILE),1) - CFLAGS+=-pg -endif - -ifeq ($(TFTP),1) - MOD_OBJ+=$(LIBBASE)modules/pico_strings.o $(LIBBASE)modules/pico_tftp.o - OPTIONS+=-DPICO_SUPPORT_TFTP -endif - -ifeq ($(AODV),1) - MOD_OBJ+=$(LIBBASE)modules/pico_aodv.o - OPTIONS+=-DPICO_SUPPORT_AODV -endif - -ifeq ($(GENERIC),1) - CFLAGS+=-DGENERIC -endif - -ifeq ($(PTHREAD),1) - CFLAGS+=-DPICO_SUPPORT_PTHREAD -endif - - -ifneq ($(ENDIAN),little) - CFLAGS+=-DPICO_BIGENDIAN -endif - -ifneq ($(RTOS),0) - OPTIONS+=-DPICO_SUPPORT_RTOS -endif - -ifeq ($(ARCH),cortexm4-hardfloat) - CFLAGS+=-DCORTEX_M4_HARDFLOAT -mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork -fsingle-precision-constant -endif - -ifeq ($(ARCH),cortexm4-softfloat) - CFLAGS+=-DCORTEX_M4_SOFTFLOAT -mcpu=cortex-m4 -mthumb -mlittle-endian -mfloat-abi=soft -mthumb-interwork -endif - -ifeq ($(ARCH),cortexm3) - CFLAGS+=-DCORTEX_M3 -mcpu=cortex-m3 -mthumb -mlittle-endian -mthumb-interwork -endif - -ifeq ($(ARCH),arm9) - CFLAGS+=-DARM9 -mcpu=arm9e -march=armv5te -gdwarf-2 -Wall -marm -mthumb-interwork -fpack-struct -endif - -ifeq ($(ADDRESS_SANITIZER),1) - TEST_LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer -endif - -ifeq ($(ARCH),faulty) - CFLAGS+=-DFAULTY -DUNIT_TEST - ifeq ($(ADDRESS_SANITIZER),1) - CFLAGS+=-fsanitize=address - endif - CFLAGS+=-fno-omit-frame-pointer - UNITS_OBJ+=test/pico_faulty.o - TEST_OBJ+=test/pico_faulty.o - DUMMY_EXTRA+=test/pico_faulty.o -endif - -ifeq ($(ARCH),msp430) - CFLAGS+=-DMSP430 -endif - -ifeq ($(ARCH),esp8266) - CFLAGS+=-DESP8266 -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -endif - -ifeq ($(ARCH),mt7681) - CFLAGS+=-DMT7681 -fno-builtin -ffunction-sections -fno-strict-aliasing -m16bit -mabi=2 -mbaseline=V2 -mcpu=n9 -mno-div -mel -mmw-count=8 -mno-ext-mac -mno-dx-regs -endif - -ifeq ($(ARCH),pic24) - CFLAGS+=-DPIC24 -c -mcpu=24FJ256GA106 -MMD -MF -g -omf=elf \ - -mlarge-code -mlarge-data -msmart-io=1 -msfr-warn=off -endif - -ifeq ($(ARCH),atmega128) - CFLAGS+=-Wall -mmcu=atmega128 -DAVR -endif - -ifeq ($(ARCH),none) - CFLAGS+=-DARCHNONE -endif - -ifeq ($(ARCH),shared) - CFLAGS+=-fPIC -endif - -%.o:%.c deps - $(CC) -c $(CFLAGS) -o $@ $< - -CORE_OBJ= stack/pico_stack.o \ - stack/pico_frame.o \ - stack/pico_device.o \ - stack/pico_protocol.o \ - stack/pico_socket.o \ - stack/pico_socket_multicast.o \ - stack/pico_tree.o \ - stack/pico_md5.o - -POSIX_OBJ+= modules/pico_dev_vde.o \ - modules/pico_dev_tun.o \ - modules/pico_dev_tap.o \ - modules/pico_dev_mock.o - -ifneq ($(ETH),0) - include rules/eth.mk -endif -ifneq ($(IPV4),0) - include rules/ipv4.mk -endif -ifneq ($(IPV4FRAG),0) - include rules/ipv4frag.mk -endif -ifneq ($(ICMP4),0) - include rules/icmp4.mk -endif -ifneq ($(TCP),0) - include rules/tcp.mk -endif -ifneq ($(UDP),0) - include rules/udp.mk -endif -ifneq ($(MCAST),0) - include rules/mcast.mk - include rules/igmp.mk - include rules/mld.mk -endif -ifneq ($(NAT),0) - include rules/nat.mk -endif -ifneq ($(DEVLOOP),0) - include rules/devloop.mk -endif -ifneq ($(DHCP_CLIENT),0) - include rules/dhcp_client.mk -endif -ifneq ($(DHCP_SERVER),0) - include rules/dhcp_server.mk -endif -ifneq ($(DNS_CLIENT),0) - include rules/dns_client.mk -endif -ifneq ($(MDNS),0) - include rules/mdns.mk -endif -ifneq ($(DNS_SD),0) - include rules/dns_sd.mk -endif -ifneq ($(IPFILTER),0) - include rules/ipfilter.mk -endif -ifneq ($(CRC),0) - include rules/crc.mk -endif -ifneq ($(OLSR),0) - include rules/olsr.mk -endif -ifneq ($(SLAACV4),0) - include rules/slaacv4.mk -endif -ifneq ($(IPV6),0) - include rules/ipv6.mk -endif -ifneq ($(MEMORY_MANAGER),0) - include rules/memory_manager.mk -endif -ifneq ($(MEMORY_MANAGER_PROFILING),0) - OPTIONS+=-DPICO_SUPPORT_MM_PROFILING -endif -ifneq ($(SNTP_CLIENT),0) - include rules/sntp_client.mk -endif -ifneq ($(TUN),0) - include rules/tun.mk -endif -ifneq ($(TAP),0) - include rules/tap.mk -endif -ifneq ($(PCAP),0) - include rules/pcap.mk -endif -ifneq ($(PPP),0) - include rules/ppp.mk -endif -ifneq ($(CYASSL),0) - include rules/cyassl.mk -endif -ifneq ($(WOLFSSL),0) - include rules/wolfssl.mk -endif -ifneq ($(POLARSSL),0) - include rules/polarssl.mk -endif - -all: mod core lib - -core: $(CORE_OBJ) - @mkdir -p $(PREFIX)/lib - @mv stack/*.o $(PREFIX)/lib - -mod: $(MOD_OBJ) - @mkdir -p $(PREFIX)/modules - @mv modules/*.o $(PREFIX)/modules || echo - -posix: all $(POSIX_OBJ) - @mv modules/*.o $(PREFIX)/modules || echo - - -TEST_ELF= test/picoapp.elf -TEST6_ELF= test/picoapp6.elf - - -test: posix - @mkdir -p $(PREFIX)/test/ - @make -C test/examples PREFIX=$(PREFIX) - @echo -e "\t[CC] picoapp.o" - @$(CC) -c -o $(PREFIX)/examples/picoapp.o test/picoapp.c $(CFLAGS) -Itest/examples - @echo -e "\t[LD] $@" - @$(CC) -g -o $(TEST_ELF) -I include -I modules -I $(PREFIX)/include -Wl,--start-group $(TEST_LDFLAGS) $(TEST_OBJ) $(PREFIX)/examples/*.o -Wl,--end-group - @mv test/*.elf $(PREFIX)/test - @install $(PREFIX)/$(TEST_ELF) $(PREFIX)/$(TEST6_ELF) - -tst: test - -$(PREFIX)/include/pico_defines.h: - @mkdir -p $(PREFIX)/lib - @mkdir -p $(PREFIX)/include - @bash ./mkdeps.sh $(PREFIX) $(OPTIONS) - - -deps: $(PREFIX)/include/pico_defines.h - - - -lib: mod core - @cp -f include/*.h $(PREFIX)/include - @cp -fa include/arch $(PREFIX)/include - @cp -f modules/*.h $(PREFIX)/include - @echo -e "\t[AR] $(PREFIX)/lib/$(LIBNAME)" - @$(AR) cru $(PREFIX)/lib/$(LIBNAME) $(PREFIX)/modules/*.o $(PREFIX)/lib/*.o \ - || $(AR) cru $(PREFIX)/lib/$(LIBNAME) $(PREFIX)/lib/*.o - @echo -e "\t[RANLIB] $(PREFIX)/lib/$(LIBNAME)" - @$(RANLIB) $(PREFIX)/lib/$(LIBNAME) - @test $(STRIP) -eq 1 && (echo -e "\t[STRIP] $(PREFIX)/lib/$(LIBNAME)" \ - && $(STRIP_BIN) $(PREFIX)/lib/$(LIBNAME)) \ - || echo -e "\t[KEEP SYMBOLS] $(PREFIX)/lib/$(LIBNAME)" - @echo -e "\t[LIBSIZE] `du -b $(PREFIX)/lib/$(LIBNAME)`" - @echo -e "`size -t $(PREFIX)/lib/$(LIBNAME)`" - -loop: mod core - mkdir -p $(PREFIX)/test - @$(CC) -c -o $(PREFIX)/modules/pico_dev_loop.o modules/pico_dev_loop.c $(CFLAGS) - @$(CC) -c -o $(PREFIX)/loop_ping.o test/loop_ping.c $(CFLAGS) -ggdb - -units: mod core lib $(UNITS_OBJ) $(MOD_OBJ) - @echo -e "\n\t[UNIT TESTS SUITE]" - @mkdir -p $(PREFIX)/test - @echo -e "\t[CC] units.o" - @$(CC) -g -c -o $(PREFIX)/test/units.o test/units.c $(CFLAGS) -I stack -I modules -I includes -I test/unit -DUNIT_TEST - @echo -e "\t[LD] $(PREFIX)/test/units" - @$(CC) -o $(PREFIX)/test/units $(CFLAGS) $(PREFIX)/test/units.o -lcheck -lm -pthread -lrt \ - $(UNITS_OBJ) $(PREFIX)/modules/pico_aodv.o \ - $(PREFIX)/modules/pico_fragments.o - @$(CC) -o $(PREFIX)/test/modunit_pico_protocol.elf $(CFLAGS) -I. test/unit/modunit_pico_protocol.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_pico_frame.elf $(CFLAGS) -I. test/unit/modunit_pico_frame.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_seq.elf $(CFLAGS) -I. test/unit/modunit_seq.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_tcp.elf $(CFLAGS) -I. test/unit/modunit_pico_tcp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dns_client.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_client.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dns_common.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_common.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_mdns.elf $(CFLAGS) -I. test/unit/modunit_pico_mdns.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dns_sd.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_sd.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dev_loop.elf $(CFLAGS) -I. test/unit/modunit_pico_dev_loop.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_ipv6_nd.elf $(CFLAGS) -I. test/unit/modunit_pico_ipv6_nd.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_pico_stack.elf $(CFLAGS) -I. test/unit/modunit_pico_stack.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_tftp.elf $(CFLAGS) -I. test/unit/modunit_pico_tftp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_sntp_client.elf $(CFLAGS) -I. test/unit/modunit_pico_sntp_client.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_ipfilter.elf $(CFLAGS) -I. test/unit/modunit_pico_ipfilter.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_aodv.elf $(CFLAGS) -I. test/unit/modunit_pico_aodv.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_fragments.elf $(CFLAGS) -I. test/unit/modunit_pico_fragments.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_queue.elf $(CFLAGS) -I. test/unit/modunit_queue.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_dev_ppp.elf $(CFLAGS) -I. test/unit/modunit_pico_dev_ppp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_mld.elf $(CFLAGS) -I. test/unit/modunit_pico_mld.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_igmp.elf $(CFLAGS) -I. test/unit/modunit_pico_igmp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_hotplug_detection.elf $(CFLAGS) -I. test/unit/modunit_pico_hotplug_detection.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - -devunits: mod core lib - @echo -e "\n\t[UNIT TESTS SUITE: device drivers]" - @mkdir -p $(PREFIX)/test/unit/device/ - @echo -e "\t[CC] picotcp_mock.o" - @$(CC) -c -o $(PREFIX)/test/unit/device/picotcp_mock.o $(CFLAGS) -I stack -I modules -I includes -I test/unit test/unit/device/picotcp_mock.c - @$(CC) -c -o $(PREFIX)/test/unit/device/unit_dev_vde.o $(CFLAGS) -I stack -I modules -I includes -I test/unit test/unit/device/unit_dev_vde.c - @echo -e "\t[LD] $(PREFIX)/test/devunits" - @$(CC) -o $(PREFIX)/test/devunits $(CFLAGS) -I stack $(PREFIX)/test/unit/device/*.o -lcheck -lm -pthread -lrt - -units_mm: mod core lib - @echo -e "\n\t[UNIT TESTS SUITE]" - @mkdir -p $(PREFIX)/test - @echo -e "\t[CC] units_mm.o" - @$(CC) -c -o $(PREFIX)/test/units_mm.o test/unit/unit_mem_manager.c $(CFLAGS) -I stack -I modules -I includes -I test/unit - @echo -e "\t[LD] $(PREFIX)/test/units" - @$(CC) -o $(PREFIX)/test/units_mm $(CFLAGS) $(PREFIX)/test/units_mm.o -lcheck -lm -pthread -lrt - - -clean: - @echo -e "\t[CLEAN] $(PREFIX)/" - @rm -rf $(PREFIX) tags - -mbed: - @echo -e "\t[Creating PicoTCP.zip]" - @rm -f PicoTCP.zip - @cp include/pico_socket.h include/socket.tmp - @echo "#define MBED\n" > include/mbed.tmp - @cat include/mbed.tmp include/socket.tmp > include/pico_socket.h - @zip -0 PicoTCP.zip -r include modules stack -x include/arch/ include/arch/* include/pico_config.h include/*.tmp modules/pico_dev_* - @rm include/pico_socket.h include/mbed.tmp - @mv include/socket.tmp include/pico_socket.h - - -style: - @find . -iname "*.[c|h]" | xargs -x uncrustify --replace -l C -c uncrustify.cfg || true - @find . -iname "*unc-backup*" |xargs -x rm || true - -dummy: mod core lib $(DUMMY_EXTRA) - @echo testing configuration... - @$(CC) -c -o test/dummy.o test/dummy.c $(CFLAGS) - @$(CC) -o dummy test/dummy.o $(DUMMY_EXTRA) $(PREFIX)/lib/libpicotcp.a $(LDFLAGS) $(CFLAGS) - @echo done. - @rm -f test/dummy.o dummy - -ppptest: test/ppp.c lib - gcc -ggdb -c -o ppp.o test/ppp.c -I build/include/ -I build/modules/ $(CFLAGS) - gcc -o ppp ppp.o build/lib/libpicotcp.a $(LDFLAGS) $(CFLAGS) - rm -f ppp.o - - -FORCE: diff --git a/ext/picotcp/Makefile.watcom b/ext/picotcp/Makefile.watcom deleted file mode 100644 index cbe04d7..0000000 --- a/ext/picotcp/Makefile.watcom +++ /dev/null @@ -1,403 +0,0 @@ --include ../../config.mk --include ../../tools/kconfig/.config - -WATCOM_PATH:=/opt/watcom -CC:=$(WATCOM_PATH)/binl/$(CROSS_COMPILE)wcc386 -LD:=$(WATCOM_PATH)/binl/$(CROSS_COMPILE)wcl386 -AR:=$(WATCOM_PATH)/binl/$(CROSS_COMPILE)wlib -RANLIB:=$(WATCOM_PATH)/binl/$(CROSS_COMPILE)ranlib -SIZE:=$(CROSS_COMPILE)size -STRIP_BIN:=$(CROSS_COMPILE)strip -TEST_LDFLAGS=-pthread $(PREFIX)/modules/*.o $(PREFIX)/lib/*.o -lvdeplug -LIBNAME:=libpicotcp.a - -PREFIX?=$(PWD)/build -DEBUG?=1 -PROFILE?=0 -PERF?=0 -ENDIAN?=little -STRIP?=0 -RTOS?=0 -GENERIC?=0 -PTHREAD?=0 -ADDRESS_SANITIZER?=1 - -# Default compiled-in protocols -# -TCP?=1 -UDP?=1 -ETH?=1 -IPV4?=1 -IPV4FRAG?=1 -IPV6FRAG?=0 -NAT?=1 -ICMP4?=1 -MCAST?=1 -DEVLOOP?=1 -PING?=1 -DHCP_CLIENT?=1 -DHCP_SERVER?=1 -DNS_CLIENT?=1 -MDNS?=1 -DNS_SD?=1 -SNTP_CLIENT?=1 -IPFILTER?=1 -CRC?=1 -OLSR?=0 -SLAACV4?=1 -TFTP?=1 -AODV?=1 -MEMORY_MANAGER?=0 -MEMORY_MANAGER_PROFILING?=0 -TUN?=0 -TAP?=0 -PCAP?=0 -PPP?=0 -CYASSL?=0 -WOLFSSL?=0 -POLARSSL?=0 - -#IPv6 related -IPV6?=1 - -EXTRA_CFLAGS+=-dPICO_COMPILE_TIME=`date +%s` -EXTRA_CFLAGS+=$(PLATFORM_CFLAGS) - -CFLAGS=-i=$(WATCOM_PATH)/h -i=$(PREFIX)/include -i=include -i=modules $(EXTRA_CFLAGS) -q - - -ifeq ($(DEBUG),1) - CFLAGS+=-od -of -d9 -else - ifeq ($(PERF), 1) - CFLAGS+= - else - CFLAGS+= - endif -endif - -ifeq ($(TFTP),1) - MOD_OBJ+=$(LIBBASE)modules/pico_strings.o $(LIBBASE)modules/pico_tftp.o - OPTIONS+=-dPICO_SUPPORT_TFTP -endif - -ifeq ($(AODV),1) - MOD_OBJ+=$(LIBBASE)modules/pico_aodv.o - OPTIONS+=-dPICO_SUPPORT_AODV -endif - -ifeq ($(GENERIC),1) - CFLAGS+=-dGENERIC -endif - -ifeq ($(PTHREAD),1) - CFLAGS+=-dPICO_SUPPORT_PTHREAD -endif - - -ifneq ($(ENDIAN),little) - CFLAGS+=-dPICO_BIGENDIAN -endif - -ifneq ($(RTOS),0) - OPTIONS+=-dPICO_SUPPORT_RTOS -endif - -ifeq ($(ARCH),cortexm4-hardfloat) - CFLAGS+=-dCORTEX_M4_HARDFLOAT -mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork -fsingle-precision-constant -endif - -ifeq ($(ARCH),cortexm4-softfloat) - CFLAGS+=-dCORTEX_M4_SOFTFLOAT -mcpu=cortex-m4 -mthumb -mlittle-endian -mfloat-abi=soft -mthumb-interwork -endif - -ifeq ($(ARCH),cortexm3) - CFLAGS+=-dCORTEX_M3 -mcpu=cortex-m3 -mthumb -mlittle-endian -mthumb-interwork -endif - -ifeq ($(ARCH),arm9) - CFLAGS+=-dARM9 -mcpu=arm9e -march=armv5te -gdwarf-2 -Wall -marm -mthumb-interwork -fpack-struct -endif - -ifeq ($(ADDRESS_SANITIZER),1) - TEST_LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer -endif - -ifeq ($(ARCH),faulty) - CFLAGS+=-dFAULTY -dUNIT_TEST - CFLAGS+=-fsanitize=address -fno-omit-frame-pointer - UNITS_OBJ+=test/pico_faulty.o - TEST_OBJ+=test/pico_faulty.o - DUMMY_EXTRA+=test/pico_faulty.o -endif - -ifeq ($(ARCH),msp430) - CFLAGS+=-dMSP430 -endif - -ifeq ($(ARCH),esp8266) - CFLAGS+=-dESP8266 -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -endif - -ifeq ($(ARCH),mt7681) - CFLAGS+=-dMT7681 -fno-builtin -ffunction-sections -fno-strict-aliasing -m16bit -mabi=2 -mbaseline=V2 -mcpu=n9 -mno-div -mel -mmw-count=8 -mno-ext-mac -mno-dx-regs -endif - -ifeq ($(ARCH),pic24) - CFLAGS+=-dPIC24 -mcpu=24FJ256GA106 -MMD -MF -g -omf=elf \ - -mlarge-code -mlarge-data -msmart-io=1 -msfr-warn=off -endif - -ifeq ($(ARCH),atmega128) - CFLAGS+=-Wall -mmcu=atmega128 -dAVR -endif - -ifeq ($(ARCH),none) - CFLAGS+=-dARCHNONE -endif - -ifeq ($(ARCH),shared) - CFLAGS+=-fPIC -endif - -%.o:%.c deps - $(CC) $(CFLAGS) -fo=$@ $< - -CORE_OBJ= stack/pico_stack.o \ - stack/pico_frame.o \ - stack/pico_device.o \ - stack/pico_protocol.o \ - stack/pico_socket.o \ - stack/pico_socket_multicast.o \ - stack/pico_tree.o \ - stack/pico_md5.o - -POSIX_OBJ+= modules/pico_dev_vde.o \ - modules/pico_dev_tun.o \ - modules/pico_dev_tap.o \ - modules/pico_dev_mock.o - -ifneq ($(ETH),0) - include rules/eth.mk -endif -ifneq ($(IPV4),0) - include rules/ipv4.mk -endif -ifneq ($(IPV4FRAG),0) - include rules/ipv4frag.mk -endif -ifneq ($(ICMP4),0) - include rules/icmp4.mk -endif -ifneq ($(TCP),0) - include rules/tcp.mk -endif -ifneq ($(UDP),0) - include rules/udp.mk -endif -ifneq ($(MCAST),0) - include rules/mcast.mk - include rules/igmp.mk -endif -ifneq ($(NAT),0) - include rules/nat.mk -endif -ifneq ($(DEVLOOP),0) - include rules/devloop.mk -endif -ifneq ($(DHCP_CLIENT),0) - include rules/dhcp_client.mk -endif -ifneq ($(DHCP_SERVER),0) - include rules/dhcp_server.mk -endif -ifneq ($(DNS_CLIENT),0) - include rules/dns_client.mk -endif -ifneq ($(MDNS),0) - include rules/mdns.mk -endif -ifneq ($(DNS_SD),0) - include rules/dns_sd.mk -endif -ifneq ($(IPFILTER),0) - include rules/ipfilter.mk -endif -ifneq ($(CRC),0) - include rules/crc.mk -endif -ifneq ($(OLSR),0) - include rules/olsr.mk -endif -ifneq ($(SLAACV4),0) - include rules/slaacv4.mk -endif -ifneq ($(IPV6),0) - include rules/ipv6.mk -endif -ifneq ($(MEMORY_MANAGER),0) - include rules/memory_manager.mk -endif -ifneq ($(MEMORY_MANAGER_PROFILING),0) - OPTIONS+=-dPICO_SUPPORT_MM_PROFILING -endif -ifneq ($(SNTP_CLIENT),0) - include rules/sntp_client.mk -endif -ifneq ($(TUN),0) - include rules/tun.mk -endif -ifneq ($(TAP),0) - include rules/tap.mk -endif -ifneq ($(PCAP),0) - include rules/pcap.mk -endif -ifneq ($(PPP),0) - include rules/ppp.mk -endif -ifneq ($(CYASSL),0) - include rules/cyassl.mk -endif -ifneq ($(WOLFSSL),0) - include rules/wolfssl.mk -endif -ifneq ($(POLARSSL),0) - include rules/polarssl.mk -endif - -all: mod core lib - -core: $(CORE_OBJ) - @mkdir -p $(PREFIX)/lib - @mv stack/*.o $(PREFIX)/lib - -mod: $(MOD_OBJ) - @mkdir -p $(PREFIX)/modules - @mv modules/*.o $(PREFIX)/modules || echo - -posix: all $(POSIX_OBJ) - @mv modules/*.o $(PREFIX)/modules || echo - - -TEST_ELF= test/picoapp.elf -TEST6_ELF= test/picoapp6.elf - - -test: posix - @mkdir -p $(PREFIX)/test/ - @make -C test/examples PREFIX=$(PREFIX) - @echo -e "\t[CC] picoapp.o" - @$(CC) -c -o $(PREFIX)/examples/picoapp.o test/picoapp.c $(CFLAGS) -Itest/examples - @echo -e "\t[LD] $@" - @$(CC) -g -o $(TEST_ELF) -I include -I modules -I $(PREFIX)/include -Wl,--start-group $(TEST_LDFLAGS) $(TEST_OBJ) $(PREFIX)/examples/*.o -Wl,--end-group - @mv test/*.elf $(PREFIX)/test - @install $(PREFIX)/$(TEST_ELF) $(PREFIX)/$(TEST6_ELF) - -tst: test - -$(PREFIX)/include/pico_defines.h: - @mkdir -p $(PREFIX)/lib - @mkdir -p $(PREFIX)/include - @bash ./mkdeps.sh $(PREFIX) $(OPTIONS) - - -deps: $(PREFIX)/include/pico_defines.h - - - -lib: mod core - @cp -f include/*.h $(PREFIX)/include - @cp -fa include/arch $(PREFIX)/include - @cp -f modules/*.h $(PREFIX)/include - @echo -e "\t[AR] $(PREFIX)/lib/$(LIBNAME)" - $(AR) -q -b -n -fag -o=$(PREFIX)/lib/$(LIBNAME) $(PREFIX)/modules/*.o $(PREFIX)/lib/*.o - @echo || $(AR) cru $(PREFIX)/lib/$(LIBNAME) $(PREFIX)/lib/*.o - @echo -e "\t[RANLIB] $(PREFIX)/lib/$(LIBNAME)" - @$(RANLIB) $(PREFIX)/lib/$(LIBNAME) - @echo -e "\t[LIBSIZE] `du -b $(PREFIX)/lib/$(LIBNAME)`" - -loop: mod core - mkdir -p $(PREFIX)/test - @$(CC) -c -o $(PREFIX)/modules/pico_dev_loop.o modules/pico_dev_loop.c $(CFLAGS) - @$(CC) -c -o $(PREFIX)/loop_ping.o test/loop_ping.c $(CFLAGS) -ggdb - -units: mod core lib $(UNITS_OBJ) $(MOD_OBJ) - @echo -e "\n\t[UNIT TESTS SUITE]" - @mkdir -p $(PREFIX)/test - @echo -e "\t[CC] units.o" - @$(CC) -c -o $(PREFIX)/test/units.o test/units.c $(CFLAGS) -I stack -I modules -I includes -I test/unit -dUNIT_TEST - @echo -e "\t[LD] $(PREFIX)/test/units" - @$(CC) -o $(PREFIX)/test/units $(CFLAGS) $(PREFIX)/test/units.o -lcheck -lm -pthread -lrt \ - $(UNITS_OBJ) $(PREFIX)/modules/pico_aodv.o \ - $(PREFIX)/modules/pico_fragments.o - @$(CC) -o $(PREFIX)/test/modunit_pico_protocol.elf $(CFLAGS) -I. test/unit/modunit_pico_protocol.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_pico_frame.elf $(CFLAGS) -I. test/unit/modunit_pico_frame.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_seq.elf $(CFLAGS) -I. test/unit/modunit_seq.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_tcp.elf $(CFLAGS) -I. test/unit/modunit_pico_tcp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dns_client.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_client.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dns_common.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_common.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_mdns.elf $(CFLAGS) -I. test/unit/modunit_pico_mdns.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dns_sd.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_sd.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dev_loop.elf $(CFLAGS) -I. test/unit/modunit_pico_dev_loop.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_ipv6_nd.elf $(CFLAGS) -I. test/unit/modunit_pico_ipv6_nd.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_pico_stack.elf $(CFLAGS) -I. test/unit/modunit_pico_stack.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_tftp.elf $(CFLAGS) -I. test/unit/modunit_pico_tftp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_sntp_client.elf $(CFLAGS) -I. test/unit/modunit_pico_sntp_client.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_ipfilter.elf $(CFLAGS) -I. test/unit/modunit_pico_ipfilter.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_aodv.elf $(CFLAGS) -I. test/unit/modunit_pico_aodv.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_fragments.elf $(CFLAGS) -I. test/unit/modunit_pico_fragments.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_queue.elf $(CFLAGS) -I. test/unit/modunit_queue.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_dev_ppp.elf $(CFLAGS) -I. test/unit/modunit_pico_dev_ppp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - -devunits: mod core lib - @echo -e "\n\t[UNIT TESTS SUITE: device drivers]" - @mkdir -p $(PREFIX)/test/unit/device/ - @echo -e "\t[CC] picotcp_mock.o" - @$(CC) -c -o $(PREFIX)/test/unit/device/picotcp_mock.o $(CFLAGS) -I stack -I modules -I includes -I test/unit test/unit/device/picotcp_mock.c - @$(CC) -c -o $(PREFIX)/test/unit/device/unit_dev_vde.o $(CFLAGS) -I stack -I modules -I includes -I test/unit test/unit/device/unit_dev_vde.c - @echo -e "\t[LD] $(PREFIX)/test/devunits" - @$(CC) -o $(PREFIX)/test/devunits $(CFLAGS) -I stack $(PREFIX)/test/unit/device/*.o -lcheck -lm -pthread -lrt - -units_mm: mod core lib - @echo -e "\n\t[UNIT TESTS SUITE]" - @mkdir -p $(PREFIX)/test - @echo -e "\t[CC] units_mm.o" - @$(CC) -c -o $(PREFIX)/test/units_mm.o test/unit/unit_mem_manager.c $(CFLAGS) -I stack -I modules -I includes -I test/unit - @echo -e "\t[LD] $(PREFIX)/test/units" - @$(CC) -o $(PREFIX)/test/units_mm $(CFLAGS) $(PREFIX)/test/units_mm.o -lcheck -lm -pthread -lrt - - -clean: - @echo -e "\t[CLEAN] $(PREFIX)/" - @rm -rf $(PREFIX) tags - -mbed: - @echo -e "\t[Creating PicoTCP.zip]" - @rm -f PicoTCP.zip - @cp include/pico_socket.h include/socket.tmp - @echo "#define MBED\n" > include/mbed.tmp - @cat include/mbed.tmp include/socket.tmp > include/pico_socket.h - @zip -0 PicoTCP.zip -r include modules stack -x include/arch/ include/arch/* include/pico_config.h include/*.tmp modules/pico_dev_* - @rm include/pico_socket.h include/mbed.tmp - @mv include/socket.tmp include/pico_socket.h - - -style: - @find . -iname "*.[c|h]" | xargs -x uncrustify --replace -l C -c uncrustify.cfg || true - @find . -iname "*unc-backup*" |xargs -x rm || true - -dummy: mod core lib $(DUMMY_EXTRA) - @echo testing configuration... - @$(CC) -c -o test/dummy.o test/dummy.c $(CFLAGS) - @$(CC) -o dummy test/dummy.o $(DUMMY_EXTRA) $(PREFIX)/lib/libpicotcp.a $(LDFLAGS) $(CFLAGS) - @echo done. - @rm -f test/dummy.o dummy - -ppptest: test/ppp.c lib - gcc -ggdb -c -o ppp.o test/ppp.c -I build/include/ -I build/modules/ $(CFLAGS) - gcc -o ppp ppp.o build/lib/libpicotcp.a $(LDFLAGS) $(CFLAGS) - rm -f ppp.o - - -FORCE: diff --git a/ext/picotcp/README.md b/ext/picotcp/README.md deleted file mode 100644 index 37c5d43..0000000 --- a/ext/picotcp/README.md +++ /dev/null @@ -1,103 +0,0 @@ -picoTCP - ---------------- - -Welcome to the one and only picoTCP repository. - -picoTCP is a small-footprint, modular TCP/IP stack designed for embedded systems and the Internet of Things. It's actively being developed by *[Altran Intelligent Systems](http://intelligent-systems.altran.com/)*. Textual information about picoTCP, you can find on the [about page of our website](http://picotcp.com/about). - -This code is released under the terms of GNU GPL v2 only. Some rights reserved. -Other licenses may apply at the sole discretion of the copyright holders. - -Learn how to use picoTCP in your project by going through the **Getting Started guide** on our [GitHub wiki](https://github.com/tass-belgium/picotcp/wiki). - -For more information visit the [picoTCP website](http://www.picotcp.com), send us an email or contact us on [Twitter](https://twitter.com/picotcp), [Facebook](https://www.facebook.com/picoTCP) or [Reddit](http://www.reddit.com/r/picotcp/). - -Wondering about picoTCP's code quality? Check [our TiCS score](http://tics.picotcp.com:42506/tiobeweb/TICS/TqiDashboard.html#axes=Project%28%29&metric=tqi&sel=Project%28PicoTCP_rel%29) - - ---------------- - -Continuous integration - -Jenkins Functional tests: -[![Jenkins autotest](http://jenkins.picotcp.com:8080/buildStatus/icon?job=picoTCP_Rel/PicoTCP_rel_autotest)](http://jenkins.picotcp.com:8080/job/picoTCP_Rel/job/PicoTCP_rel_autotest) - -Jenkins Unit tests : -[![Jenkins unit tests](http://jenkins.picotcp.com:8080/buildStatus/icon?job=picoTCP_Rel/PicoTCP_rel_unit_tests)](http://jenkins.picotcp.com:8080/job/picoTCP_Rel/job/PicoTCP_rel_unit_tests) - -Jenkins RFC compliance : -[![Jenkins RFC Compliance](http://jenkins.picotcp.com:8080/buildStatus/icon?job=picoTCP_Rel/PicoTCP_rel_RF_mbed)](http://jenkins.picotcp.com:8080/job/picoTCP_Rel/job/PicoTCP_rel_RF_mbed) - -Jenkins TICS quality : -[![Jenkins TICS](http://jenkins.picotcp.com:8080/buildStatus/icon?job=picoTCP_Rel/PicoTCP_rel_TICS)](http://jenkins.picotcp.com:8080/job/picoTCP_Rel/job/PicoTCP_rel_TICS/) - -Coverity Scan Build status: -[![Coverity Scan Build Status](https://scan.coverity.com/projects/7944/badge.svg)](https://scan.coverity.com/projects/7944) - ---------------- - -Works with ... -## Platforms -* ARM Cortex-M series - * ST Micro STM - * NXP LPC - * TI Stellaris - * Freescale K64F -* ARM ARM9-series - * ST Micro STR9 -* Texas Instruments - * MSP430 -* Microchip - * PIC24 -* Atmel - * AVR 8bit -* Linux - * User space (TUN/TAP) - * Kernel space -* Windows - * User space (TAP) - -## Network drivers -* BCM43362 (IEEE 802.11) -* MRF24WG (IEEE 802.11) -* LPC Ethernet ENET/EMAC (IEEE 802.3) -* Stellaris Ethernet (IEEE 802.3) -* STM32 Ethernet (IEEE 802.3) -* Wiznet W5100 (IEEE 802.3) -* USB CDC-ECM (CDC1.2) -* PPP -* Virtual drivers - * TUN/TAP - * VDE - * Libpcap - -## (RT)OSes -* No OS / Bare metal -* FreeRTOS -* mbed-RTOS -* Frosted -* linux / POSIX -* MS DOS -* MS Windows - -## Libraries -* wolfSSL -* mbedTLS -* Mongoose RESTful library -* MicroPython -* HTTP library -* ZeroMQ (WIP) -* MQTT - -## Compilers -* GCC -* Clang -* TCC -* ARM-RCVT -* IAR -* XC-16 -* MSP-GCC -* AVR-GCC - -Your favorite not in the list? Check out the wiki for information and examples on how to port picoTCP to a new platform! diff --git a/ext/picotcp/include/arch/pico_arm9.h b/ext/picotcp/include/arch/pico_arm9.h deleted file mode 100644 index 0d2d2e3..0000000 --- a/ext/picotcp/include/arch/pico_arm9.h +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - *********************************************************************/ -#define dbg(...) do {} while(0) - -/******************/ - -/*** MACHINE CONFIGURATION ***/ -/* Temporary (POSIX) stuff. */ -#include -#include - -extern volatile uint32_t __str9_tick; - -#define pico_native_malloc(x) calloc(x, 1) -#define pico_native_free(x) free(x) - -static inline unsigned long PICO_TIME(void) -{ - register uint32_t tick = __str9_tick; - return tick / 1000; -} - -static inline unsigned long PICO_TIME_MS(void) -{ - return __str9_tick; -} - -static inline void PICO_IDLE(void) -{ - unsigned long tick_now = __str9_tick; - while(tick_now == __str9_tick) ; -} - diff --git a/ext/picotcp/include/arch/pico_avr.h b/ext/picotcp/include/arch/pico_avr.h deleted file mode 100644 index cd7e4ab..0000000 --- a/ext/picotcp/include/arch/pico_avr.h +++ /dev/null @@ -1,39 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#define dbg(...) do {} while(0) -/* #define dbg printf */ - -/*************************/ - -/*** MACHINE CONFIGURATION ***/ -/* Temporary (POSIX) stuff. */ -#include -#include -#include -#include "pico_mm.h" - -extern volatile uint32_t __avr_tick; - -#define pico_zalloc(x) calloc(x, 1) -#define pico_free(x) free(x) - -static inline unsigned long PICO_TIME(void) -{ - register uint32_t tick = __avr_tick; - return tick / 1000; -} - -static inline unsigned long PICO_TIME_MS(void) -{ - return __avr_tick; -} - -static inline void PICO_IDLE(void) -{ - unsigned long tick_now = __avr_tick; - while(tick_now == __avr_tick) ; -} - diff --git a/ext/picotcp/include/arch/pico_cortex_m.h b/ext/picotcp/include/arch/pico_cortex_m.h deleted file mode 100644 index cfd12f3..0000000 --- a/ext/picotcp/include/arch/pico_cortex_m.h +++ /dev/null @@ -1,12 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef _INCLUDE_PICO_CORTEX_M -#define _INCLUDE_PICO_CORTEX_M - -#include "pico_generic_gcc.h" - -#endif /* PICO_CORTEX_M */ - diff --git a/ext/picotcp/include/arch/pico_esp8266.h b/ext/picotcp/include/arch/pico_esp8266.h deleted file mode 100644 index 5419e1f..0000000 --- a/ext/picotcp/include/arch/pico_esp8266.h +++ /dev/null @@ -1,55 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef _INCLUDE_PICO_ESP8266 -#define _INCLUDE_PICO_ESP8266 - -#include - -#include -#include -#include -#include "pico_constants.h" - -/* -------------- DEBUG ------------- */ - -/* #define dbg(...) */ -#define dbg printf - -/* -------------- MEMORY ------------- */ -extern void *pvPortMalloc( size_t xWantedSize ); -extern void vPortFree( void *pv ); - -#define pico_free vPortFree - -static inline void *pico_zalloc(size_t size) -{ - void *ptr = (void *)pvPortMalloc(size); - - if(ptr) - memset(ptr, 0u, size); - - return ptr; -} - -/* -------------- TIME ------------- */ - -extern volatile uint32_t esp_tick; - -static inline pico_time PICO_TIME_MS(void) { - return (pico_time) esp_tick; -} - -static inline pico_time PICO_TIME(void) { - return PICO_TIME_MS() / 1000; -} - -static inline void PICO_IDLE(void) { - uint32_t now = esp_tick; - while (now == esp_tick) - ; -} - -#endif diff --git a/ext/picotcp/include/arch/pico_generic_gcc.h b/ext/picotcp/include/arch/pico_generic_gcc.h deleted file mode 100644 index 5958e3f..0000000 --- a/ext/picotcp/include/arch/pico_generic_gcc.h +++ /dev/null @@ -1,102 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef _INCLUDE_PICO_GCC -#define _INCLUDE_PICO_GCC - -#include -#include -#include -#include "pico_constants.h" - -/* monotonically increasing tick, - * typically incremented every millisecond in a systick interrupt */ -extern volatile unsigned int pico_ms_tick; - -#define dbg(...) - -#ifdef PICO_SUPPORT_PTHREAD - #define PICO_SUPPORT_MUTEX -#endif - -#ifdef PICO_SUPPORT_RTOS - #define PICO_SUPPORT_MUTEX - -extern void *pico_mutex_init(void); -extern void pico_mutex_lock(void*); -extern void pico_mutex_unlock(void*); -extern void *pvPortMalloc( size_t xSize ); -extern void vPortFree( void *pv ); - - #define pico_free(x) vPortFree(x) - #define free(x) vPortFree(x) - -static inline void *pico_zalloc(size_t size) -{ - void *ptr = pvPortMalloc(size); - - if(ptr) - memset(ptr, 0u, size); - - return ptr; -} - -static inline pico_time PICO_TIME_MS() -{ - return pico_ms_tick; -} - -static inline pico_time PICO_TIME() -{ - return pico_ms_tick / 1000; -} - -static inline void PICO_IDLE(void) -{ - pico_time now = PICO_TIME_MS(); - while(now == PICO_TIME_MS()) ; -} - -#else /* NO RTOS SUPPORT */ - - #ifdef MEM_MEAS -/* These functions should be implemented elsewhere */ -extern void *memmeas_zalloc(size_t size); -extern void memmeas_free(void *); - #define pico_free(x) memmeas_free(x) - #define pico_zalloc(x) memmeas_zalloc(x) - #else -/* Use plain C-lib malloc and free */ - #define pico_free(x) free(x) -static inline void *pico_zalloc(size_t size) -{ - void *ptr = malloc(size); - if(ptr) - memset(ptr, 0u, size); - - return ptr; -} - #endif - -static inline pico_time PICO_TIME_MS(void) -{ - return (pico_time)pico_ms_tick; -} - -static inline pico_time PICO_TIME(void) -{ - return (pico_time)(PICO_TIME_MS() / 1000); -} - -static inline void PICO_IDLE(void) -{ - unsigned int now = pico_ms_tick; - while(now == pico_ms_tick) ; -} - -#endif /* IFNDEF RTOS */ - -#endif /* PICO_GCC */ - diff --git a/ext/picotcp/include/arch/pico_linux.h b/ext/picotcp/include/arch/pico_linux.h deleted file mode 100644 index 3910c25..0000000 --- a/ext/picotcp/include/arch/pico_linux.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef PICO_SUPPORT_LINUX -#define PICO_SUPPORT_LINUX - -#include "linux/types.h" -#include "linux/mm.h" -#include "linux/slab.h" -#include "linux/jiffies.h" - -#define dbg printk - -#define pico_zalloc(x) kcalloc(x, 1, GFP_ATOMIC) /* All allocations are GFP_ATOMIC for now */ -#define pico_free(x) kfree(x) - - -static inline unsigned long PICO_TIME(void) -{ - return (unsigned long)(jiffies_to_msecs(jiffies) / 1000); -} - -static inline unsigned long PICO_TIME_MS(void) -{ - return (unsigned long)jiffies_to_msecs(jiffies); -} - -static inline void PICO_IDLE(void) -{ - unsigned long now = jiffies; - while (now == jiffies) { - ; - } -} - -#endif diff --git a/ext/picotcp/include/arch/pico_mbed.h b/ext/picotcp/include/arch/pico_mbed.h deleted file mode 100644 index 3c3a272..0000000 --- a/ext/picotcp/include/arch/pico_mbed.h +++ /dev/null @@ -1,185 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - File: pico_mbed.h - Author: Toon Peters - *********************************************************************/ - -#ifndef PICO_SUPPORT_MBED -#define PICO_SUPPORT_MBED -#include -#include -/* #include "mbed.h" */ -/* #include "serial_api.h" */ - -/* #define TIME_PRESCALE */ -/* #define PICO_MEASURE_STACK */ -/* #define MEMORY_MEASURE */ -/* - Debug needs initialization: - * void serial_init (serial_t *obj, PinName tx, PinName rx); - * void serial_baud (serial_t *obj, int baudrate); - * void serial_format (serial_t *obj, int data_bits, SerialParity parity, int stop_bits); - */ - -#define dbg(...) - -/* - #define MEMORY_MEASURE - #define JENKINS_DEBUG - */ - -/* Intended for Mr. Jenkins endurance test loggings */ -#ifdef JENKINS_DEBUG -#include "PicoTerm.h" -#define jenkins_dbg ptm_dbg -#endif - -#ifdef PICO_MEASURE_STACK - -extern int freeStack; -#define STACK_TOTAL_WORDS 1000u -#define STACK_PATTERN (0xC0CAC01Au) - -void stack_fill_pattern(void *ptr); -void stack_count_free_words(void *ptr); -int stack_get_free_words(void); -#else -#define stack_fill_pattern(...) do {} while(0) -#define stack_count_free_words(...) do {} while(0) -#define stack_get_free_words() (0) -#endif - -#ifdef MEMORY_MEASURE /* in case, comment out the two defines above me. */ -extern uint32_t max_mem; -extern uint32_t cur_mem; - -struct mem_chunk_stats { -#ifdef MEMORY_MEASURE_ADV - uint32_t signature; - void *mem; -#endif - uint32_t size; -}; - -static inline void *pico_zalloc(int x) -{ - struct mem_chunk_stats *stats; - if ((cur_mem + x) > (10 * 1024)) - return NULL; - - stats = (struct mem_chunk_stats *)calloc(x + sizeof(struct mem_chunk_stats), 1); -#ifdef MEMORY_MEASURE_ADV - stats->signature = 0xdeadbeef; - stats->mem = ((uint8_t *)stats) + sizeof(struct mem_chunk_stats); -#endif - stats->size = x; - - /* Intended for Mr. Jenkins endurance test loggings */ - #ifdef JENKINS_DEBUG - if (!stats) { - jenkins_dbg(">> OUT OF MEM\n"); - while(1) ; - ; - } - - #endif - cur_mem += x; - if (cur_mem > max_mem) { - max_mem = cur_mem; - /* printf("max mem: %lu\n", max_mem); */ - } - -#ifdef MEMORY_MEASURE_ADV - return (void*)(stats->mem); -#else - return (void*) (((uint8_t *)stats) + sizeof(struct mem_chunk_stats)); -#endif -} - -static inline void pico_free(void *x) -{ - struct mem_chunk_stats *stats = (struct mem_chunk_stats *) ((uint8_t *)x - sizeof(struct mem_chunk_stats)); - - #ifdef JENKINS_DEBUG - #ifdef MEMORY_MEASURE_ADV - if ((stats->signature != 0xdeadbeef) || (x != stats->mem)) { - jenkins_dbg(">> FREE ERROR: caller is %p\n", __builtin_return_address(0)); - while(1) ; - ; - } - - #endif - - #endif - - cur_mem -= stats->size; - memset(stats, 0, sizeof(struct mem_chunk_stats)); - free(stats); -} -#else - -#define pico_zalloc(x) calloc(x, 1) -#define pico_free(x) free(x) - -#endif - -#define PICO_SUPPORT_MUTEX -extern void *pico_mutex_init(void); -extern void pico_mutex_lock(void*); -extern void pico_mutex_unlock(void*); -extern void pico_mutex_deinit(void*); - -extern uint32_t os_time; -extern pico_time local_time; -extern uint32_t last_os_time; - -#ifdef TIME_PRESCALE -extern int32_t prescale_time; -#endif - -#define UPDATE_LOCAL_TIME() do {local_time = local_time + ((pico_time)os_time - (pico_time)last_os_time);last_os_time = os_time;} while(0) - -static inline pico_time PICO_TIME(void) -{ - UPDATE_LOCAL_TIME(); - #ifdef TIME_PRESCALE - return (prescale_time < 0) ? (pico_time)(local_time / 1000 << (-prescale_time)) : \ - (pico_time)(local_time / 1000 >> prescale_time); - #else - return (pico_time)(local_time / 1000); - #endif -} - -static inline pico_time PICO_TIME_MS(void) -{ - UPDATE_LOCAL_TIME(); - #ifdef TIME_PRESCALE - return (prescale_time < 0) ? (pico_time)(local_time << (-prescale_time)) : \ - (pico_time)(local_time >> prescale_time); - #else - return (pico_time)local_time; - #endif -} - -static inline void PICO_IDLE(void) -{ - /* TODO needs implementation */ -} -/* - static inline void PICO_DEBUG(const char * formatter, ... ) - { - char buffer[256]; - char *ptr; - va_list args; - va_start(args, formatter); - vsnprintf(buffer, 256, formatter, args); - ptr = buffer; - while(*ptr != '\0') - serial_putc(serial_t *obj, (int) (*(ptr++))); - va_end(args); - //TODO implement serial_t - }*/ - -#endif diff --git a/ext/picotcp/include/arch/pico_msp430.h b/ext/picotcp/include/arch/pico_msp430.h deleted file mode 100644 index 27e3e5a..0000000 --- a/ext/picotcp/include/arch/pico_msp430.h +++ /dev/null @@ -1,38 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef _INCLUDE_PICO_LPC -#define _INCLUDE_PICO_LPC - -#include -#include -#include -#include "pico_constants.h" - -extern pico_time msp430_time_s(void); -extern pico_time msp430_time_ms(void); -extern void *malloc(size_t); -extern void free(void *); - - -#define PICO_TIME() msp430_time_s() -#define PICO_TIME_MS() msp430_time_ms() -#define PICO_IDLE() do {} while(0) - -#define pico_free(x) free(x) - -static inline void *pico_zalloc(size_t size) -{ - void *ptr = malloc(size); - - if(ptr) - memset(ptr, 0u, size); - - return ptr; -} - -#define dbg(...) - -#endif diff --git a/ext/picotcp/include/arch/pico_none.h b/ext/picotcp/include/arch/pico_none.h deleted file mode 100644 index fee74f9..0000000 --- a/ext/picotcp/include/arch/pico_none.h +++ /dev/null @@ -1,22 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - *********************************************************************/ - -#ifndef PICO_SUPPORT_ARCHNONE -#define PICO_SUPPORT_ARCHNONE - -#include -#include -#include -#include - -#define dbg(...) do {} while(0) -#define pico_zalloc(x) NULL -#define pico_free(x) do {} while(0) -#define PICO_TIME() 666 -#define PICO_TIME_MS() 666000 -#define PICO_IDLE() do {} while(0) - -#endif /* PICO_SUPPORT_ARCHNONE */ - diff --git a/ext/picotcp/include/arch/pico_pic24.h b/ext/picotcp/include/arch/pico_pic24.h deleted file mode 100644 index 27ff39e..0000000 --- a/ext/picotcp/include/arch/pico_pic24.h +++ /dev/null @@ -1,100 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - *********************************************************************/ -#ifndef PICO_SUPPORT_PIC24 -#define PICO_SUPPORT_PIC24 -#define dbg printf -/* #define dbg(...) */ - -/*************************/ - -/*** MACHINE CONFIGURATION ***/ -#include -#include - -/* #include "phalox_development_board.h" */ - -#ifndef __PIC24F__ -#define __PIC24F__ -#endif - -/* - #ifndef __PIC24FJ256GA106__ - #define __PIC24FJ256GA106__ - #endif - */ - -#ifndef PICO_MAX_SOCKET_FRAMES -#define PICO_MAX_SOCKET_FRAMES 16 -#endif - -/* Device header file */ - -#if defined(__PIC24E__) -# include -#elif defined(__PIC24F__) -# include -#elif defined(__PIC24H__) -# include -#endif - - -#define TIMBASE_INT_E IEC0bits.T2IE - -#ifdef PICO_SUPPORT_DEBUG_MEMORY -static inline void *pico_zalloc(int len) -{ - /* dbg("%s: Alloc object of len %d, caller: %p\n", __FUNCTION__, len, __builtin_return_address(0)); */ - return calloc(len, 1); -} - -static inline void pico_free(void *tgt) -{ - /* dbg("%s: Discarded object @%p, caller: %p\n", __FUNCTION__, tgt, __builtin_return_address(0)); */ - free(tgt); -} -#else -# define pico_zalloc(x) calloc(x, 1) -# define pico_free(x) free(x) -#endif - -extern void *pvPortMalloc( size_t xWantedSize ); -extern volatile pico_time __pic24_tick; - -static inline unsigned long PICO_TIME(void) -{ - unsigned long tick; - /* Disable timer interrupts */ - TIMBASE_INT_E = 0; - tick = __pic24_tick; - /* Enable timer interrupts */ - TIMBASE_INT_E = 1; - return tick / 1000; -} - -static inline unsigned long PICO_TIME_MS(void) -{ - unsigned long tick; - /* Disable timer interrupts */ - TIMBASE_INT_E = 0; - tick = __pic24_tick; - /* Enable timer interrupts */ - TIMBASE_INT_E = 1; - return tick; -} - -static inline void PICO_IDLE(void) -{ - unsigned long tick_now; - /* Disable timer interrupts */ - TIMBASE_INT_E = 0; - tick_now = (unsigned long)pico_tick; - /* Enable timer interrupts */ - TIMBASE_INT_E = 1; - /* Doesn't matter that this call isn't interrupt safe, */ - /* we just check for the value to change */ - while(tick_now == __pic24_tick) ; -} - -#endif diff --git a/ext/picotcp/include/arch/pico_posix.h b/ext/picotcp/include/arch/pico_posix.h deleted file mode 100644 index 30ce884..0000000 --- a/ext/picotcp/include/arch/pico_posix.h +++ /dev/null @@ -1,130 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - *********************************************************************/ - -#ifndef PICO_SUPPORT_POSIX -#define PICO_SUPPORT_POSIX - -#include -#include -#include -#include - -/* - #define MEMORY_MEASURE - #define TIME_PRESCALE - #define PICO_SUPPORT_THREADING - */ -#define dbg printf - -#define stack_fill_pattern(...) do {} while(0) -#define stack_count_free_words(...) do {} while(0) -#define stack_get_free_words() (0) - -/* measure allocated memory */ -#ifdef MEMORY_MEASURE -extern uint32_t max_mem; -extern uint32_t cur_mem; - -static inline void *pico_zalloc(int x) -{ - uint32_t *ptr; - if ((cur_mem + x) > (10 * 1024)) - return NULL; - - ptr = (uint32_t *)calloc(x + 4, 1); - *ptr = (uint32_t)x; - cur_mem += x; - if (cur_mem > max_mem) { - max_mem = cur_mem; - } - - return (void*)(ptr + 1); -} - -static inline void pico_free(void *x) -{ - uint32_t *ptr = (uint32_t*)(((uint8_t *)x) - 4); - cur_mem -= *ptr; - free(ptr); -} -#else -#define pico_zalloc(x) calloc(x, 1) -#define pico_free(x) free(x) -#endif - -/* time prescaler */ -#ifdef TIME_PRESCALE -extern int32_t prescale_time; -#endif - -#if defined(PICO_SUPPORT_RTOS) || defined (PICO_SUPPORT_PTHREAD) -/* pico_ms_tick must be defined */ -extern volatile unsigned long int pico_ms_tick; - - -static inline uint32_t PICO_TIME(void) -{ - return pico_ms_tick / 1000; -} - -static inline uint32_t PICO_TIME_MS(void) -{ - return pico_ms_tick; -} - -#else - -static inline uint32_t PICO_TIME(void) -{ - struct timeval t; - gettimeofday(&t, NULL); - #ifdef TIME_PRESCALE - return (prescale_time < 0) ? (uint32_t)(t.tv_sec / 1000 << (-prescale_time)) : \ - (uint32_t)(t.tv_sec / 1000 >> prescale_time); - #else - return (uint32_t)t.tv_sec; - #endif -} - -static inline uint32_t PICO_TIME_MS(void) -{ - struct timeval t; - gettimeofday(&t, NULL); - #ifdef TIME_PRESCALER - uint32_t tmp = ((t.tv_sec * 1000) + (t.tv_usec / 1000)); - return (prescale_time < 0) ? (uint32_t)(tmp / 1000 << (-prescale_time)) : \ - (uint32_t)(tmp / 1000 >> prescale_time); - #else - return (uint32_t)((t.tv_sec * 1000) + (t.tv_usec / 1000)); - #endif -} -#endif - -#ifdef PICO_SUPPORT_THREADING -#define PICO_SUPPORT_MUTEX -/* mutex implementations */ -extern void *pico_mutex_init(void); -extern void pico_mutex_lock(void *mux); -extern void pico_mutex_unlock(void *mux); - -/* semaphore implementations (only used in wrapper code) */ -extern void *pico_sem_init(void); -extern void pico_sem_destroy(void *sem); -extern void pico_sem_post(void *sem); -/* returns -1 on timeout (in ms), else returns 0 */ -/* if timeout < 0, the semaphore waits forever */ -extern int pico_sem_wait(void *sem, int timeout); - -/* thread implementations */ -extern void *pico_thread_create(void *(*routine)(void *), void *arg); -#endif /* PICO_SUPPORT_THREADING */ - -static inline void PICO_IDLE(void) -{ - usleep(5000); -} - -#endif /* PICO_SUPPORT_POSIX */ - diff --git a/ext/picotcp/include/heap.h b/ext/picotcp/include/heap.h deleted file mode 100644 index 88f495d..0000000 --- a/ext/picotcp/include/heap.h +++ /dev/null @@ -1,83 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ - -#define DECLARE_HEAP(type, orderby) \ - struct heap_ ## type { \ - uint32_t size; \ - uint32_t n; \ - type *top; \ - }; \ - typedef struct heap_ ## type heap_ ## type; \ - static inline int heap_insert(struct heap_ ## type *heap, type * el) \ - { \ - uint32_t i; \ - type *newTop; \ - if (++heap->n >= heap->size) { \ - newTop = PICO_ZALLOC((heap->n + 1) * sizeof(type)); \ - if(!newTop) { \ - heap->n--; \ - return -1; \ - } \ - if (heap->top) { \ - memcpy(newTop, heap->top, heap->n * sizeof(type)); \ - PICO_FREE(heap->top); \ - } \ - heap->top = newTop; \ - heap->size++; \ - } \ - if (heap->n == 1) { \ - memcpy(&heap->top[1], el, sizeof(type)); \ - return 0; \ - } \ - for (i = heap->n; ((i > 1) && (heap->top[i / 2].orderby > el->orderby)); i /= 2) { \ - memcpy(&heap->top[i], &heap->top[i / 2], sizeof(type)); \ - } \ - memcpy(&heap->top[i], el, sizeof(type)); \ - return 0; \ - } \ - static inline int heap_peek(struct heap_ ## type *heap, type * first) \ - { \ - type *last; \ - uint32_t i, child; \ - if(heap->n == 0) { \ - return -1; \ - } \ - memcpy(first, &heap->top[1], sizeof(type)); \ - last = &heap->top[heap->n--]; \ - for(i = 1; (i * 2u) <= heap->n; i = child) { \ - child = 2u * i; \ - if ((child != heap->n) && \ - (heap->top[child + 1]).orderby \ - < (heap->top[child]).orderby) \ - child++; \ - if (last->orderby > \ - heap->top[child].orderby) \ - memcpy(&heap->top[i], &heap->top[child], \ - sizeof(type)); \ - else \ - break; \ - } \ - memcpy(&heap->top[i], last, sizeof(type)); \ - return 0; \ - } \ - static inline type *heap_first(heap_ ## type * heap) \ - { \ - if (heap->n == 0) \ - return NULL; \ - return &heap->top[1]; \ - } \ - static inline heap_ ## type *heap_init(void) \ - { \ - heap_ ## type * p = (heap_ ## type *)PICO_ZALLOC(sizeof(heap_ ## type)); \ - return p; \ - } \ - /*static inline void heap_destroy(heap_ ## type * h) \ - { \ - PICO_FREE(h->top); \ - PICO_FREE(h); \ - } \*/ - - diff --git a/ext/picotcp/include/pico_addressing.h b/ext/picotcp/include/pico_addressing.h deleted file mode 100644 index de62281..0000000 --- a/ext/picotcp/include/pico_addressing.h +++ /dev/null @@ -1,52 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_ADDRESSING -#define INCLUDE_PICO_ADDRESSING - -#include "pico_config.h" - -PACKED_STRUCT_DEF pico_ip4 -{ - uint32_t addr; -}; - -PACKED_STRUCT_DEF pico_ip6 -{ - uint8_t addr[16]; -}; - -union pico_address -{ - struct pico_ip4 ip4; - struct pico_ip6 ip6; -}; - -PACKED_STRUCT_DEF pico_eth -{ - uint8_t addr[6]; - uint8_t padding[2]; -}; - -extern const uint8_t PICO_ETHADDR_ALL[]; - - -PACKED_STRUCT_DEF pico_trans -{ - uint16_t sport; - uint16_t dport; - -}; - -/* Here are some protocols. */ -#define PICO_PROTO_IPV4 0 -#define PICO_PROTO_ICMP4 1 -#define PICO_PROTO_IGMP 2 -#define PICO_PROTO_TCP 6 -#define PICO_PROTO_UDP 17 -#define PICO_PROTO_IPV6 41 -#define PICO_PROTO_ICMP6 58 - -#endif diff --git a/ext/picotcp/include/pico_config.h b/ext/picotcp/include/pico_config.h deleted file mode 100644 index 3e5047f..0000000 --- a/ext/picotcp/include/pico_config.h +++ /dev/null @@ -1,234 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#include "pico_defines.h" -#ifndef INCLUDE_PICO_CONFIG -#define INCLUDE_PICO_CONFIG -#ifndef __KERNEL__ -#include -#include -#include -#else -#include -#endif - -#if defined __IAR_SYSTEMS_ICC__ || defined ATOP -# define PACKED_STRUCT_DEF __packed struct -# define PEDANTIC_STRUCT_DEF __packed struct -# define PACKED_UNION_DEF __packed union -# define WEAK -#elif defined __WATCOMC__ -# define PACKED_STRUCT_DEF _Packed struct -# define PEDANTIC_STRUCT_DEF struct -# define PACKED_UNION_DEF _Packed union -# define WEAK -#else -# define PACKED_STRUCT_DEF struct __attribute__((packed)) -# define PEDANTIC_STRUCT_DEF struct -# define PACKED_UNION_DEF union /* Sane compilers do not require packed unions */ -# define WEAK __attribute__((weak)) -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -# if ((GCC_VERSION >= 40800)) -# define BYTESWAP_GCC -# endif -# endif -#endif - -#ifdef PICO_BIGENDIAN - -# define PICO_IDETH_IPV4 0x0800 -# define PICO_IDETH_ARP 0x0806 -# define PICO_IDETH_IPV6 0x86DD - -# define PICO_ARP_REQUEST 0x0001 -# define PICO_ARP_REPLY 0x0002 -# define PICO_ARP_HTYPE_ETH 0x0001 - -#define short_be(x) (x) -#define long_be(x) (x) -#define long_long_be(x) (x) - -static inline uint16_t short_from(void *_p) -{ - unsigned char *p = (unsigned char *)_p; - uint16_t r, p0, p1; - p0 = p[0]; - p1 = p[1]; - r = (p0 << 8) + p1; - return r; -} - -static inline uint32_t long_from(void *_p) -{ - unsigned char *p = (unsigned char *)_p; - uint32_t r, p0, p1, p2, p3; - p0 = p[0]; - p1 = p[1]; - p2 = p[2]; - p3 = p[3]; - r = (p0 << 24) + (p1 << 16) + (p2 << 8) + p3; - return r; -} - -#else - -static inline uint16_t short_from(void *_p) -{ - unsigned char *p = (unsigned char *)_p; - uint16_t r, _p0, _p1; - _p0 = p[0]; - _p1 = p[1]; - r = (uint16_t)((_p1 << 8u) + _p0); - return r; -} - -static inline uint32_t long_from(void *_p) -{ - unsigned char *p = (unsigned char *)_p; - uint32_t r, _p0, _p1, _p2, _p3; - _p0 = p[0]; - _p1 = p[1]; - _p2 = p[2]; - _p3 = p[3]; - r = (_p3 << 24) + (_p2 << 16) + (_p1 << 8) + _p0; - return r; -} - - -# define PICO_IDETH_IPV4 0x0008 -# define PICO_IDETH_ARP 0x0608 -# define PICO_IDETH_IPV6 0xDD86 - -# define PICO_ARP_REQUEST 0x0100 -# define PICO_ARP_REPLY 0x0200 -# define PICO_ARP_HTYPE_ETH 0x0100 - -# ifndef BYTESWAP_GCC -static inline uint16_t short_be(uint16_t le) -{ - return (uint16_t)(((le & 0xFFu) << 8) | ((le >> 8u) & 0xFFu)); -} - -static inline uint32_t long_be(uint32_t le) -{ - uint8_t *b = (uint8_t *)≤ - uint32_t be = 0; - uint32_t b0, b1, b2; - b0 = b[0]; - b1 = b[1]; - b2 = b[2]; - be = b[3] + (b2 << 8) + (b1 << 16) + (b0 << 24); - return be; -} -static inline uint64_t long_long_be(uint64_t le) -{ - uint8_t *b = (uint8_t *)≤ - uint64_t be = 0; - uint64_t b0, b1, b2, b3, b4, b5, b6; - b0 = b[0]; - b1 = b[1]; - b2 = b[2]; - b3 = b[3]; - b4 = b[4]; - b5 = b[5]; - b6 = b[6]; - be = b[7] + (b6 << 8) + (b5 << 16) + (b4 << 24) + (b3 << 32) + (b2 << 40) + (b1 << 48) + (b0 << 56); - return be; -} -# else -/* - extern uint32_t __builtin_bswap32(uint32_t); - extern uint16_t __builtin_bswap16(uint16_t); - extern uint64_t __builtin_bswap64(uint64_t); - */ - -static inline uint32_t long_be(uint32_t le) -{ - return (uint32_t)__builtin_bswap32(le); -} - -static inline uint16_t short_be(uint16_t le) -{ - return (uint16_t)__builtin_bswap16(le); -} - -static inline uint64_t long_long_be(uint64_t le) -{ - return (uint64_t)__builtin_bswap64(le); -} - -# endif /* BYTESWAP_GCC */ -#endif - - -/* Mockables */ -#if defined UNIT_TEST -# define MOCKABLE __attribute__((weak)) -#else -# define MOCKABLE -#endif - -#include "pico_constants.h" -#include "pico_mm.h" - -#define IGNORE_PARAMETER(x) ((void)x) - -#define PICO_MEM_DEFAULT_SLAB_SIZE 1600 -#define PICO_MEM_PAGE_SIZE 4096 -#define PICO_MEM_PAGE_LIFETIME 100 -#define PICO_MIN_HEAP_SIZE 600 -#define PICO_MIN_SLAB_SIZE 1200 -#define PICO_MAX_SLAB_SIZE 1600 -#define PICO_MEM_MINIMUM_OBJECT_SIZE 4 - - -/*** *** *** *** *** *** *** - *** PLATFORM SPECIFIC *** - *** *** *** *** *** *** ***/ -#if defined PICO_PORT_CUSTOM -# include "pico_port.h" -#elif defined CORTEX_M4_HARDFLOAT -# include "arch/pico_cortex_m.h" -#elif defined CORTEX_M4_SOFTFLOAT -# include "arch/pico_cortex_m.h" -#elif defined CORTEX_M3 -# include "arch/pico_cortex_m.h" -#elif defined PIC24 -# include "arch/pico_pic24.h" -#elif defined MSP430 -# include "arch/pico_msp430.h" -#elif defined MBED_TEST -# include "arch/pico_mbed.h" -#elif defined AVR -# include "arch/pico_avr.h" -#elif defined ARM9 -# include "arch/pico_arm9.h" -#elif defined ESP8266 -# include "arch/pico_esp8266.h" -#elif defined MT7681 -# include "arch/pico_generic_gcc.h" -#elif defined FAULTY -# include "../test/pico_faulty.h" -#elif defined ARCHNONE -# include "arch/pico_none.h" -#elif defined GENERIC -# include "arch/pico_generic_gcc.h" -#elif defined __KERNEL__ -# include "arch/pico_linux.h" -/* #elif defined ... */ -#else -# include "arch/pico_posix.h" -#endif - -#ifdef PICO_SUPPORT_MM -#define PICO_ZALLOC(x) pico_mem_zalloc(x) -#define PICO_FREE(x) pico_mem_free(x) -#else -#define PICO_ZALLOC(x) pico_zalloc(x) -#define PICO_FREE(x) pico_free(x) -#endif /* PICO_SUPPORT_MM */ - -#endif diff --git a/ext/picotcp/include/pico_constants.h b/ext/picotcp/include/pico_constants.h deleted file mode 100644 index f043408..0000000 --- a/ext/picotcp/include/pico_constants.h +++ /dev/null @@ -1,54 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_CONST -#define INCLUDE_PICO_CONST -/* Included from pico_config.h */ - -/** Non-endian dependant constants */ -#define PICO_SIZE_IP4 4 -#define PICO_SIZE_IP6 16 -#define PICO_SIZE_ETH 6 -#define PICO_SIZE_TRANS 8 - -/** Endian-dependant constants **/ -typedef uint64_t pico_time; -extern volatile uint64_t pico_tick; - - -/*** *** *** *** *** *** *** - *** ARP CONFIG *** - *** *** *** *** *** *** ***/ - -#include "pico_addressing.h" - -/* Maximum amount of accepted ARP requests per burst interval */ -#define PICO_ARP_MAX_RATE 1 -/* Duration of the burst interval in milliseconds */ -#define PICO_ARP_INTERVAL 1000 - -/* Add well-known host numbers here. (bigendian constants only beyond this point) */ -#define PICO_IP4_ANY (0x00000000U) -#define PICO_IP4_BCAST (0xffffffffU) - -/* defined in modules/pico_ipv6.c */ -#ifdef PICO_SUPPORT_IPV6 -extern const uint8_t PICO_IPV6_ANY[PICO_SIZE_IP6]; -#endif - -static inline uint32_t pico_hash(const void *buf, uint32_t size) -{ - uint32_t hash = 5381; - uint32_t i; - const uint8_t *ptr = (const uint8_t *)buf; - for(i = 0; i < size; i++) - hash = ((hash << 5) + hash) + ptr[i]; /* hash * 33 + char */ - return hash; -} - -/* Debug */ -/* #define PICO_SUPPORT_DEBUG_MEMORY */ -/* #define PICO_SUPPORT_DEBUG_TOOLS */ -#endif diff --git a/ext/picotcp/include/pico_device.h b/ext/picotcp/include/pico_device.h deleted file mode 100644 index a2d03ec..0000000 --- a/ext/picotcp/include/pico_device.h +++ /dev/null @@ -1,54 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_DEVICE -#define INCLUDE_PICO_DEVICE -#include "pico_queue.h" -#include "pico_frame.h" -#include "pico_addressing.h" -#include "pico_tree.h" -extern struct pico_tree Device_tree; -#include "pico_ipv6_nd.h" -#define MAX_DEVICE_NAME 16 - - -struct pico_ethdev { - struct pico_eth mac; -}; - -struct pico_device { - char name[MAX_DEVICE_NAME]; - uint32_t hash; - uint32_t overhead; - uint32_t mtu; - struct pico_ethdev *eth; /* Null if non-ethernet */ - struct pico_queue *q_in; - struct pico_queue *q_out; - int (*link_state)(struct pico_device *self); - int (*send)(struct pico_device *self, void *buf, int len); /* Send function. Return 0 if busy */ - int (*poll)(struct pico_device *self, int loop_score); - void (*destroy)(struct pico_device *self); - int (*dsr)(struct pico_device *self, int loop_score); - int __serving_interrupt; - /* used to signal the upper layer the number of events arrived since the last processing */ - volatile int eventCnt; - #ifdef PICO_SUPPORT_IPV6 - struct pico_nd_hostvars hostvars; - #endif -}; - - -int pico_device_init(struct pico_device *dev, const char *name, uint8_t *mac); -void pico_device_destroy(struct pico_device *dev); -int pico_devices_loop(int loop_score, int direction); -struct pico_device*pico_get_device(const char*name); -int32_t pico_device_broadcast(struct pico_frame *f); -int pico_device_link_state(struct pico_device *dev); -int pico_device_ipv6_random_ll(struct pico_device *dev); -#ifdef PICO_SUPPORT_IPV6 -struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix); -#endif - -#endif diff --git a/ext/picotcp/include/pico_eth.h b/ext/picotcp/include/pico_eth.h deleted file mode 100644 index 89846c7..0000000 --- a/ext/picotcp/include/pico_eth.h +++ /dev/null @@ -1,21 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_ETH -#define INCLUDE_PICO_ETH -#include "pico_addressing.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" - - -PACKED_STRUCT_DEF pico_eth_hdr { - uint8_t daddr[6]; - uint8_t saddr[6]; - uint16_t proto; -}; - -#define PICO_SIZE_ETHHDR 14 - -#endif diff --git a/ext/picotcp/include/pico_frame.h b/ext/picotcp/include/pico_frame.h deleted file mode 100644 index 18b2d4d..0000000 --- a/ext/picotcp/include/pico_frame.h +++ /dev/null @@ -1,122 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_FRAME -#define INCLUDE_PICO_FRAME -#include "pico_config.h" - - -#define PICO_FRAME_FLAG_BCAST (0x01) -#define PICO_FRAME_FLAG_EXT_BUFFER (0x02) -#define PICO_FRAME_FLAG_EXT_USAGE_COUNTER (0x04) -#define PICO_FRAME_FLAG_SACKED (0x80) -#define IS_BCAST(f) ((f->flags & PICO_FRAME_FLAG_BCAST) == PICO_FRAME_FLAG_BCAST) - - -struct pico_socket; - - -struct pico_frame { - - /* Connector for queues */ - struct pico_frame *next; - - /* Start of the whole buffer, total frame length. */ - unsigned char *buffer; - uint32_t buffer_len; - - /* For outgoing packets: this is the meaningful buffer. */ - unsigned char *start; - uint32_t len; - - /* Pointer to usage counter */ - uint32_t *usage_count; - - /* Pointer to protocol headers */ - uint8_t *datalink_hdr; - - uint8_t *net_hdr; - uint16_t net_len; - uint8_t *transport_hdr; - uint16_t transport_len; - uint8_t *app_hdr; - uint16_t app_len; - - /* Pointer to the phisical device this packet belongs to. - * Should be valid in both routing directions - */ - struct pico_device *dev; - - pico_time timestamp; - - /* Failures due to bad datalink addressing. */ - uint16_t failure_count; - - /* Protocol over IP */ - uint8_t proto; - - /* PICO_FRAME_FLAG_* */ - uint8_t flags; - - /* Pointer to payload */ - unsigned char *payload; - uint16_t payload_len; - -#if defined(PICO_SUPPORT_IPV4FRAG) || defined(PICO_SUPPORT_IPV6FRAG) - /* Payload fragmentation info */ - uint16_t frag; -#endif - - /* Pointer to socket */ - struct pico_socket *sock; - - /* Pointer to transport info, used to store remote UDP endpoint (IP + port) */ - void *info; - - /*Priority. "best-effort" priority, the default value is 0. Priority can be in between -10 and +10*/ - int8_t priority; - uint8_t transport_flags_saved; - - /* Callback to notify listener when the buffer has been discarded */ - void (*notify_free)(uint8_t *); - - uint8_t send_ttl; /* Special TTL/HOPS value, 0 = auto assign */ - uint8_t send_tos; /* Type of service */ -}; - -/** frame alloc/dealloc/copy **/ -void pico_frame_discard(struct pico_frame *f); -struct pico_frame *pico_frame_copy(struct pico_frame *f); -struct pico_frame *pico_frame_deepcopy(struct pico_frame *f); -struct pico_frame *pico_frame_alloc(uint32_t size); -int pico_frame_grow(struct pico_frame *f, uint32_t size); -struct pico_frame *pico_frame_alloc_skeleton(uint32_t size, int ext_buffer); -int pico_frame_skeleton_set_buffer(struct pico_frame *f, void *buf); -uint16_t pico_checksum(void *inbuf, uint32_t len); -uint16_t pico_dualbuffer_checksum(void *b1, uint32_t len1, void *b2, uint32_t len2); - -static inline int pico_is_digit(char c) -{ - if (c < '0' || c > '9') - return 0; - - return 1; -} - -static inline int pico_is_hex(char c) -{ - if (c >= '0' && c <= '9') - return 1; - - if (c >= 'a' && c <= 'f') - return 1; - - if (c >= 'A' && c <= 'F') - return 1; - - return 0; -} - -#endif diff --git a/ext/picotcp/include/pico_md5.h b/ext/picotcp/include/pico_md5.h deleted file mode 100644 index 0ba89c4..0000000 --- a/ext/picotcp/include/pico_md5.h +++ /dev/null @@ -1,17 +0,0 @@ -/********************************************************************* - * PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved. - * See LICENSE and COPYING for usage. - * - * Authors: Daniele Lacamera - * *********************************************************************/ - -#ifndef PICO_MD5_INCLUDE -#define PICO_MD5_INCLUDE - -#include -#include - -void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len); -void pico_register_md5sum(void (*md5)(uint8_t *, const uint8_t *, size_t)); - -#endif /* PICO_MD5_INCLUDE */ diff --git a/ext/picotcp/include/pico_module_eth.h b/ext/picotcp/include/pico_module_eth.h deleted file mode 100644 index c86680d..0000000 --- a/ext/picotcp/include/pico_module_eth.h +++ /dev/null @@ -1,33 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef PICO_MODULE_IPV4_H -#define PICO_MODULE_IPV4_H - -struct pico_arp_entry { - struct eth dest; -#ifdef PICO_CONFIG_IPV4 - struct ipv4 addr_ipv4; -#endif - RB_ENTRY(pico_arp_entry) node; -}; - -/* Configured device */ -struct pico_eth_link { - struct pico_device *dev; - struct eth address; - struct eth netmask; - RB_ENTRY(pico_eth_link) node; -}; - -#ifndef IS_MODULE_ETH -# define _mod extern -#else -# define _mod -#endif -_mod struct pico_module pico_module_eth; -#undef _mod - -#endif diff --git a/ext/picotcp/include/pico_protocol.h b/ext/picotcp/include/pico_protocol.h deleted file mode 100644 index fd7c122..0000000 --- a/ext/picotcp/include/pico_protocol.h +++ /dev/null @@ -1,95 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_PROTOCOL -#define INCLUDE_PICO_PROTOCOL -#include "pico_config.h" -#include "pico_queue.h" - -#define PICO_LOOP_DIR_IN 1 -#define PICO_LOOP_DIR_OUT 2 - -enum pico_layer { - PICO_LAYER_DATALINK = 2, /* Ethernet only. */ - PICO_LAYER_NETWORK = 3, /* IPv4, IPv6, ARP. Arp is there because it communicates with L2 */ - PICO_LAYER_TRANSPORT = 4, /* UDP, TCP, ICMP */ - PICO_LAYER_SOCKET = 5 /* Socket management */ -}; - -enum pico_err_e { - PICO_ERR_NOERR = 0, - PICO_ERR_EPERM = 1, - PICO_ERR_ENOENT = 2, - /* ... */ - PICO_ERR_EINTR = 4, - PICO_ERR_EIO = 5, - PICO_ERR_ENXIO = 6, - /* ... */ - PICO_ERR_EAGAIN = 11, - PICO_ERR_ENOMEM = 12, - PICO_ERR_EACCESS = 13, - PICO_ERR_EFAULT = 14, - /* ... */ - PICO_ERR_EBUSY = 16, - PICO_ERR_EEXIST = 17, - /* ... */ - PICO_ERR_EINVAL = 22, - /* ... */ - PICO_ERR_ENONET = 64, - /* ... */ - PICO_ERR_EPROTO = 71, - /* ... */ - PICO_ERR_ENOPROTOOPT = 92, - PICO_ERR_EPROTONOSUPPORT = 93, - /* ... */ - PICO_ERR_EOPNOTSUPP = 95, - PICO_ERR_EADDRINUSE = 98, - PICO_ERR_EADDRNOTAVAIL = 99, - PICO_ERR_ENETDOWN = 100, - PICO_ERR_ENETUNREACH = 101, - /* ... */ - PICO_ERR_ECONNRESET = 104, - /* ... */ - PICO_ERR_EISCONN = 106, - PICO_ERR_ENOTCONN = 107, - PICO_ERR_ESHUTDOWN = 108, - /* ... */ - PICO_ERR_ETIMEDOUT = 110, - PICO_ERR_ECONNREFUSED = 111, - PICO_ERR_EHOSTDOWN = 112, - PICO_ERR_EHOSTUNREACH = 113, -}; - -typedef enum pico_err_e pico_err_t; -extern volatile pico_err_t pico_err; - -#define IS_IPV6(f) (f && f->net_hdr && ((((uint8_t *)(f->net_hdr))[0] & 0xf0) == 0x60)) -#define IS_IPV4(f) (f && f->net_hdr && ((((uint8_t *)(f->net_hdr))[0] & 0xf0) == 0x40)) - -#define MAX_PROTOCOL_NAME 16 - -struct pico_protocol { - char name[MAX_PROTOCOL_NAME]; - uint32_t hash; - enum pico_layer layer; - uint16_t proto_number; - struct pico_queue *q_in; - struct pico_queue *q_out; - struct pico_frame *(*alloc)(struct pico_protocol *self, uint16_t size); /* Frame allocation. */ - int (*push)(struct pico_protocol *self, struct pico_frame *p); /* Push function, for active outgoing pkts from above */ - int (*process_out)(struct pico_protocol *self, struct pico_frame *p); /* Send loop. */ - int (*process_in)(struct pico_protocol *self, struct pico_frame *p); /* Recv loop. */ - uint16_t (*get_mtu)(struct pico_protocol *self); -}; - -int pico_protocols_loop(int loop_score); -void pico_protocol_init(struct pico_protocol *p); - -int pico_protocol_datalink_loop(int loop_score, int direction); -int pico_protocol_network_loop(int loop_score, int direction); -int pico_protocol_transport_loop(int loop_score, int direction); -int pico_protocol_socket_loop(int loop_score, int direction); - -#endif diff --git a/ext/picotcp/include/pico_queue.h b/ext/picotcp/include/pico_queue.h deleted file mode 100644 index 6cbb979..0000000 --- a/ext/picotcp/include/pico_queue.h +++ /dev/null @@ -1,166 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_QUEUE -#define INCLUDE_PICO_QUEUE -#include "pico_config.h" -#include "pico_frame.h" - -#define Q_LIMIT 0 - -#ifndef NULL -#define NULL ((void *)0) -#endif - -void *pico_mutex_init(void); -void pico_mutex_deinit(void *mutex); -void pico_mutex_lock(void *mutex); -int pico_mutex_lock_timeout(void *mutex, int timeout); -void pico_mutex_unlock(void *mutex); -void pico_mutex_unlock_ISR(void *mutex); - -struct pico_queue { - uint32_t frames; - uint32_t size; - uint32_t max_frames; - uint32_t max_size; - struct pico_frame *head; - struct pico_frame *tail; -#ifdef PICO_SUPPORT_MUTEX - void *mutex; -#endif - uint8_t shared; - uint16_t overhead; -}; - -#ifdef PICO_SUPPORT_MUTEX -#define PICOTCP_MUTEX_LOCK(x) { \ - if (x == NULL) \ - x = pico_mutex_init(); \ - pico_mutex_lock(x); \ -} -#define PICOTCP_MUTEX_UNLOCK(x) pico_mutex_unlock(x) -#define PICOTCP_MUTEX_DEL(x) pico_mutex_deinit(x) - -#else -#define PICOTCP_MUTEX_LOCK(x) do {} while(0) -#define PICOTCP_MUTEX_UNLOCK(x) do {} while(0) -#define PICOTCP_MUTEX_DEL(x) do {} while(0) -#endif - -#ifdef PICO_SUPPORT_DEBUG_TOOLS -static void debug_q(struct pico_queue *q) -{ - struct pico_frame *p = q->head; - dbg("%d: ", q->frames); - while(p) { - dbg("(%p)-->", p); - p = p->next; - } - dbg("X\n"); -} - -#else - -#define debug_q(x) do {} while(0) -#endif - -static inline int32_t pico_enqueue(struct pico_queue *q, struct pico_frame *p) -{ - if ((q->max_frames) && (q->max_frames <= q->frames)) - return -1; - -#if (Q_LIMIT != 0) - if ((Q_LIMIT < p->buffer_len + q->size)) - return -1; - -#endif - - if ((q->max_size) && (q->max_size < (p->buffer_len + q->size))) - return -1; - - if (q->shared) - PICOTCP_MUTEX_LOCK(q->mutex); - - p->next = NULL; - if (!q->head) { - q->head = p; - q->tail = p; - q->size = 0; - q->frames = 0; - } else { - q->tail->next = p; - q->tail = p; - } - - q->size += p->buffer_len + q->overhead; - q->frames++; - debug_q(q); - - if (q->shared) - PICOTCP_MUTEX_UNLOCK(q->mutex); - - return (int32_t)q->size; -} - -static inline struct pico_frame *pico_dequeue(struct pico_queue *q) -{ - struct pico_frame *p = q->head; - if (!p) - return NULL; - - if (q->frames < 1) - return NULL; - - if (q->shared) - PICOTCP_MUTEX_LOCK(q->mutex); - - q->head = p->next; - q->frames--; - q->size -= p->buffer_len - q->overhead; - if (q->head == NULL) - q->tail = NULL; - - debug_q(q); - - p->next = NULL; - if (q->shared) - PICOTCP_MUTEX_UNLOCK(q->mutex); - - return p; -} - -static inline struct pico_frame *pico_queue_peek(struct pico_queue *q) -{ - struct pico_frame *p = q->head; - if (q->frames < 1) - return NULL; - - debug_q(q); - return p; -} - -static inline void pico_queue_deinit(struct pico_queue *q) -{ - if (q->shared) { - PICOTCP_MUTEX_DEL(q->mutex); - } -} - -static inline void pico_queue_empty(struct pico_queue *q) -{ - struct pico_frame *p = pico_dequeue(q); - while(p) { - pico_frame_discard(p); - p = pico_dequeue(q); - } -} - -static inline void pico_queue_protect(struct pico_queue *q) -{ - q->shared = 1; -} - -#endif diff --git a/ext/picotcp/include/pico_socket.h b/ext/picotcp/include/pico_socket.h deleted file mode 100644 index 784a722..0000000 --- a/ext/picotcp/include/pico_socket.h +++ /dev/null @@ -1,261 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_SOCKET -#define INCLUDE_PICO_SOCKET -#include "pico_queue.h" -#include "pico_addressing.h" -#include "pico_config.h" -#include "pico_protocol.h" -#include "pico_tree.h" - -#ifdef __linux__ - #define PICO_DEFAULT_SOCKETQ (16 * 1024) /* Linux host, so we want full throttle */ -#else - #define PICO_DEFAULT_SOCKETQ (6 * 1024) /* seems like an acceptable default for small embedded systems */ -#endif - -#define PICO_SHUT_RD 1 -#define PICO_SHUT_WR 2 -#define PICO_SHUT_RDWR 3 - -#ifdef PICO_SUPPORT_IPV4 -# define IS_SOCK_IPV4(s) ((s->net == &pico_proto_ipv4)) -#else -# define IS_SOCK_IPV4(s) (0) -#endif - -#ifdef PICO_SUPPORT_IPV6 -# define IS_SOCK_IPV6(s) ((s->net == &pico_proto_ipv6)) -#else -# define IS_SOCK_IPV6(s) (0) -#endif - - -struct pico_sockport -{ - struct pico_tree socks; /* how you make the connection ? */ - uint16_t number; - uint16_t proto; -}; - - -struct pico_socket { - struct pico_protocol *proto; - struct pico_protocol *net; - - union pico_address local_addr; - union pico_address remote_addr; - - uint16_t local_port; - uint16_t remote_port; - - struct pico_queue q_in; - struct pico_queue q_out; - - void (*wakeup)(uint16_t ev, struct pico_socket *s); - - -#ifdef PICO_SUPPORT_TCP - /* For the TCP backlog queue */ - struct pico_socket *backlog; - struct pico_socket *next; - struct pico_socket *parent; - uint16_t max_backlog; - uint16_t number_of_pending_conn; -#endif -#ifdef PICO_SUPPORT_MCAST - struct pico_tree *MCASTListen; -#ifdef PICO_SUPPORT_IPV6 - struct pico_tree *MCASTListen_ipv6; -#endif -#endif - uint16_t ev_pending; - - struct pico_device *dev; - - /* Private field. */ - int id; - uint16_t state; - uint16_t opt_flags; - pico_time timestamp; - void *priv; -}; - -struct pico_remote_endpoint { - union pico_address remote_addr; - uint16_t remote_port; -}; - - -struct pico_ip_mreq { - union pico_address mcast_group_addr; - union pico_address mcast_link_addr; -}; -struct pico_ip_mreq_source { - union pico_address mcast_group_addr; - union pico_address mcast_source_addr; - union pico_address mcast_link_addr; -}; - - -#define PICO_SOCKET_STATE_UNDEFINED 0x0000u -#define PICO_SOCKET_STATE_SHUT_LOCAL 0x0001u -#define PICO_SOCKET_STATE_SHUT_REMOTE 0x0002u -#define PICO_SOCKET_STATE_BOUND 0x0004u -#define PICO_SOCKET_STATE_CONNECTED 0x0008u -#define PICO_SOCKET_STATE_CLOSING 0x0010u -#define PICO_SOCKET_STATE_CLOSED 0x0020u - -# define PICO_SOCKET_STATE_TCP 0xFF00u -# define PICO_SOCKET_STATE_TCP_UNDEF 0x00FFu -# define PICO_SOCKET_STATE_TCP_CLOSED 0x0100u -# define PICO_SOCKET_STATE_TCP_LISTEN 0x0200u -# define PICO_SOCKET_STATE_TCP_SYN_SENT 0x0300u -# define PICO_SOCKET_STATE_TCP_SYN_RECV 0x0400u -# define PICO_SOCKET_STATE_TCP_ESTABLISHED 0x0500u -# define PICO_SOCKET_STATE_TCP_CLOSE_WAIT 0x0600u -# define PICO_SOCKET_STATE_TCP_LAST_ACK 0x0700u -# define PICO_SOCKET_STATE_TCP_FIN_WAIT1 0x0800u -# define PICO_SOCKET_STATE_TCP_FIN_WAIT2 0x0900u -# define PICO_SOCKET_STATE_TCP_CLOSING 0x0a00u -# define PICO_SOCKET_STATE_TCP_TIME_WAIT 0x0b00u -# define PICO_SOCKET_STATE_TCP_ARRAYSIZ 0x0cu - - -/* Socket options */ -# define PICO_TCP_NODELAY 1 -# define PICO_SOCKET_OPT_TCPNODELAY 0x0000u - -# define PICO_IP_MULTICAST_EXCLUDE 0 -# define PICO_IP_MULTICAST_INCLUDE 1 -# define PICO_IP_MULTICAST_IF 32 -# define PICO_IP_MULTICAST_TTL 33 -# define PICO_IP_MULTICAST_LOOP 34 -# define PICO_IP_ADD_MEMBERSHIP 35 -# define PICO_IP_DROP_MEMBERSHIP 36 -# define PICO_IP_UNBLOCK_SOURCE 37 -# define PICO_IP_BLOCK_SOURCE 38 -# define PICO_IP_ADD_SOURCE_MEMBERSHIP 39 -# define PICO_IP_DROP_SOURCE_MEMBERSHIP 40 - -# define PICO_SOCKET_OPT_MULTICAST_LOOP 1 -# define PICO_SOCKET_OPT_KEEPIDLE 4 -# define PICO_SOCKET_OPT_KEEPINTVL 5 -# define PICO_SOCKET_OPT_KEEPCNT 6 - -#define PICO_SOCKET_OPT_LINGER 13 - -# define PICO_SOCKET_OPT_RCVBUF 52 -# define PICO_SOCKET_OPT_SNDBUF 53 - - -/* Constants */ -# define PICO_IP_DEFAULT_MULTICAST_TTL 1 -# define PICO_IP_DEFAULT_MULTICAST_LOOP 1 - -#define PICO_SOCKET_TIMEOUT 5000u /* 5 seconds */ -#define PICO_SOCKET_LINGER_TIMEOUT 3000u /* 3 seconds */ -#define PICO_SOCKET_BOUND_TIMEOUT 30000u /* 30 seconds */ - -#define PICO_SOCKET_SHUTDOWN_WRITE 0x01u -#define PICO_SOCKET_SHUTDOWN_READ 0x02u -#define TCPSTATE(s) ((s)->state & PICO_SOCKET_STATE_TCP) - -#define PICO_SOCK_EV_RD 1u -#define PICO_SOCK_EV_WR 2u -#define PICO_SOCK_EV_CONN 4u -#define PICO_SOCK_EV_CLOSE 8u -#define PICO_SOCK_EV_FIN 0x10u -#define PICO_SOCK_EV_ERR 0x80u - -struct pico_msginfo { - struct pico_device *dev; - uint8_t ttl; - uint8_t tos; -}; - -struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s)); - -int pico_socket_read(struct pico_socket *s, void *buf, int len); -int pico_socket_write(struct pico_socket *s, const void *buf, int len); - -int pico_socket_sendto(struct pico_socket *s, const void *buf, int len, void *dst, uint16_t remote_port); -int pico_socket_sendto_extended(struct pico_socket *s, const void *buf, const int len, - void *dst, uint16_t remote_port, struct pico_msginfo *msginfo); - -int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *local_port); -int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, void *orig, - uint16_t *remote_port, struct pico_msginfo *msginfo); - -int pico_socket_send(struct pico_socket *s, const void *buf, int len); -int pico_socket_recv(struct pico_socket *s, void *buf, int len); - -int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port); -int pico_socket_getname(struct pico_socket *s, void *local_addr, uint16_t *port, uint16_t *proto); -int pico_socket_getpeername(struct pico_socket *s, void *remote_addr, uint16_t *port, uint16_t *proto); - -int pico_socket_connect(struct pico_socket *s, const void *srv_addr, uint16_t remote_port); -int pico_socket_listen(struct pico_socket *s, const int backlog); -struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port); -int8_t pico_socket_del(struct pico_socket *s); - -int pico_socket_setoption(struct pico_socket *s, int option, void *value); -int pico_socket_getoption(struct pico_socket *s, int option, void *value); - -int pico_socket_shutdown(struct pico_socket *s, int mode); -int pico_socket_close(struct pico_socket *s); - -struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, uint16_t len); - -#ifdef PICO_SUPPORT_IPV4 -# define is_sock_ipv4(x) (x->net == &pico_proto_ipv4) -#else -# define is_sock_ipv4(x) (0) -#endif - -#ifdef PICO_SUPPORT_IPV6 -# define is_sock_ipv6(x) (x->net == &pico_proto_ipv6) -#else -# define is_sock_ipv6(x) (0) -#endif - -#ifdef PICO_SUPPORT_UDP -# define is_sock_udp(x) (x->proto == &pico_proto_udp) -#else -# define is_sock_udp(x) (0) -#endif - -#ifdef PICO_SUPPORT_TCP -# define is_sock_tcp(x) (x->proto == &pico_proto_tcp) -#else -# define is_sock_tcp(x) (0) -#endif - -/* Interface towards transport protocol */ -int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f); -struct pico_socket *pico_socket_clone(struct pico_socket *facsimile); -int8_t pico_socket_add(struct pico_socket *s); -int pico_transport_error(struct pico_frame *f, uint8_t proto, int code); - -/* Socket loop */ -int pico_sockets_loop(int loop_score); -struct pico_socket*pico_sockets_find(uint16_t local, uint16_t remote); -/* Port check */ -int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net); - -struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port); - -uint32_t pico_socket_get_mss(struct pico_socket *s); -int pico_socket_set_family(struct pico_socket *s, uint16_t family); - -int pico_count_sockets(uint8_t proto); - -#define PICO_SOCKET_SETOPT_EN(socket, index) (socket->opt_flags |= (1 << index)) -#define PICO_SOCKET_SETOPT_DIS(socket, index) (socket->opt_flags &= (uint16_t) ~(1 << index)) -#define PICO_SOCKET_GETOPT(socket, index) ((socket->opt_flags & (1u << index)) != 0) - - -#endif diff --git a/ext/picotcp/include/pico_socket_multicast.h b/ext/picotcp/include/pico_socket_multicast.h deleted file mode 100644 index 44c30c5..0000000 --- a/ext/picotcp/include/pico_socket_multicast.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef PICO_SOCKET_MULTICAST_H -#define PICO_SOCKET_MULTICAST_H -int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src); -void pico_multicast_delete(struct pico_socket *s); -int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value); -int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value); -int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl); -int pico_udp_set_mc_ttl(struct pico_socket *s, void *_ttl); - -#endif diff --git a/ext/picotcp/include/pico_stack.h b/ext/picotcp/include/pico_stack.h deleted file mode 100644 index ab34df6..0000000 --- a/ext/picotcp/include/pico_stack.h +++ /dev/null @@ -1,85 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_STACK -#define INCLUDE_PICO_STACK -#include "pico_config.h" -#include "pico_frame.h" - -#define PICO_MAX_TIMERS 20 - -#define PICO_ETH_MRU (1514u) -#define PICO_IP_MRU (1500u) - -/* ===== RECEIVING FUNCTIONS (from dev up to socket) ===== */ - -/* TRANSPORT LEVEL */ -/* interface towards network */ -int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto); - -/* NETWORK LEVEL */ -/* interface towards ethernet */ -int32_t pico_network_receive(struct pico_frame *f); - - -/* LOWEST LEVEL: interface towards devices. */ -/* Device driver will call this function which returns immediately. - * Incoming packet will be processed later on in the dev loop. - * The zerocopy version will associate the current buffer to the newly created frame. - * Warning: the buffer used in the zerocopy version MUST have been allocated using PICO_ZALLOC() - */ -int32_t pico_stack_recv(struct pico_device *dev, uint8_t *buffer, uint32_t len); -int32_t pico_stack_recv_zerocopy(struct pico_device *dev, uint8_t *buffer, uint32_t len); -int32_t pico_stack_recv_zerocopy_ext_buffer(struct pico_device *dev, uint8_t *buffer, uint32_t len); -int32_t pico_stack_recv_zerocopy_ext_buffer_notify(struct pico_device *dev, uint8_t *buffer, uint32_t len, void (*notify_free)(uint8_t *buffer)); - -/* ===== SENDING FUNCTIONS (from socket down to dev) ===== */ - -int32_t pico_network_send(struct pico_frame *f); -int32_t pico_sendto_dev(struct pico_frame *f); - -#ifdef PICO_SUPPORT_ETH -int32_t pico_ethernet_send(struct pico_frame *f); - -/* The pico_ethernet_receive() function is used by - * those devices supporting ETH in order to push packets up - * into the stack. - */ -/* DATALINK LEVEL */ -int32_t pico_ethernet_receive(struct pico_frame *f); -#else -/* When ETH is not supported by the stack... */ -# define pico_ethernet_send(f) (-1) -# define pico_ethernet_receive(f) (-1) -#endif - -/* ----- Initialization ----- */ -int pico_stack_init(void); - -/* ----- Loop Function. ----- */ -void pico_stack_tick(void); -void pico_stack_loop(void); - -/* ---- Notifications for stack errors */ -int pico_notify_socket_unreachable(struct pico_frame *f); -int pico_notify_proto_unreachable(struct pico_frame *f); -int pico_notify_dest_unreachable(struct pico_frame *f); -int pico_notify_ttl_expired(struct pico_frame *f); -int pico_notify_frag_expired(struct pico_frame *f); -int pico_notify_pkt_too_big(struct pico_frame *f); - -/* Various. */ -int pico_source_is_local(struct pico_frame *f); -int pico_frame_dst_is_unicast(struct pico_frame *f); -void pico_store_network_origin(void *src, struct pico_frame *f); -uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg); -void pico_timer_cancel(uint32_t id); -uint32_t pico_rand(void); -void pico_rand_feed(uint32_t feed); -void pico_to_lowercase(char *str); -int pico_address_compare(union pico_address *a, union pico_address *b, uint16_t proto); -int32_t pico_seq_compare(uint32_t a, uint32_t b); - -#endif diff --git a/ext/picotcp/include/pico_tree.h b/ext/picotcp/include/pico_tree.h deleted file mode 100644 index 8667a1f..0000000 --- a/ext/picotcp/include/pico_tree.h +++ /dev/null @@ -1,93 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Author: Andrei Carp - *********************************************************************/ - -#ifndef PICO_RBTREE_H -#define PICO_RBTREE_H - -#include "pico_config.h" - -/* This is used to declare a new tree, leaf root by default */ -#define PICO_TREE_DECLARE(name, compareFunction) \ - struct pico_tree name = \ - { \ - &LEAF, \ - compareFunction \ - } - -#define USE_PICO_PAGE0_ZALLOC (1) -#define USE_PICO_ZALLOC (2) - -struct pico_tree_node -{ - void*keyValue; /* generic key */ - struct pico_tree_node*parent; - struct pico_tree_node*leftChild; - struct pico_tree_node*rightChild; - uint8_t color; -}; - -struct pico_tree -{ - struct pico_tree_node *root; /* root of the tree */ - - /* this function directly provides the keys as parameters not the nodes. */ - int (*compare)(void*keyA, void*keyB); -}; - -extern struct pico_tree_node LEAF; /* generic leaf node */ - -#ifdef PICO_SUPPORT_MM -void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator); -void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator); -#endif - - -/* - * Manipulation functions - */ -void *pico_tree_insert(struct pico_tree *tree, void *key); -void *pico_tree_delete(struct pico_tree *tree, void *key); -void *pico_tree_findKey(struct pico_tree *tree, void *key); -void pico_tree_drop(struct pico_tree *tree); -int pico_tree_empty(struct pico_tree *tree); -struct pico_tree_node *pico_tree_findNode(struct pico_tree *tree, void *key); - -void *pico_tree_first(struct pico_tree *tree); -void *pico_tree_last(struct pico_tree *tree); -/* - * Traverse functions - */ -struct pico_tree_node *pico_tree_lastNode(struct pico_tree_node *node); -struct pico_tree_node *pico_tree_firstNode(struct pico_tree_node *node); -struct pico_tree_node *pico_tree_next(struct pico_tree_node *node); -struct pico_tree_node *pico_tree_prev(struct pico_tree_node *node); - -/* - * For each macros - */ - -#define pico_tree_foreach(idx, tree) \ - for ((idx) = pico_tree_firstNode((tree)->root); \ - (idx) != &LEAF; \ - (idx) = pico_tree_next(idx)) - -#define pico_tree_foreach_reverse(idx, tree) \ - for ((idx) = pico_tree_lastNode((tree)->root); \ - (idx) != &LEAF; \ - (idx) = pico_tree_prev(idx)) - -#define pico_tree_foreach_safe(idx, tree, idx2) \ - for ((idx) = pico_tree_firstNode((tree)->root); \ - ((idx) != &LEAF) && ((idx2) = pico_tree_next(idx), 1); \ - (idx) = (idx2)) - -#define pico_tree_foreach_reverse_safe(idx, tree, idx2) \ - for ((idx) = pico_tree_lastNode((tree)->root); \ - ((idx) != &LEAF) && ((idx2) = pico_tree_prev(idx), 1); \ - (idx) = (idx2)) - -#endif diff --git a/ext/picotcp/mkdeps.sh b/ext/picotcp/mkdeps.sh deleted file mode 100755 index e313ef2..0000000 --- a/ext/picotcp/mkdeps.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -PREFIX=$1 -shift -echo "/* PicoTCP - Definition file - DO NOT EDIT */" >$PREFIX/include/pico_defines.h -echo "/* This file is automatically generated at compile time */" >>$PREFIX/include/pico_defines.h -echo "#ifndef PICO_DEFINES_H" >>$PREFIX/include/pico_defines.h -echo "#define PICO_DEFINES_H" >>$PREFIX/include/pico_defines.h -echo >>$PREFIX/include/pico_defines.h - -for i in $@; do - if (echo $i | grep "^-D" |grep PICO_SUPPORT >/dev/null); then - my_def=`echo $i |sed -e "s/-D//g"` - echo "#define $my_def" >> $PREFIX/include/pico_defines.h - fi -done -echo "#endif" >>$PREFIX/include/pico_defines.h diff --git a/ext/picotcp/modcheck.py b/ext/picotcp/modcheck.py deleted file mode 100755 index 05d2075..0000000 --- a/ext/picotcp/modcheck.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/python -import os,sys -import subprocess - -f = open('MODTREE') -mods = {} -commands = [] - -def get_deps(mod): - if not mod in mods.keys(): - return [] - deps = mods[mod] - retlist = [mod] - for i in deps.split(' '): - retlist.append(i) - for j in get_deps(i): - retlist.append(j) - return retlist - - -while(True): - r = f.readline() - if r == '': - break - if r != '\n': - strings = r.split(':') - mod = strings[0] - deps = strings[1].rstrip('\n') - mods[mod] = deps.strip(' ') - -for k,v in mods.iteritems(): - command = 'make dummy ' - deps = get_deps(k) - for i in mods.keys(): - if i in deps: - command += i + "=1 " - else: - command += i + "=0 " - commands.append(command) - -nul = open('/dev/null', 'w') -for i in commands: - print 'Checking config:\n\t%s' % i - os.system('make clean >/dev/null') - args = i.split(' ') - subprocess.call(['make','clean'], shell=True, stdout=nul, stderr=nul) - subprocess.call(args[-1], shell=True,stdout=nul, stderr=nul)==0 or sys.exit(1) - print "CONFIG OK!" - print -sys.exit(0) diff --git a/ext/picotcp/modules/pico_aodv.c b/ext/picotcp/modules/pico_aodv.c deleted file mode 100644 index b0751da..0000000 --- a/ext/picotcp/modules/pico_aodv.c +++ /dev/null @@ -1,674 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Author: Daniele Lacamera - *********************************************************************/ -#include -#include -#include -#include -#include - -#include -#ifdef PICO_SUPPORT_IPV4 - -#define pico_aodv_dbg(...) do {} while(0) -/* #define pico_aodv_dbg dbg */ - -#define AODV_MAX_PKT (64) -static const struct pico_ip4 HOST_NETMASK = { - 0xffffffff -}; -static struct pico_ip4 all_bcast = { - .addr = 0xFFFFFFFFu -}; - -static const struct pico_ip4 ANY_HOST = { - 0x0 -}; - -static uint32_t pico_aodv_local_id = 0; -static int aodv_node_compare(void *ka, void *kb) -{ - struct pico_aodv_node *a = ka, *b = kb; - if (a->dest.ip4.addr < b->dest.ip4.addr) - return -1; - - if (b->dest.ip4.addr < a->dest.ip4.addr) - return 1; - - return 0; -} - -static int aodv_dev_cmp(void *ka, void *kb) -{ - struct pico_device *a = ka, *b = kb; - if (a->hash < b->hash) - return -1; - - if (a->hash > b->hash) - return 1; - - return 0; -} - -PICO_TREE_DECLARE(aodv_nodes, aodv_node_compare); -PICO_TREE_DECLARE(aodv_devices, aodv_dev_cmp); - -static struct pico_socket *aodv_socket = NULL; - -static struct pico_aodv_node *get_node_by_addr(const union pico_address *addr) -{ - struct pico_aodv_node search; - memcpy(&search.dest, addr, sizeof(union pico_address)); - return pico_tree_findKey(&aodv_nodes, &search); - -} - -static void pico_aodv_set_dev(struct pico_device *dev) -{ - pico_ipv4_route_set_bcast_link(pico_ipv4_link_by_dev(dev)); -} - - -static int aodv_peer_refresh(struct pico_aodv_node *node, uint32_t seq) -{ - if ((0 == (node->flags & PICO_AODV_NODE_SYNC)) || (pico_seq_compare(seq, node->dseq) > 0)) { - node->dseq = seq; - node->flags |= PICO_AODV_NODE_SYNC; - node->last_seen = PICO_TIME_MS(); - return 0; - } - - return -1; -} - -static void aodv_elect_route(struct pico_aodv_node *node, union pico_address *gw, uint8_t metric, struct pico_device *dev) -{ - metric++; - if (!(PICO_AODV_ACTIVE(node)) || metric < node->metric) { - pico_ipv4_route_del(node->dest.ip4, HOST_NETMASK, node->metric); - if (!gw) { - pico_ipv4_route_add(node->dest.ip4, HOST_NETMASK, ANY_HOST, 1, pico_ipv4_link_by_dev(dev)); - node->metric = 1; - } else { - node->metric = metric; - pico_ipv4_route_add(node->dest.ip4, HOST_NETMASK, gw->ip4, metric, NULL); - } - } -} - -static struct pico_aodv_node *aodv_peer_new(const union pico_address *addr) -{ - struct pico_aodv_node *node = PICO_ZALLOC(sizeof(struct pico_aodv_node)); - if (!node) - return NULL; - - memcpy(&node->dest, addr, sizeof(union pico_address)); - pico_tree_insert(&aodv_nodes, node); - return node; -} - - -static struct pico_aodv_node *aodv_peer_eval(union pico_address *addr, uint32_t seq, int valid_seq) -{ - struct pico_aodv_node *node = NULL; - node = get_node_by_addr(addr); - if (!node) { - node = aodv_peer_new(addr); - } - - if (!valid_seq) - return node; - - if (node && (aodv_peer_refresh(node, long_be(seq)) == 0)) - return node; - - return NULL; -} - -static void aodv_forward(void *pkt, struct pico_msginfo *info, int reply) -{ - struct pico_aodv_node *orig; - union pico_address orig_addr; - struct pico_tree_node *index; - struct pico_device *dev; - pico_time now; - int size; - - pico_aodv_dbg("Forwarding %s packet\n", reply ? "REPLY" : "REQUEST"); - - if (reply) { - struct pico_aodv_rrep *rep = (struct pico_aodv_rrep *)pkt; - orig_addr.ip4.addr = rep->dest; - rep->hop_count++; - pico_aodv_dbg("RREP hop count: %d\n", rep->hop_count); - size = sizeof(struct pico_aodv_rrep); - } else { - struct pico_aodv_rreq *req = (struct pico_aodv_rreq *)pkt; - orig_addr.ip4.addr = req->orig; - req->hop_count++; - size = sizeof(struct pico_aodv_rreq); - } - - orig = get_node_by_addr(&orig_addr); - if (!orig) - orig = aodv_peer_new(&orig_addr); - - if (!orig) - return; - - now = PICO_TIME_MS(); - - pico_aodv_dbg("Forwarding %s: last fwd_time: %llu now: %llu ttl: %d ==== \n", reply ? "REPLY" : "REQUEST", - orig->fwd_time, now, info->ttl); - if (((orig->fwd_time == 0) || ((now - orig->fwd_time) > AODV_NODE_TRAVERSAL_TIME)) && (--info->ttl > 0)) { - orig->fwd_time = now; - info->dev = NULL; - pico_tree_foreach(index, &aodv_devices){ - dev = index->keyValue; - pico_aodv_set_dev(dev); - pico_socket_sendto_extended(aodv_socket, pkt, size, &all_bcast, short_be(PICO_AODV_PORT), info); - pico_aodv_dbg("Forwarding %s: complete! ==== \n", reply ? "REPLY" : "REQUEST"); - } - } -} - -static uint32_t aodv_lifetime(struct pico_aodv_node *node) -{ - uint32_t lifetime; - pico_time now = PICO_TIME_MS(); - if (!node->last_seen) - node->last_seen = now; - - if ((now - node->last_seen) > AODV_ACTIVE_ROUTE_TIMEOUT) - return 0; - - lifetime = AODV_ACTIVE_ROUTE_TIMEOUT - (uint32_t)(now - node->last_seen); - return lifetime; -} - -static void aodv_send_reply(struct pico_aodv_node *node, struct pico_aodv_rreq *req, int node_is_local, struct pico_msginfo *info) -{ - struct pico_aodv_rrep reply; - union pico_address dest; - union pico_address oaddr; - struct pico_aodv_node *orig; - oaddr.ip4.addr = req->orig; - orig = get_node_by_addr(&oaddr); - reply.type = AODV_TYPE_RREP; - reply.dest = req->dest; - reply.dseq = req->dseq; - reply.orig = req->orig; - if (!orig) - return; - - reply.hop_count = (uint8_t)(orig->metric - 1u); - - - dest.ip4.addr = 0xFFFFFFFF; /* wide broadcast */ - - if (short_be(req->req_flags) & AODV_RREQ_FLAG_G) { - dest.ip4.addr = req->orig; - } else { - pico_aodv_set_dev(info->dev); - } - - if (node_is_local) { - reply.lifetime = long_be(AODV_MY_ROUTE_TIMEOUT); - reply.dseq = long_be(++pico_aodv_local_id); - pico_socket_sendto(aodv_socket, &reply, sizeof(reply), &dest, short_be(PICO_AODV_PORT)); - } else if (((short_be(req->req_flags) & AODV_RREQ_FLAG_D) == 0) && (node->flags & PICO_AODV_NODE_SYNC)) { - reply.lifetime = long_be(aodv_lifetime(node)); - reply.dseq = long_be(node->dseq); - pico_aodv_dbg("Generating RREP for node %x, id=%x\n", reply.dest, reply.dseq); - pico_socket_sendto(aodv_socket, &reply, sizeof(reply), &dest, short_be(PICO_AODV_PORT)); - } - - pico_aodv_dbg("no rrep generated.\n"); -} - -/* Parser functions */ - -static int aodv_send_req(struct pico_aodv_node *node); - -static void aodv_reverse_path_discover(pico_time now, void *arg) -{ - struct pico_aodv_node *origin = (struct pico_aodv_node *)arg; - (void)now; - pico_aodv_dbg("Sending G RREQ to ORIGIN (metric = %d).\n", origin->metric); - origin->ring_ttl = origin->metric; - aodv_send_req(origin); -} - -static void aodv_recv_valid_rreq(struct pico_aodv_node *node, struct pico_aodv_rreq *req, struct pico_msginfo *info) -{ - struct pico_device *dev; - dev = pico_ipv4_link_find(&node->dest.ip4); - pico_aodv_dbg("Valid req.\n"); - if (dev || PICO_AODV_ACTIVE(node)) { - /* if destination is ourselves, or we have a possible route: Send reply. */ - aodv_send_reply(node, req, dev != NULL, info); - if (dev) { - /* if really for us, we need to build the return route. Initiate a gratuitous request. */ - union pico_address origin_addr; - struct pico_aodv_node *origin; - origin_addr.ip4.addr = req->orig; - origin = get_node_by_addr(&origin_addr); - if (origin) { - origin->flags |= PICO_AODV_NODE_ROUTE_DOWN; - pico_timer_add(AODV_PATH_DISCOVERY_TIME, aodv_reverse_path_discover, origin); - } - } - - pico_aodv_dbg("Replied.\n"); - } else { - /* destination unknown. Evaluate forwarding. */ - pico_aodv_dbg(" == Forwarding == .\n"); - aodv_forward(req, info, 0); - } -} - - -static void aodv_parse_rreq(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) -{ - struct pico_aodv_rreq *req = (struct pico_aodv_rreq *) buf; - struct pico_aodv_node *node = NULL; - struct pico_device *dev; - union pico_address orig, dest; - (void)from; - if (len != (int)sizeof(struct pico_aodv_rreq)) - return; - - orig.ip4.addr = req->orig; - dev = pico_ipv4_link_find(&orig.ip4); - if (dev) { - pico_aodv_dbg("RREQ <-- myself\n"); - return; - } - - node = aodv_peer_eval(&orig, req->oseq, 1); - if (!node) { - pico_aodv_dbg("RREQ: Neighbor is not valid. oseq=%d\n", long_be(req->oseq)); - return; - } - - if (req->hop_count > 0) - aodv_elect_route(node, from, req->hop_count, msginfo->dev); - else - aodv_elect_route(node, NULL, 0, msginfo->dev); - - dest.ip4.addr = req->dest; - node = aodv_peer_eval(&dest, req->dseq, !(req->req_flags & short_be(AODV_RREQ_FLAG_U))); - if (!node) { - node = aodv_peer_new(&dest); - pico_aodv_dbg("RREQ: New peer! %08x\n", dest.ip4.addr); - } - - if (!node) - return; - - aodv_recv_valid_rreq(node, req, msginfo); -} - -static void aodv_parse_rrep(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) -{ - struct pico_aodv_rrep *rep = (struct pico_aodv_rrep *) buf; - struct pico_aodv_node *node = NULL; - union pico_address dest; - union pico_address orig; - struct pico_device *dev = NULL; - if (len != (int)sizeof(struct pico_aodv_rrep)) - return; - - dest.ip4.addr = rep->dest; - orig.ip4.addr = rep->orig; - dev = pico_ipv4_link_find(&dest.ip4); - - if (dev) /* Our reply packet got rebounced, no useful information here, no need to fwd. */ - return; - - pico_aodv_dbg("::::::::::::: Parsing RREP for node %08x\n", rep->dest); - node = aodv_peer_eval(&dest, rep->dseq, 1); - if (node) { - pico_aodv_dbg("::::::::::::: Node found. Electing route and forwarding.\n"); - dest.ip4.addr = node->dest.ip4.addr; - if (rep->hop_count > 0) - aodv_elect_route(node, from, rep->hop_count, msginfo->dev); - else - aodv_elect_route(node, NULL, 0, msginfo->dev); - - /* If we are the final destination for the reply (orig), no need to forward. */ - if (pico_ipv4_link_find(&orig.ip4)) { - node->flags |= PICO_AODV_NODE_ROUTE_UP; - } else { - aodv_forward(rep, msginfo, 1); - } - } -} - -static void aodv_parse_rerr(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) -{ - if ((uint32_t)len < sizeof(struct pico_aodv_rerr) || - (((uint32_t)len - sizeof(struct pico_aodv_rerr)) % sizeof(struct pico_aodv_unreachable)) > 0) - return; - - (void)from; - (void)buf; - (void)len; - (void)msginfo; - /* TODO: invalidate routes. This only makes sense if we are using HELLO messages. */ -} - -static void aodv_parse_rack(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) -{ - if (len != (int)sizeof(struct pico_aodv_rack)) - return; - - (void)from; - (void)buf; - (void)len; - (void)msginfo; -} - -struct aodv_parser_s { - void (*call)(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo); -}; - -struct aodv_parser_s aodv_parser[5] = { - {.call = NULL}, - {.call = aodv_parse_rreq }, - {.call = aodv_parse_rrep }, - {.call = aodv_parse_rerr }, - {.call = aodv_parse_rack } -}; - - -static void pico_aodv_parse(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) -{ - struct pico_aodv_node *node; - uint8_t hopcount = 0; - if ((buf[0] < 1) || (buf[0] > 4)) { - /* Type is invalid. Discard silently. */ - return; - } - - if (buf[0] == AODV_TYPE_RREQ) { - hopcount = ((struct pico_aodv_rreq *)buf)->hop_count; - } - - if (buf[0] == AODV_TYPE_RREP) { - hopcount = ((struct pico_aodv_rrep *)buf)->hop_count; - } - - node = aodv_peer_eval(from, 0, 0); - if (!node) - node = aodv_peer_new(from); - - if (node && (hopcount == 0)) { - aodv_elect_route(node, NULL, hopcount, msginfo->dev); - } - - pico_aodv_dbg("Received AODV packet, ttl = %d\n", msginfo->ttl); - aodv_parser[buf[0]].call(from, buf, len, msginfo); -} - -static void pico_aodv_socket_callback(uint16_t ev, struct pico_socket *s) -{ - static uint8_t aodv_pkt[AODV_MAX_PKT]; - static union pico_address from; - static struct pico_msginfo msginfo; - uint16_t sport; - int r; - if (s != aodv_socket) - return; - - if (ev & PICO_SOCK_EV_RD) { - r = pico_socket_recvfrom_extended(s, aodv_pkt, AODV_MAX_PKT, &from, &sport, &msginfo); - if (r <= 0) - return; - - pico_aodv_dbg("Received AODV packet: %d bytes \n", r); - - pico_aodv_parse(&from, aodv_pkt, r, &msginfo); - } -} - -static void aodv_make_rreq(struct pico_aodv_node *node, struct pico_aodv_rreq *req) -{ - memset(req, 0, sizeof(struct pico_aodv_rreq)); - req->type = AODV_TYPE_RREQ; - - if (0 == (node->flags & PICO_AODV_NODE_SYNC)) { - req->req_flags |= short_be(AODV_RREQ_FLAG_U); /* no known dseq, mark as U */ - req->dseq = 0; /* Unknown */ - } else { - req->dseq = long_be(node->dseq); - req->req_flags |= short_be(AODV_RREQ_FLAG_G); /* RFC3561 $6.3: we SHOULD set G flag as originators */ - } - - /* Hop count = 0; */ - req->rreq_id = long_be(++pico_aodv_local_id); - req->dest = node->dest.ip4.addr; - req->oseq = long_be(pico_aodv_local_id); -} - -static void aodv_retrans_rreq(pico_time now, void *arg) -{ - struct pico_aodv_node *node = (struct pico_aodv_node *)arg; - struct pico_device *dev; - struct pico_tree_node *index; - static struct pico_aodv_rreq rreq; - struct pico_ipv4_link *ip4l = NULL; - struct pico_msginfo info = { - .dev = NULL, .tos = 0, .ttl = AODV_TTL_START - }; - (void)now; - - memset(&rreq, 0, sizeof(rreq)); - - if (node->flags & PICO_AODV_NODE_ROUTE_UP) { - pico_aodv_dbg("------------------------------------------------------ Node %08x already active.\n", node->dest.ip4.addr); - return; - } - - if (node->ring_ttl > AODV_TTL_THRESHOLD) { - node->ring_ttl = AODV_NET_DIAMETER; - pico_aodv_dbg("----------- DIAMETER reached.\n"); - } - - - if (node->rreq_retry > AODV_RREQ_RETRIES) { - node->rreq_retry = 0; - node->ring_ttl = 0; - pico_aodv_dbg("Node is unreachable.\n"); - node->flags &= (uint16_t)(~PICO_AODV_NODE_ROUTE_DOWN); - return; - } - - if (node->ring_ttl == AODV_NET_DIAMETER) { - node->rreq_retry++; - pico_aodv_dbg("Retry #%d\n", node->rreq_retry); - } - - aodv_make_rreq(node, &rreq); - info.ttl = (uint8_t)node->ring_ttl; - pico_tree_foreach(index, &aodv_devices){ - dev = index->keyValue; - pico_aodv_set_dev(dev); - ip4l = pico_ipv4_link_by_dev(dev); - if (ip4l) { - rreq.orig = ip4l->address.addr; - pico_socket_sendto_extended(aodv_socket, &rreq, sizeof(rreq), &all_bcast, short_be(PICO_AODV_PORT), &info); - } - } - if (node->ring_ttl < AODV_NET_DIAMETER) - node->ring_ttl = (uint8_t)(node->ring_ttl + AODV_TTL_INCREMENT); - - pico_timer_add((pico_time)AODV_RING_TRAVERSAL_TIME(node->ring_ttl), aodv_retrans_rreq, node); -} - -static int aodv_send_req(struct pico_aodv_node *node) -{ - struct pico_device *dev; - struct pico_tree_node *index; - static struct pico_aodv_rreq rreq; - int n = 0; - struct pico_ipv4_link *ip4l = NULL; - struct pico_msginfo info = { - .dev = NULL, .tos = 0, .ttl = AODV_TTL_START - }; - memset(&rreq, 0, sizeof(rreq)); - - if (PICO_AODV_ACTIVE(node)) - return 0; - - node->flags |= PICO_AODV_NODE_REQUESTING; - - if (pico_tree_empty(&aodv_devices)) - return n; - - if (!aodv_socket) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (node->flags & PICO_AODV_NODE_ROUTE_DOWN) { - info.ttl = node->metric; - } - - aodv_make_rreq(node, &rreq); - pico_tree_foreach(index, &aodv_devices) { - dev = index->keyValue; - pico_aodv_set_dev(dev); - ip4l = pico_ipv4_link_by_dev(dev); - if (ip4l) { - rreq.orig = ip4l->address.addr; - pico_socket_sendto_extended(aodv_socket, &rreq, sizeof(rreq), &all_bcast, short_be(PICO_AODV_PORT), &info); - n++; - } - } - pico_timer_add((pico_time)AODV_RING_TRAVERSAL_TIME(1), aodv_retrans_rreq, node); - return n; -} - -static void pico_aodv_expired(struct pico_aodv_node *node) -{ - node->flags |= PICO_AODV_NODE_UNREACH; - node->flags &= (uint8_t)(~PICO_AODV_NODE_ROUTE_UP); - node->flags &= (uint8_t)(~PICO_AODV_NODE_ROUTE_DOWN); - pico_ipv4_route_del(node->dest.ip4, HOST_NETMASK, node->metric); - node->ring_ttl = 0; - /* TODO: send err */ - -} - -static void pico_aodv_collector(pico_time now, void *arg) -{ - struct pico_tree_node *index; - struct pico_aodv_node *node; - (void)arg; - (void)now; - pico_tree_foreach(index, &aodv_nodes){ - node = index->keyValue; - if (PICO_AODV_ACTIVE(node)) { - uint32_t lifetime = aodv_lifetime(node); - if (lifetime == 0) - pico_aodv_expired(node); - } - } - pico_timer_add(AODV_HELLO_INTERVAL, pico_aodv_collector, NULL); -} - -MOCKABLE int pico_aodv_init(void) -{ - struct pico_ip4 any = { - 0 - }; - uint16_t port = short_be(PICO_AODV_PORT); - if (aodv_socket) { - pico_err = PICO_ERR_EADDRINUSE; - return -1; - } - - aodv_socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, pico_aodv_socket_callback); - if (!aodv_socket) - return -1; - - if (pico_socket_bind(aodv_socket, &any, &port) != 0) { - uint16_t err = pico_err; - pico_socket_close(aodv_socket); - pico_err = err; - aodv_socket = NULL; - return -1; - } - - pico_aodv_local_id = pico_rand(); - pico_timer_add(AODV_HELLO_INTERVAL, pico_aodv_collector, NULL); - return 0; -} - - -int pico_aodv_add(struct pico_device *dev) -{ - return (pico_tree_insert(&aodv_devices, dev)) ? (0) : (-1); -} - -void pico_aodv_refresh(const union pico_address *addr) -{ - struct pico_aodv_node *node = get_node_by_addr(addr); - if (node) { - node->last_seen = PICO_TIME_MS(); - } -} - -int pico_aodv_lookup(const union pico_address *addr) -{ - struct pico_aodv_node *node = get_node_by_addr(addr); - if (!node) - node = aodv_peer_new(addr); - - if (!node) - return -1; - - if ((node->flags & PICO_AODV_NODE_ROUTE_UP) || (node->flags & PICO_AODV_NODE_ROUTE_DOWN)) - return 0; - - if (node->ring_ttl < AODV_TTL_START) { - node->ring_ttl = AODV_TTL_START; - aodv_send_req(node); - return 0; - } - - pico_err = PICO_ERR_EINVAL; - return -1; -} - -#else - -int pico_aodv_init(void) -{ - return -1; -} - -int pico_aodv_add(struct pico_device *dev) -{ - (void)dev; - return -1; -} - -int pico_aodv_lookup(const union pico_address *addr) -{ - (void)addr; - return -1; -} - -void pico_aodv_refresh(const union pico_address *addr) -{ - (void)addr; -} - -#endif diff --git a/ext/picotcp/modules/pico_aodv.h b/ext/picotcp/modules/pico_aodv.h deleted file mode 100644 index 0937ed1..0000000 --- a/ext/picotcp/modules/pico_aodv.h +++ /dev/null @@ -1,130 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Author: Daniele Lacamera - *********************************************************************/ -#ifndef PICO_AODV_H_ -#define PICO_AODV_H_ - -/* RFC3561 */ -#define PICO_AODV_PORT (654) - -/* RFC3561 $10 */ -#define AODV_ACTIVE_ROUTE_TIMEOUT (8000u) /* Conservative value for link breakage detection */ -#define AODV_DELETE_PERIOD (5 * AODV_ACTIVE_ROUTE_TIMEOUT) /* Recommended value K = 5 */ -#define AODV_ALLOWED_HELLO_LOSS (4) /* conservative */ -#define AODV_NET_DIAMETER ((uint8_t)(35)) -#define AODV_RREQ_RETRIES (2) -#define AODV_NODE_TRAVERSAL_TIME (40) -#define AODV_HELLO_INTERVAL (1000) -#define AODV_LOCAL_ADD_TTL 2 -#define AODV_RREQ_RATELIMIT (10) -#define AODV_TIMEOUT_BUFFER (2) -#define AODV_TTL_START ((uint8_t)(1)) -#define AODV_TTL_INCREMENT 2 -#define AODV_TTL_THRESHOLD ((uint8_t)(7)) -#define AODV_RERR_RATELIMIT (10) -#define AODV_MAX_REPAIR_TTL ((uint8_t)(AODV_NET_DIAMETER / 3)) -#define AODV_MY_ROUTE_TIMEOUT (2 * AODV_ACTIVE_ROUTE_TIMEOUT) -#define AODV_NET_TRAVERSAL_TIME (2 * AODV_NODE_TRAVERSAL_TIME * AODV_NET_DIAMETER) -#define AODV_BLACKLIST_TIMEOUT (AODV_RREQ_RETRIES * AODV_NET_TRAVERSAL_TIME) -#define AODV_NEXT_HOP_WAIT (AODV_NODE_TRAVERSAL_TIME + 10) -#define AODV_PATH_DISCOVERY_TIME (2 * AODV_NET_TRAVERSAL_TIME) -#define AODV_RING_TRAVERSAL_TIME(ttl) (2 * AODV_NODE_TRAVERSAL_TIME * (ttl + AODV_TIMEOUT_BUFFER)) -/* End section RFC3561 $10 */ - - -#define AODV_TYPE_RREQ 1 -#define AODV_TYPE_RREP 2 -#define AODV_TYPE_RERR 3 -#define AODV_TYPE_RACK 4 - -PACKED_STRUCT_DEF pico_aodv_rreq -{ - uint8_t type; - uint16_t req_flags; - uint8_t hop_count; - uint32_t rreq_id; - uint32_t dest; - uint32_t dseq; - uint32_t orig; - uint32_t oseq; -}; - -#define AODV_RREQ_FLAG_J 0x8000 -#define AODV_RREQ_FLAG_R 0x4000 -#define AODV_RREQ_FLAG_G 0x2000 -#define AODV_RREQ_FLAG_D 0x1000 -#define AODV_RREQ_FLAG_U 0x0800 -#define AODV_RREQ_FLAG_RESERVED 0x07FF - -PACKED_STRUCT_DEF pico_aodv_rrep -{ - uint8_t type; - uint8_t rep_flags; - uint8_t prefix_sz; - uint8_t hop_count; - uint32_t dest; - uint32_t dseq; - uint32_t orig; - uint32_t lifetime; -}; - -#define AODV_RREP_MAX_PREFIX 0x1F -#define AODV_RREP_FLAG_R 0x80 -#define AODV_RREP_FLAG_A 0x40 -#define AODV_RREP_FLAG_RESERVED 0x3F - -#define PICO_AODV_NODE_NEW 0x0000 -#define PICO_AODV_NODE_SYNC 0x0001 -#define PICO_AODV_NODE_REQUESTING 0x0002 -#define PICO_AODV_NODE_ROUTE_UP 0x0004 -#define PICO_AODV_NODE_ROUTE_DOWN 0x0008 -#define PICO_AODV_NODE_IDLING 0x0010 -#define PICO_AODV_NODE_UNREACH 0x0020 - -#define PICO_AODV_ACTIVE(node) ((node->flags & PICO_AODV_NODE_ROUTE_UP) && (node->flags & PICO_AODV_NODE_ROUTE_DOWN)) - - -struct pico_aodv_node -{ - union pico_address dest; - pico_time last_seen; - pico_time fwd_time; - uint32_t dseq; - uint16_t flags; - uint8_t metric; - uint8_t ring_ttl; - uint8_t rreq_retry; -}; - -PACKED_STRUCT_DEF pico_aodv_unreachable -{ - uint32_t addr; - uint32_t dseq; -}; - -PACKED_STRUCT_DEF pico_aodv_rerr -{ - uint8_t type; - uint16_t rerr_flags; - uint8_t dst_count; - uint32_t unreach_addr; - uint32_t unreach_dseq; - struct pico_aodv_unreachable unreach[1]; /* unrechable nodes: must be at least 1. See dst_count field above */ -}; - -PACKED_STRUCT_DEF pico_aodv_rack -{ - uint8_t type; - uint8_t reserved; -}; - -int pico_aodv_init(void); -int pico_aodv_add(struct pico_device *dev); -int pico_aodv_lookup(const union pico_address *addr); -void pico_aodv_refresh(const union pico_address *addr); -#endif diff --git a/ext/picotcp/modules/pico_arp.c b/ext/picotcp/modules/pico_arp.c deleted file mode 100644 index 850ca35..0000000 --- a/ext/picotcp/modules/pico_arp.c +++ /dev/null @@ -1,537 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include "pico_config.h" -#include "pico_arp.h" -#include "pico_tree.h" -#include "pico_ipv4.h" -#include "pico_device.h" -#include "pico_stack.h" - -extern const uint8_t PICO_ETHADDR_ALL[6]; -#define PICO_ARP_TIMEOUT 600000llu -#define PICO_ARP_RETRY 300lu -#define PICO_ARP_MAX_PENDING 5 - -#ifdef DEBUG_ARP - #define arp_dbg dbg -#else - #define arp_dbg(...) do {} while(0) -#endif - -static int max_arp_reqs = PICO_ARP_MAX_RATE; -static struct pico_frame *frames_queued[PICO_ARP_MAX_PENDING] = { 0 }; - -static void pico_arp_queued_trigger(void) -{ - int i; - struct pico_frame *f; - for (i = 0; i < PICO_ARP_MAX_PENDING; i++) - { - f = frames_queued[i]; - if (f) { - if (!pico_ethernet_send(f)) - { - pico_frame_discard(f); - frames_queued[i] = NULL; - } - } - } -} - -static void update_max_arp_reqs(pico_time now, void *unused) -{ - IGNORE_PARAMETER(now); - IGNORE_PARAMETER(unused); - if (max_arp_reqs < PICO_ARP_MAX_RATE) - max_arp_reqs++; - - pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL); -} - -void pico_arp_init(void) -{ - pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL); -} - -PACKED_STRUCT_DEF pico_arp_hdr -{ - uint16_t htype; - uint16_t ptype; - uint8_t hsize; - uint8_t psize; - uint16_t opcode; - uint8_t s_mac[PICO_SIZE_ETH]; - struct pico_ip4 src; - uint8_t d_mac[PICO_SIZE_ETH]; - struct pico_ip4 dst; -}; - - - -/* Callback handler for ip conflict service (e.g. IPv4 SLAAC) - * Whenever the IP address registered here is seen in the network, - * the callback is awaken to take countermeasures against IP collisions. - * - */ - -struct arp_service_ipconflict { - struct pico_eth mac; - struct pico_ip4 ip; - void (*conflict)(int); -}; - -static struct arp_service_ipconflict conflict_ipv4; - - - -#define PICO_SIZE_ARPHDR ((sizeof(struct pico_arp_hdr))) - -/* Arp Entries for the tables. */ -struct pico_arp { -/* CAREFUL MAN! ARP entry MUST begin with a pico_eth structure, - * due to in-place casting!!! */ - struct pico_eth eth; - struct pico_ip4 ipv4; - int arp_status; - pico_time timestamp; - struct pico_device *dev; - uint32_t timer; -}; - - - -/*****************/ -/** ARP TREE **/ -/*****************/ - -/* Routing destination */ - -static int arp_compare(void *ka, void *kb) -{ - struct pico_arp *a = ka, *b = kb; - return pico_ipv4_compare(&a->ipv4, &b->ipv4); -} - -PICO_TREE_DECLARE(arp_tree, arp_compare); - -/*********************/ -/** END ARP TREE **/ -/*********************/ - -struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst) -{ - struct pico_arp search, *found; - search.ipv4.addr = dst->addr; - found = pico_tree_findKey(&arp_tree, &search); - if (found && (found->arp_status != PICO_ARP_STATUS_STALE)) - return &found->eth; - - return NULL; -} - -struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst) -{ - struct pico_arp*search; - struct pico_tree_node *index; - pico_tree_foreach(index, &arp_tree){ - search = index->keyValue; - if(memcmp(&(search->eth.addr), &dst->addr, 6) == 0) - return &search->ipv4; - } - return NULL; -} - -static void pico_arp_unreachable(struct pico_ip4 *a) -{ - int i; - struct pico_frame *f; - struct pico_ipv4_hdr *hdr; - struct pico_ip4 dst; - for (i = 0; i < PICO_ARP_MAX_PENDING; i++) - { - f = frames_queued[i]; - if (f) { - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - dst = pico_ipv4_route_get_gateway(&hdr->dst); - if (!dst.addr) - dst.addr = hdr->dst.addr; - - if (dst.addr == a->addr) { - if (!pico_source_is_local(f)) { - pico_notify_dest_unreachable(f); - } - - pico_frame_discard(f); - frames_queued[i] = NULL; - } - } - } -} - -static void pico_arp_retry(struct pico_frame *f, struct pico_ip4 *where) -{ - if (++f->failure_count < 4) { - arp_dbg ("================= ARP REQUIRED: %d =============\n\n", f->failure_count); - /* check if dst is local (gateway = 0), or if to use gateway */ - pico_arp_request(f->dev, where, PICO_ARP_QUERY); - } else { - pico_arp_unreachable(where); - } -} - -struct pico_eth *pico_arp_get(struct pico_frame *f) -{ - struct pico_eth *a4; - struct pico_ip4 gateway; - struct pico_ip4 *where; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_ipv4_link *l; - if (!hdr) - return NULL; - - l = pico_ipv4_link_get(&hdr->dst); - if(l) { - /* address belongs to ourself */ - return &l->dev->eth->mac; - } - - gateway = pico_ipv4_route_get_gateway(&hdr->dst); - /* check if dst is local (gateway = 0), or if to use gateway */ - if (gateway.addr != 0) - where = &gateway; - else - where = &hdr->dst; - - a4 = pico_arp_lookup(where); /* check if dst ip mac in cache */ - - if (!a4) - pico_arp_retry(f, where); - - return a4; -} - - -void pico_arp_postpone(struct pico_frame *f) -{ - int i; - for (i = 0; i < PICO_ARP_MAX_PENDING; i++) - { - if (!frames_queued[i]) { - frames_queued[i] = pico_frame_copy(f); - return; - } - } - /* Not possible to enqueue: caller will discard packet */ -} - - -#ifdef DEBUG_ARP -void dbg_arp(void) -{ - struct pico_arp *a; - struct pico_tree_node *index; - - pico_tree_foreach(index, &arp_tree) { - a = index->keyValue; - arp_dbg("ARP to %08x, mac: %02x:%02x:%02x:%02x:%02x:%02x\n", a->ipv4.addr, a->eth.addr[0], a->eth.addr[1], a->eth.addr[2], a->eth.addr[3], a->eth.addr[4], a->eth.addr[5] ); - } -} -#endif - -static void arp_expire(pico_time now, void *_stale) -{ - struct pico_arp *stale = (struct pico_arp *) _stale; - if (now >= (stale->timestamp + PICO_ARP_TIMEOUT)) { - stale->arp_status = PICO_ARP_STATUS_STALE; - arp_dbg("ARP: Setting arp_status to STALE\n"); - pico_arp_request(stale->dev, &stale->ipv4, PICO_ARP_QUERY); - } else { - /* Timer must be rescheduled, ARP entry has been renewed lately. - * No action required to refresh the entry, will check on the next timeout */ - pico_timer_add(PICO_ARP_TIMEOUT + stale->timestamp - now, arp_expire, stale); - } -} - -static void pico_arp_add_entry(struct pico_arp *entry) -{ - entry->arp_status = PICO_ARP_STATUS_REACHABLE; - entry->timestamp = PICO_TIME(); - - pico_tree_insert(&arp_tree, entry); - arp_dbg("ARP ## reachable.\n"); - pico_arp_queued_trigger(); - pico_timer_add(PICO_ARP_TIMEOUT, arp_expire, entry); -} - -int pico_arp_create_entry(uint8_t *hwaddr, struct pico_ip4 ipv4, struct pico_device *dev) -{ - struct pico_arp*arp = PICO_ZALLOC(sizeof(struct pico_arp)); - if(!arp) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - memcpy(arp->eth.addr, hwaddr, 6); - arp->ipv4.addr = ipv4.addr; - arp->dev = dev; - - pico_arp_add_entry(arp); - - return 0; -} - -static void pico_arp_check_conflict(struct pico_arp_hdr *hdr) -{ - if (conflict_ipv4.conflict) - { - if((conflict_ipv4.ip.addr == hdr->src.addr) && - (memcmp(hdr->s_mac, conflict_ipv4.mac.addr, PICO_SIZE_ETH) != 0)) - conflict_ipv4.conflict(PICO_ARP_CONFLICT_REASON_CONFLICT ); - if((hdr->src.addr == 0) && (hdr->dst.addr == conflict_ipv4.ip.addr) ) - conflict_ipv4.conflict(PICO_ARP_CONFLICT_REASON_PROBE ); - } -} - -static struct pico_arp *pico_arp_lookup_entry(struct pico_frame *f) -{ - struct pico_arp search; - struct pico_arp *found = NULL; - struct pico_arp_hdr *hdr = (struct pico_arp_hdr *) f->net_hdr; - /* Populate a new arp entry */ - search.ipv4.addr = hdr->src.addr; - - /* Search for already existing entry */ - found = pico_tree_findKey(&arp_tree, &search); - if (found) { - if (found->arp_status == PICO_ARP_STATUS_STALE) { - /* Replace if stale */ - pico_tree_delete(&arp_tree, found); - pico_arp_add_entry(found); - } else { - /* Update mac address */ - memcpy(found->eth.addr, hdr->s_mac, PICO_SIZE_ETH); - arp_dbg("ARP entry updated!\n"); - - /* Refresh timestamp, this will force a reschedule on the next timeout*/ - found->timestamp = PICO_TIME(); - } - } - - return found; -} - - -static int pico_arp_check_incoming_hdr_type(struct pico_arp_hdr *h) -{ - /* Check the hardware type and protocol */ - if ((h->htype != PICO_ARP_HTYPE_ETH) || (h->ptype != PICO_IDETH_IPV4)) - return -1; - - return 0; -} - -static int pico_arp_check_incoming_hdr(struct pico_frame *f, struct pico_ip4 *dst_addr) -{ - struct pico_arp_hdr *hdr = (struct pico_arp_hdr *) f->net_hdr; - if (!hdr) - return -1; - - dst_addr->addr = hdr->dst.addr; - if (pico_arp_check_incoming_hdr_type(hdr) < 0) - return -1; - - /* The source mac address must not be a multicast or broadcast address */ - if (hdr->s_mac[0] & 0x01) - return -1; - - return 0; -} - -static void pico_arp_reply_on_request(struct pico_frame *f, struct pico_ip4 me) -{ - struct pico_arp_hdr *hdr; - struct pico_eth_hdr *eh; - - hdr = (struct pico_arp_hdr *) f->net_hdr; - eh = (struct pico_eth_hdr *)f->datalink_hdr; - if (hdr->opcode != PICO_ARP_REQUEST) - return; - - hdr->opcode = PICO_ARP_REPLY; - memcpy(hdr->d_mac, hdr->s_mac, PICO_SIZE_ETH); - memcpy(hdr->s_mac, f->dev->eth->mac.addr, PICO_SIZE_ETH); - hdr->dst.addr = hdr->src.addr; - hdr->src.addr = me.addr; - - /* Prepare eth header for arp reply */ - memcpy(eh->daddr, eh->saddr, PICO_SIZE_ETH); - memcpy(eh->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH); - f->start = f->datalink_hdr; - f->len = PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR; - f->dev->send(f->dev, f->start, (int)f->len); -} - -static int pico_arp_check_flooding(struct pico_frame *f, struct pico_ip4 me) -{ - struct pico_device *link_dev; - struct pico_arp_hdr *hdr; - hdr = (struct pico_arp_hdr *) f->net_hdr; - - /* Prevent ARP flooding */ - link_dev = pico_ipv4_link_find(&me); - if ((link_dev == f->dev) && (hdr->opcode == PICO_ARP_REQUEST)) { - if (max_arp_reqs == 0) - return -1; - else - max_arp_reqs--; - } - - /* Check if we are the target IP address */ - if (link_dev != f->dev) - return -1; - - return 0; -} - -static int pico_arp_process_in(struct pico_frame *f, struct pico_arp_hdr *hdr, struct pico_arp *found) -{ - struct pico_ip4 me; - if (pico_arp_check_incoming_hdr(f, &me) < 0) { - pico_frame_discard(f); - return -1; - } - - if (pico_arp_check_flooding(f, me) < 0) { - pico_frame_discard(f); - return -1; - } - - /* If no existing entry was found, create a new entry, or fail trying. */ - if ((!found) && (pico_arp_create_entry(hdr->s_mac, hdr->src, f->dev) < 0)) { - pico_frame_discard(f); - return -1; - } - - /* If the packet is a request, send a reply */ - pico_arp_reply_on_request(f, me); - -#ifdef DEBUG_ARP - dbg_arp(); -#endif - pico_frame_discard(f); - return 0; -} - -int pico_arp_receive(struct pico_frame *f) -{ - struct pico_arp_hdr *hdr; - struct pico_arp *found = NULL; - - hdr = (struct pico_arp_hdr *) f->net_hdr; - if (!hdr) - return -1; - - pico_arp_check_conflict(hdr); - found = pico_arp_lookup_entry(f); - return pico_arp_process_in(f, hdr, found); - -} - -static int32_t pico_arp_request_xmit(struct pico_device *dev, struct pico_frame *f, struct pico_ip4 *src, struct pico_ip4 *dst, uint8_t type) -{ - struct pico_arp_hdr *ah = (struct pico_arp_hdr *) (f->start + PICO_SIZE_ETHHDR); - int ret; - - /* Fill arp header */ - ah->htype = PICO_ARP_HTYPE_ETH; - ah->ptype = PICO_IDETH_IPV4; - ah->hsize = PICO_SIZE_ETH; - ah->psize = PICO_SIZE_IP4; - ah->opcode = PICO_ARP_REQUEST; - memcpy(ah->s_mac, dev->eth->mac.addr, PICO_SIZE_ETH); - - switch (type) { - case PICO_ARP_ANNOUNCE: - ah->src.addr = dst->addr; - ah->dst.addr = dst->addr; - break; - case PICO_ARP_PROBE: - ah->src.addr = 0; - ah->dst.addr = dst->addr; - break; - case PICO_ARP_QUERY: - ah->src.addr = src->addr; - ah->dst.addr = dst->addr; - break; - default: - pico_frame_discard(f); - return -1; - } - arp_dbg("Sending arp request.\n"); - ret = dev->send(dev, f->start, (int) f->len); - pico_frame_discard(f); - return ret; -} - -int32_t pico_arp_request(struct pico_device *dev, struct pico_ip4 *dst, uint8_t type) -{ - struct pico_frame *q = pico_frame_alloc(PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR); - struct pico_eth_hdr *eh; - struct pico_ip4 *src = NULL; - - if (!q) - return -1; - - if (type == PICO_ARP_QUERY) - { - src = pico_ipv4_source_find(dst); - if (!src) { - pico_frame_discard(q); - return -1; - } - } - - arp_dbg("QUERY: %08x\n", dst->addr); - - eh = (struct pico_eth_hdr *)q->start; - - /* Fill eth header */ - memcpy(eh->saddr, dev->eth->mac.addr, PICO_SIZE_ETH); - memcpy(eh->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH); - eh->proto = PICO_IDETH_ARP; - - return pico_arp_request_xmit(dev, q, src, dst, type); -} - -int pico_arp_get_neighbors(struct pico_device *dev, struct pico_ip4 *neighbors, int maxlen) -{ - struct pico_arp*search; - struct pico_tree_node *index; - int i = 0; - pico_tree_foreach(index, &arp_tree){ - search = index->keyValue; - if (search->dev == dev) { - neighbors[i++].addr = search->ipv4.addr; - if (i >= maxlen) - return i; - } - } - return i; -} - -void pico_arp_register_ipconflict(struct pico_ip4 *ip, struct pico_eth *mac, void (*cb)(int reason)) -{ - conflict_ipv4.conflict = cb; - conflict_ipv4.ip.addr = ip->addr; - if (mac != NULL) - memcpy(conflict_ipv4.mac.addr, mac, 6); -} - diff --git a/ext/picotcp/modules/pico_arp.h b/ext/picotcp/modules/pico_arp.h deleted file mode 100644 index 36f7210..0000000 --- a/ext/picotcp/modules/pico_arp.h +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_ARP -#define INCLUDE_PICO_ARP -#include "pico_eth.h" -#include "pico_device.h" - -int pico_arp_receive(struct pico_frame *); - - -struct pico_eth *pico_arp_get(struct pico_frame *f); -int32_t pico_arp_request(struct pico_device *dev, struct pico_ip4 *dst, uint8_t type); - -#define PICO_ARP_STATUS_REACHABLE 0x00 -#define PICO_ARP_STATUS_PERMANENT 0x01 -#define PICO_ARP_STATUS_STALE 0x02 - -#define PICO_ARP_QUERY 0x00 -#define PICO_ARP_PROBE 0x01 -#define PICO_ARP_ANNOUNCE 0x02 - -#define PICO_ARP_CONFLICT_REASON_CONFLICT 0 -#define PICO_ARP_CONFLICT_REASON_PROBE 1 - -struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst); -struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst); -int pico_arp_create_entry(uint8_t*hwaddr, struct pico_ip4 ipv4, struct pico_device*dev); -int pico_arp_get_neighbors(struct pico_device *dev, struct pico_ip4 *neighbors, int maxlen); -void pico_arp_register_ipconflict(struct pico_ip4 *ip, struct pico_eth *mac, void (*cb)(int reason)); -void pico_arp_postpone(struct pico_frame *f); -void pico_arp_init(void); -#endif diff --git a/ext/picotcp/modules/pico_dev_loop.c b/ext/picotcp/modules/pico_dev_loop.c deleted file mode 100644 index 4416d0b..0000000 --- a/ext/picotcp/modules/pico_dev_loop.c +++ /dev/null @@ -1,66 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include "pico_device.h" -#include "pico_dev_loop.h" -#include "pico_stack.h" - - -#define LOOP_MTU 1500 -static uint8_t l_buf[LOOP_MTU]; -static int l_bufsize = 0; - - -static int pico_loop_send(struct pico_device *dev, void *buf, int len) -{ - IGNORE_PARAMETER(dev); - if (len > LOOP_MTU) - return 0; - - if (l_bufsize == 0) { - memcpy(l_buf, buf, (size_t)len); - l_bufsize += len; - return len; - } - - return 0; -} - -static int pico_loop_poll(struct pico_device *dev, int loop_score) -{ - if (loop_score <= 0) - return 0; - - if (l_bufsize > 0) { - pico_stack_recv(dev, l_buf, (uint32_t)l_bufsize); - l_bufsize = 0; - loop_score--; - } - - return loop_score; -} - - -struct pico_device *pico_loop_create(void) -{ - struct pico_device *loop = PICO_ZALLOC(sizeof(struct pico_device)); - if (!loop) - return NULL; - - if( 0 != pico_device_init(loop, "loop", NULL)) { - dbg ("Loop init failed.\n"); - pico_device_destroy(loop); - return NULL; - } - - loop->send = pico_loop_send; - loop->poll = pico_loop_poll; - dbg("Device %s created.\n", loop->name); - return loop; -} - diff --git a/ext/picotcp/modules/pico_dev_loop.h b/ext/picotcp/modules/pico_dev_loop.h deleted file mode 100644 index 6cb8de1..0000000 --- a/ext/picotcp/modules/pico_dev_loop.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_LOOP -#define INCLUDE_PICO_LOOP -#include "pico_config.h" -#include "pico_device.h" - -void pico_loop_destroy(struct pico_device *loop); -struct pico_device *pico_loop_create(void); - -#endif - diff --git a/ext/picotcp/modules/pico_dev_mock.c b/ext/picotcp/modules/pico_dev_mock.c deleted file mode 100644 index 59fae01..0000000 --- a/ext/picotcp/modules/pico_dev_mock.c +++ /dev/null @@ -1,307 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Frederik Van Slycken - *********************************************************************/ - - -#include "pico_device.h" -#include "pico_dev_mock.h" -#include "pico_stack.h" -#include "pico_tree.h" - -#define MOCK_MTU 1500 - - - -/* Tree for finding mock_device based on pico_device* */ - - -static int mock_dev_cmp(void *ka, void *kb) -{ - struct mock_device *a = ka, *b = kb; - if (a->dev < b->dev) - return -1; - - if (a->dev > b->dev) - return 1; - - return 0; -} - -PICO_TREE_DECLARE(mock_device_tree, mock_dev_cmp); - -static int pico_mock_send(struct pico_device *dev, void *buf, int len) -{ - struct mock_device search = { - .dev = dev - }; - struct mock_device*mock = pico_tree_findKey(&mock_device_tree, &search); - struct mock_frame*frame; - - if(!mock) - return 0; - - if (len > MOCK_MTU) - return 0; - - frame = PICO_ZALLOC(sizeof(struct mock_frame)); - if(!frame) { - return 0; - } - - if(mock->out_head == NULL) - mock->out_head = frame; - else - mock->out_tail->next = frame; - - mock->out_tail = frame; - - mock->out_tail->buffer = PICO_ZALLOC((uint32_t)len); - if(!mock->out_tail->buffer) - return 0; - - memcpy(mock->out_tail->buffer, buf, (uint32_t)len); - mock->out_tail->len = len; - - return len; - -} - -static int pico_mock_poll(struct pico_device *dev, int loop_score) -{ - struct mock_device search = { - .dev = dev - }; - struct mock_device*mock = pico_tree_findKey(&mock_device_tree, &search); - struct mock_frame*nxt; - - if(!mock) - return 0; - - if (loop_score <= 0) - return 0; - - while(mock->in_head != NULL && loop_score > 0) - { - pico_stack_recv(dev, mock->in_head->buffer, (uint32_t)mock->in_head->len); - loop_score--; - - PICO_FREE(mock->in_head->buffer); - - if(mock->in_tail == mock->in_head) { - PICO_FREE(mock->in_head); - mock->in_tail = mock->in_head = NULL; - return loop_score; - } - - nxt = mock->in_head->next; - PICO_FREE(mock->in_head); - mock->in_head = nxt; - } - return loop_score; -} - -int pico_mock_network_read(struct mock_device*mock, void *buf, int len) -{ - struct mock_frame*nxt; - if(mock->out_head == NULL) - return 0; - - if(len > mock->out_head->len - mock->out_head->read) - len = mock->out_head->len - mock->out_head->read; - - memcpy(buf, mock->out_head->buffer, (uint32_t)len); - - if(len + mock->out_head->read != mock->out_head->len) { - mock->out_head->read += len; - return len; - } - - PICO_FREE(mock->out_head->buffer); - - if(mock->out_tail == mock->out_head) { - PICO_FREE(mock->out_head); - mock->out_tail = mock->out_head = NULL; - return len; - } - - nxt = mock->out_head->next; - PICO_FREE(mock->out_head); - mock->out_head = nxt; - - return len; -} - -int pico_mock_network_write(struct mock_device*mock, const void *buf, int len) -{ - struct mock_frame*frame; - if (len > MOCK_MTU) - return 0; - - frame = PICO_ZALLOC(sizeof(struct mock_frame)); - if(!frame) { - return 0; - } - - if(mock->in_head == NULL) - mock->in_head = frame; - else - mock->in_tail->next = frame; - - mock->in_tail = frame; - - mock->in_tail->buffer = PICO_ZALLOC((uint32_t)len); - if(!mock->in_tail->buffer) - return 0; - - memcpy(mock->in_tail->buffer, buf, (uint32_t)len); - mock->in_tail->len = len; - - return len; - -} - -/* Public interface: create/destroy. */ - -void pico_mock_destroy(struct pico_device *dev) -{ - struct mock_device search = { - .dev = dev - }; - struct mock_device*mock = pico_tree_findKey(&mock_device_tree, &search); - struct mock_frame*nxt; - - if(!mock) - return; - - nxt = mock->in_head; - while(nxt != NULL) { - mock->in_head = mock->in_head->next; - PICO_FREE(nxt); - nxt = mock->in_head; - } - nxt = mock->out_head; - while(nxt != NULL) { - mock->out_head = mock->out_head->next; - PICO_FREE(nxt); - nxt = mock->out_head; - } - pico_tree_delete(&mock_device_tree, mock); -} - -struct mock_device *pico_mock_create(uint8_t*mac) -{ - - struct mock_device*mock = PICO_ZALLOC(sizeof(struct mock_device)); - if(!mock) - return NULL; - - mock->dev = PICO_ZALLOC(sizeof(struct pico_device)); - if (!mock->dev) { - PICO_FREE(mock); - return NULL; - } - - if(mac != NULL) { - mock->mac = PICO_ZALLOC(6 * sizeof(uint8_t)); - if(!mock->mac) { - PICO_FREE(mock->mac); - PICO_FREE(mock); - return NULL; - } - - memcpy(mock->mac, mac, 6); - } - - if( 0 != pico_device_init((struct pico_device *)mock->dev, "mock", mac)) { - dbg ("Loop init failed.\n"); - pico_mock_destroy((struct pico_device *)mock->dev); - if(mock->mac != NULL) - PICO_FREE(mock->mac); - - PICO_FREE(mock); - return NULL; - } - - mock->dev->send = pico_mock_send; - mock->dev->poll = pico_mock_poll; - mock->dev->destroy = pico_mock_destroy; - dbg("Device %s created.\n", mock->dev->name); - - pico_tree_insert(&mock_device_tree, mock); - return mock; -} - -/* - * a few utility functions that check certain fields - */ - -uint32_t mock_get_sender_ip4(struct mock_device*mock, void*buf, int len) -{ - uint32_t ret; - int start = mock->mac ? 14 : 0; - if(start + 16 > len) { - dbg("out of range!\n"); - return 0; - } - - memcpy(&ret, buf + start + 12, 4); - return ret; -} - -/* - * TODO - * find a way to create ARP replies - * - * create the other utility functions, e.g. - * -is_arp_request - * -create_arp_reply - * -get_destination_ip4 - * -get_ip4_total_length - * -is_ip4_checksum_valid - * -is_tcp_syn - * -create_tcp_synack - * -is_tcp_checksum_valid - * etc. - * - */ - -int mock_ip_protocol(struct mock_device*mock, void*buf, int len) -{ - uint8_t type; - int start = mock->mac ? 14 : 0; - if(start + 10 > len) { - return 0; - } - - memcpy(&type, buf + start + 9, 1); - return type; -} - -/* note : this function doesn't check if the IP header has any options */ -int mock_icmp_type(struct mock_device*mock, void*buf, int len) -{ - uint8_t type; - int start = mock->mac ? 14 : 0; - if(start + 21 > len) { - return 0; - } - - memcpy(&type, buf + start + 20, 1); - return type; -} - -/* note : this function doesn't check if the IP header has any options */ -int mock_icmp_code(struct mock_device*mock, void*buf, int len) -{ - uint8_t type; - int start = mock->mac ? 14 : 0; - if(start + 22 > len) { - return 0; - } - - memcpy(&type, buf + start + 21, 1); - return type; -} diff --git a/ext/picotcp/modules/pico_dev_mock.h b/ext/picotcp/modules/pico_dev_mock.h deleted file mode 100644 index dfc2cfc..0000000 --- a/ext/picotcp/modules/pico_dev_mock.h +++ /dev/null @@ -1,47 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_MOCK -#define INCLUDE_PICO_MOCK -#include "pico_config.h" -#include "pico_device.h" - - -struct mock_frame { - uint8_t*buffer; - int len; - int read; - - struct mock_frame*next; -}; - -struct mock_device { - struct pico_device*dev; - struct mock_frame*in_head; - struct mock_frame*in_tail; - struct mock_frame*out_head; - struct mock_frame*out_tail; - - uint8_t*mac; - -}; - -struct mock_device; -/* A mockup-device for the purpose of testing. It provides a couple of extra "network"-functions, which represent the network-side of the device. A network_send will result in mock_poll reading something, a network_read will see if the stack has sent anything through our mock-device. */ -void pico_mock_destroy(struct pico_device *dev); -struct mock_device *pico_mock_create(uint8_t*mac); - -int pico_mock_network_read(struct mock_device*mock, void *buf, int len); -int pico_mock_network_write(struct mock_device*mock, const void *buf, int len); - -/* TODO */ -/* we could use a few checking functions, e.g. one to see if it's a valid IP packet, if it's TCP, if the IP-address matches,... */ -/* That would be useful to avoid having to manually create buffers of what you expect, probably with masks for things that are random,... */ -uint32_t mock_get_sender_ip4(struct mock_device*mock, void*buf, int len); - -int mock_ip_protocol(struct mock_device*mock, void*buf, int len); -int mock_icmp_type(struct mock_device*mock, void*buf, int len); -int mock_icmp_code(struct mock_device*mock, void*buf, int len); -#endif diff --git a/ext/picotcp/modules/pico_dev_null.c b/ext/picotcp/modules/pico_dev_null.c deleted file mode 100644 index 5fed494..0000000 --- a/ext/picotcp/modules/pico_dev_null.c +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include "pico_device.h" -#include "pico_dev_null.h" -#include "pico_stack.h" - -struct pico_device_null { - struct pico_device dev; - int statistics_frames_out; -}; - -#define NULL_MTU 0 - -static int pico_null_send(struct pico_device *dev, void *buf, int len) -{ - struct pico_device_null *null = (struct pico_device_null *) dev; - IGNORE_PARAMETER(buf); - - /* Increase the statistic count */ - null->statistics_frames_out++; - - /* Discard the frame content silently. */ - return len; -} - -static int pico_null_poll(struct pico_device *dev, int loop_score) -{ - /* We never have packet to receive, no score is used. */ - IGNORE_PARAMETER(dev); - return loop_score; -} - -/* Public interface: create/destroy. */ - - -struct pico_device *pico_null_create(char *name) -{ - struct pico_device_null *null = PICO_ZALLOC(sizeof(struct pico_device_null)); - - if (!null) - return NULL; - - if( 0 != pico_device_init((struct pico_device *)null, name, NULL)) { - return NULL; - } - - null->dev.overhead = 0; - null->statistics_frames_out = 0; - null->dev.send = pico_null_send; - null->dev.poll = pico_null_poll; - dbg("Device %s created.\n", null->dev.name); - return (struct pico_device *)null; -} - diff --git a/ext/picotcp/modules/pico_dev_null.h b/ext/picotcp/modules/pico_dev_null.h deleted file mode 100644 index a0eb98e..0000000 --- a/ext/picotcp/modules/pico_dev_null.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_NULL -#define INCLUDE_PICO_NULL -#include "pico_config.h" -#include "pico_device.h" - -void pico_null_destroy(struct pico_device *null); -struct pico_device *pico_null_create(char *name); - -#endif - diff --git a/ext/picotcp/modules/pico_dev_pcap.c b/ext/picotcp/modules/pico_dev_pcap.c deleted file mode 100644 index f62fb14..0000000 --- a/ext/picotcp/modules/pico_dev_pcap.c +++ /dev/null @@ -1,96 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include -#include "pico_device.h" -#include "pico_dev_pcap.h" -#include "pico_stack.h" - -#include - -struct pico_device_pcap { - struct pico_device dev; - pcap_t *conn; -}; - -#define VDE_MTU 2048 - -static int pico_pcap_send(struct pico_device *dev, void *buf, int len) -{ - struct pico_device_pcap *pcap = (struct pico_device_pcap *) dev; - /* dbg("[%s] send %d bytes.\n", dev->name, len); */ - return pcap_inject(pcap->conn, buf, (uint32_t)len); -} - -static void pico_dev_pcap_cb(u_char *u, const struct pcap_pkthdr *h, const u_char *data) -{ - struct pico_device *dev = (struct pico_device *)u; - const uint8_t *buf = (const uint8_t *)data; - pico_stack_recv(dev, buf, (uint32_t)h->len); -} - - -static int pico_pcap_poll(struct pico_device *dev, int loop_score) -{ - struct pico_device_pcap *pcap = (struct pico_device_pcap *) dev; - loop_score -= pcap_dispatch(pcap->conn, loop_score, pico_dev_pcap_cb, (u_char *) pcap); - return loop_score; -} - -/* Public interface: create/destroy. */ - -void pico_pcap_destroy(struct pico_device *dev) -{ - struct pico_device_pcap *pcap = (struct pico_device_pcap *) dev; - pcap_close(pcap->conn); -} - -#define PICO_PCAP_MODE_LIVE 0 -#define PICO_PCAP_MODE_STORED 1 - -static struct pico_device *pico_pcap_create(char *if_file_name, char *name, uint8_t *mac, int mode) -{ - struct pico_device_pcap *pcap = PICO_ZALLOC(sizeof(struct pico_device_pcap)); - char errbuf[2000]; - if (!pcap) - return NULL; - - if( 0 != pico_device_init((struct pico_device *)pcap, name, mac)) { - dbg ("Pcap init failed.\n"); - pico_pcap_destroy((struct pico_device *)pcap); - return NULL; - } - - pcap->dev.overhead = 0; - - if (mode == PICO_PCAP_MODE_LIVE) - pcap->conn = pcap_open_live(if_file_name, 2000, 100, 10, errbuf); - else - pcap->conn = pcap_open_offline(if_file_name, errbuf); - - if (!pcap->conn) { - pico_pcap_destroy((struct pico_device *)pcap); - return NULL; - } - - pcap->dev.send = pico_pcap_send; - pcap->dev.poll = pico_pcap_poll; - pcap->dev.destroy = pico_pcap_destroy; - dbg("Device %s created.\n", pcap->dev.name); - return (struct pico_device *)pcap; -} - -struct pico_device *pico_pcap_create_fromfile(char *filename, char *name, uint8_t *mac) -{ - return pico_pcap_create(filename, name, mac, PICO_PCAP_MODE_STORED); -} - -struct pico_device *pico_pcap_create_live(char *ifname, char *name, uint8_t *mac) -{ - return pico_pcap_create(ifname, name, mac, PICO_PCAP_MODE_LIVE); -} diff --git a/ext/picotcp/modules/pico_dev_pcap.h b/ext/picotcp/modules/pico_dev_pcap.h deleted file mode 100644 index 887be27..0000000 --- a/ext/picotcp/modules/pico_dev_pcap.h +++ /dev/null @@ -1,19 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - - Author: Daniele Lacamera - *********************************************************************/ -#ifndef INCLUDE_PICO_PCAP -#define INCLUDE_PICO_PCAP -#include "pico_config.h" -#include "pico_device.h" -#include - -void pico_pcap_destroy(struct pico_device *pcap); -struct pico_device *pico_pcap_create_live(char *ifname, char *name, uint8_t *mac); -struct pico_device *pico_pcap_create_fromfile(char *filename, char *name, uint8_t *mac); - -#endif - diff --git a/ext/picotcp/modules/pico_dev_ppp.c b/ext/picotcp/modules/pico_dev_ppp.c deleted file mode 100644 index 8c67f19..0000000 --- a/ext/picotcp/modules/pico_dev_ppp.c +++ /dev/null @@ -1,2294 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Serge Gadeyne, Daniele Lacamera, Maxime Vincent - - *********************************************************************/ - - -#include -#include -#include - -#include "pico_device.h" -#include "pico_dev_ppp.h" -#include "pico_stack.h" -#include "pico_ipv4.h" -#include "pico_md5.h" -#include "pico_dns_client.h" - -#define ppp_dbg(...) do {} while(0) -/* #define ppp_dbg dbg */ - -/* We should define this in a global header. */ -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -#define PICO_PPP_MRU 1514 /* RFC default MRU */ -#define PICO_PPP_MTU 1500 -#define PPP_MAXPKT 2048 -#define PPP_MAX_APN 134 -#define PPP_MAX_USERNAME 134 -#define PPP_MAX_PASSWORD 134 -#define PPP_HDR_SIZE 3u -#define PPP_PROTO_SLOT_SIZE 2u -#define PPP_FCS_SIZE 2u -#define PPP_PROTO_LCP short_be(0xc021) -#define PPP_PROTO_IP short_be(0x0021) -#define PPP_PROTO_PAP short_be(0xc023) -#define PPP_PROTO_CHAP short_be(0xc223) -#define PPP_PROTO_IPCP short_be(0x8021) - -#define PICO_CONF_REQ 1 -#define PICO_CONF_ACK 2 -#define PICO_CONF_NAK 3 -#define PICO_CONF_REJ 4 -#define PICO_CONF_TERM 5 -#define PICO_CONF_TERM_ACK 6 -#define PICO_CONF_CODE_REJ 7 -#define PICO_CONF_PROTO_REJ 8 -#define PICO_CONF_ECHO_REQ 9 -#define PICO_CONF_ECHO_REP 10 -#define PICO_CONF_DISCARD_REQ 11 - -#define LCPOPT_MRU 1u /* param size: 4, fixed: MRU */ -#define LCPOPT_AUTH 3u /* param size: 4-5: AUTH proto */ -#define LCPOPT_QUALITY 4u /* unused for now */ -#define LCPOPT_MAGIC 5u /* param size: 6, fixed: Magic */ -#define LCPOPT_PROTO_COMP 7u /* param size: 0, flag */ -#define LCPOPT_ADDRCTL_COMP 8u /* param size: 0, flag */ - -#define CHAP_MD5_SIZE 16u -#define CHAP_CHALLENGE 1 -#define CHAP_RESPONSE 2 -#define CHAP_SUCCESS 3 -#define CHAP_FAILURE 4 -#define CHALLENGE_SIZE(ppp, ch) ((size_t)((1 + strlen(ppp->password) + short_be((ch)->len)))) - -#define PAP_AUTH_REQ 1 -#define PAP_AUTH_ACK 2 -#define PAP_AUTH_NAK 3 - - -#define PICO_PPP_DEFAULT_TIMER (3) /* seconds */ -#define PICO_PPP_DEFAULT_MAX_TERMINATE (2) -#define PICO_PPP_DEFAULT_MAX_CONFIGURE (10) -#define PICO_PPP_DEFAULT_MAX_FAILURE (5) -#define PICO_PPP_DEFAULT_MAX_DIALTIME (20) - -#define IPCP_ADDR_LEN 6u -#define IPCP_VJ_LEN 6u -#define IPCP_OPT_IP 0x03 -#define IPCP_OPT_VJ 0x02 -#define IPCP_OPT_DNS1 0x81 -#define IPCP_OPT_NBNS1 0x82 -#define IPCP_OPT_DNS2 0x83 -#define IPCP_OPT_NBNS2 0x84 - -static uint8_t LCPOPT_LEN[9] = { - 0, 4, 0, 4, 4, 6, 2, 2, 2 -}; - - -/* Protocol defines */ -static const unsigned char AT_S3 = 0x0du; -static const unsigned char AT_S4 = 0x0au; -static const unsigned char PPPF_FLAG_SEQ = 0x7eu; -static const unsigned char PPPF_CTRL_ESC = 0x7du; -static const unsigned char PPPF_ADDR = 0xffu; -static const unsigned char PPPF_CTRL = 0x03u; - -static int ppp_devnum = 0; -static uint8_t ppp_recv_buf[PPP_MAXPKT]; - -PACKED_STRUCT_DEF pico_lcp_hdr { - uint8_t code; - uint8_t id; - uint16_t len; -}; - -PACKED_STRUCT_DEF pico_chap_hdr { - uint8_t code; - uint8_t id; - uint16_t len; -}; - -PACKED_STRUCT_DEF pico_pap_hdr { - uint8_t code; - uint8_t id; - uint16_t len; -}; - -PACKED_STRUCT_DEF pico_ipcp_hdr { - uint8_t code; - uint8_t id; - uint16_t len; -}; - -#ifdef DEBUG_PPP -static int fifo_fd = -1; -#endif - -enum ppp_modem_state { - PPP_MODEM_STATE_INITIAL = 0, - PPP_MODEM_STATE_RESET, - PPP_MODEM_STATE_ECHO, - PPP_MODEM_STATE_CREG, - PPP_MODEM_STATE_CGREG, - PPP_MODEM_STATE_CGDCONT, - PPP_MODEM_STATE_CGATT, - PPP_MODEM_STATE_DIAL, - PPP_MODEM_STATE_CONNECTED, - PPP_MODEM_STATE_MAX -}; - -enum ppp_modem_event { - PPP_MODEM_EVENT_START = 0, - PPP_MODEM_EVENT_STOP, - PPP_MODEM_EVENT_OK, - PPP_MODEM_EVENT_CONNECT, - PPP_MODEM_EVENT_TIMEOUT, - PPP_MODEM_EVENT_MAX -}; - -enum ppp_lcp_state { - PPP_LCP_STATE_INITIAL = 0, - PPP_LCP_STATE_STARTING, - PPP_LCP_STATE_CLOSED, - PPP_LCP_STATE_STOPPED, - PPP_LCP_STATE_CLOSING, - PPP_LCP_STATE_STOPPING, - PPP_LCP_STATE_REQ_SENT, - PPP_LCP_STATE_ACK_RCVD, - PPP_LCP_STATE_ACK_SENT, - PPP_LCP_STATE_OPENED, - PPP_LCP_STATE_MAX -}; - -enum ppp_lcp_event { - PPP_LCP_EVENT_UP = 0, - PPP_LCP_EVENT_DOWN, - PPP_LCP_EVENT_OPEN, - PPP_LCP_EVENT_CLOSE, - PPP_LCP_EVENT_TO_POS, - PPP_LCP_EVENT_TO_NEG, - PPP_LCP_EVENT_RCR_POS, - PPP_LCP_EVENT_RCR_NEG, - PPP_LCP_EVENT_RCA, - PPP_LCP_EVENT_RCN, - PPP_LCP_EVENT_RTR, - PPP_LCP_EVENT_RTA, - PPP_LCP_EVENT_RUC, - PPP_LCP_EVENT_RXJ_POS, - PPP_LCP_EVENT_RXJ_NEG, - PPP_LCP_EVENT_RXR, - PPP_LCP_EVENT_MAX -}; - -enum ppp_auth_state { - PPP_AUTH_STATE_INITIAL = 0, - PPP_AUTH_STATE_STARTING, - PPP_AUTH_STATE_RSP_SENT, - PPP_AUTH_STATE_REQ_SENT, - PPP_AUTH_STATE_AUTHENTICATED, - PPP_AUTH_STATE_MAX -}; - -enum ppp_auth_event { - PPP_AUTH_EVENT_UP_NONE = 0, - PPP_AUTH_EVENT_UP_PAP, - PPP_AUTH_EVENT_UP_CHAP, - PPP_AUTH_EVENT_DOWN, - PPP_AUTH_EVENT_RAC, - PPP_AUTH_EVENT_RAA, - PPP_AUTH_EVENT_RAN, - PPP_AUTH_EVENT_TO, - PPP_AUTH_EVENT_MAX -}; - -enum ppp_ipcp_state { - PPP_IPCP_STATE_INITIAL = 0, - PPP_IPCP_STATE_REQ_SENT, - PPP_IPCP_STATE_ACK_RCVD, - PPP_IPCP_STATE_ACK_SENT, - PPP_IPCP_STATE_OPENED, - PPP_IPCP_STATE_MAX -}; - -enum ppp_ipcp_event { - PPP_IPCP_EVENT_UP = 0, - PPP_IPCP_EVENT_DOWN, - PPP_IPCP_EVENT_RCR_POS, - PPP_IPCP_EVENT_RCR_NEG, - PPP_IPCP_EVENT_RCA, - PPP_IPCP_EVENT_RCN, - PPP_IPCP_EVENT_TO, - PPP_IPCP_EVENT_MAX -}; - -enum pico_ppp_state { - PPP_MODEM_RST = 0, - PPP_MODEM_CREG, - PPP_MODEM_CGREG, - PPP_MODEM_CGDCONT, - PPP_MODEM_CGATT, - PPP_MODEM_CONNECT, - /* From here on, PPP states */ - PPP_ESTABLISH, - PPP_AUTH, - PPP_NETCONFIG, - PPP_NETWORK, - PPP_TERMINATE, - /* MAXSTATE is the last one */ - PPP_MODEM_MAXSTATE -}; - - -#define IPCP_ALLOW_IP 0x01u -#define IPCP_ALLOW_DNS1 0x02u -#define IPCP_ALLOW_DNS2 0x04u -#define IPCP_ALLOW_NBNS1 0x08u -#define IPCP_ALLOW_NBNS2 0x10u - -struct pico_device_ppp { - struct pico_device dev; - int autoreconnect; - enum ppp_modem_state modem_state; - enum ppp_lcp_state lcp_state; - enum ppp_auth_state auth_state; - enum ppp_ipcp_state ipcp_state; - enum pico_ppp_state state; - char apn[PPP_MAX_APN]; - char password[PPP_MAX_PASSWORD]; - char username[PPP_MAX_USERNAME]; - uint16_t lcpopt_local; - uint16_t lcpopt_peer; - uint8_t *pkt; - uint32_t len; - uint16_t rej; - uint16_t auth; - int (*serial_recv)(struct pico_device *dev, void *buf, int len); - int (*serial_send)(struct pico_device *dev, const void *buf, int len); - int (*serial_set_speed)(struct pico_device *dev, uint32_t speed); - uint32_t ipcp_allowed_fields; - uint32_t ipcp_ip; - uint32_t ipcp_dns1; - uint32_t ipcp_nbns1; - uint32_t ipcp_dns2; - uint32_t ipcp_nbns2; - uint32_t timer; - uint8_t timer_val; - uint8_t timer_count; - uint8_t frame_id; - uint8_t timer_on; - uint16_t mru; -}; - - -/* Unit test interceptor */ -static void (*mock_modem_state)(struct pico_device_ppp *ppp, enum ppp_modem_event event) = NULL; -static void (*mock_lcp_state)(struct pico_device_ppp *ppp, enum ppp_lcp_event event) = NULL; -static void (*mock_auth_state)(struct pico_device_ppp *ppp, enum ppp_auth_event event) = NULL; -static void (*mock_ipcp_state)(struct pico_device_ppp *ppp, enum ppp_ipcp_event event) = NULL; - -/* Debug prints */ -#ifdef PPP_DEBUG -static void lcp_optflags_print(struct pico_device_ppp *ppp, uint8_t *opts, uint32_t opts_len); -#endif - -#define PPP_TIMER_ON_MODEM 0x01u -#define PPP_TIMER_ON_LCPREQ 0x04u -#define PPP_TIMER_ON_LCPTERM 0x08u -#define PPP_TIMER_ON_AUTH 0x10u -#define PPP_TIMER_ON_IPCP 0x20u - -/* Escape and send */ -static int ppp_serial_send_escape(struct pico_device_ppp *ppp, void *buf, int len) -{ - uint8_t *in_buf = (uint8_t *)buf; - uint8_t *out_buf = NULL; - int esc_char_count = 0; - int newlen = 0, ret = -1; - int i, j; - -#ifdef PPP_DEBUG - { - uint32_t idx; - if (len > 0) { - ppp_dbg("PPP >>>> "); - for(idx = 0; idx < (uint32_t)len; idx++) { - ppp_dbg(" %02x", ((uint8_t *)buf)[idx]); - } - ppp_dbg("\n"); - } - } -#endif - - for (i = 1; i < (len - 1); i++) /* from 1 to len -1, as start/stop are not escaped */ - { - if (((in_buf[i] + 1u) >> 1) == 0x3Fu) - esc_char_count++; - } - if (!esc_char_count) { - return ppp->serial_send(&ppp->dev, buf, len); - } - - newlen = len + esc_char_count; - out_buf = PICO_ZALLOC((uint32_t)newlen); - if(!out_buf) - return -1; - - /* Start byte. */ - out_buf[0] = in_buf[0]; - for(i = 1, j = 1; i < (len - 1); i++) { - if (((in_buf[i] + 1u) >> 1) == 0x3Fu) { - out_buf[j++] = PPPF_CTRL_ESC; - out_buf[j++] = in_buf[i] ^ 0x20; - } else { - out_buf[j++] = in_buf[i]; - } - } - /* Stop byte. */ - out_buf[newlen - 1] = in_buf[len - 1]; - - ret = ppp->serial_send(&ppp->dev, out_buf, newlen); - - PICO_FREE(out_buf); - - if (ret == newlen) - return len; - - return ret; - -} - -static void lcp_timer_start(struct pico_device_ppp *ppp, uint8_t timer_type) -{ - uint8_t count = 0; - ppp->timer_on |= timer_type; - - if (ppp->timer_val == 0) { - ppp->timer_val = PICO_PPP_DEFAULT_TIMER; - } - - if (timer_type == PPP_TIMER_ON_LCPTERM) { - count = PICO_PPP_DEFAULT_MAX_TERMINATE; - } - - if (timer_type == PPP_TIMER_ON_LCPREQ) { - count = PICO_PPP_DEFAULT_MAX_CONFIGURE; - } - - if (timer_type == 0) { - ppp->timer_on |= PPP_TIMER_ON_LCPREQ; - ppp->timer_count = 0; - } - - if (ppp->timer_count == 0) - ppp->timer_count = count; -} - -static void lcp_zero_restart_count(struct pico_device_ppp *ppp) -{ - lcp_timer_start(ppp, 0); -} - -static void lcp_timer_stop(struct pico_device_ppp *ppp, uint8_t timer_type) -{ - ppp->timer_on = (uint8_t)ppp->timer_on & (uint8_t)(~timer_type); -} - - -#define PPP_FSM_MAX_ACTIONS 3 - -struct pico_ppp_fsm { - int next_state; - void (*event_handler[PPP_FSM_MAX_ACTIONS]) (struct pico_device_ppp *); -}; - -#define LCPOPT_SET_LOCAL(ppp, opt) ppp->lcpopt_local |= (uint16_t)(1u << opt) -#define LCPOPT_SET_PEER(ppp, opt) ppp->lcpopt_peer |= (uint16_t)(1u << opt) -#define LCPOPT_UNSET_LOCAL(ppp, opt) ppp->lcpopt_local &= (uint16_t)~(1u << opt) -#define LCPOPT_UNSET_LOCAL_MASK(ppp, opt) ppp->lcpopt_local &= (uint16_t)~(opt) -#define LCPOPT_UNSET_PEER(ppp, opt) ppp->lcpopt_peer &= (uint16_t)~(1u << opt) -#define LCPOPT_ISSET_LOCAL(ppp, opt) ((ppp->lcpopt_local & (uint16_t)(1u << opt)) != 0) -#define LCPOPT_ISSET_PEER(ppp, opt) ((ppp->lcpopt_peer & (uint16_t)(1u << opt)) != 0) - -static void evaluate_modem_state(struct pico_device_ppp *ppp, enum ppp_modem_event event); -static void evaluate_lcp_state(struct pico_device_ppp *ppp, enum ppp_lcp_event event); -static void evaluate_auth_state(struct pico_device_ppp *ppp, enum ppp_auth_event event); -static void evaluate_ipcp_state(struct pico_device_ppp *ppp, enum ppp_ipcp_event event); - - -static uint32_t ppp_ctl_packet_size(struct pico_device_ppp *ppp, uint16_t proto, uint32_t *size) -{ - uint32_t prefix = 0; - - IGNORE_PARAMETER(ppp); - IGNORE_PARAMETER(proto); - - prefix += PPP_HDR_SIZE; /* 7e ff 03 ... */ - prefix += PPP_PROTO_SLOT_SIZE; - *size += prefix; - *size += PPP_FCS_SIZE; - (*size)++; /* STOP byte 0x7e */ - return prefix; -} - -/* CRC16 / FCS Calculation */ -static uint16_t ppp_fcs_char(uint16_t old_crc, uint8_t data) -{ - uint16_t word = (old_crc ^ data) & (uint16_t)0x00FFu; - word = (uint16_t)(word ^ (uint16_t)((word << 4u) & (uint16_t)0x00FFu)); - word = (uint16_t)((word << 8u) ^ (word << 3u) ^ (word >> 4u)); - return ((old_crc >> 8u) ^ word); -} - -static uint16_t ppp_fcs_continue(uint16_t fcs, uint8_t *buf, uint32_t len) -{ - uint8_t *pos = buf; - for (pos = buf; pos < buf + len; pos++) - { - fcs = ppp_fcs_char(fcs, *pos); - } - return fcs; -} - -static uint16_t ppp_fcs_finish(uint16_t fcs) -{ - return fcs ^ 0xFFFF; -} - -static uint16_t ppp_fcs_start(uint8_t *buf, uint32_t len) -{ - uint16_t fcs = 0xFFFF; - return ppp_fcs_continue(fcs, buf, len); -} - -static int ppp_fcs_verify(uint8_t *buf, uint32_t len) -{ - uint16_t fcs = ppp_fcs_start(buf, len - 2); - fcs = ppp_fcs_finish(fcs); - if ((((fcs & 0xFF00u) >> 8) != buf[len - 1]) || ((fcs & 0xFFu) != buf[len - 2])) { - return -1; - } - - return 0; -} - -/* Serial send (DTE->DCE) functions */ -static int pico_ppp_ctl_send(struct pico_device *dev, uint16_t code, uint8_t *pkt, uint32_t len) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *) dev; - uint16_t fcs; - uint8_t *ptr = pkt; - int i = 0; - - if (!ppp->serial_send) - return (int)len; - - /* PPP Header */ - ptr[i++] = PPPF_FLAG_SEQ; - ptr[i++] = PPPF_ADDR; - ptr[i++] = PPPF_CTRL; - /* protocol */ - ptr[i++] = (uint8_t)(code & 0xFFu); - ptr[i++] = (uint8_t)((code & 0xFF00u) >> 8); - - /* payload is already in place. Calculate FCS. */ - fcs = ppp_fcs_start(pkt + 1, len - 4); /* FCS excludes: start (1), FCS(2), stop(1), total 4 bytes */ - fcs = ppp_fcs_finish(fcs); - pkt[len - 3] = (uint8_t)(fcs & 0xFFu); - pkt[len - 2] = (uint8_t)((fcs & 0xFF00u) >> 8); - pkt[len - 1] = PPPF_FLAG_SEQ; - ppp_serial_send_escape(ppp, pkt, (int)len); - return (int)len; -} - -static uint8_t pico_ppp_data_buffer[PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + PICO_PPP_MTU + PPP_FCS_SIZE + 1]; -static int pico_ppp_send(struct pico_device *dev, void *buf, int len) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *) dev; - uint16_t fcs = 0; - int fcs_start; - int i = 0; - - ppp_dbg(" >>>>>>>>> PPP OUT\n"); - - if (ppp->ipcp_state != PPP_IPCP_STATE_OPENED) - return len; - - if (!ppp->serial_send) - return len; - - pico_ppp_data_buffer[i++] = PPPF_FLAG_SEQ; - if (!LCPOPT_ISSET_PEER(ppp, LCPOPT_ADDRCTL_COMP)) - { - pico_ppp_data_buffer[i++] = PPPF_ADDR; - pico_ppp_data_buffer[i++] = PPPF_CTRL; - } - - fcs_start = i; - - if (!LCPOPT_ISSET_PEER(ppp, LCPOPT_PROTO_COMP)) - { - pico_ppp_data_buffer[i++] = 0x00; - } - - pico_ppp_data_buffer[i++] = 0x21; - memcpy(pico_ppp_data_buffer + i, buf, (uint32_t)len); - i += len; - fcs = ppp_fcs_start(pico_ppp_data_buffer + fcs_start, (uint32_t)(i - fcs_start)); - fcs = ppp_fcs_finish(fcs); - pico_ppp_data_buffer[i++] = (uint8_t)(fcs & 0xFFu); - pico_ppp_data_buffer[i++] = (uint8_t)((fcs & 0xFF00u) >> 8); - pico_ppp_data_buffer[i++] = PPPF_FLAG_SEQ; - - ppp_serial_send_escape(ppp, pico_ppp_data_buffer, i); - return len; -} - - -/* FSM functions */ - -static void ppp_modem_start_timer(struct pico_device_ppp *ppp) -{ - ppp->timer_on = ppp->timer_on | PPP_TIMER_ON_MODEM; - ppp->timer_val = PICO_PPP_DEFAULT_TIMER; -} - -#define PPP_AT_CREG0 "ATZ\r\n" -static void ppp_modem_send_reset(struct pico_device_ppp *ppp) -{ - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_AT_CREG0, strlen(PPP_AT_CREG0)); - - ppp_modem_start_timer(ppp); -} - -#define PPP_AT_CREG1 "ATE0\r\n" -static void ppp_modem_send_echo(struct pico_device_ppp *ppp) -{ - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_AT_CREG1, strlen(PPP_AT_CREG1)); - - ppp_modem_start_timer(ppp); -} - -#define PPP_AT_CREG2 "AT+CREG=1\r\n" -static void ppp_modem_send_creg(struct pico_device_ppp *ppp) -{ - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_AT_CREG2, strlen(PPP_AT_CREG2)); - - ppp_modem_start_timer(ppp); -} - -#define PPP_AT_CGREG "AT+CGREG=1\r\n" -static void ppp_modem_send_cgreg(struct pico_device_ppp *ppp) -{ - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_AT_CGREG, strlen(PPP_AT_CGREG)); - - ppp_modem_start_timer(ppp); -} - - -#define PPP_AT_CGDCONT "AT+CGDCONT=1,\"IP\",\"%s\",,,\r\n" -static void ppp_modem_send_cgdcont(struct pico_device_ppp *ppp) -{ - char at_cgdcont[200]; - - if (ppp->serial_send) { - snprintf(at_cgdcont, 200, PPP_AT_CGDCONT, ppp->apn); - ppp->serial_send(&ppp->dev, at_cgdcont, (int)strlen(at_cgdcont)); - } - - ppp_modem_start_timer(ppp); -} - - -#define PPP_AT_CGATT "AT+CGATT=1\r\n" -static void ppp_modem_send_cgatt(struct pico_device_ppp *ppp) -{ - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_AT_CGATT, strlen(PPP_AT_CGATT)); - - ppp_modem_start_timer(ppp); -} - -#ifdef PICOTCP_PPP_SUPPORT_QUERIES -#define PPP_AT_CGATT_Q "AT+CGATT?\r\n" -static void ppp_modem_send_cgatt_q(struct pico_device_ppp *ppp) -{ - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_AT_CGATT_Q, strlen(PPP_AT_CGATT_Q)); - - ppp_modem_start_timer(ppp); -} -#define PPP_AT_CGDCONT_Q "AT+CGDCONT?\r\n" -static void ppp_modem_send_cgdcont_q(struct pico_device_ppp *ppp) -{ - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_AT_CGDCONT_Q, strlen(PPP_AT_CGDCONT_Q)); - - ppp_modem_start_timer(ppp); -} - -#define PPP_AT_CGREG_Q "AT+CGREG?\r\n" -static void ppp_modem_send_cgreg_q(struct pico_device_ppp *ppp) -{ - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_AT_CGREG_Q, strlen(PPP_AT_CGREG_Q)); - - ppp_modem_start_timer(ppp); -} - -#define PPP_AT_CREG3 "AT+CREG?\r\n" -static void ppp_modem_send_creg_q(struct pico_device_ppp *ppp) -{ - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_AT_CREG3, strlen(PPP_AT_CREG3)); - - ppp_modem_start_timer(ppp); -} -#endif /* PICOTCP_PPP_SUPPORT_QUERIES */ - -#define PPP_AT_DIALIN "ATD*99***1#\r\n" -static void ppp_modem_send_dial(struct pico_device_ppp *ppp) -{ - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_AT_DIALIN, strlen(PPP_AT_DIALIN)); - - ppp_modem_start_timer(ppp); - ppp->timer_val = PICO_PPP_DEFAULT_MAX_DIALTIME; -} - -static void ppp_modem_connected(struct pico_device_ppp *ppp) -{ - ppp_dbg("PPP: Modem connected to peer.\n"); - evaluate_lcp_state(ppp, PPP_LCP_EVENT_UP); -} - -#define PPP_ATH "+++ATH\r\n" -static void ppp_modem_disconnected(struct pico_device_ppp *ppp) -{ - ppp_dbg("PPP: Modem disconnected.\n"); - if (ppp->serial_send) - ppp->serial_send(&ppp->dev, PPP_ATH, strlen(PPP_ATH)); - - evaluate_lcp_state(ppp, PPP_LCP_EVENT_DOWN); -} - -static const struct pico_ppp_fsm ppp_modem_fsm[PPP_MODEM_STATE_MAX][PPP_MODEM_EVENT_MAX] = { - [PPP_MODEM_STATE_INITIAL] = { - [PPP_MODEM_EVENT_START] = { PPP_MODEM_STATE_RESET, {ppp_modem_send_reset} }, - [PPP_MODEM_EVENT_STOP] = { PPP_MODEM_STATE_INITIAL, {} }, - [PPP_MODEM_EVENT_OK] = { PPP_MODEM_STATE_INITIAL, {} }, - [PPP_MODEM_EVENT_CONNECT] = { PPP_MODEM_STATE_INITIAL, {} }, - [PPP_MODEM_EVENT_TIMEOUT] = { PPP_MODEM_STATE_INITIAL, {ppp_modem_send_reset} } - }, - [PPP_MODEM_STATE_RESET] = { - [PPP_MODEM_EVENT_START] = { PPP_MODEM_STATE_RESET, {} }, - [PPP_MODEM_EVENT_STOP] = { PPP_MODEM_STATE_INITIAL, {} }, - [PPP_MODEM_EVENT_OK] = { PPP_MODEM_STATE_ECHO, { ppp_modem_send_echo } }, - [PPP_MODEM_EVENT_CONNECT] = { PPP_MODEM_STATE_RESET, {} }, - [PPP_MODEM_EVENT_TIMEOUT] = { PPP_MODEM_STATE_RESET, {ppp_modem_send_reset} } - }, - [PPP_MODEM_STATE_ECHO] = { - [PPP_MODEM_EVENT_START] = { PPP_MODEM_STATE_ECHO, {} }, - [PPP_MODEM_EVENT_STOP] = { PPP_MODEM_STATE_INITIAL, {} }, - [PPP_MODEM_EVENT_OK] = { PPP_MODEM_STATE_CREG, { ppp_modem_send_creg } }, - [PPP_MODEM_EVENT_CONNECT] = { PPP_MODEM_STATE_ECHO, {} }, - [PPP_MODEM_EVENT_TIMEOUT] = { PPP_MODEM_STATE_RESET, {ppp_modem_send_reset} } - }, - [PPP_MODEM_STATE_CREG] = { - [PPP_MODEM_EVENT_START] = { PPP_MODEM_STATE_CREG, {} }, - [PPP_MODEM_EVENT_STOP] = { PPP_MODEM_STATE_INITIAL, {} }, - [PPP_MODEM_EVENT_OK] = { PPP_MODEM_STATE_CGREG, { ppp_modem_send_cgreg } }, - [PPP_MODEM_EVENT_CONNECT] = { PPP_MODEM_STATE_CREG, {} }, - [PPP_MODEM_EVENT_TIMEOUT] = { PPP_MODEM_STATE_RESET, {ppp_modem_send_reset} } - }, - [PPP_MODEM_STATE_CGREG] = { - [PPP_MODEM_EVENT_START] = { PPP_MODEM_STATE_CGREG, {} }, - [PPP_MODEM_EVENT_STOP] = { PPP_MODEM_STATE_INITIAL, {} }, - [PPP_MODEM_EVENT_OK] = { PPP_MODEM_STATE_CGDCONT, { ppp_modem_send_cgdcont } }, - [PPP_MODEM_EVENT_CONNECT] = { PPP_MODEM_STATE_CGREG, {} }, - [PPP_MODEM_EVENT_TIMEOUT] = { PPP_MODEM_STATE_RESET, {ppp_modem_send_reset} } - }, - [PPP_MODEM_STATE_CGDCONT] = { - [PPP_MODEM_EVENT_START] = { PPP_MODEM_STATE_CGDCONT, {} }, - [PPP_MODEM_EVENT_STOP] = { PPP_MODEM_STATE_INITIAL, {} }, - [PPP_MODEM_EVENT_OK] = { PPP_MODEM_STATE_CGATT, { ppp_modem_send_cgatt } }, - [PPP_MODEM_EVENT_CONNECT] = { PPP_MODEM_STATE_CGDCONT, {} }, - [PPP_MODEM_EVENT_TIMEOUT] = { PPP_MODEM_STATE_RESET, {ppp_modem_send_reset} } - }, - [PPP_MODEM_STATE_CGATT] = { - [PPP_MODEM_EVENT_START] = { PPP_MODEM_STATE_CGATT, {} }, - [PPP_MODEM_EVENT_STOP] = { PPP_MODEM_STATE_INITIAL, {} }, - [PPP_MODEM_EVENT_OK] = { PPP_MODEM_STATE_DIAL, { ppp_modem_send_dial } }, - [PPP_MODEM_EVENT_CONNECT] = { PPP_MODEM_STATE_CGATT, {} }, - [PPP_MODEM_EVENT_TIMEOUT] = { PPP_MODEM_STATE_RESET, {ppp_modem_send_reset} } - }, - [PPP_MODEM_STATE_DIAL] = { - [PPP_MODEM_EVENT_START] = { PPP_MODEM_STATE_DIAL, {} }, - [PPP_MODEM_EVENT_STOP] = { PPP_MODEM_STATE_INITIAL, {} }, - [PPP_MODEM_EVENT_OK] = { PPP_MODEM_STATE_DIAL, {} }, - [PPP_MODEM_EVENT_CONNECT] = { PPP_MODEM_STATE_CONNECTED, { ppp_modem_connected } }, - [PPP_MODEM_EVENT_TIMEOUT] = { PPP_MODEM_STATE_RESET, {ppp_modem_send_reset} } - }, - [PPP_MODEM_STATE_CONNECTED] = { - [PPP_MODEM_EVENT_START] = { PPP_MODEM_STATE_CONNECTED, {} }, - [PPP_MODEM_EVENT_STOP] = { PPP_MODEM_STATE_INITIAL, { ppp_modem_disconnected } }, - [PPP_MODEM_EVENT_OK] = { PPP_MODEM_STATE_CONNECTED, {} }, - [PPP_MODEM_EVENT_CONNECT] = { PPP_MODEM_STATE_CONNECTED, {} }, - [PPP_MODEM_EVENT_TIMEOUT] = { PPP_MODEM_STATE_CONNECTED, {} } - } -}; -static void evaluate_modem_state(struct pico_device_ppp *ppp, enum ppp_modem_event event) -{ - const struct pico_ppp_fsm *fsm; - int i; - if (mock_modem_state) { - mock_modem_state(ppp, event); - return; - } - - fsm = &ppp_modem_fsm[ppp->modem_state][event]; - - ppp->modem_state = (enum ppp_modem_state)fsm->next_state; - - for (i = 0; i < PPP_FSM_MAX_ACTIONS; i++) { - if (fsm->event_handler[i]) - fsm->event_handler[i](ppp); - } -} - -static void ppp_modem_recv(struct pico_device_ppp *ppp, void *data, uint32_t len) -{ - IGNORE_PARAMETER(len); - - ppp_dbg("PPP: Recv: '%s'\n", (char *)data); - - if (strcmp(data, "OK") == 0) { - evaluate_modem_state(ppp, PPP_MODEM_EVENT_OK); - } - - if (strcmp(data, "ERROR") == 0) { - evaluate_modem_state(ppp, PPP_MODEM_EVENT_STOP); - } - - if (strncmp(data, "CONNECT", 7) == 0) { - evaluate_modem_state(ppp, PPP_MODEM_EVENT_CONNECT); - } -} - -static void lcp_send_configure_request(struct pico_device_ppp *ppp) -{ -# define MY_LCP_REQ_SIZE 12 /* Max value. */ - struct pico_lcp_hdr *req; - uint8_t *lcpbuf, *opts; - uint32_t size = MY_LCP_REQ_SIZE; - uint32_t prefix; - uint32_t optsize = 0; - - prefix = ppp_ctl_packet_size(ppp, PPP_PROTO_LCP, &size); - lcpbuf = PICO_ZALLOC(size); - if (!lcpbuf) - return; - - req = (struct pico_lcp_hdr *)(lcpbuf + prefix); - - opts = lcpbuf + prefix + (sizeof(struct pico_lcp_hdr)); - /* uint8_t my_pkt[] = { 0x7e, 0xff, 0x03, 0xc0, 0x21, 0x01, 0x00, 0x00, 0x06, 0x07, 0x02, 0x64, 0x7b, 0x7e }; */ - - ppp_dbg("Sending LCP CONF REQ\n"); - req->code = PICO_CONF_REQ; - req->id = ppp->frame_id++; - - if (LCPOPT_ISSET_LOCAL(ppp, LCPOPT_PROTO_COMP)) { - opts[optsize++] = LCPOPT_PROTO_COMP; - opts[optsize++] = LCPOPT_LEN[LCPOPT_PROTO_COMP]; - } - - if (LCPOPT_ISSET_LOCAL(ppp, LCPOPT_MRU)) { - opts[optsize++] = LCPOPT_MRU; - opts[optsize++] = LCPOPT_LEN[LCPOPT_MRU]; - opts[optsize++] = (uint8_t)((ppp->mru >> 8) & 0xFF); - opts[optsize++] = (uint8_t)(ppp->mru & 0xFF); - } else { - ppp->mru = PICO_PPP_MRU; - } - - if (LCPOPT_ISSET_LOCAL(ppp, LCPOPT_ADDRCTL_COMP)) { - opts[optsize++] = LCPOPT_ADDRCTL_COMP; - opts[optsize++] = LCPOPT_LEN[LCPOPT_ADDRCTL_COMP]; - } - - req->len = short_be((uint16_t)((unsigned long)optsize + sizeof(struct pico_lcp_hdr))); - -#ifdef PPP_DEBUG - lcp_optflags_print(ppp, opts, optsize); -#endif - - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_LCP, - lcpbuf, /* Start of PPP packet */ - (uint32_t)(prefix + /* PPP Header, etc. */ - sizeof(struct pico_lcp_hdr) + /* LCP HDR */ - optsize + /* Actual options size */ - PPP_FCS_SIZE + /* FCS at the end of the frame */ - 1u) /* STOP Byte */ - ); - PICO_FREE(lcpbuf); - ppp->timer_val = PICO_PPP_DEFAULT_TIMER; - lcp_timer_start(ppp, PPP_TIMER_ON_LCPREQ); -} - -#ifdef PPP_DEBUG -static void lcp_optflags_print(struct pico_device_ppp *ppp, uint8_t *opts, uint32_t opts_len) -{ - uint8_t *p = opts; - int off; - IGNORE_PARAMETER(ppp); - ppp_dbg("Parsing options:\n"); - while(p < (opts + opts_len)) { - int i; - - ppp_dbg("-- LCP opt: %d - len: %d - data:", p[0], p[1]); - for (i=0; imru = (uint16_t)((p[2] << 8) + p[3]); - break; - case LCPOPT_AUTH: - ppp_dbg("Setting AUTH to %02x%02x\n", p[2], p[3]); - ppp->auth = (uint16_t)((p[2] << 8) + p[3]); - break; - default: - break; - } - } - - off = p[1]; /* opt length field */ - if (!off) - break; - - p += off; - } -#ifdef PPP_DEBUG - lcp_optflags_print(ppp, pkt + sizeof(struct pico_lcp_hdr), (uint32_t)(len - sizeof(struct pico_lcp_hdr)) ); -#endif - return flags; -} - - -static void lcp_send_configure_ack(struct pico_device_ppp *ppp) -{ - uint8_t ack[ppp->len + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_lcp_hdr) + PPP_FCS_SIZE + 1]; - struct pico_lcp_hdr *ack_hdr = (struct pico_lcp_hdr *) (ack + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE); - struct pico_lcp_hdr *lcpreq = (struct pico_lcp_hdr *)ppp->pkt; - memcpy(ack + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE, ppp->pkt, ppp->len); - ack_hdr->code = PICO_CONF_ACK; - ack_hdr->id = lcpreq->id; - ack_hdr->len = lcpreq->len; - ppp_dbg("Sending LCP CONF ACK\n"); - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_LCP, ack, - PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */ - short_be(lcpreq->len) + /* Actual options size + hdr (whole lcp packet) */ - PPP_FCS_SIZE + /* FCS at the end of the frame */ - 1 /* STOP Byte */ - ); -} - -static void lcp_send_terminate_request(struct pico_device_ppp *ppp) -{ - uint8_t term[PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_lcp_hdr) + PPP_FCS_SIZE + 1]; - struct pico_lcp_hdr *term_hdr = (struct pico_lcp_hdr *) (term + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE); - term_hdr->code = PICO_CONF_TERM; - term_hdr->id = ppp->frame_id++; - term_hdr->len = short_be((uint16_t)sizeof(struct pico_lcp_hdr)); - ppp_dbg("Sending LCP TERMINATE REQUEST\n"); - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_LCP, term, - PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */ - sizeof(struct pico_lcp_hdr) + /* Actual options size + hdr (whole lcp packet) */ - PPP_FCS_SIZE + /* FCS at the end of the frame */ - 1 /* STOP Byte */ - ); - lcp_timer_start(ppp, PPP_TIMER_ON_LCPTERM); -} - -static void lcp_send_terminate_ack(struct pico_device_ppp *ppp) -{ - uint8_t ack[ppp->len + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_lcp_hdr) + PPP_FCS_SIZE + 1]; - struct pico_lcp_hdr *ack_hdr = (struct pico_lcp_hdr *) (ack + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE); - struct pico_lcp_hdr *lcpreq = (struct pico_lcp_hdr *)ppp->pkt; - memcpy(ack + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE, ppp->pkt, ppp->len); - ack_hdr->code = PICO_CONF_TERM_ACK; - ack_hdr->id = lcpreq->id; - ack_hdr->len = lcpreq->len; - ppp_dbg("Sending LCP TERM ACK\n"); - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_LCP, ack, - PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */ - short_be(lcpreq->len) + /* Actual options size + hdr (whole lcp packet) */ - PPP_FCS_SIZE + /* FCS at the end of the frame */ - 1 /* STOP Byte */ - ); -} - -static void lcp_send_configure_nack(struct pico_device_ppp *ppp) -{ - uint8_t reject[64]; - uint8_t *p = ppp->pkt + sizeof(struct pico_lcp_hdr); - struct pico_lcp_hdr *lcpreq = (struct pico_lcp_hdr *)ppp->pkt; - struct pico_lcp_hdr *lcprej = (struct pico_lcp_hdr *)(reject + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE); - uint8_t *dst_opts = reject + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_lcp_hdr); - uint32_t dstopts_len = 0; - ppp_dbg("CONF_NACK: rej = %04X\n", ppp->rej); - while (p < (ppp->pkt + ppp->len)) { - uint8_t i = 0; - if ((1u << p[0]) & ppp->rej || (p[0] > 8u)) { /* Reject anything we dont support or with option id >8 */ - ppp_dbg("rejecting option %d -- ", p[0]); - dst_opts[dstopts_len++] = p[0]; - - ppp_dbg("len: %d -- ", p[1]); - dst_opts[dstopts_len++] = p[1]; - - ppp_dbg("data: "); - for(i = 0; i < p[1]-2u; i++) { /* length includes type, length and data fields */ - dst_opts[dstopts_len++] = p[2 + i]; - ppp_dbg("%02X ", p[2+i]); - } - ppp_dbg("\n"); - } - - p += p[1]; - } - lcprej->code = PICO_CONF_REJ; - lcprej->id = lcpreq->id; - lcprej->len = short_be((uint16_t)(dstopts_len + sizeof(struct pico_lcp_hdr))); - - ppp_dbg("Sending LCP CONF REJ\n"); -#ifdef PPP_DEBUG - lcp_optflags_print(ppp, dst_opts, dstopts_len); -#endif - - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_LCP, reject, - (uint32_t)(PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */ - sizeof(struct pico_lcp_hdr) + /* LCP HDR */ - dstopts_len + /* Actual options size */ - PPP_FCS_SIZE + /* FCS at the end of the frame */ - 1u) /* STOP Byte */ - ); -} - -static void lcp_process_in(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len) -{ - uint16_t optflags; - if (!ppp) - return; - if (pkt[0] == PICO_CONF_REQ) { - uint16_t rejected = 0; - ppp_dbg("Received LCP CONF REQ\n"); - optflags = lcp_optflags(ppp, pkt, len, 1u); - rejected = (uint16_t)(optflags & (~ppp->lcpopt_local)); - ppp->pkt = pkt; - ppp->len = len; - ppp->rej = rejected; - if (rejected) { - evaluate_lcp_state(ppp, PPP_LCP_EVENT_RCR_NEG); - } else { - ppp->lcpopt_peer = optflags; - evaluate_lcp_state(ppp, PPP_LCP_EVENT_RCR_POS); - } - - return; - } - - if (pkt[0] == PICO_CONF_ACK) { - ppp_dbg("Received LCP CONF ACK\nOptflags: %04x\n", lcp_optflags(NULL, pkt, len, 0u)); - evaluate_lcp_state(ppp, PPP_LCP_EVENT_RCA); - return; - } - - if (pkt[0] == PICO_CONF_NAK) { - /* Every instance of the received Configuration Options is recognizable, but some values are not acceptable */ - optflags = lcp_optflags(ppp, pkt, len, 1u); /* We want our options adjusted */ - ppp_dbg("Received LCP CONF NAK - changed optflags: %04X\n", optflags); - evaluate_lcp_state(ppp, PPP_LCP_EVENT_RCN); - return; - } - - if (pkt[0] == PICO_CONF_REJ) { - /* Some Configuration Options received in a Configure-Request are not recognizable or are not acceptable for negotiation */ - optflags = lcp_optflags(ppp, pkt, len, 0u); - ppp_dbg("Received LCP CONF REJ - will disable optflags: %04X\n", optflags); - /* Disable the options that are not supported by the peer */ - LCPOPT_UNSET_LOCAL_MASK(ppp, optflags); - evaluate_lcp_state(ppp, PPP_LCP_EVENT_RCN); - return; - } - - if (pkt[0] == PICO_CONF_ECHO_REQ) { - ppp_dbg("Received LCP ECHO REQ\n"); - evaluate_lcp_state(ppp, PPP_LCP_EVENT_RXR); - return; - } -} - -static void pap_process_in(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len) -{ - struct pico_pap_hdr *p = (struct pico_pap_hdr *)pkt; - (void)len; - if (!p) - return; - - if (ppp->auth != 0xc023) - return; - - switch(p->code) { - case PAP_AUTH_ACK: - ppp_dbg("PAP: Received Authentication OK!\n"); - evaluate_auth_state(ppp, PPP_AUTH_EVENT_RAA); - break; - case PAP_AUTH_NAK: - ppp_dbg("PAP: Received Authentication Reject!\n"); - evaluate_auth_state(ppp, PPP_AUTH_EVENT_RAN); - break; - - default: - ppp_dbg("PAP: Received invalid packet with code %d\n", p->code); - } -} - - -static void chap_process_in(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len) -{ - struct pico_chap_hdr *ch = (struct pico_chap_hdr *)pkt; - - if (!pkt) - return; - - if (ppp->auth != 0xc223) - return; - - switch(ch->code) { - case CHAP_CHALLENGE: - ppp_dbg("Received CHAP CHALLENGE\n"); - ppp->pkt = pkt; - ppp->len = len; - evaluate_auth_state(ppp, PPP_AUTH_EVENT_RAC); - break; - case CHAP_SUCCESS: - ppp_dbg("Received CHAP SUCCESS\n"); - evaluate_auth_state(ppp, PPP_AUTH_EVENT_RAA); - break; - case CHAP_FAILURE: - ppp_dbg("Received CHAP FAILURE\n"); - evaluate_auth_state(ppp, PPP_AUTH_EVENT_RAN); - break; - } -} - - -static void ipcp_send_ack(struct pico_device_ppp *ppp) -{ - uint8_t ack[ppp->len + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_lcp_hdr) + PPP_FCS_SIZE + 1]; - struct pico_ipcp_hdr *ack_hdr = (struct pico_ipcp_hdr *) (ack + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE); - struct pico_ipcp_hdr *ipcpreq = (struct pico_ipcp_hdr *)ppp->pkt; - memcpy(ack + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE, ppp->pkt, ppp->len); - ack_hdr->code = PICO_CONF_ACK; - ack_hdr->id = ipcpreq->id; - ack_hdr->len = ipcpreq->len; - ppp_dbg("Sending IPCP CONF ACK\n"); - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_IPCP, ack, - PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */ - short_be(ipcpreq->len) + /* Actual options size + hdr (whole ipcp packet) */ - PPP_FCS_SIZE + /* FCS at the end of the frame */ - 1 /* STOP Byte */ - ); -} - -static inline uint32_t ipcp_request_options_size(struct pico_device_ppp *ppp) -{ - uint32_t size = 0; - -/* if (ppp->ipcp_ip) */ - size += IPCP_ADDR_LEN; -/* if (ppp->ipcp_dns1) */ - size += IPCP_ADDR_LEN; -/* if (ppp->ipcp_dns2) */ - size += IPCP_ADDR_LEN; - if (ppp->ipcp_nbns1) - size += IPCP_ADDR_LEN; - - if (ppp->ipcp_nbns2) - size += IPCP_ADDR_LEN; - - return size; -} - -static int ipcp_request_add_address(uint8_t *dst, uint8_t tag, uint32_t arg) -{ - uint32_t addr = long_be(arg); - dst[0] = tag; - dst[1] = IPCP_ADDR_LEN; - dst[2] = (uint8_t)((addr & 0xFF000000u) >> 24); - dst[3] = (uint8_t)((addr & 0x00FF0000u) >> 16); - dst[4] = (uint8_t)((addr & 0x0000FF00u) >> 8); - dst[5] = (addr & 0x000000FFu); - return IPCP_ADDR_LEN; -} - -static void ipcp_request_fill(struct pico_device_ppp *ppp, uint8_t *opts) -{ - if (ppp->ipcp_allowed_fields & IPCP_ALLOW_IP) - opts += ipcp_request_add_address(opts, IPCP_OPT_IP, ppp->ipcp_ip); - if (ppp->ipcp_allowed_fields & IPCP_ALLOW_DNS1) - opts += ipcp_request_add_address(opts, IPCP_OPT_DNS1, ppp->ipcp_dns1); - if (ppp->ipcp_allowed_fields & IPCP_ALLOW_DNS2) - opts += ipcp_request_add_address(opts, IPCP_OPT_DNS2, ppp->ipcp_dns2); - if ((ppp->ipcp_allowed_fields & IPCP_ALLOW_NBNS1) && (ppp->ipcp_nbns1)) - opts += ipcp_request_add_address(opts, IPCP_OPT_NBNS1, ppp->ipcp_nbns1); - if ((ppp->ipcp_allowed_fields & IPCP_ALLOW_NBNS2) && (ppp->ipcp_nbns2)) - opts += ipcp_request_add_address(opts, IPCP_OPT_NBNS2, ppp->ipcp_nbns2); -} - -static void ipcp_send_req(struct pico_device_ppp *ppp) -{ - uint8_t ipcp_req[PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_ipcp_hdr) + ipcp_request_options_size(ppp) + PPP_FCS_SIZE + 1]; - uint32_t prefix = PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE; - struct pico_ipcp_hdr *ih = (struct pico_ipcp_hdr *) (ipcp_req + prefix); - uint8_t *p = ipcp_req + prefix + sizeof(struct pico_ipcp_hdr); - uint16_t len = (uint16_t)(ipcp_request_options_size(ppp) + sizeof(struct pico_ipcp_hdr)); - - ih->id = ppp->frame_id++; - ih->code = PICO_CONF_REQ; - ih->len = short_be(len); - ipcp_request_fill(ppp, p); - - ppp_dbg("Sending IPCP CONF REQ, ipcp size = %d\n", len); - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_IPCP, - ipcp_req, /* Start of PPP packet */ - (uint32_t)(prefix + /* PPP Header, etc. */ - (uint32_t)len + /* IPCP Header + options */ - PPP_FCS_SIZE + /* FCS at the end of the frame */ - 1u) /* STOP Byte */ - ); -} - -static void ipcp_reject_vj(struct pico_device_ppp *ppp, uint8_t *comp_req) -{ - uint8_t ipcp_req[PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_ipcp_hdr) + IPCP_VJ_LEN + PPP_FCS_SIZE + 1]; - uint32_t prefix = PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE; - struct pico_ipcp_hdr *ih = (struct pico_ipcp_hdr *) (ipcp_req + prefix); - uint8_t *p = ipcp_req + prefix + sizeof(struct pico_ipcp_hdr); - uint32_t i; - - ih->id = ppp->frame_id++; - ih->code = PICO_CONF_REQ; - ih->len = short_be(IPCP_VJ_LEN + sizeof(struct pico_ipcp_hdr)); - for(i = 0; i < IPCP_OPT_VJ; i++) - p[i] = comp_req[i + sizeof(struct pico_ipcp_hdr)]; - ppp_dbg("Sending IPCP CONF REJ VJ\n"); - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_IPCP, - ipcp_req, /* Start of PPP packet */ - (uint32_t)(prefix + /* PPP Header, etc. */ - sizeof(struct pico_ipcp_hdr) + /* LCP HDR */ - IPCP_VJ_LEN + /* Actual options size */ - PPP_FCS_SIZE + /* FCS at the end of the frame */ - 1u) /* STOP Byte */ - ); -} - -static void ppp_ipv4_conf(struct pico_device_ppp *ppp) -{ - struct pico_ip4 ip; - struct pico_ip4 nm; - struct pico_ip4 dns1; - struct pico_ip4 dns2; - struct pico_ip4 any = { - 0 - }; - ip.addr = ppp->ipcp_ip; - nm.addr = 0xFFFFFF00; - pico_ipv4_link_add(&ppp->dev, ip, nm); - pico_ipv4_route_add(any, any, any, 1, pico_ipv4_link_by_dev(&ppp->dev)); - - dns1.addr = ppp->ipcp_dns1; - dns2.addr = ppp->ipcp_dns2; - pico_dns_client_nameserver(&dns1, PICO_DNS_NS_ADD); - pico_dns_client_nameserver(&dns2, PICO_DNS_NS_ADD); -} - - -static void ipcp_process_in(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len) -{ - struct pico_ipcp_hdr *ih = (struct pico_ipcp_hdr *)pkt; - uint8_t *p = pkt + sizeof(struct pico_ipcp_hdr); - int reject = 0; - while (p < pkt + len) { - if (p[0] == IPCP_OPT_VJ) { - reject++; - } - - if (p[0] == IPCP_OPT_IP) { - if (ih->code != PICO_CONF_REJ) - ppp->ipcp_ip = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5])); - else { - ppp->ipcp_allowed_fields &= (~IPCP_ALLOW_IP); - ppp->ipcp_ip = 0; - } - } - - if (p[0] == IPCP_OPT_DNS1) { - if (ih->code != PICO_CONF_REJ) - ppp->ipcp_dns1 = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5])); - else { - ppp->ipcp_allowed_fields &= (~IPCP_ALLOW_DNS1); - ppp->ipcp_dns1 = 0; - } - } - - if (p[0] == IPCP_OPT_NBNS1) { - if (ih->code != PICO_CONF_REJ) - ppp->ipcp_nbns1 = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5])); - else { - ppp->ipcp_allowed_fields &= (~IPCP_ALLOW_NBNS1); - ppp->ipcp_nbns1 = 0; - } - } - - if (p[0] == IPCP_OPT_DNS2) { - if (ih->code != PICO_CONF_REJ) - ppp->ipcp_dns2 = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5])); - else { - ppp->ipcp_allowed_fields &= (~IPCP_ALLOW_DNS2); - ppp->ipcp_dns2 = 0; - } - } - - if (p[0] == IPCP_OPT_NBNS2) { - if (ih->code != PICO_CONF_REJ) - ppp->ipcp_nbns2 = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5])); - else { - ppp->ipcp_allowed_fields &= (~IPCP_ALLOW_NBNS2); - ppp->ipcp_nbns2 = 0; - } - } - - p += p[1]; - } - if (reject) { - ipcp_reject_vj(ppp, p); - return; - } - - ppp->pkt = pkt; - ppp->len = len; - - switch(ih->code) { - case PICO_CONF_ACK: - ppp_dbg("Received IPCP CONF ACK\n"); - evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_RCA); - break; - case PICO_CONF_REQ: - ppp_dbg("Received IPCP CONF REQ\n"); - evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_RCR_POS); - break; - case PICO_CONF_NAK: - ppp_dbg("Received IPCP CONF NAK\n"); - evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_RCN); - break; - case PICO_CONF_REJ: - ppp_dbg("Received IPCP CONF REJ\n"); - - evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_RCN); - break; - } -} - -static void ipcp6_process_in(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len) -{ - IGNORE_PARAMETER(ppp); - IGNORE_PARAMETER(pkt); - IGNORE_PARAMETER(len); -} - -static void ppp_process_packet_payload(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len) -{ - if (pkt[0] == 0xc0) { - /* Link control packet */ - if (pkt[1] == 0x21) { - /* LCP */ - lcp_process_in(ppp, pkt + 2, len - 2); - } - - if (pkt[1] == 0x23) { - /* PAP */ - pap_process_in(ppp, pkt + 2, len - 2); - } - - return; - } - - if ((pkt[0] == 0xc2) && (pkt[1] == 0x23)) { - /* CHAP */ - chap_process_in(ppp, pkt + 2, len - 2); - return; - } - - if (pkt[0] == 0x80) { - /* IP assignment (IPCP/IPCP6) */ - if (pkt[1] == 0x21) { - /* IPCP */ - ipcp_process_in(ppp, pkt + 2, len - 2); - } - - if (pkt[1] == 0x57) { - /* IPCP6 */ - ipcp6_process_in(ppp, pkt + 2, len - 2); - } - - return; - } - - if (pkt[0] == 0x00) { - /* Uncompressed protocol: leading zero. */ - pkt++; - len--; - } - - if ((pkt[0] == 0x21) || (pkt[0] == 0x57)) { - /* IPv4 /v6 Data */ - pico_stack_recv(&ppp->dev, pkt + 1, len - 1); - return; - } - - ppp_dbg("PPP: Unrecognized protocol %02x%02x\n", pkt[0], pkt[1]); -} - -static void ppp_process_packet(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len) -{ - /* Verify incoming FCS */ - if (ppp_fcs_verify(pkt, len) != 0) - return; - - /* Remove trailing FCS */ - len -= 2; - - /* Remove ADDR/CTRL, then process */ - if ((pkt[0] == PPPF_ADDR) && (pkt[1] == PPPF_CTRL)) { - pkt += 2; - len -= 2; - } - - ppp_process_packet_payload(ppp, pkt, len); - -} - -static void ppp_recv_data(struct pico_device_ppp *ppp, void *data, uint32_t len) -{ - uint8_t *pkt = (uint8_t *)data; - -#ifdef PPP_DEBUG - uint32_t idx; - if (len > 0) { - ppp_dbg("PPP <<<<< "); - for(idx = 0; idx < len; idx++) { - ppp_dbg(" %02x", ((uint8_t *)data)[idx]); - } - ppp_dbg("\n"); - } -#endif - - ppp_process_packet(ppp, pkt, len); -} - -static void lcp_this_layer_up(struct pico_device_ppp *ppp) -{ - ppp_dbg("PPP: LCP up.\n"); - - switch (ppp->auth) { - case 0x0000: - evaluate_auth_state(ppp, PPP_AUTH_EVENT_UP_NONE); - break; - case 0xc023: - evaluate_auth_state(ppp, PPP_AUTH_EVENT_UP_PAP); - break; - case 0xc223: - evaluate_auth_state(ppp, PPP_AUTH_EVENT_UP_CHAP); - break; - default: - ppp_dbg("PPP: Unknown authentication protocol.\n"); - break; - } -} - -static void lcp_this_layer_down(struct pico_device_ppp *ppp) -{ - ppp_dbg("PPP: LCP down.\n"); - evaluate_auth_state(ppp, PPP_AUTH_EVENT_DOWN); -} - -static void lcp_this_layer_started(struct pico_device_ppp *ppp) -{ - ppp_dbg("PPP: LCP started.\n"); - evaluate_modem_state(ppp, PPP_MODEM_EVENT_START); -} - -static void lcp_this_layer_finished(struct pico_device_ppp *ppp) -{ - ppp_dbg("PPP: LCP finished.\n"); - evaluate_modem_state(ppp, PPP_MODEM_EVENT_STOP); -} - -static void lcp_initialize_restart_count(struct pico_device_ppp *ppp) -{ - lcp_timer_start(ppp, PPP_TIMER_ON_LCPREQ); -} - -static void lcp_send_code_reject(struct pico_device_ppp *ppp) -{ - IGNORE_PARAMETER(ppp); -} - -static void lcp_send_echo_reply(struct pico_device_ppp *ppp) -{ - uint8_t reply[ppp->len + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_lcp_hdr) + PPP_FCS_SIZE + 1]; - struct pico_lcp_hdr *reply_hdr = (struct pico_lcp_hdr *) (reply + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE); - struct pico_lcp_hdr *lcpreq = (struct pico_lcp_hdr *)ppp->pkt; - memcpy(reply + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE, ppp->pkt, ppp->len); - reply_hdr->code = PICO_CONF_ECHO_REP; - reply_hdr->id = lcpreq->id; - reply_hdr->len = lcpreq->len; - ppp_dbg("Sending LCP ECHO REPLY\n"); - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_LCP, reply, - PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */ - short_be(lcpreq->len) + /* Actual options size + hdr (whole lcp packet) */ - PPP_FCS_SIZE + /* FCS at the end of the frame */ - 1 /* STOP Byte */ - ); -} - -static const struct pico_ppp_fsm ppp_lcp_fsm[PPP_LCP_STATE_MAX][PPP_LCP_EVENT_MAX] = { - [PPP_LCP_STATE_INITIAL] = { - [PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_CLOSED, {} }, - [PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_STARTING, { lcp_this_layer_started } }, - [PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_RCR_POS] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_RCR_NEG] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_RCA] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_RCN] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_RTR] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_RTA] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_RUC] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_RXJ_POS] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_RXJ_NEG] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_RXR] = { PPP_LCP_STATE_INITIAL, {} } - }, - [PPP_LCP_STATE_STARTING] = { - [PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_request } }, - [PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_INITIAL, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_RCR_POS] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_RCR_NEG] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_RCA] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_RCN] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_RTR] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_RTA] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_RUC] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_RXJ_POS] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_RXJ_NEG] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_RXR] = { PPP_LCP_STATE_STARTING, {} } - }, - [PPP_LCP_STATE_CLOSED] = { - [PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_CLOSED, {} }, - [PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_request} }, - [PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_CLOSED, {} }, - [PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_CLOSED, {} }, - [PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_CLOSED, {} }, - [PPP_LCP_EVENT_RCR_POS] = { PPP_LCP_STATE_CLOSED, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RCR_NEG] = { PPP_LCP_STATE_CLOSED, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RCA] = { PPP_LCP_STATE_CLOSED, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RCN] = { PPP_LCP_STATE_CLOSED, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RTR] = { PPP_LCP_STATE_CLOSED, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RTA] = { PPP_LCP_STATE_CLOSED, {} }, - [PPP_LCP_EVENT_RUC] = { PPP_LCP_STATE_CLOSED, { lcp_send_code_reject } }, - [PPP_LCP_EVENT_RXJ_POS] = { PPP_LCP_STATE_CLOSED, {} }, - [PPP_LCP_EVENT_RXJ_NEG] = { PPP_LCP_STATE_CLOSED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RXR] = { PPP_LCP_STATE_CLOSED, {} } - }, - [PPP_LCP_STATE_STOPPED] = { - [PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_STOPPED, {} }, - [PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_STARTING, { lcp_this_layer_started } }, - [PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_STOPPED, {}}, - [PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_CLOSED, {}}, - [PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_STOPPED, {} }, - [PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_STOPPED, {} }, - [PPP_LCP_EVENT_RCR_POS] = { PPP_LCP_STATE_ACK_SENT, - { lcp_send_configure_request, lcp_send_configure_ack}}, - [PPP_LCP_EVENT_RCR_NEG] = { PPP_LCP_STATE_REQ_SENT, - { lcp_send_configure_request, lcp_send_configure_nack}}, - [PPP_LCP_EVENT_RCA] = { PPP_LCP_STATE_STOPPED, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RCN] = { PPP_LCP_STATE_STOPPED, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RTR] = { PPP_LCP_STATE_STOPPED, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RTA] = { PPP_LCP_STATE_STOPPED, {} }, - [PPP_LCP_EVENT_RUC] = { PPP_LCP_STATE_STOPPED, { lcp_send_code_reject } }, - [PPP_LCP_EVENT_RXJ_POS] = { PPP_LCP_STATE_STOPPED, {} }, - [PPP_LCP_EVENT_RXJ_NEG] = { PPP_LCP_STATE_STOPPED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RXR] = { PPP_LCP_STATE_STOPPED, {} } - }, - [PPP_LCP_STATE_CLOSING] = { - [PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_CLOSING, {} }, - [PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_INITIAL, {} }, - [PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_STOPPING, {} }, - [PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_CLOSING, {} }, - [PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_CLOSING, { lcp_send_terminate_request } }, - [PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_CLOSED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RCR_POS] = { PPP_LCP_STATE_CLOSING, {} }, - [PPP_LCP_EVENT_RCR_NEG] = { PPP_LCP_STATE_CLOSING, {} }, - [PPP_LCP_EVENT_RCA] = { PPP_LCP_STATE_CLOSING, {} }, - [PPP_LCP_EVENT_RCN] = { PPP_LCP_STATE_CLOSING, {} }, - [PPP_LCP_EVENT_RTR] = { PPP_LCP_STATE_CLOSING, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RTA] = { PPP_LCP_STATE_CLOSED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RUC] = { PPP_LCP_STATE_CLOSING, { lcp_send_code_reject } }, - [PPP_LCP_EVENT_RXJ_POS] = { PPP_LCP_STATE_CLOSING, {} }, - [PPP_LCP_EVENT_RXJ_NEG] = { PPP_LCP_STATE_CLOSED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RXR] = { PPP_LCP_STATE_CLOSING, {} } - }, - [PPP_LCP_STATE_STOPPING] = { - [PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_STOPPING, {} }, - [PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_STOPPING, {} }, - [PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_CLOSING, {} }, - [PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_STOPPING, { lcp_send_terminate_request } }, - [PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_STOPPED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RCR_POS] = { PPP_LCP_STATE_STOPPING, {} }, - [PPP_LCP_EVENT_RCR_NEG] = { PPP_LCP_STATE_STOPPING, {} }, - [PPP_LCP_EVENT_RCA] = { PPP_LCP_STATE_STOPPING, {} }, - [PPP_LCP_EVENT_RCN] = { PPP_LCP_STATE_STOPPING, {} }, - [PPP_LCP_EVENT_RTR] = { PPP_LCP_STATE_STOPPING, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RTA] = { PPP_LCP_STATE_STOPPED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RUC] = { PPP_LCP_STATE_STOPPING, { lcp_send_code_reject } }, - [PPP_LCP_EVENT_RXJ_POS] = { PPP_LCP_STATE_STOPPING, {} }, - [PPP_LCP_EVENT_RXJ_NEG] = { PPP_LCP_STATE_STOPPED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RXR] = { PPP_LCP_STATE_STOPPING, {} } - }, - [PPP_LCP_STATE_REQ_SENT] = { - [PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_REQ_SENT, {} }, - [PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_REQ_SENT, {} }, - [PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_CLOSING, { lcp_send_terminate_request } }, - [PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_request } }, - [PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_STOPPED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RCR_POS] = { PPP_LCP_STATE_ACK_SENT, { lcp_send_configure_ack } }, - [PPP_LCP_EVENT_RCR_NEG] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_nack } }, - [PPP_LCP_EVENT_RCA] = { PPP_LCP_STATE_ACK_RCVD, { lcp_initialize_restart_count } }, - [PPP_LCP_EVENT_RCN] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_request} }, - [PPP_LCP_EVENT_RTR] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RTA] = { PPP_LCP_STATE_REQ_SENT, {} }, - [PPP_LCP_EVENT_RUC] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_code_reject } }, - [PPP_LCP_EVENT_RXJ_POS] = { PPP_LCP_STATE_REQ_SENT, {} }, - [PPP_LCP_EVENT_RXJ_NEG] = { PPP_LCP_STATE_STOPPED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RXR] = { PPP_LCP_STATE_REQ_SENT, {} } - }, - [PPP_LCP_STATE_ACK_RCVD] = { - [PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_ACK_RCVD, {} }, - [PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_ACK_RCVD, {} }, - [PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_CLOSING, { lcp_send_terminate_request} }, - [PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_request } }, - [PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_STOPPED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RCR_POS] = { PPP_LCP_STATE_OPENED, { lcp_send_configure_ack, lcp_this_layer_up} }, - [PPP_LCP_EVENT_RCR_NEG] = { PPP_LCP_STATE_ACK_RCVD, { lcp_send_configure_nack } }, - [PPP_LCP_EVENT_RCA] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_request } }, - [PPP_LCP_EVENT_RCN] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_request } }, - [PPP_LCP_EVENT_RTR] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RTA] = { PPP_LCP_STATE_REQ_SENT, {} }, - [PPP_LCP_EVENT_RUC] = { PPP_LCP_STATE_ACK_RCVD, { lcp_send_code_reject } }, - [PPP_LCP_EVENT_RXJ_POS] = { PPP_LCP_STATE_REQ_SENT, {} }, - [PPP_LCP_EVENT_RXJ_NEG] = { PPP_LCP_STATE_STOPPED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RXR] = { PPP_LCP_STATE_ACK_RCVD, {} } - }, - [PPP_LCP_STATE_ACK_SENT] = { - [PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_ACK_SENT, {} }, - [PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_STARTING, {} }, - [PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_ACK_SENT, {} }, - [PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_CLOSING, { lcp_send_terminate_request} }, - [PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_ACK_SENT, { lcp_send_configure_request } }, - [PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_STOPPED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RCR_POS] = { PPP_LCP_STATE_ACK_SENT, { lcp_send_configure_ack } }, - [PPP_LCP_EVENT_RCR_NEG] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_nack } }, - [PPP_LCP_EVENT_RCA] = { PPP_LCP_STATE_OPENED, { lcp_this_layer_up} }, - [PPP_LCP_EVENT_RCN] = { PPP_LCP_STATE_ACK_SENT, { lcp_send_configure_request} }, - [PPP_LCP_EVENT_RTR] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_terminate_ack } }, - [PPP_LCP_EVENT_RTA] = { PPP_LCP_STATE_ACK_SENT, {} }, - [PPP_LCP_EVENT_RUC] = { PPP_LCP_STATE_ACK_SENT, { lcp_send_code_reject } }, - [PPP_LCP_EVENT_RXJ_POS] = { PPP_LCP_STATE_ACK_SENT, {} }, - [PPP_LCP_EVENT_RXJ_NEG] = { PPP_LCP_STATE_STOPPED, { lcp_this_layer_finished } }, - [PPP_LCP_EVENT_RXR] = { PPP_LCP_STATE_ACK_SENT, {} } - }, - [PPP_LCP_STATE_OPENED] = { - [PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_OPENED, {} }, - [PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_STARTING, {lcp_this_layer_down } }, - [PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_OPENED, {} }, - [PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_CLOSING, - { lcp_this_layer_down, lcp_send_terminate_request }}, - [PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_OPENED, {} }, - [PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_OPENED, {} }, - [PPP_LCP_EVENT_RCR_POS] = { PPP_LCP_STATE_ACK_SENT, - { lcp_this_layer_down, lcp_send_terminate_request, lcp_send_configure_ack }}, - [PPP_LCP_EVENT_RCR_NEG] = { PPP_LCP_STATE_REQ_SENT, - { lcp_this_layer_down, lcp_send_configure_request, lcp_send_configure_nack }}, - [PPP_LCP_EVENT_RCA] = { PPP_LCP_STATE_REQ_SENT, { lcp_this_layer_down, lcp_send_terminate_request } }, - [PPP_LCP_EVENT_RCN] = { PPP_LCP_STATE_REQ_SENT, { lcp_this_layer_down, lcp_send_terminate_request } }, - [PPP_LCP_EVENT_RTR] = { PPP_LCP_STATE_STOPPING, { lcp_this_layer_down, lcp_zero_restart_count, lcp_send_terminate_ack} }, - [PPP_LCP_EVENT_RTA] = { PPP_LCP_STATE_REQ_SENT, { lcp_this_layer_down, lcp_send_terminate_request} }, - [PPP_LCP_EVENT_RUC] = { PPP_LCP_STATE_OPENED, { lcp_send_code_reject } }, - [PPP_LCP_EVENT_RXJ_POS] = { PPP_LCP_STATE_OPENED, { } }, - [PPP_LCP_EVENT_RXJ_NEG] = { PPP_LCP_STATE_STOPPING, - {lcp_this_layer_down, lcp_send_terminate_request}}, - [PPP_LCP_EVENT_RXR] = { PPP_LCP_STATE_OPENED, { lcp_send_echo_reply} } - } -}; - -static void evaluate_lcp_state(struct pico_device_ppp *ppp, enum ppp_lcp_event event) -{ - const struct pico_ppp_fsm *fsm, *next_fsm_to; - int i; - if (!ppp) - return; - - if (mock_lcp_state) { - mock_lcp_state(ppp, event); - return; - } - - fsm = &ppp_lcp_fsm[ppp->lcp_state][event]; - ppp->lcp_state = (enum ppp_lcp_state)fsm->next_state; - /* RFC1661: The states in which the Restart timer is running are identifiable by - * the presence of TO events. - */ - next_fsm_to = &ppp_lcp_fsm[ppp->lcp_state][PPP_LCP_EVENT_TO_POS]; - if (!next_fsm_to->event_handler[0]) { - /* The Restart timer is stopped when transitioning - * from any state where the timer is running to a state where the timer - * is not running. - */ - lcp_timer_stop(ppp, PPP_TIMER_ON_LCPREQ); - lcp_timer_stop(ppp, PPP_TIMER_ON_LCPTERM); - } - - for (i = 0; i < PPP_FSM_MAX_ACTIONS; i++) { - if (fsm->event_handler[i]) - fsm->event_handler[i](ppp); - } -} - -static void auth(struct pico_device_ppp *ppp) -{ - ppp_dbg("PPP: Authenticated.\n"); - ppp->ipcp_allowed_fields = 0xFFFF; - evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_UP); -} - -static void deauth(struct pico_device_ppp *ppp) -{ - ppp_dbg("PPP: De-authenticated.\n"); - evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_DOWN); -} - -static void auth_abort(struct pico_device_ppp *ppp) -{ - ppp_dbg("PPP: Authentication failed!\n"); - ppp->timer_on = (uint8_t) (ppp->timer_on & (~PPP_TIMER_ON_AUTH)); - evaluate_lcp_state(ppp, PPP_LCP_EVENT_CLOSE); - -} - -static void auth_req(struct pico_device_ppp *ppp) -{ - uint16_t ppp_usr_len = 0; - uint16_t ppp_pwd_len = 0; - uint8_t *req = NULL, *p; - struct pico_pap_hdr *hdr; - uint16_t pap_len = 0; - uint8_t field_len = 0; - ppp_usr_len = (uint16_t)strlen(ppp->username); - ppp_pwd_len = (uint16_t)strlen(ppp->password); - - pap_len = (uint16_t)(sizeof(struct pico_pap_hdr) + 1u + 1u + ppp_usr_len + ppp_pwd_len); - - req = PICO_ZALLOC(PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + pap_len + PPP_FCS_SIZE + 1); - if (!req) - return; - - hdr = (struct pico_pap_hdr *) (req + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE); - - hdr->code = PAP_AUTH_REQ; - hdr->id = ppp->frame_id++; - hdr->len = short_be(pap_len); - - p = req + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_pap_hdr); - - /* Populate authentication domain */ - field_len = (uint8_t)(ppp_usr_len & 0xFF); - *p = field_len; - ++p; - if (ppp_usr_len > 0) { - memcpy(p, ppp->username, ppp_usr_len); - p += ppp_usr_len; - } - - /* Populate authentication password */ - field_len = (uint8_t)(ppp_pwd_len & 0xFF); - *p = field_len; - ++p; - if (ppp_pwd_len > 0) { - memcpy(p, ppp->password, ppp_pwd_len); - p += ppp_pwd_len; - } - ppp_dbg("PAP: Sending authentication request.\n"); - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_PAP, - req, /* Start of PPP packet */ - (uint32_t)( - PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */ - pap_len + /* Authentication packet len */ - PPP_FCS_SIZE + /* FCS */ - 1) /* STOP Byte */ - ); - PICO_FREE(req); -} - -static void auth_rsp(struct pico_device_ppp *ppp) -{ - struct pico_chap_hdr *ch = (struct pico_chap_hdr *)ppp->pkt; - uint8_t resp[PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_chap_hdr) + CHAP_MD5_SIZE + PPP_FCS_SIZE + 2]; - struct pico_chap_hdr *rh = (struct pico_chap_hdr *) (resp + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE); - uint8_t *md5resp = resp + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_chap_hdr) + 1; - uint8_t *md5resp_len = resp + PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_chap_hdr); - uint8_t *challenge; - uint32_t i = 0, pwdlen; - uint8_t *recvd_challenge_len = ppp->pkt + sizeof(struct pico_chap_hdr); - uint8_t *recvd_challenge = recvd_challenge_len + 1; - size_t challenge_size = CHALLENGE_SIZE(ppp, ch); - - challenge = PICO_ZALLOC(challenge_size); - - if (!challenge) - return; - - - pwdlen = (uint32_t)strlen(ppp->password); - challenge[i++] = ch->id; - memcpy(challenge + i, ppp->password, pwdlen); - i += pwdlen; - memcpy(challenge + i, recvd_challenge, *recvd_challenge_len); - i += *recvd_challenge_len; - pico_md5sum(md5resp, challenge, i); - PICO_FREE(challenge); - rh->id = ch->id; - rh->code = CHAP_RESPONSE; - rh->len = short_be(CHAP_MD5_SIZE + sizeof(struct pico_chap_hdr) + 1); - *md5resp_len = CHAP_MD5_SIZE; - ppp_dbg("Sending CHAP RESPONSE, \n"); - pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_CHAP, - resp, /* Start of PPP packet */ - (uint32_t)( - PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */ - sizeof(struct pico_chap_hdr) + /* CHAP HDR */ - 1 + /* Value length */ - CHAP_MD5_SIZE + /* Actual payload size */ - PPP_FCS_SIZE + /* FCS at the end of the frame */ - 1) /* STOP Byte */ - ); -} - -static void auth_start_timer(struct pico_device_ppp *ppp) -{ - ppp->timer_on = ppp->timer_on | PPP_TIMER_ON_AUTH; - ppp->timer_val = PICO_PPP_DEFAULT_TIMER; -} - -static const struct pico_ppp_fsm ppp_auth_fsm[PPP_AUTH_STATE_MAX][PPP_AUTH_EVENT_MAX] = { - [PPP_AUTH_STATE_INITIAL] = { - [PPP_AUTH_EVENT_UP_NONE] = { PPP_AUTH_STATE_AUTHENTICATED, {auth} }, - [PPP_AUTH_EVENT_UP_PAP] = { PPP_AUTH_STATE_REQ_SENT, {auth_req, auth_start_timer} }, - [PPP_AUTH_EVENT_UP_CHAP] = { PPP_AUTH_STATE_STARTING, {} }, - [PPP_AUTH_EVENT_DOWN] = { PPP_AUTH_STATE_INITIAL, {} }, - [PPP_AUTH_EVENT_RAC] = { PPP_AUTH_STATE_INITIAL, {} }, - [PPP_AUTH_EVENT_RAA] = { PPP_AUTH_STATE_INITIAL, {} }, - [PPP_AUTH_EVENT_RAN] = { PPP_AUTH_STATE_INITIAL, {auth_abort} }, - [PPP_AUTH_EVENT_TO] = { PPP_AUTH_STATE_INITIAL, {} } - }, - [PPP_AUTH_STATE_STARTING] = { - [PPP_AUTH_EVENT_UP_NONE] = { PPP_AUTH_STATE_STARTING, {} }, - [PPP_AUTH_EVENT_UP_PAP] = { PPP_AUTH_STATE_STARTING, {} }, - [PPP_AUTH_EVENT_UP_CHAP] = { PPP_AUTH_STATE_STARTING, {} }, - [PPP_AUTH_EVENT_DOWN] = { PPP_AUTH_STATE_INITIAL, {deauth} }, - [PPP_AUTH_EVENT_RAC] = { PPP_AUTH_STATE_RSP_SENT, {auth_rsp, auth_start_timer} }, - [PPP_AUTH_EVENT_RAA] = { PPP_AUTH_STATE_STARTING, {auth_start_timer} }, - [PPP_AUTH_EVENT_RAN] = { PPP_AUTH_STATE_STARTING, {auth_abort} }, - [PPP_AUTH_EVENT_TO] = { PPP_AUTH_STATE_INITIAL, {auth_req, auth_start_timer} } - }, - [PPP_AUTH_STATE_RSP_SENT] = { - [PPP_AUTH_EVENT_UP_NONE] = { PPP_AUTH_STATE_RSP_SENT, {} }, - [PPP_AUTH_EVENT_UP_PAP] = { PPP_AUTH_STATE_RSP_SENT, {} }, - [PPP_AUTH_EVENT_UP_CHAP] = { PPP_AUTH_STATE_RSP_SENT, {} }, - [PPP_AUTH_EVENT_DOWN] = { PPP_AUTH_STATE_INITIAL, {deauth} }, - [PPP_AUTH_EVENT_RAC] = { PPP_AUTH_STATE_RSP_SENT, {auth_rsp, auth_start_timer} }, - [PPP_AUTH_EVENT_RAA] = { PPP_AUTH_STATE_AUTHENTICATED, {auth} }, - [PPP_AUTH_EVENT_RAN] = { PPP_AUTH_STATE_STARTING, {auth_abort} }, - [PPP_AUTH_EVENT_TO] = { PPP_AUTH_STATE_STARTING, {auth_start_timer} } - }, - [PPP_AUTH_STATE_REQ_SENT] = { - [PPP_AUTH_EVENT_UP_NONE] = { PPP_AUTH_STATE_REQ_SENT, {} }, - [PPP_AUTH_EVENT_UP_PAP] = { PPP_AUTH_STATE_REQ_SENT, {} }, - [PPP_AUTH_EVENT_UP_CHAP] = { PPP_AUTH_STATE_REQ_SENT, {} }, - [PPP_AUTH_EVENT_DOWN] = { PPP_AUTH_STATE_INITIAL, {deauth} }, - [PPP_AUTH_EVENT_RAC] = { PPP_AUTH_STATE_REQ_SENT, {} }, - [PPP_AUTH_EVENT_RAA] = { PPP_AUTH_STATE_AUTHENTICATED, {auth} }, - [PPP_AUTH_EVENT_RAN] = { PPP_AUTH_STATE_REQ_SENT, {auth_abort} }, - [PPP_AUTH_EVENT_TO] = { PPP_AUTH_STATE_REQ_SENT, {auth_req, auth_start_timer} } - }, - [PPP_AUTH_STATE_AUTHENTICATED] = { - [PPP_AUTH_EVENT_UP_NONE] = { PPP_AUTH_STATE_AUTHENTICATED, {} }, - [PPP_AUTH_EVENT_UP_PAP] = { PPP_AUTH_STATE_AUTHENTICATED, {} }, - [PPP_AUTH_EVENT_UP_CHAP] = { PPP_AUTH_STATE_AUTHENTICATED, {} }, - [PPP_AUTH_EVENT_DOWN] = { PPP_AUTH_STATE_INITIAL, {deauth} }, - [PPP_AUTH_EVENT_RAC] = { PPP_AUTH_STATE_RSP_SENT, {auth_rsp} }, - [PPP_AUTH_EVENT_RAA] = { PPP_AUTH_STATE_AUTHENTICATED, {} }, - [PPP_AUTH_EVENT_RAN] = { PPP_AUTH_STATE_AUTHENTICATED, {} }, - [PPP_AUTH_EVENT_TO] = { PPP_AUTH_STATE_AUTHENTICATED, {} }, - } -}; - -static void evaluate_auth_state(struct pico_device_ppp *ppp, enum ppp_auth_event event) -{ - const struct pico_ppp_fsm *fsm; - int i; - if (mock_auth_state) { - mock_auth_state(ppp, event); - return; - } - - fsm = &ppp_auth_fsm[ppp->auth_state][event]; - - ppp->auth_state = (enum ppp_auth_state)fsm->next_state; - for (i = 0; i < PPP_FSM_MAX_ACTIONS; i++) { - if (fsm->event_handler[i]) - fsm->event_handler[i](ppp); - } -} - -static void ipcp_send_nack(struct pico_device_ppp *ppp) -{ - IGNORE_PARAMETER(ppp); -} - -static void ipcp_bring_up(struct pico_device_ppp *ppp) -{ - ppp_dbg("PPP: IPCP up.\n"); - - if (ppp->ipcp_ip) { - char my_ip[16], my_dns[16]; - pico_ipv4_to_string(my_ip, ppp->ipcp_ip); - ppp_dbg("Received IP config %s\n", my_ip); - pico_ipv4_to_string(my_dns, ppp->ipcp_dns1); - ppp_dbg("Received DNS: %s\n", my_dns); - ppp_ipv4_conf(ppp); - } -} - -static void ipcp_bring_down(struct pico_device_ppp *ppp) -{ - IGNORE_PARAMETER(ppp); - - ppp_dbg("PPP: IPCP down.\n"); -} - -static void ipcp_start_timer(struct pico_device_ppp *ppp) -{ - ppp->timer_on = ppp->timer_on | PPP_TIMER_ON_IPCP; - ppp->timer_val = PICO_PPP_DEFAULT_TIMER * PICO_PPP_DEFAULT_MAX_FAILURE; -} - -static const struct pico_ppp_fsm ppp_ipcp_fsm[PPP_IPCP_STATE_MAX][PPP_IPCP_EVENT_MAX] = { - [PPP_IPCP_STATE_INITIAL] = { - [PPP_IPCP_EVENT_UP] = { PPP_IPCP_STATE_REQ_SENT, {ipcp_send_req, ipcp_start_timer} }, - [PPP_IPCP_EVENT_DOWN] = { PPP_IPCP_STATE_INITIAL, {} }, - [PPP_IPCP_EVENT_RCR_POS] = { PPP_IPCP_STATE_INITIAL, {} }, - [PPP_IPCP_EVENT_RCR_NEG] = { PPP_IPCP_STATE_INITIAL, {} }, - [PPP_IPCP_EVENT_RCA] = { PPP_IPCP_STATE_INITIAL, {} }, - [PPP_IPCP_EVENT_RCN] = { PPP_IPCP_STATE_INITIAL, {} }, - [PPP_IPCP_EVENT_TO] = { PPP_IPCP_STATE_INITIAL, {} } - }, - [PPP_IPCP_STATE_REQ_SENT] = { - [PPP_IPCP_EVENT_UP] = { PPP_IPCP_STATE_REQ_SENT, {} }, - [PPP_IPCP_EVENT_DOWN] = { PPP_IPCP_STATE_INITIAL, {} }, - [PPP_IPCP_EVENT_RCR_POS] = { PPP_IPCP_STATE_ACK_SENT, {ipcp_send_ack} }, - [PPP_IPCP_EVENT_RCR_NEG] = { PPP_IPCP_STATE_REQ_SENT, {ipcp_send_nack} }, - [PPP_IPCP_EVENT_RCA] = { PPP_IPCP_STATE_ACK_RCVD, {} }, - [PPP_IPCP_EVENT_RCN] = { PPP_IPCP_STATE_REQ_SENT, {ipcp_send_req, ipcp_start_timer} }, - [PPP_IPCP_EVENT_TO] = { PPP_IPCP_STATE_REQ_SENT, {ipcp_send_req, ipcp_start_timer} } - }, - [PPP_IPCP_STATE_ACK_RCVD] = { - [PPP_IPCP_EVENT_UP] = { PPP_IPCP_STATE_ACK_RCVD, {} }, - [PPP_IPCP_EVENT_DOWN] = { PPP_IPCP_STATE_INITIAL, {} }, - [PPP_IPCP_EVENT_RCR_POS] = { PPP_IPCP_STATE_OPENED, {ipcp_send_ack, ipcp_bring_up} }, - [PPP_IPCP_EVENT_RCR_NEG] = { PPP_IPCP_STATE_ACK_RCVD, {ipcp_send_nack} }, - [PPP_IPCP_EVENT_RCA] = { PPP_IPCP_STATE_REQ_SENT, {ipcp_send_req, ipcp_start_timer} }, - [PPP_IPCP_EVENT_RCN] = { PPP_IPCP_STATE_REQ_SENT, {ipcp_send_req, ipcp_start_timer} }, - [PPP_IPCP_EVENT_TO] = { PPP_IPCP_STATE_ACK_RCVD, {ipcp_send_req, ipcp_start_timer} } - }, - [PPP_IPCP_STATE_ACK_SENT] = { - [PPP_IPCP_EVENT_UP] = { PPP_IPCP_STATE_ACK_SENT, {} }, - [PPP_IPCP_EVENT_DOWN] = { PPP_IPCP_STATE_INITIAL, {} }, - [PPP_IPCP_EVENT_RCR_POS] = { PPP_IPCP_STATE_ACK_SENT, {ipcp_send_ack} }, - [PPP_IPCP_EVENT_RCR_NEG] = { PPP_IPCP_STATE_REQ_SENT, {ipcp_send_nack} }, - [PPP_IPCP_EVENT_RCA] = { PPP_IPCP_STATE_OPENED, {ipcp_bring_up} }, - [PPP_IPCP_EVENT_RCN] = { PPP_IPCP_STATE_ACK_SENT, {ipcp_send_req, ipcp_start_timer} }, - [PPP_IPCP_EVENT_TO] = { PPP_IPCP_STATE_ACK_SENT, {ipcp_send_req, ipcp_start_timer} } - }, - [PPP_IPCP_STATE_OPENED] = { - [PPP_IPCP_EVENT_UP] = { PPP_IPCP_STATE_OPENED, {} }, - [PPP_IPCP_EVENT_DOWN] = { PPP_IPCP_STATE_INITIAL, {ipcp_bring_down} }, - [PPP_IPCP_EVENT_RCR_POS] = { PPP_IPCP_STATE_ACK_SENT, {ipcp_bring_down, ipcp_send_req, ipcp_send_ack} }, - [PPP_IPCP_EVENT_RCR_NEG] = { PPP_IPCP_STATE_REQ_SENT, {ipcp_bring_down, ipcp_send_req, ipcp_send_nack} }, - [PPP_IPCP_EVENT_RCA] = { PPP_IPCP_STATE_REQ_SENT, {ipcp_send_req} }, - [PPP_IPCP_EVENT_RCN] = { PPP_IPCP_STATE_REQ_SENT, {ipcp_send_req} }, - [PPP_IPCP_EVENT_TO] = { PPP_IPCP_STATE_OPENED, {} } - } -}; - -static void evaluate_ipcp_state(struct pico_device_ppp *ppp, enum ppp_ipcp_event event) -{ - const struct pico_ppp_fsm *fsm; - int i; - if (mock_ipcp_state) { - mock_ipcp_state(ppp, event); - return; - } - - fsm = &ppp_ipcp_fsm[ppp->ipcp_state][event]; - - ppp->ipcp_state = (enum ppp_ipcp_state)fsm->next_state; - for (i = 0; i < PPP_FSM_MAX_ACTIONS; i++) { - if (fsm->event_handler[i]) - fsm->event_handler[i](ppp); - } -} - -static int pico_ppp_poll(struct pico_device *dev, int loop_score) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *) dev; - static uint32_t len = 0; - int r; - if (ppp->serial_recv) { - do { - r = ppp->serial_recv(&ppp->dev, &ppp_recv_buf[len], 1); - if (r <= 0) - break; - - if (ppp->modem_state == PPP_MODEM_STATE_CONNECTED) { - static int control_escape = 0; - - if (ppp_recv_buf[len] == PPPF_FLAG_SEQ) { - if (control_escape) { - /* Illegal sequence, discard frame */ - ppp_dbg("Illegal sequence, ppp_recv_buf[%d] = %d\n", len, ppp_recv_buf[len]); - control_escape = 0; - len = 0; - } - - if (len > 1) { - ppp_recv_data(ppp, ppp_recv_buf, len); - loop_score--; - len = 0; - } - } else if (control_escape) { - ppp_recv_buf[len] ^= 0x20; - control_escape = 0; - len++; - } else if (ppp_recv_buf[len] == PPPF_CTRL_ESC) { - control_escape = 1; - } else { - len++; - } - } else { - static int s3 = 0; - - if (ppp_recv_buf[len] == AT_S3) { - s3 = 1; - if (len > 0) { - ppp_recv_buf[len] = '\0'; - ppp_modem_recv(ppp, ppp_recv_buf, len); - len = 0; - } - } else if (ppp_recv_buf[len] == AT_S4) { - if (!s3) { - len++; - } - - s3 = 0; - } else { - s3 = 0; - len++; - } - } - } while ((r > 0) && (len < ARRAY_SIZE(ppp_recv_buf)) && (loop_score > 0)); - } - - return loop_score; -} - -/* Public interface: create/destroy. */ - -static int pico_ppp_link_state(struct pico_device *dev) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev; - if (ppp->ipcp_state == PPP_IPCP_STATE_OPENED) - return 1; - - return 0; -} - -void pico_ppp_destroy(struct pico_device *ppp) -{ - if (!ppp) - return; - - /* Perform custom cleanup here before calling 'pico_device_destroy' - * or register a custom cleanup function during initialization - * by setting 'ppp->dev.destroy'. */ - - pico_device_destroy(ppp); -} - -static void check_to_modem(struct pico_device_ppp *ppp) -{ - if (ppp->timer_on & PPP_TIMER_ON_MODEM) { - if (ppp->timer_val == 0) { - ppp->timer_on = (uint8_t) (ppp->timer_on & (~PPP_TIMER_ON_MODEM)); - evaluate_modem_state(ppp, PPP_MODEM_EVENT_TIMEOUT); - } - } -} - -static void check_to_lcp(struct pico_device_ppp *ppp) -{ - if (ppp->timer_on & (PPP_TIMER_ON_LCPREQ | PPP_TIMER_ON_LCPTERM)) { - if (ppp->timer_val == 0) { - if (ppp->timer_count == 0) - evaluate_lcp_state(ppp, PPP_LCP_EVENT_TO_NEG); - else{ - evaluate_lcp_state(ppp, PPP_LCP_EVENT_TO_POS); - ppp->timer_count--; - } - } - } -} - -static void check_to_auth(struct pico_device_ppp *ppp) -{ - if (ppp->timer_on & PPP_TIMER_ON_AUTH) { - if (ppp->timer_val == 0) { - ppp->timer_on = (uint8_t) (ppp->timer_on & (~PPP_TIMER_ON_AUTH)); - evaluate_auth_state(ppp, PPP_AUTH_EVENT_TO); - } - } -} - -static void check_to_ipcp(struct pico_device_ppp *ppp) -{ - if (ppp->timer_on & PPP_TIMER_ON_IPCP) { - if (ppp->timer_val == 0) { - ppp->timer_on = (uint8_t) (ppp->timer_on & (~PPP_TIMER_ON_IPCP)); - evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_TO); - } - } -} - -static void pico_ppp_tick(pico_time t, void *arg) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *) arg; - (void)t; - if (ppp->timer_val > 0) - ppp->timer_val--; - - check_to_modem(ppp); - check_to_lcp(ppp); - check_to_auth(ppp); - check_to_ipcp(ppp); - - if (ppp->autoreconnect && ppp->lcp_state == PPP_LCP_STATE_INITIAL) { - ppp_dbg("(Re)connecting...\n"); - evaluate_lcp_state(ppp, PPP_LCP_EVENT_OPEN); - } - - pico_timer_add(1000, pico_ppp_tick, arg); -} - -struct pico_device *pico_ppp_create(void) -{ - struct pico_device_ppp *ppp = PICO_ZALLOC(sizeof(struct pico_device_ppp)); - char devname[MAX_DEVICE_NAME]; - - if (!ppp) - return NULL; - - snprintf(devname, MAX_DEVICE_NAME, "ppp%d", ppp_devnum++); - - if( 0 != pico_device_init((struct pico_device *)ppp, devname, NULL)) { - return NULL; - } - - ppp->dev.overhead = PPP_HDR_SIZE; - ppp->dev.mtu = PICO_PPP_MTU; - ppp->dev.send = pico_ppp_send; - ppp->dev.poll = pico_ppp_poll; - ppp->dev.link_state = pico_ppp_link_state; - ppp->frame_id = (uint8_t)(pico_rand() % 0xFF); - - ppp->modem_state = PPP_MODEM_STATE_INITIAL; - ppp->lcp_state = PPP_LCP_STATE_INITIAL; - ppp->auth_state = PPP_AUTH_STATE_INITIAL; - ppp->ipcp_state = PPP_IPCP_STATE_INITIAL; - - ppp->timer = pico_timer_add(1000, pico_ppp_tick, ppp); - ppp->mru = PICO_PPP_MRU; - - LCPOPT_SET_LOCAL(ppp, LCPOPT_MRU); - LCPOPT_SET_LOCAL(ppp, LCPOPT_AUTH); /* We support authentication, even if it's not part of the req */ - LCPOPT_SET_LOCAL(ppp, LCPOPT_PROTO_COMP); - LCPOPT_SET_LOCAL(ppp, LCPOPT_ADDRCTL_COMP); - - - ppp_dbg("Device %s created.\n", ppp->dev.name); - return (struct pico_device *)ppp; -} - -int pico_ppp_connect(struct pico_device *dev) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev; - ppp->autoreconnect = 1; - return 0; -} - -int pico_ppp_disconnect(struct pico_device *dev) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev; - ppp->autoreconnect = 0; - evaluate_lcp_state(ppp, PPP_LCP_EVENT_CLOSE); - return 0; -} - -int pico_ppp_set_serial_read(struct pico_device *dev, int (*sread)(struct pico_device *, void *, int)) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev; - - if (!dev) - return -1; - - ppp->serial_recv = sread; - return 0; -} - -int pico_ppp_set_serial_write(struct pico_device *dev, int (*swrite)(struct pico_device *, const void *, int)) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev; - - if (!dev) - return -1; - - ppp->serial_send = swrite; - return 0; -} - -int pico_ppp_set_serial_set_speed(struct pico_device *dev, int (*sspeed)(struct pico_device *, uint32_t)) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev; - - if (!dev) - return -1; - - ppp->serial_set_speed = sspeed; - return 0; -} - -int pico_ppp_set_apn(struct pico_device *dev, const char *apn) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev; - - if (!dev) - return -1; - - if (!apn) - return -1; - - strncpy(ppp->apn, apn, sizeof(ppp->apn) - 1); - return 0; -} - -int pico_ppp_set_username(struct pico_device *dev, const char *username) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev; - - if (!dev) - return -1; - - if (!username) - return -1; - - strncpy(ppp->username, username, sizeof(ppp->username) - 1); - return 0; -} - -int pico_ppp_set_password(struct pico_device *dev, const char *password) -{ - struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev; - - if (!dev) - return -1; - - if (!password) - return -1; - - strncpy(ppp->password, password, sizeof(ppp->password) - 1); - return 0; -} diff --git a/ext/picotcp/modules/pico_dev_ppp.h b/ext/picotcp/modules/pico_dev_ppp.h deleted file mode 100644 index 6110e50..0000000 --- a/ext/picotcp/modules/pico_dev_ppp.h +++ /dev/null @@ -1,26 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_PPP -#define INCLUDE_PICO_PPP - -#include "pico_config.h" -#include "pico_device.h" - -void pico_ppp_destroy(struct pico_device *ppp); -struct pico_device *pico_ppp_create(void); - -int pico_ppp_connect(struct pico_device *dev); -int pico_ppp_disconnect(struct pico_device *dev); - -int pico_ppp_set_serial_read(struct pico_device *dev, int (*sread)(struct pico_device *, void *, int)); -int pico_ppp_set_serial_write(struct pico_device *dev, int (*swrite)(struct pico_device *, const void *, int)); -int pico_ppp_set_serial_set_speed(struct pico_device *dev, int (*sspeed)(struct pico_device *, uint32_t)); - -int pico_ppp_set_apn(struct pico_device *dev, const char *apn); -int pico_ppp_set_username(struct pico_device *dev, const char *username); -int pico_ppp_set_password(struct pico_device *dev, const char *password); - -#endif /* INCLUDE_PICO_PPP */ diff --git a/ext/picotcp/modules/pico_dev_tap.c b/ext/picotcp/modules/pico_dev_tap.c deleted file mode 100644 index b80ea6d..0000000 --- a/ext/picotcp/modules/pico_dev_tap.c +++ /dev/null @@ -1,220 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include -#include -#include -#include -#include "pico_device.h" -#include "pico_dev_tap.h" -#include "pico_stack.h" - -#ifndef __FreeBSD__ -#include -#endif - -#include - -struct pico_device_tap { - struct pico_device dev; - int fd; -}; - -#define TUN_MTU 2048 - -// We only support one global link state - we only have two USR signals, we -// can't spread these out over an arbitrary amount of devices. When you unplug -// one tap, you unplug all of them. - -static int link_state = 0; - -static void sig_handler(int signo) -{ - if (signo == SIGUSR1) - link_state = 0; - if (signo == SIGUSR2) - link_state = 1; -} - -static int tap_link_state(__attribute__((unused)) struct pico_device *self) -{ - return link_state; -} - - -static int pico_tap_send(struct pico_device *dev, void *buf, int len) -{ - struct pico_device_tap *tap = (struct pico_device_tap *) dev; - return (int)write(tap->fd, buf, (uint32_t)len); -} - -static int pico_tap_poll(struct pico_device *dev, int loop_score) -{ - struct pico_device_tap *tap = (struct pico_device_tap *) dev; - struct pollfd pfd; - unsigned char buf[TUN_MTU]; - int len; - pfd.fd = tap->fd; - pfd.events = POLLIN; - do { - if (poll(&pfd, 1, 0) <= 0) - return loop_score; - - len = (int)read(tap->fd, buf, TUN_MTU); - if (len > 0) { - loop_score--; - pico_stack_recv(dev, buf, (uint32_t)len); - } - } while(loop_score > 0); - return 0; -} - -/* Public interface: create/destroy. */ - -void pico_tap_destroy(struct pico_device *dev) -{ - struct pico_device_tap *tap = (struct pico_device_tap *) dev; - if(tap->fd > 0) - close(tap->fd); -} - -#ifndef __FreeBSD__ -static int tap_open(char *name) -{ - struct ifreq ifr; - int tap_fd; - if((tap_fd = open("/dev/net/tun", O_RDWR)) < 0) { - return(-1); - } - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - strncpy(ifr.ifr_name, name, IFNAMSIZ); - if(ioctl(tap_fd, TUNSETIFF, &ifr) < 0) { - return(-1); - } - - return tap_fd; -} -#else -static int tap_open(char *name) -{ - int tap_fd; - (void)name; - tap_fd = open("/dev/tap0", O_RDWR); - return tap_fd; -} -#endif - - -#ifndef __FreeBSD__ -static int tap_get_mac(char *name, uint8_t *mac) -{ - int sck; - struct ifreq eth; - int retval = -1; - - - - - sck = socket(AF_INET, SOCK_DGRAM, 0); - if(sck < 0) { - return retval; - } - - memset(ð, 0, sizeof(struct ifreq)); - strcpy(eth.ifr_name, name); - /* call the IOCTL */ - if (ioctl(sck, SIOCGIFHWADDR, ð) < 0) { - perror("ioctl(SIOCGIFHWADDR)"); - return -1; - ; - } - - memcpy (mac, ð.ifr_hwaddr.sa_data, 6); - - - close(sck); - return 0; - -} -#else -#include -#include -#include -static int tap_get_mac(char *name, uint8_t *mac) -{ - struct sockaddr_dl *sdl; - struct ifaddrs *ifap, *root; - if (getifaddrs(&ifap) != 0) - return -1; - - root = ifap; - while(ifap) { - if (strcmp(name, ifap->ifa_name) == 0) - sdl = (struct sockaddr_dl *) ifap->ifa_addr; - - if (sdl->sdl_type == IFT_ETHER) { - memcpy(mac, LLADDR(sdl), 6); - freeifaddrs(root); - return 0; - } - - ifap = ifap->ifa_next; - } - freeifaddrs(root); - return 0; -} -#endif - -struct pico_device *pico_tap_create(char *name) -{ - struct pico_device_tap *tap = PICO_ZALLOC(sizeof(struct pico_device_tap)); - uint8_t mac[6] = {}; - struct sigaction sa; - - if (!tap) - return NULL; - - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - sa.sa_handler = sig_handler; - - if ((sigaction(SIGUSR1, &sa, NULL) == 0) && - (sigaction(SIGUSR2, &sa, NULL) == 0)) - tap->dev.link_state = &tap_link_state; - - tap->dev.overhead = 0; - tap->fd = tap_open(name); - if (tap->fd < 0) { - dbg("Tap creation failed.\n"); - pico_tap_destroy((struct pico_device *)tap); - return NULL; - } - - if (tap_get_mac(name, mac) < 0) { - dbg("Tap mac query failed.\n"); - pico_tap_destroy((struct pico_device *)tap); - return NULL; - } - - mac[5]++; - - if( 0 != pico_device_init((struct pico_device *)tap, name, mac)) { - dbg("Tap init failed.\n"); - pico_tap_destroy((struct pico_device *)tap); - return NULL; - } - - tap->dev.send = pico_tap_send; - tap->dev.poll = pico_tap_poll; - tap->dev.destroy = pico_tap_destroy; - dbg("Device %s created.\n", tap->dev.name); - return (struct pico_device *)tap; -} - diff --git a/ext/picotcp/modules/pico_dev_tap.h b/ext/picotcp/modules/pico_dev_tap.h deleted file mode 100644 index ebc21fe..0000000 --- a/ext/picotcp/modules/pico_dev_tap.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_TAP -#define INCLUDE_PICO_TAP -#include "pico_config.h" -#include "pico_device.h" - -void pico_tap_destroy(struct pico_device *tap); -struct pico_device *pico_tap_create(char *name); - -#endif - diff --git a/ext/picotcp/modules/pico_dev_tap_windows.c b/ext/picotcp/modules/pico_dev_tap_windows.c deleted file mode 100644 index 2e003f8..0000000 --- a/ext/picotcp/modules/pico_dev_tap_windows.c +++ /dev/null @@ -1,1083 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Maxime Vincent - Based on the OpenVPN tun.c driver, under GPL - - NOTES: This is the Windows-only driver, a Linux-equivalent is available, too - You need to have an OpenVPN TUN/TAP network adapter installed, first - This driver is barely working: - * Only TAP-mode is supported (TUN is not) - * it will simply open the first TAP device it can find - * there is memory being allocated that's never freed - * there is no destroy function, yet - * it has only been tested on a Windows 7 machine - *********************************************************************/ - -#include "pico_device.h" -#include "pico_dev_null.h" -#include "pico_stack.h" -#include "pico_dev_tap_windows.h" - -#include -#include -#include -#include "pico_dev_tap_windows_private.h" - -/* - * Debugging info - */ -#define dbg_tap_info(...) /* tap info messages */ -#define dbg_tap(...) /* first level debug */ -#define dbg_win32(...) /* second level detailed win32 debug */ -#define dbg_reg(...) /* third level: registry debug */ - -/* - * Tunnel types - */ -#define DEV_TYPE_UNDEF 0 -#define DEV_TYPE_NULL 1 -#define DEV_TYPE_TUN 2 /* point-to-point IP tunnel */ -#define DEV_TYPE_TAP 3 /* ethernet (802.3) tunnel */ - - -/* - * We try to do all Win32 I/O using overlapped - * (i.e. asynchronous) I/O for a performance win. - */ -struct overlapped_io { -# define IOSTATE_INITIAL 0 -# define IOSTATE_QUEUED 1 /* overlapped I/O has been queued */ -# define IOSTATE_IMMEDIATE_RETURN 2 /* I/O function returned immediately without queueing */ - int iostate; - OVERLAPPED overlapped; - DWORD size; - DWORD flags; - int status; - int addr_defined; - uint8_t *buf_init; - uint32_t buf_init_len; - uint8_t *buf; - uint32_t buf_len; -}; - -struct rw_handle { - HANDLE read; - HANDLE write; -}; - -struct tuntap -{ - int type; /* DEV_TYPE_x as defined in proto.h */ - int ipv6; - int persistent_if; /* if existed before, keep on program end */ - char *actual_name; /* actual name of TUN/TAP dev, usually including unit number */ - int post_open_mtu; - uint8_t mac[6]; - - /* Windows stuff */ - DWORD adapter_index; /*adapter index for TAP-Windows adapter, ~0 if undefined */ - HANDLE hand; - struct overlapped_io reads; /* for overlapped IO */ - struct overlapped_io writes; - struct rw_handle rw_handle; - -}; - - -struct pico_device_tap { - struct pico_device dev; - int statistics_frames_out; - struct tuntap *tt; -}; - - -/* - * Private function prototypes - */ -const struct tap_reg *get_tap_reg (void); -const struct panel_reg *get_panel_reg (void); - - -/* - * Private functions - */ - -/* Get TAP info from Windows registry */ -const struct tap_reg *get_tap_reg (void) -{ - HKEY adapter_key; - LONG status; - DWORD len; - struct tap_reg *first = NULL; - struct tap_reg *last = NULL; - int i = 0; - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - ADAPTER_KEY, - 0, - KEY_READ, - &adapter_key); - - if (status != ERROR_SUCCESS) - { - dbg_reg("Error opening registry key: %s\n", ADAPTER_KEY); - return NULL; - } - - while (1) - { - char enum_name[256]; - char unit_string[256]; - HKEY unit_key; - char component_id_string[] = "ComponentId"; - char component_id[256]; - char net_cfg_instance_id_string[] = "NetCfgInstanceId"; - char net_cfg_instance_id[256]; - DWORD data_type; - - len = sizeof (enum_name); - status = RegEnumKeyEx( - adapter_key, - i, - enum_name, - &len, - NULL, - NULL, - NULL, - NULL); - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) - dbg_reg("Error enumerating registry subkeys of key: %s.\n", ADAPTER_KEY); - - snprintf (unit_string, sizeof(unit_string), "%s\\%s", - ADAPTER_KEY, enum_name); - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - unit_string, - 0, - KEY_READ, - &unit_key); - - if (status != ERROR_SUCCESS) - { - dbg_reg("Error opening registry key: %s\n", unit_string); - } - else - { - len = sizeof (component_id); - status = RegQueryValueEx( - unit_key, - component_id_string, - NULL, - &data_type, - (LPBYTE)component_id, - &len); - - if (status != ERROR_SUCCESS || data_type != REG_SZ) - { - dbg_reg("Error opening registry key: %s\\%s\n", unit_string, component_id_string); - } - else - { - len = sizeof (net_cfg_instance_id); - status = RegQueryValueEx( - unit_key, - net_cfg_instance_id_string, - NULL, - &data_type, - (LPBYTE)net_cfg_instance_id, - &len); - - if (status == ERROR_SUCCESS && data_type == REG_SZ) - { - if (!strcmp (component_id, TAP_WIN_COMPONENT_ID)) - { - struct tap_reg *reg; - reg = PICO_ZALLOC(sizeof(struct tap_reg), 1); - /* ALLOC_OBJ_CLEAR_GC (reg, struct tap_reg, gc); */ - if (!reg) - return NULL; - - /* reg->guid = string_alloc (net_cfg_instance_id, gc); */ - reg->guid = PICO_ZALLOC (strlen(net_cfg_instance_id) + 1, 1); - if (!(reg->guid)) - { - PICO_FREE(reg); - return NULL; - } - - strcpy((char *)reg->guid, net_cfg_instance_id); - /* link into return list */ - if (!first) - first = reg; - - if (last) - last->next = reg; - - last = reg; - } - } - } - - RegCloseKey (unit_key); - } - - ++i; - } - RegCloseKey (adapter_key); - return first; -} - -/* Get Panel info from Windows registry */ -const struct panel_reg *get_panel_reg (void) -{ - LONG status; - HKEY network_connections_key; - DWORD len; - struct panel_reg *first = NULL; - struct panel_reg *last = NULL; - int i = 0; - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - NETWORK_CONNECTIONS_KEY, - 0, - KEY_READ, - &network_connections_key); - - if (status != ERROR_SUCCESS) - { - dbg_reg("Error opening registry key: %s\n", NETWORK_CONNECTIONS_KEY); - return NULL; - } - - while (1) - { - char enum_name[256]; - char connection_string[256]; - HKEY connection_key; - WCHAR name_data[256]; - DWORD name_type; - const WCHAR name_string[] = L"Name"; - - len = sizeof (enum_name); - status = RegEnumKeyEx( - network_connections_key, - i, - enum_name, - &len, - NULL, - NULL, - NULL, - NULL); - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) - dbg_reg("Error enumerating registry subkeys of key: %s.\n", NETWORK_CONNECTIONS_KEY); - - snprintf (connection_string, sizeof(connection_string), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, enum_name); - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - connection_string, - 0, - KEY_READ, - &connection_key); - if (status != ERROR_SUCCESS) - dbg_reg("Error opening registry key: %s\n", connection_string); - else - { - len = sizeof (name_data); - status = RegQueryValueExW( - connection_key, - name_string, - NULL, - &name_type, - (LPBYTE) name_data, - &len); - - if (status != ERROR_SUCCESS || name_type != REG_SZ) - dbg_reg("Error opening registry key: %s\\%s\\%S\n", NETWORK_CONNECTIONS_KEY, connection_string, name_string); - else - { - int n; - LPSTR name; - struct panel_reg *reg; - - /* ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc); */ - reg = PICO_ZALLOC(sizeof(struct panel_reg), 1); - if (!reg) - return NULL; - - n = WideCharToMultiByte (CP_UTF8, 0, name_data, -1, NULL, 0, NULL, NULL); - /* name = gc_malloc (n, false, gc); */ - name = PICO_ZALLOC(n, 1); - if (!name) - { - PICO_FREE(reg); - return NULL; - } - - WideCharToMultiByte (CP_UTF8, 0, name_data, -1, name, n, NULL, NULL); - reg->name = name; - /* reg->guid = string_alloc (enum_name, gc); */ - reg->guid = PICO_ZALLOC(strlen(enum_name) + 1, 1); - if (!reg->guid) - { - PICO_FREE((void *)reg->name); - PICO_FREE((void *)reg); - return NULL; - } - - strcpy((char *)reg->guid, enum_name); - - /* link into return list */ - if (!first) - first = reg; - - if (last) - last->next = reg; - - last = reg; - } - - RegCloseKey (connection_key); - } - - ++i; - } - RegCloseKey (network_connections_key); - - return first; -} - - -void show_tap_win_adapters (void) -{ - int warn_panel_null = 0; - int warn_panel_dup = 0; - int warn_tap_dup = 0; - - int links; - - const struct tap_reg *tr; - const struct tap_reg *tr1; - const struct panel_reg *pr; - - const struct tap_reg *tap_reg = get_tap_reg (); - const struct panel_reg *panel_reg = get_panel_reg (); - - if (!(tap_reg && panel_reg)) - return; - - dbg_tap_info("Available TAP-WIN32 adapters [name, GUID]:\n"); - - /* loop through each TAP-Windows adapter registry entry */ - for (tr = tap_reg; tr != NULL; tr = tr->next) - { - links = 0; - - /* loop through each network connections entry in the control panel */ - for (pr = panel_reg; pr != NULL; pr = pr->next) - { - if (!strcmp (tr->guid, pr->guid)) - { - dbg_tap_info("\t>> '%s' %s\n", pr->name, tr->guid); - ++links; - } - } - if (links > 1) - { - warn_panel_dup = 1; - } - else if (links == 0) - { - /* a TAP adapter exists without a link from the network - connections control panel */ - warn_panel_null = 1; - dbg_tap_info("\t>> [NULL] %s\n", tr->guid); - } - } - /* check for TAP-Windows adapter duplicated GUIDs */ - for (tr = tap_reg; tr != NULL; tr = tr->next) - { - for (tr1 = tap_reg; tr1 != NULL; tr1 = tr1->next) - { - if (tr != tr1 && !strcmp (tr->guid, tr1->guid)) - warn_tap_dup = 1; - } - } - /* warn on registry inconsistencies */ - if (warn_tap_dup) - dbg_tap_info("WARNING: Some TAP-Windows adapters have duplicate GUIDs\n"); - - if (warn_panel_dup) - dbg_tap_info("WARNING: Some TAP-Windows adapters have duplicate links from the Network Connections control panel\n"); - - if (warn_panel_null) - dbg_tap_info("WARNING: Some TAP-Windows adapters have no link from the Network Connections control panel\n"); -} - - -/* Get the GUID of the first TAP device found */ -const char *get_first_device_guid(const struct tap_reg *tap_reg, const struct panel_reg *panel_reg, char *name) -{ - const struct tap_reg *tr; - const struct panel_reg *pr; - /* loop through each TAP-Windows adapter registry entry */ - for (tr = tap_reg; tr != NULL; tr = tr->next) - { - /* loop through each network connections entry in the control panel */ - for (pr = panel_reg; pr != NULL; pr = pr->next) - { - if (!strcmp (tr->guid, pr->guid)) - { - dbg_tap_info("Using first TAP device: '%s' %s\n", pr->name, tr->guid); - if (name) - strcpy(name, pr->name); - - return tr->guid; - } - } - } - return NULL; -} - - - -int open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) -{ - char device_path[256]; - const char *device_guid = NULL; - DWORD len; - - dbg_tap_info("open_tun, tt->ipv6=%d\n", tt->ipv6 ); - - if (!(tt->type == DEV_TYPE_TAP || tt->type == DEV_TYPE_TUN)) - { - dbg_tap_info("Unknown virtual device type: '%s'\n", dev); - return -1; - } - - /* - * Lookup the device name in the registry, using the --dev-node high level name. - */ - { - const struct tap_reg *tap_reg = get_tap_reg(); - const struct panel_reg *panel_reg = get_panel_reg(); - char name[256]; - - if (!(tap_reg && panel_reg)) - { - dbg_tap_info("No TUN/TAP devices found\n"); - return -1; - } - - /* Get the device GUID for the device specified with --dev-node. */ - device_guid = get_first_device_guid (tap_reg, panel_reg, name); - - if (!device_guid) - dbg_tap_info("TAP-Windows adapter '%s' not found\n", dev_node); - - /* Open Windows TAP-Windows adapter */ - snprintf (device_path, sizeof(device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAP_WIN_SUFFIX); - - tt->hand = CreateFile ( - device_path, - GENERIC_READ | GENERIC_WRITE, - 0, /* was: FILE_SHARE_READ */ - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, - 0 - ); - - if (tt->hand == INVALID_HANDLE_VALUE) - dbg_tap_info("CreateFile failed on TAP device: %s\n", device_path); - - /* translate high-level device name into a device instance - GUID using the registry */ - tt->actual_name = PICO_ZALLOC(strlen(name) + 1); - if (tt->actual_name) - strcpy(tt->actual_name, name); - } - - dbg_tap_info("TAP-WIN32 device [%s] opened: %s\n", tt->actual_name, device_path); - /* TODO TODO TODO */ - /* tt->adapter_index = get_adapter_index (device_guid); */ - - /* get driver version info */ - { - ULONG info[3]; - /* TODO TODO TODO */ - /* CLEAR (info); */ - if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_VERSION, &info, sizeof (info), &info, sizeof (info), &len, NULL)) - { - dbg_tap_info ("TAP-Windows Driver Version %d.%d %s\n", - (int) info[0], - (int) info[1], - (info[2] ? "(DEBUG)" : "")); - - } - - if (!(info[0] == TAP_WIN_MIN_MAJOR && info[1] >= TAP_WIN_MIN_MINOR)) - dbg_tap_info ("ERROR: This version of " PACKAGE_NAME " requires a TAP-Windows driver that is at least version %d.%d \ - -- If you recently upgraded your " PACKAGE_NAME " distribution, \ - a reboot is probably required at this point to get Windows to see the new driver.\n", - TAP_WIN_MIN_MAJOR, - TAP_WIN_MIN_MINOR); - - /* usage of numeric constants is ugly, but this is really tied to - * *this* version of the driver - */ - if ( tt->ipv6 && tt->type == DEV_TYPE_TUN && info[0] == 9 && info[1] < 8) - { - dbg_tap_info("WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will be disabled. \ - Upgrade to Tap-Win32 9.8 (2.2-beta3 release or later) or use TAP mode to get IPv6\n", (int) info[0], (int) info[1] ); - tt->ipv6 = 0; - } - - /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy - */ - if ( tt->type == DEV_TYPE_TUN && info[0] == 9 && info[1] == 8) - { - dbg_tap_info("ERROR: Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode. Upgrade to Tap-Win32 9.9 (2.2.2 release or later) or use TAP mode\n", (int) info[0], (int) info[1] ); - } - } - - /* get driver MTU */ - { - ULONG mtu; - if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_MTU, - &mtu, sizeof (mtu), - &mtu, sizeof (mtu), &len, NULL)) - { - tt->post_open_mtu = (int) mtu; - dbg_tap_info("TAP-Windows MTU=%d\n", (int) mtu); - } - } - - - /* get driver MAC */ - { - uint8_t mac[6] = { - 0, 0, 0, 0, 0, 0 - }; - if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_MAC, - mac, sizeof (mac), - mac, sizeof (mac), &len, NULL)) - { - dbg_tap_info("TAP-Windows MAC=[%x,%x,%x,%x,%x,%x]\n", mac[0], mac[1], mac[2], - mac[2], mac[4], mac[5]); - memcpy(tt->mac, mac, sizeof(mac)); - } - } - - /* set point-to-point mode if TUN device */ - - if (tt->type == DEV_TYPE_TUN) - { - dbg_tap_info("TUN type not supported for now...\n"); - return -1; - } - else if (tt->type == DEV_TYPE_TAP) - { /* TAP DEVICE */ - dbg_tap_info("TODO: Set Point-to-point through DeviceIoControl\n"); - } - - /* set driver media status to 'connected' */ - { - ULONG status = TRUE; - if (!DeviceIoControl (tt->hand, TAP_WIN_IOCTL_SET_MEDIA_STATUS, - &status, sizeof (status), - &status, sizeof (status), &len, NULL)) - dbg_tap_info("WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call."); - } - - return 0; -} - - - - -/* TODO: Closing a TUN device is currently not implemented */ -/* - void close_tun (struct tuntap *tt) - { - (void)tt; - } - */ - - -int tap_win_getinfo (const struct tuntap *tt, char *buf, int bufsize) -{ - if (tt && tt->hand != NULL && buf != NULL) - { - DWORD len; - if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_INFO, - buf, bufsize, - buf, bufsize, - &len, NULL)) - { - return 0; - } - } - - return -1; -} - -void tun_show_debug (struct tuntap *tt, char *buf, int bufsize) -{ - if (tt && tt->hand != NULL && buf != NULL) - { - DWORD len; - while (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_LOG_LINE, - buf, bufsize, - buf, bufsize, - &len, NULL)) - { - dbg_tap_info("TAP-Windows: %s\n", buf); - } - } -} - - -/* returns the state */ -int tun_read_queue (struct tuntap *tt, uint8_t *buffer, int maxsize) -{ - if (tt->reads.iostate == IOSTATE_INITIAL) - { - DWORD len = 1500; - BOOL status; - int err; - - /* reset buf to its initial state */ - tt->reads.buf = tt->reads.buf_init; - tt->reads.buf_len = tt->reads.buf_init_len; - - len = maxsize ? maxsize : (tt->reads.buf_len); - if (len > (tt->reads.buf_len)) /* clip to buffer len */ - len = tt->reads.buf_len; - - /* the overlapped read will signal this event on I/O completion */ - if (!ResetEvent (tt->reads.overlapped.hEvent)) - dbg_tap("ResetEvent failed\n"); - - status = ReadFile( - tt->hand, - buffer, - len, - &tt->reads.size, - &tt->reads.overlapped - ); - - if (status) /* operation completed immediately? */ - { - /* since we got an immediate return, we must signal the event object ourselves */ - /* ASSERT (SetEvent (tt->reads.overlapped.hEvent)); */ - if (!SetEvent (tt->reads.overlapped.hEvent)) - dbg_tap("SetEvent failed\n"); - - tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN; - tt->reads.status = 0; - - dbg_win32 ("WIN32 I/O: TAP Read immediate return [%d,%d]\n", - (int) len, - (int) tt->reads.size); - } - else - { - err = GetLastError (); - if (err == ERROR_IO_PENDING) /* operation queued? */ - { - tt->reads.iostate = IOSTATE_QUEUED; - tt->reads.status = err; - dbg_win32 ("WIN32 I/O: TAP Read queued [%d]\n", (int) len); - } - else /* error occurred */ - { - if (!SetEvent (tt->reads.overlapped.hEvent)) - dbg_tap("SetEvent failed\n"); - - tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN; - tt->reads.status = err; - dbg_tap ("WIN32 I/O: TAP Read error [%d] : %d\n", (int) len, (int) err); - } - } - } - - return tt->reads.iostate; -} - -/* Finalize any pending overlapped IO's */ -int tun_finalize(HANDLE h, struct overlapped_io *io, uint8_t **buf, uint32_t *buf_len) -{ - int ret = -1; - BOOL status; - - switch (io->iostate) - { - case IOSTATE_QUEUED: - status = GetOverlappedResult( - h, - &io->overlapped, - &io->size, - 0u - ); - if (status) - { - /* successful return for a queued operation */ - if (buf) - { - *buf = io->buf; - *buf_len = io->buf_len; - } - - ret = io->size; - io->iostate = IOSTATE_INITIAL; - - if (!ResetEvent (io->overlapped.hEvent)) - dbg_tap("ResetEvent in finalize failed!\n"); - - dbg_win32 ("WIN32 I/O: TAP Completion success: QUEUED! [%d]\n", ret); - } - else - { - /* error during a queued operation */ - /* error, or just not completed? */ - ret = 0; - if (GetLastError() != ERROR_IO_INCOMPLETE) - { - /* if no error (i.e. just not finished yet), - then DON'T execute this code */ - io->iostate = IOSTATE_INITIAL; - if (!ResetEvent (io->overlapped.hEvent)) - dbg_tap("ResetEvent in finalize failed!\n"); - - dbg_tap("WIN32 I/O: TAP Completion error\n"); - ret = -1; /* There actually was an error */ - } - } - - break; - - case IOSTATE_IMMEDIATE_RETURN: - io->iostate = IOSTATE_INITIAL; - if (!ResetEvent (io->overlapped.hEvent)) - dbg_tap("ResetEvent in finalize failed!\n"); - - if (io->status) - { - /* error return for a non-queued operation */ - SetLastError (io->status); - ret = -1; - dbg_tap("WIN32 I/O: TAP Completion non-queued error\n"); - } - else - { - /* successful return for a non-queued operation */ - if (buf) - *buf = io->buf; - - ret = io->size; - dbg_win32 ("WIN32 I/O: TAP Completion non-queued success [%d]\n", ret); - } - - break; - - case IOSTATE_INITIAL: /* were we called without proper queueing? */ - SetLastError (ERROR_INVALID_FUNCTION); - ret = -1; - dbg_tap ("WIN32 I/O: TAP Completion BAD STATE\n"); - break; - - default: - dbg_tap ("Some weird case happened..\n"); - } - - if (buf) - *buf_len = ret; - - return ret; -} - - - -/* returns the amount of bytes written */ -int tun_write_queue (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) -{ - if (tt->writes.iostate == IOSTATE_INITIAL) - { - BOOL status; - int err; - - /* make a private copy of buf */ - tt->writes.buf = tt->writes.buf_init; - tt->writes.buf_len = buf_len; - memcpy(tt->writes.buf, buf, buf_len); - - /* the overlapped write will signal this event on I/O completion */ - if (!ResetEvent (tt->writes.overlapped.hEvent)) - dbg_tap("ResetEvent in write_queue failed!\n"); - - status = WriteFile( - tt->hand, - tt->writes.buf, - tt->writes.buf_len, - &tt->writes.size, - &tt->writes.overlapped - ); - - if (status) /* operation completed immediately? */ - { - tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN; - - /* since we got an immediate return, we must signal the event object ourselves */ - if (!SetEvent (tt->writes.overlapped.hEvent)) - dbg_tap("SetEvent in write_queue failed!\n"); - - tt->writes.status = 0; - - dbg_win32 ("WIN32 I/O: TAP Write immediate return [%d,%d]\n", - (int)(tt->writes.buf_len), - (int)tt->writes.size); - } - else - { - err = GetLastError (); - if (err == ERROR_IO_PENDING) /* operation queued? */ - { - tt->writes.iostate = IOSTATE_QUEUED; - tt->writes.status = err; - dbg_win32("WIN32 I/O: TAP Write queued [%d]\n", - (tt->writes.buf_len)); - } - else /* error occurred */ - { - if (!SetEvent (tt->writes.overlapped.hEvent)) - dbg_tap("SetEvent in write_queue failed!\n"); - - tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN; - tt->writes.status = err; - dbg_tap ("WIN32 I/O: TAP Write error [%d] : %d\n", (int) &tt->writes.buf_len, (int) err); - } - } - } - - return tt->writes.iostate; -} - -static inline int overlapped_io_active (struct overlapped_io *o) -{ - return o->iostate == IOSTATE_QUEUED || o->iostate == IOSTATE_IMMEDIATE_RETURN; -} - -/* if >= 0: returns the amount of bytes read, otherwise error! */ -static int tun_write_win32 (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) -{ - int err = 0; - int status = 0; - if (overlapped_io_active (&tt->writes)) - { - status = tun_finalize (tt->hand, &tt->writes, NULL, 0); - if (status == 0) - { - /* busy, just wait, do not schedule a new write */ - return 0; - } - - if (status < 0) - err = GetLastError (); - } - - /* the overlapped IO is done, now we can schedule a new write */ - tun_write_queue (tt, buf, buf_len); - if (status < 0) - { - SetLastError (err); - return status; - } - else - return buf_len; -} - - -/* if >= 0: returns the amount of bytes read, otherwise error! */ -static int tun_read_win32 (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) -{ - int err = 0; - int status = 0; - - - /* First, finish possible pending IOs */ - if (overlapped_io_active (&tt->reads)) - { - status = tun_finalize (tt->hand, &tt->reads, &buf, &buf_len); - if (status == 0) - { - /* busy, just wait, do not schedule a new read */ - return 0; - } - - if (status < 0) - { - dbg_tap ("tun_finalize status < 0: %d\n", status); - err = GetLastError (); - } - - if (status > 0) - { - return buf_len; - } - } - - /* If no pending IOs, schedule a new read */ - /* queue, or immediate return */ - if (IOSTATE_IMMEDIATE_RETURN == tun_read_queue(tt, buf, buf_len)) - { - return tt->reads.size; - } - - /* If the pending IOs gave an error, report it */ - if (status < 0) - { - SetLastError (err); - return status; - } - else - { - /* no errors, but the newly scheduled read is now pending */ - return 0; - } -} - - -static int read_tun_buffered(struct tuntap *tt, uint8_t *buf, uint32_t buf_len) -{ - return tun_read_win32 (tt, buf, buf_len); -} - -static int write_tun_buffered(struct tuntap *tt, uint8_t *buf, uint32_t buf_len) -{ - return tun_write_win32 (tt, buf, buf_len); -} - - -static int pico_tap_send(struct pico_device *dev, void *buf, int len) -{ - uint32_t bytes_sent = 0; - struct pico_device_tap *tap = (struct pico_device_tap *) dev; - - /* Increase the statistic count */ - tap->statistics_frames_out++; - - bytes_sent = write_tun_buffered (tap->tt, buf, len); - dbg_tap("TX> sent %d bytes\n", bytes_sent); - - /* Discard the frame content silently. */ - return bytes_sent; -} - -uint8_t recv_buffer[1500]; - -static int pico_tap_poll(struct pico_device *dev, int loop_score) -{ - struct pico_device_tap *tap = (struct pico_device_tap *) dev; - while (loop_score) - { - int bytes_read = read_tun_buffered(tap->tt, recv_buffer, 1500); - loop_score--; - if (bytes_read > 0) - { - dbg_tap("RX< recvd: %d bytes\n", bytes_read); - pico_stack_recv(dev, recv_buffer, bytes_read); - /* break; */ - } - else - break; - } - return loop_score; -} - - - -#define CLEAR(x) memset(&(x), 0, sizeof(x)) - -void overlapped_io_init (struct overlapped_io *o, int event_state) -{ - CLEAR (*o); - - /* manual reset event, initially set according to event_state */ - o->overlapped.hEvent = CreateEvent (NULL, TRUE, event_state, NULL); - if (o->overlapped.hEvent == NULL) - dbg_tap ("Error: overlapped_io_init: CreateEvent failed\n"); - - /* allocate buffer for overlapped I/O */ - o->buf_init = PICO_ZALLOC(1500); /* XXX: MTU */ - o->buf_init_len = 1500; /* XXX: MTU */ - if (!(o->buf_init)) - dbg_tap("buffer alloc failed!\n"); /* XXX: return -1 or so? */ - else - dbg_tap("overlapped_io_init buffer allocated!\n"); -} - -void init_tun_post (struct tuntap *tt) -{ - dbg_tap("TUN post init (for overlapped io)\n"); - overlapped_io_init (&tt->reads, FALSE); - overlapped_io_init (&tt->writes, TRUE); - tt->rw_handle.read = tt->reads.overlapped.hEvent; - tt->rw_handle.write = tt->writes.overlapped.hEvent; -} - - -/* - * Public interface: pico_tap_create - * TODO: pico_tap_destroy - */ - -struct pico_device *pico_tap_create(char *name, uint8_t *mac) -{ - struct pico_device_tap *tap = PICO_ZALLOC(sizeof(struct pico_device_tap)); - struct tuntap *tt = PICO_ZALLOC(sizeof(struct tuntap), 1); - - if (!(tap) || !(tt)) - return NULL; - - tap->dev.overhead = 0; - tap->statistics_frames_out = 0; - tap->dev.send = pico_tap_send; - tap->dev.poll = pico_tap_poll; - - show_tap_win_adapters(); - - tt->type = DEV_TYPE_TAP; - if (open_tun(NULL, NULL, "tap0", tt)) - { - dbg_tap("Failed to create TAP device!\n"); - PICO_FREE(tt); - PICO_FREE(tap); - return NULL; - } - - tap->tt = tt; - - if( 0 != pico_device_init((struct pico_device *)tap, name, mac)) { - return NULL; - } - - init_tun_post(tt); /* init overlapped io */ - - dbg_tap("Device %s created.\n", tap->dev.name); - - return (struct pico_device *)tap; -} - diff --git a/ext/picotcp/modules/pico_dev_tap_windows.h b/ext/picotcp/modules/pico_dev_tap_windows.h deleted file mode 100755 index 25bd4fc..0000000 --- a/ext/picotcp/modules/pico_dev_tap_windows.h +++ /dev/null @@ -1,17 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_TAP -#define INCLUDE_PICO_TAP -#include "pico_config.h" -#include "pico_device.h" - -/* will look for the first TAP device available, and use it */ -struct pico_device *pico_tap_create(char *name, uint8_t *mac); -/* TODO: not implemented yet */ -/* void pico_tap_destroy(struct pico_device *null); */ - -#endif - diff --git a/ext/picotcp/modules/pico_dev_tap_windows_private.h b/ext/picotcp/modules/pico_dev_tap_windows_private.h deleted file mode 100644 index 8f3b192..0000000 --- a/ext/picotcp/modules/pico_dev_tap_windows_private.h +++ /dev/null @@ -1,89 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Maxime Vincent - Based on the OpenVPN tun.c driver, under GPL - - NOTES: This is the Windows-only driver, a Linux-equivalent is available, too - You need to have an OpenVPN TUN/TAP network adapter installed, first - This driver is barely working: - * Only TAP-mode is supported (TUN is not) - * it will simply open the first TAP device it can find - * there is memory being allocated that's never freed - * there is no destroy function, yet - * it has only been tested on a Windows 7 machine - *********************************************************************/ - -#ifndef __PICO_DEV_TAP_WINDOWS_PRIVATE_H -#define __PICO_DEV_TAP_WINDOWS_PRIVATE_H - -/* Extra defines (vnz) */ -#define TAP_WIN_COMPONENT_ID "tap0901" -#define TAP_WIN_MIN_MAJOR 9 -#define TAP_WIN_MIN_MINOR 9 -#define PACKAGE_NAME "PicoTCP WinTAP" - -/* Extra structs */ -struct tap_reg -{ - const char *guid; - struct tap_reg *next; -}; - -struct panel_reg -{ - const char *name; - const char *guid; - struct panel_reg *next; -}; - - -/* - * ============= - * TAP IOCTLs - * ============= - */ - -#define TAP_WIN_CONTROL_CODE(request, method) \ - CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) - -/* Present in 8.1 */ - -#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED) - -/* Added in 8.2 */ - -/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */ -#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED) - -/* - * ================= - * Registry keys - * ================= - */ - -#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" - -#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" - -/* - * ====================== - * Filesystem prefixes - * ====================== - */ - -#define USERMODEDEVICEDIR "\\\\.\\Global\\" -#define SYSDEVICEDIR "\\Device\\" -#define USERDEVICEDIR "\\DosDevices\\Global\\" -#define TAP_WIN_SUFFIX ".tap" - -#endif diff --git a/ext/picotcp/modules/pico_dev_tun.c b/ext/picotcp/modules/pico_dev_tun.c deleted file mode 100644 index c5791d6..0000000 --- a/ext/picotcp/modules/pico_dev_tun.c +++ /dev/null @@ -1,110 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include -#include -#include -#include -#include "pico_device.h" -#include "pico_dev_tun.h" -#include "pico_stack.h" - -#include - -struct pico_device_tun { - struct pico_device dev; - int fd; -}; - -#define TUN_MTU 2048 - -static int pico_tun_send(struct pico_device *dev, void *buf, int len) -{ - struct pico_device_tun *tun = (struct pico_device_tun *) dev; - return (int)write(tun->fd, buf, (uint32_t)len); -} - -static int pico_tun_poll(struct pico_device *dev, int loop_score) -{ - struct pico_device_tun *tun = (struct pico_device_tun *) dev; - struct pollfd pfd; - unsigned char buf[TUN_MTU]; - int len; - pfd.fd = tun->fd; - pfd.events = POLLIN; - do { - if (poll(&pfd, 1, 0) <= 0) - return loop_score; - - len = (int)read(tun->fd, buf, TUN_MTU); - if (len > 0) { - loop_score--; - pico_stack_recv(dev, buf, (uint32_t)len); - } - } while(loop_score > 0); - return 0; -} - -/* Public interface: create/destroy. */ - -void pico_tun_destroy(struct pico_device *dev) -{ - struct pico_device_tun *tun = (struct pico_device_tun *) dev; - if(tun->fd > 0) - close(tun->fd); -} - - -static int tun_open(char *name) -{ - struct ifreq ifr; - int tun_fd; - if((tun_fd = open("/dev/net/tun", O_RDWR)) < 0) { - return(-1); - } - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - strncpy(ifr.ifr_name, name, IFNAMSIZ); - if(ioctl(tun_fd, TUNSETIFF, &ifr) < 0) { - return(-1); - } - - return tun_fd; -} - - - -struct pico_device *pico_tun_create(char *name) -{ - struct pico_device_tun *tun = PICO_ZALLOC(sizeof(struct pico_device_tun)); - - if (!tun) - return NULL; - - if( 0 != pico_device_init((struct pico_device *)tun, name, NULL)) { - dbg("Tun init failed.\n"); - pico_tun_destroy((struct pico_device *)tun); - return NULL; - } - - tun->dev.overhead = 0; - tun->fd = tun_open(name); - if (tun->fd < 0) { - dbg("Tun creation failed.\n"); - pico_tun_destroy((struct pico_device *)tun); - return NULL; - } - - tun->dev.send = pico_tun_send; - tun->dev.poll = pico_tun_poll; - tun->dev.destroy = pico_tun_destroy; - dbg("Device %s created.\n", tun->dev.name); - return (struct pico_device *)tun; -} - diff --git a/ext/picotcp/modules/pico_dev_tun.h b/ext/picotcp/modules/pico_dev_tun.h deleted file mode 100644 index 4dd477e..0000000 --- a/ext/picotcp/modules/pico_dev_tun.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_TUN -#define INCLUDE_PICO_TUN -#include "pico_config.h" -#include "pico_device.h" - -void pico_tun_destroy(struct pico_device *tun); -struct pico_device *pico_tun_create(char *name); - -#endif - diff --git a/ext/picotcp/modules/pico_dev_vde.c b/ext/picotcp/modules/pico_dev_vde.c deleted file mode 100644 index df07a3b..0000000 --- a/ext/picotcp/modules/pico_dev_vde.c +++ /dev/null @@ -1,115 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera - *********************************************************************/ - -#ifndef UNIT_TEST -#include -#endif -#include "pico_device.h" -#include "pico_dev_vde.h" -#include "pico_stack.h" - -#include - -struct pico_device_vde { - struct pico_device dev; - char *sock; - VDECONN *conn; - uint32_t counter_in; - uint32_t counter_out; - uint32_t lost_in; - uint32_t lost_out; -}; - -#define VDE_MTU 65536 - -static int pico_vde_send(struct pico_device *dev, void *buf, int len) -{ - struct pico_device_vde *vde = (struct pico_device_vde *) dev; - /* dbg("[%s] send %d bytes.\n", dev->name, len); */ - if ((vde->lost_out == 0) || ((pico_rand() % 100) > vde->lost_out)) - return (int)vde_send(vde->conn, buf, (uint32_t)len, 0); - else - return len; /* Silently discarded "on the wire" */ - -} - -static int pico_vde_poll(struct pico_device *dev, int loop_score) -{ - struct pico_device_vde *vde = (struct pico_device_vde *) dev; - struct pollfd pfd; - unsigned char buf[VDE_MTU]; - int len; - pfd.fd = vde_datafd(vde->conn); - pfd.events = POLLIN; - do { - if (poll(&pfd, 1, 0) <= 0) - return loop_score; - - len = (int)vde_recv(vde->conn, buf, VDE_MTU, 0); - if (len > 0) { - /* dbg("Received pkt.\n"); */ - if ((vde->lost_in == 0) || ((pico_rand() % 100) > vde->lost_in)) { - loop_score--; - pico_stack_recv(dev, buf, (uint32_t)len); - } - } - } while(loop_score > 0); - return 0; -} - -/* Public interface: create/destroy. */ - -void pico_vde_destroy(struct pico_device *dev) -{ - struct pico_device_vde *vde = (struct pico_device_vde *) dev; - vde_close(vde->conn); - usleep(100000); - sync(); -} - -void pico_vde_set_packetloss(struct pico_device *dev, uint32_t in_pct, uint32_t out_pct) -{ - struct pico_device_vde *vde = (struct pico_device_vde *) dev; - vde->lost_in = in_pct; - vde->lost_out = out_pct; -} - - - -struct pico_device *pico_vde_create(char *sock, char *name, uint8_t *mac) -{ - struct pico_device_vde *vde = PICO_ZALLOC(sizeof(struct pico_device_vde)); - struct vde_open_args open_args = { - .mode = 0700 - }; - char vdename[] = "picotcp"; - - if (!vde) - return NULL; - - if( 0 != pico_device_init((struct pico_device *)vde, name, mac)) { - dbg ("Vde init failed.\n"); - pico_vde_destroy((struct pico_device *)vde); - return NULL; - } - - vde->dev.overhead = 0; - vde->sock = PICO_ZALLOC(strlen(sock) + 1); - memcpy(vde->sock, sock, strlen(sock)); - vde->conn = vde_open(sock, vdename, &open_args); - if (!vde->conn) { - pico_vde_destroy((struct pico_device *)vde); - return NULL; - } - - vde->dev.send = pico_vde_send; - vde->dev.poll = pico_vde_poll; - vde->dev.destroy = pico_vde_destroy; - dbg("Device %s created.\n", vde->dev.name); - return (struct pico_device *)vde; -} - diff --git a/ext/picotcp/modules/pico_dev_vde.h b/ext/picotcp/modules/pico_dev_vde.h deleted file mode 100644 index c6c999e..0000000 --- a/ext/picotcp/modules/pico_dev_vde.h +++ /dev/null @@ -1,18 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - - *********************************************************************/ -#ifndef INCLUDE_PICO_VDE -#define INCLUDE_PICO_VDE -#include "pico_config.h" -#include "pico_device.h" -#include - -void pico_vde_destroy(struct pico_device *vde); -struct pico_device *pico_vde_create(char *sock, char *name, uint8_t *mac); -void pico_vde_set_packetloss(struct pico_device *dev, uint32_t in_pct, uint32_t out_pct); - -#endif - diff --git a/ext/picotcp/modules/pico_dhcp_client.c b/ext/picotcp/modules/pico_dhcp_client.c deleted file mode 100644 index f834dd6..0000000 --- a/ext/picotcp/modules/pico_dhcp_client.c +++ /dev/null @@ -1,990 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Kristof Roelants, Frederik Van Slycken - *********************************************************************/ - - -#include "pico_dhcp_client.h" -#include "pico_stack.h" -#include "pico_config.h" -#include "pico_device.h" -#include "pico_ipv4.h" -#include "pico_socket.h" -#include "pico_eth.h" - -#if (defined PICO_SUPPORT_DHCPC && defined PICO_SUPPORT_UDP) -#define dhcpc_dbg(...) do {} while(0) -/* #define dhcpc_dbg dbg */ - -/* timer values */ -#define DHCP_CLIENT_REINIT 6000 /* msec */ -#define DHCP_CLIENT_RETRANS 4 /* sec */ -#define DHCP_CLIENT_RETRIES 3 - -#define DHCP_CLIENT_TIMER_STOPPED 0 -#define DHCP_CLIENT_TIMER_STARTED 1 - -/* maximum size of a DHCP message */ -#define DHCP_CLIENT_MAXMSGZISE (PICO_IP_MRU - PICO_SIZE_IP4HDR) -#define PICO_DHCP_HOSTNAME_MAXLEN 64U - -static char dhcpc_host_name[PICO_DHCP_HOSTNAME_MAXLEN] = ""; -static char dhcpc_domain_name[PICO_DHCP_HOSTNAME_MAXLEN] = ""; - - -enum dhcp_client_state { - DHCP_CLIENT_STATE_INIT_REBOOT = 0, - DHCP_CLIENT_STATE_REBOOTING, - DHCP_CLIENT_STATE_INIT, - DHCP_CLIENT_STATE_SELECTING, - DHCP_CLIENT_STATE_REQUESTING, - DHCP_CLIENT_STATE_BOUND, - DHCP_CLIENT_STATE_RENEWING, - DHCP_CLIENT_STATE_REBINDING -}; - - -#define PICO_DHCPC_TIMER_INIT 0 -#define PICO_DHCPC_TIMER_REQUEST 1 -#define PICO_DHCPC_TIMER_RENEW 2 -#define PICO_DHCPC_TIMER_REBIND 3 -#define PICO_DHCPC_TIMER_T1 4 -#define PICO_DHCPC_TIMER_T2 5 -#define PICO_DHCPC_TIMER_LEASE 6 -#define PICO_DHCPC_TIMER_ARRAY_SIZE 7 - -struct dhcp_client_timer -{ - uint8_t state; - unsigned int type; - uint32_t xid; -}; - -struct pico_dhcp_client_cookie -{ - uint8_t event; - uint8_t retry; - uint32_t xid; - uint32_t *uid; - enum dhcp_client_state state; - void (*cb)(void*dhcpc, int code); - pico_time init_timestamp; - struct pico_socket *s; - struct pico_ip4 address; - struct pico_ip4 netmask; - struct pico_ip4 gateway; - struct pico_ip4 nameserver[2]; - struct pico_ip4 server_id; - struct pico_device *dev; - struct dhcp_client_timer *timer[PICO_DHCPC_TIMER_ARRAY_SIZE]; - uint32_t t1_time; - uint32_t t2_time; - uint32_t lease_time; - uint32_t renew_time; - uint32_t rebind_time; -}; - -static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc); -static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf); -static int8_t pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type); -static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s); -static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf); - -static const struct pico_ip4 bcast_netmask = { - .addr = 0xFFFFFFFF -}; - -static struct pico_ip4 inaddr_any = { - 0 -}; - - -static int dhcp_cookies_cmp(void *ka, void *kb) -{ - struct pico_dhcp_client_cookie *a = ka, *b = kb; - if (a->xid == b->xid) - return 0; - - return (a->xid < b->xid) ? (-1) : (1); -} -PICO_TREE_DECLARE(DHCPCookies, dhcp_cookies_cmp); - -static struct pico_dhcp_client_cookie *pico_dhcp_client_add_cookie(uint32_t xid, struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid) -{ - struct pico_dhcp_client_cookie *dhcpc = NULL, *found = NULL, test = { - 0 - }; - - test.xid = xid; - found = pico_tree_findKey(&DHCPCookies, &test); - if (found) { - pico_err = PICO_ERR_EAGAIN; - return NULL; - } - - dhcpc = PICO_ZALLOC(sizeof(struct pico_dhcp_client_cookie)); - if (!dhcpc) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - dhcpc->state = DHCP_CLIENT_STATE_INIT; - dhcpc->xid = xid; - dhcpc->uid = uid; - *(dhcpc->uid) = 0; - dhcpc->cb = cb; - dhcpc->dev = dev; - - pico_tree_insert(&DHCPCookies, dhcpc); - return dhcpc; -} - -static void pico_dhcp_client_stop_timers(struct pico_dhcp_client_cookie *dhcpc); -static int pico_dhcp_client_del_cookie(uint32_t xid) -{ - struct pico_dhcp_client_cookie test = { - 0 - }, *found = NULL; - - test.xid = xid; - found = pico_tree_findKey(&DHCPCookies, &test); - if (!found) - return -1; - - pico_dhcp_client_stop_timers(found); - pico_socket_close(found->s); - found->s = NULL; - pico_ipv4_link_del(found->dev, found->address); - pico_tree_delete(&DHCPCookies, found); - PICO_FREE(found); - return 0; -} - -static struct pico_dhcp_client_cookie *pico_dhcp_client_find_cookie(uint32_t xid) -{ - struct pico_dhcp_client_cookie test = { - 0 - }, *found = NULL; - - test.xid = xid; - found = pico_tree_findKey(&DHCPCookies, &test); - if (found) - return found; - else - return NULL; -} - -static void pico_dhcp_client_timer_handler(pico_time now, void *arg); -static void pico_dhcp_client_reinit(pico_time now, void *arg); -static struct dhcp_client_timer *pico_dhcp_timer_add(uint8_t type, uint32_t time, struct pico_dhcp_client_cookie *ck) -{ - struct dhcp_client_timer *t; - - t = PICO_ZALLOC(sizeof(struct dhcp_client_timer)); - if (!t) - return NULL; - - t->state = DHCP_CLIENT_TIMER_STARTED; - t->xid = ck->xid; - t->type = type; - pico_timer_add(time, pico_dhcp_client_timer_handler, t); - if (ck->timer[type]) { - ck->timer[type]->state = DHCP_CLIENT_TIMER_STOPPED; - } - - ck->timer[type] = t; - return t; -} - -static int dhcp_get_timer_event(struct pico_dhcp_client_cookie *dhcpc, unsigned int type) -{ - const int events[PICO_DHCPC_TIMER_ARRAY_SIZE] = - { - PICO_DHCP_EVENT_RETRANSMIT, - PICO_DHCP_EVENT_RETRANSMIT, - PICO_DHCP_EVENT_RETRANSMIT, - PICO_DHCP_EVENT_RETRANSMIT, - PICO_DHCP_EVENT_T1, - PICO_DHCP_EVENT_T2, - PICO_DHCP_EVENT_LEASE - }; - - if (type == PICO_DHCPC_TIMER_REQUEST) { - if (++dhcpc->retry > DHCP_CLIENT_RETRIES) { - reset(dhcpc, NULL); - return PICO_DHCP_EVENT_NONE; - } - } else if (type < PICO_DHCPC_TIMER_T1) { - dhcpc->retry++; - } - - return events[type]; -} - -static void pico_dhcp_client_timer_handler(pico_time now, void *arg) -{ - struct dhcp_client_timer *t = (struct dhcp_client_timer *)arg; - struct pico_dhcp_client_cookie *dhcpc; - - if (!t) - return; - - (void) now; - if (t->state != DHCP_CLIENT_TIMER_STOPPED) { - dhcpc = pico_dhcp_client_find_cookie(t->xid); - if (dhcpc && dhcpc->timer) { - t->state = DHCP_CLIENT_TIMER_STOPPED; - if ((t->type == PICO_DHCPC_TIMER_INIT) && (dhcpc->state < DHCP_CLIENT_STATE_SELECTING)) { - pico_dhcp_client_reinit(now, dhcpc); - } else if (t->type != PICO_DHCPC_TIMER_INIT) { - dhcpc->event = (uint8_t)dhcp_get_timer_event(dhcpc, t->type); - if (dhcpc->event != PICO_DHCP_EVENT_NONE) - pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL); - } - } - } -} - -static void pico_dhcp_client_timer_stop(struct pico_dhcp_client_cookie *dhcpc, int type) -{ - if (dhcpc->timer[type]) { - dhcpc->timer[type]->state = DHCP_CLIENT_TIMER_STOPPED; - } - -} - - -static void pico_dhcp_client_reinit(pico_time now, void *arg) -{ - struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg; - (void) now; - - if (dhcpc->s) { - pico_socket_close(dhcpc->s); - dhcpc->s = NULL; - } - - if (++dhcpc->retry > DHCP_CLIENT_RETRIES) { - pico_err = PICO_ERR_EAGAIN; - if (dhcpc->cb) - dhcpc->cb(dhcpc, PICO_DHCP_ERROR); - - pico_dhcp_client_del_cookie(dhcpc->xid); - return; - } - - pico_dhcp_client_init(dhcpc); - return; -} - - -static void pico_dhcp_client_stop_timers(struct pico_dhcp_client_cookie *dhcpc) -{ - int i; - dhcpc->retry = 0; - for (i = 0; i < PICO_DHCPC_TIMER_ARRAY_SIZE; i++) - pico_dhcp_client_timer_stop(dhcpc, i); -} - -static void pico_dhcp_client_start_init_timer(struct pico_dhcp_client_cookie *dhcpc) -{ - uint32_t time = 0; - /* timer value is doubled with every retry (exponential backoff) */ - time = (uint32_t) (DHCP_CLIENT_RETRANS << dhcpc->retry); - pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, time * 1000, dhcpc); -} - -static void pico_dhcp_client_start_requesting_timer(struct pico_dhcp_client_cookie *dhcpc) -{ - uint32_t time = 0; - - /* timer value is doubled with every retry (exponential backoff) */ - time = (uint32_t)(DHCP_CLIENT_RETRANS << dhcpc->retry); - pico_dhcp_timer_add(PICO_DHCPC_TIMER_REQUEST, time * 1000, dhcpc); -} - -static void pico_dhcp_client_start_renewing_timer(struct pico_dhcp_client_cookie *dhcpc) -{ - uint32_t halftime = 0; - - /* wait one-half of the remaining time until T2, down to a minimum of 60 seconds */ - /* (dhcpc->retry + 1): initial -> divide by 2, 1st retry -> divide by 4, 2nd retry -> divide by 8, etc */ - pico_dhcp_client_stop_timers(dhcpc); - halftime = dhcpc->renew_time >> (dhcpc->retry + 1); - if (halftime < 60) - halftime = 60; - - pico_dhcp_timer_add(PICO_DHCPC_TIMER_RENEW, halftime * 1000, dhcpc); - - return; -} - -static void pico_dhcp_client_start_rebinding_timer(struct pico_dhcp_client_cookie *dhcpc) -{ - uint32_t halftime = 0; - - pico_dhcp_client_stop_timers(dhcpc); - halftime = dhcpc->rebind_time >> (dhcpc->retry + 1); - if (halftime < 60) - halftime = 60; - - pico_dhcp_timer_add(PICO_DHCPC_TIMER_REBIND, halftime * 1000, dhcpc); - - return; -} - -static void pico_dhcp_client_start_reacquisition_timers(struct pico_dhcp_client_cookie *dhcpc) -{ - - pico_dhcp_client_stop_timers(dhcpc); - pico_dhcp_timer_add(PICO_DHCPC_TIMER_T1, dhcpc->t1_time * 1000, dhcpc); - pico_dhcp_timer_add(PICO_DHCPC_TIMER_T2, dhcpc->t2_time * 1000, dhcpc); - pico_dhcp_timer_add(PICO_DHCPC_TIMER_LEASE, dhcpc->lease_time * 1000, dhcpc); -} - -static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc) -{ - uint16_t port = PICO_DHCP_CLIENT_PORT; - if (!dhcpc) - return -1; - - /* adding a link with address 0.0.0.0 and netmask 0.0.0.0, - * automatically adds a route for a global broadcast */ - pico_ipv4_link_add(dhcpc->dev, inaddr_any, bcast_netmask); - if (!dhcpc->s) - dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup); - - if (!dhcpc->s) { - pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc); - return 0; - } - - dhcpc->s->dev = dhcpc->dev; - if (pico_socket_bind(dhcpc->s, &inaddr_any, &port) < 0) { - pico_socket_close(dhcpc->s); - dhcpc->s = NULL; - pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc); - return 0; - } - - if (pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER) < 0) { - pico_socket_close(dhcpc->s); - dhcpc->s = NULL; - pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc); - return 0; - } - - dhcpc->retry = 0; - dhcpc->init_timestamp = PICO_TIME_MS(); - pico_dhcp_client_start_init_timer(dhcpc); - return 0; -} - -int pico_dhcp_initiate_negotiation(struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid) -{ - uint8_t retry = 32; - uint32_t xid = 0; - struct pico_dhcp_client_cookie *dhcpc = NULL; - - if (!dev || !cb || !uid) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (!dev->eth) { - pico_err = PICO_ERR_EOPNOTSUPP; - return -1; - } - - /* attempt to generate a correct xid, else fail */ - do { - xid = pico_rand(); - } while (!xid && --retry); - - if (!xid) { - pico_err = PICO_ERR_EAGAIN; - return -1; - } - - dhcpc = pico_dhcp_client_add_cookie(xid, dev, cb, uid); - if (!dhcpc) - return -1; - - dhcpc_dbg("DHCP client: cookie with xid %u\n", dhcpc->xid); - *uid = xid; - return pico_dhcp_client_init(dhcpc); -} - -static void pico_dhcp_client_recv_params(struct pico_dhcp_client_cookie *dhcpc, struct pico_dhcp_opt *opt) -{ - do { - switch (opt->code) - { - case PICO_DHCP_OPT_PAD: - break; - - case PICO_DHCP_OPT_END: - break; - - case PICO_DHCP_OPT_MSGTYPE: - dhcpc->event = opt->ext.msg_type.type; - dhcpc_dbg("DHCP client: message type %u\n", dhcpc->event); - break; - - case PICO_DHCP_OPT_LEASETIME: - dhcpc->lease_time = long_be(opt->ext.lease_time.time); - dhcpc_dbg("DHCP client: lease time %u\n", dhcpc->lease_time); - break; - - case PICO_DHCP_OPT_RENEWALTIME: - dhcpc->t1_time = long_be(opt->ext.renewal_time.time); - dhcpc_dbg("DHCP client: renewal time %u\n", dhcpc->t1_time); - break; - - case PICO_DHCP_OPT_REBINDINGTIME: - dhcpc->t2_time = long_be(opt->ext.rebinding_time.time); - dhcpc_dbg("DHCP client: rebinding time %u\n", dhcpc->t2_time); - break; - - case PICO_DHCP_OPT_ROUTER: - dhcpc->gateway = opt->ext.router.ip; - dhcpc_dbg("DHCP client: router %08X\n", dhcpc->gateway.addr); - break; - - case PICO_DHCP_OPT_DNS: - dhcpc->nameserver[0] = opt->ext.dns1.ip; - dhcpc_dbg("DHCP client: dns1 %08X\n", dhcpc->nameserver[0].addr); - if (opt->len >= 8) { - dhcpc->nameserver[1] = opt->ext.dns2.ip; - dhcpc_dbg("DHCP client: dns1 %08X\n", dhcpc->nameserver[1].addr); - } - - break; - - case PICO_DHCP_OPT_NETMASK: - dhcpc->netmask = opt->ext.netmask.ip; - dhcpc_dbg("DHCP client: netmask %08X\n", dhcpc->netmask.addr); - break; - - case PICO_DHCP_OPT_SERVERID: - dhcpc->server_id = opt->ext.server_id.ip; - dhcpc_dbg("DHCP client: server ID %08X\n", dhcpc->server_id.addr); - break; - - case PICO_DHCP_OPT_OPTOVERLOAD: - dhcpc_dbg("DHCP client: WARNING option overload present (not processed)"); - break; - - case PICO_DHCP_OPT_HOSTNAME: - { - uint32_t maxlen = PICO_DHCP_HOSTNAME_MAXLEN; - if (opt->len < maxlen) - maxlen = opt->len; - strncpy(dhcpc_host_name, opt->ext.string.txt, maxlen); - } - break; - - case PICO_DHCP_OPT_DOMAINNAME: - { - uint32_t maxlen = PICO_DHCP_HOSTNAME_MAXLEN; - if (opt->len < maxlen) - maxlen = opt->len; - strncpy(dhcpc_domain_name, opt->ext.string.txt, maxlen); - } - break; - - default: - dhcpc_dbg("DHCP client: WARNING unsupported option %u\n", opt->code); - break; - } - } while (pico_dhcp_next_option(&opt)); - - /* default values for T1 and T2 when not provided */ - if (!dhcpc->t1_time) - dhcpc->t1_time = dhcpc->lease_time >> 1; - - if (!dhcpc->t2_time) - dhcpc->t2_time = (dhcpc->lease_time * 875) / 1000; - - return; -} - -static int recv_offer(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf) -{ - struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf; - struct pico_dhcp_opt *opt = DHCP_OPT(hdr,0); - - pico_dhcp_client_recv_params(dhcpc, opt); - if ((dhcpc->event != PICO_DHCP_MSG_OFFER) || !dhcpc->server_id.addr || !dhcpc->netmask.addr || !dhcpc->lease_time) - return -1; - - dhcpc->address.addr = hdr->yiaddr; - - /* we skip state SELECTING, process first offer received */ - dhcpc->state = DHCP_CLIENT_STATE_REQUESTING; - dhcpc->retry = 0; - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST); - pico_dhcp_client_start_requesting_timer(dhcpc); - return 0; -} - -static int recv_ack(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf) -{ - struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf; - struct pico_dhcp_opt *opt = DHCP_OPT(hdr,0); - struct pico_ip4 address = { - 0 - }; - struct pico_ip4 any_address = { - 0 - }; - - struct pico_ipv4_link *l; - - pico_dhcp_client_recv_params(dhcpc, opt); - if ((dhcpc->event != PICO_DHCP_MSG_ACK) || !dhcpc->server_id.addr || !dhcpc->netmask.addr || !dhcpc->lease_time) - return -1; - - /* Issue #20 the server can transmit on ACK a different IP than the one in OFFER */ - /* RFC2131 ch 4.3.2 ... The client SHOULD use the parameters in the DHCPACK message for configuration */ - if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING) - dhcpc->address.addr = hdr->yiaddr; - - - /* close the socket used for address (re)acquisition */ - pico_socket_close(dhcpc->s); - dhcpc->s = NULL; - - /* Delete all the links before adding the address */ - pico_ipv4_link_del(dhcpc->dev, address); - l = pico_ipv4_link_by_dev(dhcpc->dev); - while(l) { - pico_ipv4_link_del(dhcpc->dev, l->address); - l = pico_ipv4_link_by_dev_next(dhcpc->dev, l); - } - pico_ipv4_link_add(dhcpc->dev, dhcpc->address, dhcpc->netmask); - - dbg("DHCP client: renewal time (T1) %u\n", (unsigned int)dhcpc->t1_time); - dbg("DHCP client: rebinding time (T2) %u\n", (unsigned int)dhcpc->t2_time); - dbg("DHCP client: lease time %u\n", (unsigned int)dhcpc->lease_time); - - /* If router option is received, use it as default gateway */ - if (dhcpc->gateway.addr != 0U) { - pico_ipv4_route_add(any_address, any_address, dhcpc->gateway, 1, NULL); - } - - dhcpc->retry = 0; - dhcpc->renew_time = dhcpc->t2_time - dhcpc->t1_time; - dhcpc->rebind_time = dhcpc->lease_time - dhcpc->t2_time; - pico_dhcp_client_start_reacquisition_timers(dhcpc); - - *(dhcpc->uid) = dhcpc->xid; - if (dhcpc->cb) - dhcpc->cb(dhcpc, PICO_DHCP_SUCCESS); - - dhcpc->state = DHCP_CLIENT_STATE_BOUND; - return 0; -} - -static int renew(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf) -{ - uint16_t port = PICO_DHCP_CLIENT_PORT; - (void) buf; - dhcpc->state = DHCP_CLIENT_STATE_RENEWING; - dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup); - if (!dhcpc->s) { - dhcpc_dbg("DHCP client ERROR: failure opening socket on renew, aborting DHCP! (%s)\n", strerror(pico_err)); - if (dhcpc->cb) - dhcpc->cb(dhcpc, PICO_DHCP_ERROR); - - return -1; - } - - if (pico_socket_bind(dhcpc->s, &dhcpc->address, &port) != 0) { - dhcpc_dbg("DHCP client ERROR: failure binding socket on renew, aborting DHCP! (%s)\n", strerror(pico_err)); - pico_socket_close(dhcpc->s); - dhcpc->s = NULL; - if (dhcpc->cb) - dhcpc->cb(dhcpc, PICO_DHCP_ERROR); - - return -1; - } - - dhcpc->retry = 0; - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST); - pico_dhcp_client_start_renewing_timer(dhcpc); - - return 0; -} - -static int rebind(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf) -{ - (void) buf; - - dhcpc->state = DHCP_CLIENT_STATE_REBINDING; - dhcpc->retry = 0; - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST); - pico_dhcp_client_start_rebinding_timer(dhcpc); - - return 0; -} - -static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf) -{ - struct pico_ip4 address = { - 0 - }; - (void) buf; - - if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING) - address.addr = PICO_IP4_ANY; - else - address.addr = dhcpc->address.addr; - - /* close the socket used for address (re)acquisition */ - pico_socket_close(dhcpc->s); - dhcpc->s = NULL; - /* delete the link with the currently in use address */ - pico_ipv4_link_del(dhcpc->dev, address); - - if (dhcpc->cb) - dhcpc->cb(dhcpc, PICO_DHCP_RESET); - - if (dhcpc->state < DHCP_CLIENT_STATE_BOUND) - { - /* pico_dhcp_client_timer_stop(dhcpc, PICO_DHCPC_TIMER_INIT); */ - } - - - dhcpc->state = DHCP_CLIENT_STATE_INIT; - pico_dhcp_client_stop_timers(dhcpc); - pico_dhcp_client_init(dhcpc); - return 0; -} - -static int retransmit(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf) -{ - (void) buf; - switch (dhcpc->state) - { - case DHCP_CLIENT_STATE_INIT: - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER); - pico_dhcp_client_start_init_timer(dhcpc); - break; - - case DHCP_CLIENT_STATE_REQUESTING: - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST); - pico_dhcp_client_start_requesting_timer(dhcpc); - break; - - case DHCP_CLIENT_STATE_RENEWING: - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST); - pico_dhcp_client_start_renewing_timer(dhcpc); - break; - - case DHCP_CLIENT_STATE_REBINDING: - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER); - pico_dhcp_client_start_rebinding_timer(dhcpc); - break; - - default: - dhcpc_dbg("DHCP client WARNING: retransmit in incorrect state (%u)!\n", dhcpc->state); - return -1; - } - return 0; -} - -struct dhcp_action_entry { - int (*offer)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf); - int (*ack)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf); - int (*nak)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf); - int (*timer1)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf); - int (*timer2)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf); - int (*timer_lease)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf); - int (*timer_retransmit)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf); -}; - -static struct dhcp_action_entry dhcp_fsm[] = -{ /* event |offer |ack |nak |T1 |T2 |lease |retransmit */ -/* state init-reboot */ - { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, -/* state rebooting */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, -/* state init */ { recv_offer, NULL, NULL, NULL, NULL, NULL, retransmit }, -/* state selecting */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, -/* state requesting */ { NULL, recv_ack, reset, NULL, NULL, NULL, retransmit }, -/* state bound */ { NULL, NULL, NULL, renew, NULL, NULL, NULL }, -/* state renewing */ { NULL, recv_ack, reset, NULL, rebind, NULL, retransmit }, -/* state rebinding */ { NULL, recv_ack, reset, NULL, NULL, reset, retransmit }, -}; - -/* TIMERS REMARK: - * In state bound we have T1, T2 and the lease timer running. If T1 goes off, we attempt to renew. - * If the renew succeeds a new T1, T2 and lease timer is started. The former T2 and lease timer is - * still running though. This poses no concerns as the T2 and lease event in state bound have a NULL - * pointer in the fsm. If the former T2 or lease timer goes off, nothing happens. Same situation - * applies for T2 and a succesfull rebind. */ - -static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf) -{ - switch (event) - { - case PICO_DHCP_MSG_OFFER: - dhcpc_dbg("DHCP client: received OFFER\n"); - if (dhcp_fsm[dhcpc->state].offer) - dhcp_fsm[dhcpc->state].offer(dhcpc, buf); - - break; - - case PICO_DHCP_MSG_ACK: - dhcpc_dbg("DHCP client: received ACK\n"); - if (dhcp_fsm[dhcpc->state].ack) - dhcp_fsm[dhcpc->state].ack(dhcpc, buf); - - break; - - case PICO_DHCP_MSG_NAK: - dhcpc_dbg("DHCP client: received NAK\n"); - if (dhcp_fsm[dhcpc->state].nak) - dhcp_fsm[dhcpc->state].nak(dhcpc, buf); - - break; - - case PICO_DHCP_EVENT_T1: - dhcpc_dbg("DHCP client: received T1 timeout\n"); - if (dhcp_fsm[dhcpc->state].timer1) - dhcp_fsm[dhcpc->state].timer1(dhcpc, NULL); - - break; - - case PICO_DHCP_EVENT_T2: - dhcpc_dbg("DHCP client: received T2 timeout\n"); - if (dhcp_fsm[dhcpc->state].timer2) - dhcp_fsm[dhcpc->state].timer2(dhcpc, NULL); - - break; - - case PICO_DHCP_EVENT_LEASE: - dhcpc_dbg("DHCP client: received LEASE timeout\n"); - if (dhcp_fsm[dhcpc->state].timer_lease) - dhcp_fsm[dhcpc->state].timer_lease(dhcpc, NULL); - - break; - - case PICO_DHCP_EVENT_RETRANSMIT: - dhcpc_dbg("DHCP client: received RETRANSMIT timeout\n"); - if (dhcp_fsm[dhcpc->state].timer_retransmit) - dhcp_fsm[dhcpc->state].timer_retransmit(dhcpc, NULL); - - break; - - default: - dhcpc_dbg("DHCP client WARNING: unrecognized event (%u)!\n", dhcpc->event); - return; - } - return; -} - -static int16_t pico_dhcp_client_opt_parse(void *ptr, uint16_t len) -{ - uint32_t optlen = len - (uint32_t)sizeof(struct pico_dhcp_hdr); - struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)ptr; - struct pico_dhcp_opt *opt = DHCP_OPT(hdr,0); - - if (hdr->dhcp_magic != PICO_DHCPD_MAGIC_COOKIE) - return -1; - - if (!pico_dhcp_are_options_valid(opt, (int32_t)optlen)) - return -1; - - do { - if (opt->code == PICO_DHCP_OPT_MSGTYPE) - return opt->ext.msg_type.type; - } while (pico_dhcp_next_option(&opt)); - - return -1; -} - -static int8_t pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type) -{ - int32_t r = 0; - uint16_t optlen = 0, offset = 0; - struct pico_ip4 destination = { - .addr = 0xFFFFFFFF - }; - struct pico_dhcp_hdr *hdr = NULL; - - - /* RFC 2131 3.1.3: Request is always BROADCAST */ - - /* Set again default route for the bcast request */ - pico_ipv4_route_set_bcast_link(pico_ipv4_link_by_dev(dhcpc->dev)); - - switch (msg_type) - { - case PICO_DHCP_MSG_DISCOVER: - dhcpc_dbg("DHCP client: sent DHCPDISCOVER\n"); - optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_END; - hdr = PICO_ZALLOC((size_t)(sizeof(struct pico_dhcp_hdr) + optlen)); - if (!hdr) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - /* specific options */ - offset = (uint16_t)(offset + pico_dhcp_opt_maxmsgsize(DHCP_OPT(hdr,offset), DHCP_CLIENT_MAXMSGZISE)); - break; - - case PICO_DHCP_MSG_REQUEST: - optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_REQIP + PICO_DHCP_OPTLEN_SERVERID - + PICO_DHCP_OPTLEN_END; - hdr = PICO_ZALLOC(sizeof(struct pico_dhcp_hdr) + optlen); - if (!hdr) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - /* specific options */ - offset = (uint16_t)(offset + pico_dhcp_opt_maxmsgsize(DHCP_OPT(hdr,offset), DHCP_CLIENT_MAXMSGZISE)); - if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING) { - offset = (uint16_t)(offset + pico_dhcp_opt_reqip(DHCP_OPT(hdr,offset), &dhcpc->address)); - offset = (uint16_t)(offset + pico_dhcp_opt_serverid(DHCP_OPT(hdr,offset), &dhcpc->server_id)); - } - - break; - - default: - return -1; - } - - /* common options */ - offset = (uint16_t)(offset + pico_dhcp_opt_msgtype(DHCP_OPT(hdr,offset), msg_type)); - offset = (uint16_t)(offset + pico_dhcp_opt_paramlist(DHCP_OPT(hdr,offset))); - offset = (uint16_t)(offset + pico_dhcp_opt_end(DHCP_OPT(hdr,offset))); - - switch (dhcpc->state) - { - case DHCP_CLIENT_STATE_BOUND: - destination.addr = dhcpc->server_id.addr; - hdr->ciaddr = dhcpc->address.addr; - break; - - case DHCP_CLIENT_STATE_RENEWING: - destination.addr = dhcpc->server_id.addr; - hdr->ciaddr = dhcpc->address.addr; - break; - - case DHCP_CLIENT_STATE_REBINDING: - hdr->ciaddr = dhcpc->address.addr; - break; - - default: - /* do nothing */ - break; - } - - /* header information */ - hdr->op = PICO_DHCP_OP_REQUEST; - hdr->htype = PICO_DHCP_HTYPE_ETH; - hdr->hlen = PICO_SIZE_ETH; - hdr->xid = dhcpc->xid; - /* hdr->flags = short_be(PICO_DHCP_FLAG_BROADCAST); / * Nope: see bug #96! * / */ - hdr->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE; - /* copy client hardware address */ - memcpy(hdr->hwaddr, &dhcpc->dev->eth->mac, PICO_SIZE_ETH); - - if (destination.addr == PICO_IP4_BCAST) - pico_ipv4_route_set_bcast_link(pico_ipv4_link_get(&dhcpc->address)); - - r = pico_socket_sendto(dhcpc->s, hdr, (int)(sizeof(struct pico_dhcp_hdr) + optlen), &destination, PICO_DHCPD_PORT); - PICO_FREE(hdr); - if (r < 0) - return -1; - - return 0; -} - -static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s) -{ - - uint8_t *buf; - int r = 0; - struct pico_dhcp_hdr *hdr = NULL; - struct pico_dhcp_client_cookie *dhcpc = NULL; - - if ((ev & PICO_SOCK_EV_RD) == 0) - return; - - buf = PICO_ZALLOC(DHCP_CLIENT_MAXMSGZISE); - if (!buf) { - return; - } - - r = pico_socket_recvfrom(s, buf, DHCP_CLIENT_MAXMSGZISE, NULL, NULL); - if (r < 0) - goto out_discard_buf; - - /* If the 'xid' of an arriving message does not match the 'xid' - * of the most recent transmitted message, the message must be - * silently discarded. */ - hdr = (struct pico_dhcp_hdr *)buf; - dhcpc = pico_dhcp_client_find_cookie(hdr->xid); - if (!dhcpc) - goto out_discard_buf; - - dhcpc->event = (uint8_t)pico_dhcp_client_opt_parse(buf, (uint16_t)r); - pico_dhcp_state_machine(dhcpc->event, dhcpc, buf); - -out_discard_buf: - PICO_FREE(buf); -} - -void *pico_dhcp_get_identifier(uint32_t xid) -{ - return (void *)pico_dhcp_client_find_cookie(xid); -} - -struct pico_ip4 pico_dhcp_get_address(void*dhcpc) -{ - return ((struct pico_dhcp_client_cookie*)dhcpc)->address; -} - -struct pico_ip4 pico_dhcp_get_gateway(void*dhcpc) -{ - return ((struct pico_dhcp_client_cookie*)dhcpc)->gateway; -} - -struct pico_ip4 pico_dhcp_get_netmask(void *dhcpc) -{ - return ((struct pico_dhcp_client_cookie*)dhcpc)->netmask; -} - -struct pico_ip4 pico_dhcp_get_nameserver(void*dhcpc, int index) -{ - struct pico_ip4 fault = { - .addr = 0xFFFFFFFFU - }; - if ((index != 0) && (index != 1)) - return fault; - - return ((struct pico_dhcp_client_cookie*)dhcpc)->nameserver[index]; -} - -int pico_dhcp_client_abort(uint32_t xid) -{ - return pico_dhcp_client_del_cookie(xid); -} - - -char *pico_dhcp_get_hostname(void) -{ - return dhcpc_host_name; -} - -char *pico_dhcp_get_domain(void) -{ - return dhcpc_domain_name; -} - -#endif diff --git a/ext/picotcp/modules/pico_dhcp_client.h b/ext/picotcp/modules/pico_dhcp_client.h deleted file mode 100644 index 4dafb2a..0000000 --- a/ext/picotcp/modules/pico_dhcp_client.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - *********************************************************************/ -#ifndef INCLUDE_PICO_DHCP_CLIENT -#define INCLUDE_PICO_DHCP_CLIENT -#include "pico_defines.h" -#ifdef PICO_SUPPORT_UDP -#include "pico_dhcp_common.h" -#include "pico_addressing.h" -#include "pico_protocol.h" - -int pico_dhcp_initiate_negotiation(struct pico_device *device, void (*callback)(void*cli, int code), uint32_t *xid); -void *pico_dhcp_get_identifier(uint32_t xid); -struct pico_ip4 pico_dhcp_get_address(void *cli); -struct pico_ip4 pico_dhcp_get_gateway(void *cli); -struct pico_ip4 pico_dhcp_get_netmask(void *cli); -struct pico_ip4 pico_dhcp_get_nameserver(void*cli, int index); -int pico_dhcp_client_abort(uint32_t xid); -char *pico_dhcp_get_hostname(void); -char *pico_dhcp_get_domain(void); - -/* possible codes for the callback */ -#define PICO_DHCP_SUCCESS 0 -#define PICO_DHCP_ERROR 1 -#define PICO_DHCP_RESET 2 - -#endif -#endif diff --git a/ext/picotcp/modules/pico_dhcp_common.c b/ext/picotcp/modules/pico_dhcp_common.c deleted file mode 100644 index 7edb1e2..0000000 --- a/ext/picotcp/modules/pico_dhcp_common.c +++ /dev/null @@ -1,190 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Frederik Van Slycken - *********************************************************************/ - -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_dhcp_common.h" - -#if defined (PICO_SUPPORT_DHCPC) || defined (PICO_SUPPORT_DHCPD) -/* pico_dhcp_are_options_valid needs to be called first to prevent illegal memory access */ -/* The argument pointer is moved forward to the next option */ -struct pico_dhcp_opt *pico_dhcp_next_option(struct pico_dhcp_opt **ptr) -{ - uint8_t **p = (uint8_t **)ptr; - struct pico_dhcp_opt *opt = *ptr; - - if (opt->code == PICO_DHCP_OPT_END) - return NULL; - - if (opt->code == PICO_DHCP_OPT_PAD) { - *p += 1; - return *ptr; - } - - *p += (opt->len + 2); /* (len + 2) to account for code and len octet */ - return *ptr; -} - -uint8_t pico_dhcp_are_options_valid(void *ptr, int32_t len) -{ - uint8_t optlen = 0, *p = ptr; - - while (len > 0) { - switch (*p) - { - case PICO_DHCP_OPT_END: - return 1; - - case PICO_DHCP_OPT_PAD: - p++; - len--; - break; - - default: - p++; /* move pointer from code octet to len octet */ - len--; - if ((len <= 0) || (len - (*p + 1) < 0)) /* (*p + 1) to account for len octet */ - return 0; - - optlen = *p; - p += optlen + 1; - len -= optlen; - break; - } - } - return 0; -} - -uint8_t pico_dhcp_opt_netmask(void *ptr, struct pico_ip4 *ip) -{ - struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr; - - /* option: netmask */ - opt->code = PICO_DHCP_OPT_NETMASK; - opt->len = PICO_DHCP_OPTLEN_NETMASK - PICO_DHCP_OPTLEN_HDR; - opt->ext.netmask.ip = *ip; - return PICO_DHCP_OPTLEN_NETMASK; -} - -uint8_t pico_dhcp_opt_router(void *ptr, struct pico_ip4 *ip) -{ - struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr; - - /* option: router */ - opt->code = PICO_DHCP_OPT_ROUTER; - opt->len = PICO_DHCP_OPTLEN_ROUTER - PICO_DHCP_OPTLEN_HDR; - opt->ext.router.ip = *ip; - return PICO_DHCP_OPTLEN_ROUTER; -} - -uint8_t pico_dhcp_opt_dns(void *ptr, struct pico_ip4 *ip) -{ - struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr; - - /* option: dns */ - opt->code = PICO_DHCP_OPT_DNS; - opt->len = PICO_DHCP_OPTLEN_DNS - PICO_DHCP_OPTLEN_HDR; - opt->ext.dns1.ip = *ip; - return PICO_DHCP_OPTLEN_DNS; -} - -uint8_t pico_dhcp_opt_broadcast(void *ptr, struct pico_ip4 *ip) -{ - struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr; - - /* option: broadcast */ - opt->code = PICO_DHCP_OPT_BROADCAST; - opt->len = PICO_DHCP_OPTLEN_BROADCAST - PICO_DHCP_OPTLEN_HDR; - opt->ext.broadcast.ip = *ip; - return PICO_DHCP_OPTLEN_BROADCAST; -} - -uint8_t pico_dhcp_opt_reqip(void *ptr, struct pico_ip4 *ip) -{ - struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr; - - /* option: request IP address */ - opt->code = PICO_DHCP_OPT_REQIP; - opt->len = PICO_DHCP_OPTLEN_REQIP - PICO_DHCP_OPTLEN_HDR; - opt->ext.req_ip.ip = *ip; - return PICO_DHCP_OPTLEN_REQIP; -} - -uint8_t pico_dhcp_opt_leasetime(void *ptr, uint32_t time) -{ - struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr; - - /* option: lease time */ - opt->code = PICO_DHCP_OPT_LEASETIME; - opt->len = PICO_DHCP_OPTLEN_LEASETIME - PICO_DHCP_OPTLEN_HDR; - opt->ext.lease_time.time = time; - return PICO_DHCP_OPTLEN_LEASETIME; -} - -uint8_t pico_dhcp_opt_msgtype(void *ptr, uint8_t type) -{ - struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr; - - /* option: message type */ - opt->code = PICO_DHCP_OPT_MSGTYPE; - opt->len = PICO_DHCP_OPTLEN_MSGTYPE - PICO_DHCP_OPTLEN_HDR; - opt->ext.msg_type.type = type; - return PICO_DHCP_OPTLEN_MSGTYPE; -} - -uint8_t pico_dhcp_opt_serverid(void *ptr, struct pico_ip4 *ip) -{ - struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr; - - /* option: server identifier */ - opt->code = PICO_DHCP_OPT_SERVERID; - opt->len = PICO_DHCP_OPTLEN_SERVERID - PICO_DHCP_OPTLEN_HDR; - opt->ext.server_id.ip = *ip; - return PICO_DHCP_OPTLEN_SERVERID; -} - -uint8_t pico_dhcp_opt_paramlist(void *ptr) -{ - struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr; - uint8_t *param_code = &(opt->ext.param_list.code[0]); - - /* option: parameter list */ - opt->code = PICO_DHCP_OPT_PARAMLIST; - opt->len = PICO_DHCP_OPTLEN_PARAMLIST - PICO_DHCP_OPTLEN_HDR; - param_code[0] = PICO_DHCP_OPT_NETMASK; - param_code[1] = PICO_DHCP_OPT_TIME; - param_code[2] = PICO_DHCP_OPT_ROUTER; - param_code[3] = PICO_DHCP_OPT_HOSTNAME; - param_code[4] = PICO_DHCP_OPT_RENEWALTIME; - param_code[5] = PICO_DHCP_OPT_REBINDINGTIME; - param_code[6] = PICO_DHCP_OPT_DNS; - return PICO_DHCP_OPTLEN_PARAMLIST; -} - -uint8_t pico_dhcp_opt_maxmsgsize(void *ptr, uint16_t size) -{ - struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr; - - /* option: maximum message size */ - opt->code = PICO_DHCP_OPT_MAXMSGSIZE; - opt->len = PICO_DHCP_OPTLEN_MAXMSGSIZE - PICO_DHCP_OPTLEN_HDR; - opt->ext.max_msg_size.size = short_be(size); - return PICO_DHCP_OPTLEN_MAXMSGSIZE; -} - -uint8_t pico_dhcp_opt_end(void *ptr) -{ - uint8_t *opt = (uint8_t *)ptr; - - /* option: end of options */ - *opt = PICO_DHCP_OPT_END; - return PICO_DHCP_OPTLEN_END; -} - -#endif diff --git a/ext/picotcp/modules/pico_dhcp_common.h b/ext/picotcp/modules/pico_dhcp_common.h deleted file mode 100644 index 62c94da..0000000 --- a/ext/picotcp/modules/pico_dhcp_common.h +++ /dev/null @@ -1,191 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - *********************************************************************/ -#ifndef INCLUDE_PICO_DHCP_COMMON -#define INCLUDE_PICO_DHCP_COMMON -#include "pico_config.h" -#include "pico_addressing.h" - -#define PICO_DHCPD_PORT (short_be(67)) -#define PICO_DHCP_CLIENT_PORT (short_be(68)) -#define PICO_DHCPD_MAGIC_COOKIE (long_be(0x63825363)) -#define PICO_DHCP_HTYPE_ETH 1 - -/* Macro to get DHCP option field */ -#define DHCP_OPT(hdr,off) ((struct pico_dhcp_opt *)(((uint8_t *)hdr)+sizeof(struct pico_dhcp_hdr) + off)) - -/* flags */ -#define PICO_DHCP_FLAG_BROADCAST 0x8000 - -/* options */ -#define PICO_DHCP_OPT_PAD 0x00 -#define PICO_DHCP_OPT_NETMASK 0x01 -#define PICO_DHCP_OPT_TIME 0x02 -#define PICO_DHCP_OPT_ROUTER 0x03 -#define PICO_DHCP_OPT_DNS 0x06 -#define PICO_DHCP_OPT_HOSTNAME 0x0c -#define PICO_DHCP_OPT_DOMAINNAME 0x0f -#define PICO_DHCP_OPT_MTU 0x1a -#define PICO_DHCP_OPT_BROADCAST 0x1c -#define PICO_DHCP_OPT_NETBIOSNS 0x2c -#define PICO_DHCP_OPT_NETBIOSSCOPE 0x2f -#define PICO_DHCP_OPT_REQIP 0x32 -#define PICO_DHCP_OPT_LEASETIME 0x33 -#define PICO_DHCP_OPT_OPTOVERLOAD 0x34 -#define PICO_DHCP_OPT_MSGTYPE 0x35 -#define PICO_DHCP_OPT_SERVERID 0x36 -#define PICO_DHCP_OPT_PARAMLIST 0x37 -#define PICO_DHCP_OPT_MESSAGE 0x38 -#define PICO_DHCP_OPT_MAXMSGSIZE 0x39 -#define PICO_DHCP_OPT_RENEWALTIME 0x3a -#define PICO_DHCP_OPT_REBINDINGTIME 0x3b -#define PICO_DHCP_OPT_VENDORID 0x3c -#define PICO_DHCP_OPT_CLIENTID 0x3d -#define PICO_DHCP_OPT_DOMAINSEARCH 0x77 -#define PICO_DHCP_OPT_STATICROUTE 0x79 -#define PICO_DHCP_OPT_END 0xFF - -/* options len */ -#define PICO_DHCP_OPTLEN_HDR 2 /* account for code and len field */ -#define PICO_DHCP_OPTLEN_NETMASK 6 -#define PICO_DHCP_OPTLEN_ROUTER 6 -#define PICO_DHCP_OPTLEN_DNS 6 -#define PICO_DHCP_OPTLEN_BROADCAST 6 -#define PICO_DHCP_OPTLEN_REQIP 6 -#define PICO_DHCP_OPTLEN_LEASETIME 6 -#define PICO_DHCP_OPTLEN_OPTOVERLOAD 3 -#define PICO_DHCP_OPTLEN_MSGTYPE 3 -#define PICO_DHCP_OPTLEN_SERVERID 6 -#define PICO_DHCP_OPTLEN_PARAMLIST 9 /* PicoTCP specific */ -#define PICO_DHCP_OPTLEN_MAXMSGSIZE 4 -#define PICO_DHCP_OPTLEN_RENEWALTIME 6 -#define PICO_DHCP_OPTLEN_REBINDINGTIME 6 -#define PICO_DHCP_OPTLEN_END 1 - -/* op codes */ -#define PICO_DHCP_OP_REQUEST 1 -#define PICO_DHCP_OP_REPLY 2 - -/* rfc message types */ -#define PICO_DHCP_MSG_DISCOVER 1 -#define PICO_DHCP_MSG_OFFER 2 -#define PICO_DHCP_MSG_REQUEST 3 -#define PICO_DHCP_MSG_DECLINE 4 -#define PICO_DHCP_MSG_ACK 5 -#define PICO_DHCP_MSG_NAK 6 -#define PICO_DHCP_MSG_RELEASE 7 -#define PICO_DHCP_MSG_INFORM 8 - -/* custom message types */ -#define PICO_DHCP_EVENT_T1 9 -#define PICO_DHCP_EVENT_T2 10 -#define PICO_DHCP_EVENT_LEASE 11 -#define PICO_DHCP_EVENT_RETRANSMIT 12 -#define PICO_DHCP_EVENT_NONE 0xff - -PACKED_STRUCT_DEF pico_dhcp_hdr -{ - uint8_t op; - uint8_t htype; - uint8_t hlen; - uint8_t hops; /* zero */ - uint32_t xid; /* store this in the request */ - uint16_t secs; /* ignore */ - uint16_t flags; - uint32_t ciaddr; /* client address - if asking for renewal */ - uint32_t yiaddr; /* your address (client) */ - uint32_t siaddr; /* dhcp offered address */ - uint32_t giaddr; /* relay agent, bootp. */ - uint8_t hwaddr[6]; - uint8_t hwaddr_padding[10]; - char hostname[64]; - char bootp_filename[128]; - uint32_t dhcp_magic; -}; - -PACKED_STRUCT_DEF pico_dhcp_opt -{ - uint8_t code; - uint8_t len; - PACKED_UNION_DEF dhcp_opt_ext_u { - PEDANTIC_STRUCT_DEF netmask_s { - struct pico_ip4 ip; - } netmask; - PEDANTIC_STRUCT_DEF router_s { - struct pico_ip4 ip; - } router; - PEDANTIC_STRUCT_DEF dns_s { - struct pico_ip4 ip; - } dns1; - struct dns_s dns2; - PEDANTIC_STRUCT_DEF broadcast_s { - struct pico_ip4 ip; - } broadcast; - PEDANTIC_STRUCT_DEF req_ip_s { - struct pico_ip4 ip; - } req_ip; - PEDANTIC_STRUCT_DEF lease_time_s { - uint32_t time; - } lease_time; - PEDANTIC_STRUCT_DEF opt_overload_s { - uint8_t value; - } opt_overload; - PEDANTIC_STRUCT_DEF tftp_server_s { - char name[1]; - } tftp_server; - PEDANTIC_STRUCT_DEF bootfile_s { - char name[1]; - } bootfile; - PEDANTIC_STRUCT_DEF msg_type_s { - uint8_t type; - } msg_type; - PEDANTIC_STRUCT_DEF server_id_s { - struct pico_ip4 ip; - } server_id; - PEDANTIC_STRUCT_DEF param_list_s { - uint8_t code[1]; - } param_list; - PEDANTIC_STRUCT_DEF message_s { - char error[1]; - } message; - PEDANTIC_STRUCT_DEF max_msg_size_s { - uint16_t size; - } max_msg_size; - PEDANTIC_STRUCT_DEF renewal_time_s { - uint32_t time; - } renewal_time; - PEDANTIC_STRUCT_DEF rebinding_time_s { - uint32_t time; - } rebinding_time; - PEDANTIC_STRUCT_DEF vendor_id_s { - uint8_t id[1]; - } vendor_id; - PEDANTIC_STRUCT_DEF client_id_s { - uint8_t id[1]; - } client_id; - PEDANTIC_STRUCT_DEF text_s { - char txt[1]; - } string; - } ext; -}; - -uint8_t dhcp_get_next_option(uint8_t *begin, uint8_t *data, int *len, uint8_t **nextopt); -struct pico_dhcp_opt *pico_dhcp_next_option(struct pico_dhcp_opt **ptr); -uint8_t pico_dhcp_are_options_valid(void *ptr, int32_t len); - -uint8_t pico_dhcp_opt_netmask(void *ptr, struct pico_ip4 *ip); -uint8_t pico_dhcp_opt_router(void *ptr, struct pico_ip4 *ip); -uint8_t pico_dhcp_opt_dns(void *ptr, struct pico_ip4 *ip); -uint8_t pico_dhcp_opt_broadcast(void *ptr, struct pico_ip4 *ip); -uint8_t pico_dhcp_opt_reqip(void *ptr, struct pico_ip4 *ip); -uint8_t pico_dhcp_opt_leasetime(void *ptr, uint32_t time); -uint8_t pico_dhcp_opt_msgtype(void *ptr, uint8_t type); -uint8_t pico_dhcp_opt_serverid(void *ptr, struct pico_ip4 *ip); -uint8_t pico_dhcp_opt_paramlist(void *ptr); -uint8_t pico_dhcp_opt_maxmsgsize(void *ptr, uint16_t size); -uint8_t pico_dhcp_opt_end(void *ptr); -#endif diff --git a/ext/picotcp/modules/pico_dhcp_server.c b/ext/picotcp/modules/pico_dhcp_server.c deleted file mode 100644 index dbef3bb..0000000 --- a/ext/picotcp/modules/pico_dhcp_server.c +++ /dev/null @@ -1,411 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - - Authors: Frederik Van Slycken, Kristof Roelants - *********************************************************************/ - -#include "pico_dhcp_server.h" -#include "pico_config.h" -#include "pico_addressing.h" -#include "pico_socket.h" -#include "pico_udp.h" -#include "pico_stack.h" -#include "pico_arp.h" - -#if (defined PICO_SUPPORT_DHCPD && defined PICO_SUPPORT_UDP) - -#define dhcps_dbg(...) do {} while(0) -/* #define dhcps_dbg dbg */ - -/* default configurations */ -#define DHCP_SERVER_OPENDNS long_be(0xd043dede) /* OpenDNS DNS server 208.67.222.222 */ -#define DHCP_SERVER_POOL_START long_be(0x00000064) -#define DHCP_SERVER_POOL_END long_be(0x000000fe) -#define DHCP_SERVER_LEASE_TIME long_be(0x00000078) - -/* maximum size of a DHCP message */ -#define DHCP_SERVER_MAXMSGSIZE (PICO_IP_MRU - sizeof(struct pico_ipv4_hdr) - sizeof(struct pico_udp_hdr)) - -enum dhcp_server_state { - PICO_DHCP_STATE_DISCOVER = 0, - PICO_DHCP_STATE_OFFER, - PICO_DHCP_STATE_REQUEST, - PICO_DHCP_STATE_BOUND, - PICO_DHCP_STATE_RENEWING -}; - -struct pico_dhcp_server_negotiation { - uint32_t xid; - enum dhcp_server_state state; - struct pico_dhcp_server_setting *dhcps; - struct pico_ip4 ciaddr; - struct pico_eth hwaddr; - uint8_t bcast; -}; - -static inline int ip_address_is_in_dhcp_range(struct pico_dhcp_server_negotiation *n, uint32_t x) -{ - uint32_t ip_hostendian = long_be(x); - if (ip_hostendian < long_be(n->dhcps->pool_start)) - return 0; - - if (ip_hostendian > long_be(n->dhcps->pool_end)) - return 0; - - return 1; -} - - -static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s); - -static int dhcp_settings_cmp(void *ka, void *kb) -{ - struct pico_dhcp_server_setting *a = ka, *b = kb; - if (a->dev == b->dev) - return 0; - - return (a->dev < b->dev) ? (-1) : (1); -} -PICO_TREE_DECLARE(DHCPSettings, dhcp_settings_cmp); - -static int dhcp_negotiations_cmp(void *ka, void *kb) -{ - struct pico_dhcp_server_negotiation *a = ka, *b = kb; - if (a->xid == b->xid) - return 0; - - return (a->xid < b->xid) ? (-1) : (1); -} -PICO_TREE_DECLARE(DHCPNegotiations, dhcp_negotiations_cmp); - - -static inline void dhcps_set_default_pool_start_if_not_provided(struct pico_dhcp_server_setting *dhcps) -{ - if (!dhcps->pool_start) - dhcps->pool_start = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_START; -} - -static inline void dhcps_set_default_pool_end_if_not_provided(struct pico_dhcp_server_setting *dhcps) -{ - if (!dhcps->pool_end) - dhcps->pool_end = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_END; -} -static inline void dhcps_set_default_lease_time_if_not_provided(struct pico_dhcp_server_setting *dhcps) -{ - if (!dhcps->lease_time) - dhcps->lease_time = DHCP_SERVER_LEASE_TIME; -} - -static inline struct pico_dhcp_server_setting *dhcps_try_open_socket(struct pico_dhcp_server_setting *dhcps) -{ - uint16_t port = PICO_DHCPD_PORT; - dhcps->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcpd_wakeup); - if (!dhcps->s) { - dhcps_dbg("DHCP server ERROR: failure opening socket (%s)\n", strerror(pico_err)); - PICO_FREE(dhcps); - return NULL; - } - - if (pico_socket_bind(dhcps->s, &dhcps->server_ip, &port) < 0) { - dhcps_dbg("DHCP server ERROR: failure binding socket (%s)\n", strerror(pico_err)); - PICO_FREE(dhcps); - return NULL; - } - - pico_tree_insert(&DHCPSettings, dhcps); - return dhcps; -} - -static struct pico_dhcp_server_setting *pico_dhcp_server_add_setting(struct pico_dhcp_server_setting *setting) -{ - struct pico_dhcp_server_setting *dhcps = NULL, *found = NULL, test = { - 0 - }; - struct pico_ipv4_link *link = NULL; - - link = pico_ipv4_link_get(&setting->server_ip); - if (!link) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - test.dev = setting->dev; - found = pico_tree_findKey(&DHCPSettings, &test); - if (found) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - dhcps = PICO_ZALLOC(sizeof(struct pico_dhcp_server_setting)); - if (!dhcps) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - dhcps->lease_time = setting->lease_time; - dhcps->pool_start = setting->pool_start; - dhcps->pool_next = setting->pool_next; - dhcps->pool_end = setting->pool_end; - dhcps->dev = link->dev; - dhcps->server_ip = link->address; - dhcps->netmask = link->netmask; - - /* default values if not provided */ - dhcps_set_default_lease_time_if_not_provided(dhcps); - dhcps_set_default_pool_end_if_not_provided(dhcps); - dhcps_set_default_pool_start_if_not_provided(dhcps); - - dhcps->pool_next = dhcps->pool_start; - - return dhcps_try_open_socket(dhcps); - -} - -static struct pico_dhcp_server_negotiation *pico_dhcp_server_find_negotiation(uint32_t xid) -{ - struct pico_dhcp_server_negotiation test = { - 0 - }, *found = NULL; - - test.xid = xid; - found = pico_tree_findKey(&DHCPNegotiations, &test); - if (found) - return found; - else - return NULL; -} - -static inline void dhcp_negotiation_set_ciaddr(struct pico_dhcp_server_negotiation *dhcpn) -{ - struct pico_ip4 *ciaddr = NULL; - ciaddr = pico_arp_reverse_lookup(&dhcpn->hwaddr); - if (!ciaddr) { - dhcpn->ciaddr.addr = dhcpn->dhcps->pool_next; - dhcpn->dhcps->pool_next = long_be(long_be(dhcpn->dhcps->pool_next) + 1); - pico_arp_create_entry(dhcpn->hwaddr.addr, dhcpn->ciaddr, dhcpn->dhcps->dev); - } else { - dhcpn->ciaddr = *ciaddr; - } -} - -static struct pico_dhcp_server_negotiation *pico_dhcp_server_add_negotiation(struct pico_device *dev, struct pico_dhcp_hdr *hdr) -{ - struct pico_dhcp_server_negotiation *dhcpn = NULL; - struct pico_dhcp_server_setting test = { - 0 - }; - - if (pico_dhcp_server_find_negotiation(hdr->xid)) - return NULL; - - dhcpn = PICO_ZALLOC(sizeof(struct pico_dhcp_server_negotiation)); - if (!dhcpn) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - dhcpn->xid = hdr->xid; - dhcpn->state = PICO_DHCP_STATE_DISCOVER; - dhcpn->bcast = ((short_be(hdr->flags) & PICO_DHCP_FLAG_BROADCAST) != 0) ? (1) : (0); - memcpy(dhcpn->hwaddr.addr, hdr->hwaddr, PICO_SIZE_ETH); - - test.dev = dev; - dhcpn->dhcps = pico_tree_findKey(&DHCPSettings, &test); - if (!dhcpn->dhcps) { - dhcps_dbg("DHCP server WARNING: received DHCP message on unconfigured link %s\n", dev->name); - PICO_FREE(dhcpn); - return NULL; - } - - dhcp_negotiation_set_ciaddr(dhcpn); - pico_tree_insert(&DHCPNegotiations, dhcpn); - return dhcpn; -} - -static void dhcpd_make_reply(struct pico_dhcp_server_negotiation *dhcpn, uint8_t msg_type) -{ - int r = 0, optlen = 0, offset = 0; - struct pico_ip4 broadcast = { - 0 - }, dns = { - 0 - }, destination = { - .addr = 0xFFFFFFFF - }; - struct pico_dhcp_hdr *hdr = NULL; - - dns.addr = DHCP_SERVER_OPENDNS; - broadcast.addr = dhcpn->dhcps->server_ip.addr | ~(dhcpn->dhcps->netmask.addr); - - optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_SERVERID + PICO_DHCP_OPTLEN_LEASETIME + PICO_DHCP_OPTLEN_NETMASK + PICO_DHCP_OPTLEN_ROUTER - + PICO_DHCP_OPTLEN_BROADCAST + PICO_DHCP_OPTLEN_DNS + PICO_DHCP_OPTLEN_END; - hdr = PICO_ZALLOC(sizeof(struct pico_dhcp_hdr) + (uint32_t)optlen); - if (!hdr) { - return; - } - - hdr->op = PICO_DHCP_OP_REPLY; - hdr->htype = PICO_DHCP_HTYPE_ETH; - hdr->hlen = PICO_SIZE_ETH; - hdr->xid = dhcpn->xid; - hdr->yiaddr = dhcpn->ciaddr.addr; - hdr->siaddr = dhcpn->dhcps->server_ip.addr; - hdr->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE; - memcpy(hdr->hwaddr, dhcpn->hwaddr.addr, PICO_SIZE_ETH); - - /* options */ - offset += pico_dhcp_opt_msgtype(DHCP_OPT(hdr,offset), msg_type); - offset += pico_dhcp_opt_serverid(DHCP_OPT(hdr,offset), &dhcpn->dhcps->server_ip); - offset += pico_dhcp_opt_leasetime(DHCP_OPT(hdr,offset), dhcpn->dhcps->lease_time); - offset += pico_dhcp_opt_netmask(DHCP_OPT(hdr,offset), &dhcpn->dhcps->netmask); - offset += pico_dhcp_opt_router(DHCP_OPT(hdr,offset), &dhcpn->dhcps->server_ip); - offset += pico_dhcp_opt_broadcast(DHCP_OPT(hdr,offset), &broadcast); - offset += pico_dhcp_opt_dns(DHCP_OPT(hdr,offset), &dns); - offset += pico_dhcp_opt_end(DHCP_OPT(hdr,offset)); - - if (dhcpn->bcast == 0) - destination.addr = hdr->yiaddr; - else { - hdr->flags |= short_be(PICO_DHCP_FLAG_BROADCAST); - destination.addr = broadcast.addr; - } - - r = pico_socket_sendto(dhcpn->dhcps->s, hdr, (int)(sizeof(struct pico_dhcp_hdr) + (uint32_t)optlen), &destination, PICO_DHCP_CLIENT_PORT); - if (r < 0) - dhcps_dbg("DHCP server WARNING: failure sending: %s!\n", strerror(pico_err)); - - PICO_FREE(hdr); - - return; -} - -static inline void parse_opt_msgtype(struct pico_dhcp_opt *opt, uint8_t *msgtype) -{ - if (opt->code == PICO_DHCP_OPT_MSGTYPE) { - *msgtype = opt->ext.msg_type.type; - dhcps_dbg("DHCP server: message type %u\n", msgtype); - } -} - -static inline void parse_opt_reqip(struct pico_dhcp_opt *opt, struct pico_ip4 *reqip) -{ - if (opt->code == PICO_DHCP_OPT_REQIP) - reqip->addr = opt->ext.req_ip.ip.addr; -} - -static inline void parse_opt_serverid(struct pico_dhcp_opt *opt, struct pico_ip4 *serverid) -{ - if (opt->code == PICO_DHCP_OPT_SERVERID) - *serverid = opt->ext.server_id.ip; -} - -static inline void dhcps_make_reply_to_request_msg(struct pico_dhcp_server_negotiation *dhcpn, int bound_valid_flag) -{ - if ((dhcpn->state == PICO_DHCP_STATE_BOUND) && bound_valid_flag) - dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_ACK); - - if (dhcpn->state == PICO_DHCP_STATE_OFFER) { - dhcpn->state = PICO_DHCP_STATE_BOUND; - dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_ACK); - } -} - -static inline void dhcps_make_reply_to_discover_or_request(struct pico_dhcp_server_negotiation *dhcpn, uint8_t msgtype, int bound_valid_flag) -{ - if (PICO_DHCP_MSG_DISCOVER == msgtype) { - dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_OFFER); - dhcpn->state = PICO_DHCP_STATE_OFFER; - } else if (PICO_DHCP_MSG_REQUEST == msgtype) { - dhcps_make_reply_to_request_msg(dhcpn, bound_valid_flag); - } -} - -static inline void dhcps_parse_options_loop(struct pico_dhcp_server_negotiation *dhcpn, struct pico_dhcp_hdr *hdr) -{ - struct pico_dhcp_opt *opt = DHCP_OPT(hdr,0); - uint8_t msgtype = 0; - struct pico_ip4 reqip = { - 0 - }, server_id = { - 0 - }; - - do { - parse_opt_msgtype(opt, &msgtype); - parse_opt_reqip(opt, &reqip); - parse_opt_serverid(opt, &server_id); - } while (pico_dhcp_next_option(&opt)); - dhcps_make_reply_to_discover_or_request(dhcpn, msgtype, (!reqip.addr) && (!server_id.addr) && (hdr->ciaddr == dhcpn->ciaddr.addr)); -} - -static void pico_dhcp_server_recv(struct pico_socket *s, uint8_t *buf, uint32_t len) -{ - int32_t optlen = (int32_t)(len - sizeof(struct pico_dhcp_hdr)); - struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf; - struct pico_dhcp_server_negotiation *dhcpn = NULL; - struct pico_device *dev = NULL; - - if (!pico_dhcp_are_options_valid(DHCP_OPT(hdr,0), optlen)) - return; - - dev = pico_ipv4_link_find(&s->local_addr.ip4); - dhcpn = pico_dhcp_server_find_negotiation(hdr->xid); - if (!dhcpn) - dhcpn = pico_dhcp_server_add_negotiation(dev, hdr); - - if (!ip_address_is_in_dhcp_range(dhcpn, dhcpn->ciaddr.addr)) - return; - - dhcps_parse_options_loop(dhcpn, hdr); - -} - -static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s) -{ - uint8_t buf[DHCP_SERVER_MAXMSGSIZE] = { - 0 - }; - int r = 0; - - if (ev != PICO_SOCK_EV_RD) - return; - - r = pico_socket_recvfrom(s, buf, DHCP_SERVER_MAXMSGSIZE, NULL, NULL); - if (r < 0) - return; - - pico_dhcp_server_recv(s, buf, (uint32_t)r); - return; -} - -int pico_dhcp_server_initiate(struct pico_dhcp_server_setting *setting) -{ - if (!setting || !setting->server_ip.addr) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (pico_dhcp_server_add_setting(setting) == NULL) - return -1; - - return 0; -} - -int pico_dhcp_server_destroy(struct pico_device *dev) -{ - struct pico_dhcp_server_setting *found, test = { 0 }; - test.dev = dev; - found = pico_tree_findKey(&DHCPSettings, &test); - if (!found) { - pico_err = PICO_ERR_ENOENT; - return -1; - } - - pico_tree_delete(&DHCPSettings, found); - PICO_FREE(found); - return 0; -} - -#endif /* PICO_SUPPORT_DHCP */ diff --git a/ext/picotcp/modules/pico_dhcp_server.h b/ext/picotcp/modules/pico_dhcp_server.h deleted file mode 100644 index d5df820..0000000 --- a/ext/picotcp/modules/pico_dhcp_server.h +++ /dev/null @@ -1,34 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_DHCP_SERVER -#define INCLUDE_PICO_DHCP_SERVER -#include "pico_defines.h" -#ifdef PICO_SUPPORT_UDP - -#include "pico_dhcp_common.h" -#include "pico_addressing.h" - -struct pico_dhcp_server_setting -{ - uint32_t pool_start; - uint32_t pool_next; - uint32_t pool_end; - uint32_t lease_time; - struct pico_device *dev; - struct pico_socket *s; - struct pico_ip4 server_ip; - struct pico_ip4 netmask; - uint8_t flags; /* unused atm */ -}; - -/* required field: IP address of the interface to serve, only IPs of this network will be served. */ -int pico_dhcp_server_initiate(struct pico_dhcp_server_setting *dhcps); - -/* To destroy an existing DHCP server configuration, running on a given interface */ -int pico_dhcp_server_destroy(struct pico_device *dev); - -#endif /* _INCLUDE_PICO_DHCP_SERVER */ -#endif diff --git a/ext/picotcp/modules/pico_dns_client.c b/ext/picotcp/modules/pico_dns_client.c deleted file mode 100644 index 806cff5..0000000 --- a/ext/picotcp/modules/pico_dns_client.c +++ /dev/null @@ -1,808 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See LICENSE and COPYING for usage. - . - Authors: Kristof Roelants - *********************************************************************/ -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_addressing.h" -#include "pico_socket.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_dns_client.h" -#include "pico_dns_common.h" -#include "pico_tree.h" - -#ifdef PICO_SUPPORT_DNS_CLIENT - -#ifdef PICO_SUPPORT_IPV4 - -#define dns_dbg(...) do {} while(0) -/* #define dns_dbg dbg */ - -/* DNS response length */ -#define PICO_DNS_MAX_QUERY_LEN 255 -#define PICO_DNS_MAX_QUERY_LABEL_LEN 63 - -/* DNS client retransmission time (msec) + frequency */ -#define PICO_DNS_CLIENT_RETRANS 4000 -#define PICO_DNS_CLIENT_MAX_RETRANS 3 - -static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s); -static void pico_dns_client_retransmission(pico_time now, void *arg); -static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg); - -struct pico_dns_ns -{ - struct pico_ip4 ns; /* nameserver */ -}; - -static int dns_ns_cmp(void *ka, void *kb) -{ - struct pico_dns_ns *a = ka, *b = kb; - return pico_ipv4_compare(&a->ns, &b->ns); -} -PICO_TREE_DECLARE(NSTable, dns_ns_cmp); - -struct pico_dns_query -{ - char *query; - uint16_t len; - uint16_t id; - uint16_t qtype; - uint16_t qclass; - uint8_t retrans; - struct pico_dns_ns q_ns; - struct pico_socket *s; - void (*callback)(char *, void *); - void *arg; -}; - -static int dns_query_cmp(void *ka, void *kb) -{ - struct pico_dns_query *a = ka, *b = kb; - if (a->id == b->id) - return 0; - - return (a->id < b->id) ? (-1) : (1); -} -PICO_TREE_DECLARE(DNSTable, dns_query_cmp); - -static int pico_dns_client_del_ns(struct pico_ip4 *ns_addr) -{ - struct pico_dns_ns test = {{0}}, *found = NULL; - - test.ns = *ns_addr; - found = pico_tree_findKey(&NSTable, &test); - if (!found) - return -1; - - pico_tree_delete(&NSTable, found); - PICO_FREE(found); - - /* no NS left, add default NS */ - if (pico_tree_empty(&NSTable)) - pico_dns_client_init(); - - return 0; -} - -static struct pico_dns_ns *pico_dns_client_add_ns(struct pico_ip4 *ns_addr) -{ - struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}}; - struct pico_ip4 zero = {0}; /* 0.0.0.0 */ - - /* Do not add 0.0.0.0 addresses, which some DHCP servers might reply */ - if (!pico_ipv4_compare(ns_addr, &zero)) - { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - dns = PICO_ZALLOC(sizeof(struct pico_dns_ns)); - if (!dns) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - dns->ns = *ns_addr; - - found = pico_tree_insert(&NSTable, dns); - if (found) { /* nameserver already present */ - PICO_FREE(dns); - return found; - } - - /* default NS found, remove it */ - pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&test.ns.addr); - found = pico_tree_findKey(&NSTable, &test); - if (found && (found->ns.addr != ns_addr->addr)) - pico_dns_client_del_ns(&found->ns); - - return dns; -} - -static struct pico_dns_ns pico_dns_client_next_ns(struct pico_ip4 *ns_addr) -{ - struct pico_dns_ns dns = {{0}}, *nxtdns = NULL; - struct pico_tree_node *node = NULL, *nxtnode = NULL; - - dns.ns = *ns_addr; - node = pico_tree_findNode(&NSTable, &dns); - if (!node) - return dns; /* keep using current NS */ - - nxtnode = pico_tree_next(node); - nxtdns = nxtnode->keyValue; - if (!nxtdns) - nxtdns = (struct pico_dns_ns *)pico_tree_first(&NSTable); - - return *nxtdns; -} - -static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_header *hdr, uint16_t len, struct pico_dns_question_suffix *suffix, - void (*callback)(char *, void *), void *arg) -{ - struct pico_dns_query *q = NULL, *found = NULL; - - q = PICO_ZALLOC(sizeof(struct pico_dns_query)); - if (!q) - return NULL; - - q->query = (char *)hdr; - q->len = len; - q->id = short_be(hdr->id); - q->qtype = short_be(suffix->qtype); - q->qclass = short_be(suffix->qclass); - q->retrans = 1; - q->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); - q->callback = callback; - q->arg = arg; - q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback); - if (!q->s) { - PICO_FREE(q); - return NULL; - } - - found = pico_tree_insert(&DNSTable, q); - if (found) { - pico_err = PICO_ERR_EAGAIN; - pico_socket_close(q->s); - PICO_FREE(q); - return NULL; - } - - return q; -} - -static int pico_dns_client_del_query(uint16_t id) -{ - struct pico_dns_query test = { - 0 - }, *found = NULL; - - test.id = id; - found = pico_tree_findKey(&DNSTable, &test); - if (!found) - return -1; - - PICO_FREE(found->query); - pico_socket_close(found->s); - pico_tree_delete(&DNSTable, found); - PICO_FREE(found); - return 0; -} - -static struct pico_dns_query *pico_dns_client_find_query(uint16_t id) -{ - struct pico_dns_query test = { - 0 - }, *found = NULL; - - test.id = id; - found = pico_tree_findKey(&DNSTable, &test); - if (found) - return found; - else - return NULL; -} - -/* seek end of string */ -static char *pico_dns_client_seek(char *ptr) -{ - if (!ptr) - return NULL; - - while (*ptr != 0) - ptr++; - return ptr + 1; -} - -static struct pico_dns_query *pico_dns_client_idcheck(uint16_t id) -{ - struct pico_dns_query test = { - 0 - }; - - test.id = id; - return pico_tree_findKey(&DNSTable, &test); -} - -static int pico_dns_client_query_header(struct pico_dns_header *hdr) -{ - uint16_t id = 0; - uint8_t retry = 32; - - do { - id = (uint16_t)(pico_rand() & 0xFFFFU); - dns_dbg("DNS: generated id %u\n", id); - } while (retry-- && pico_dns_client_idcheck(id)); - if (!retry) - return -1; - - hdr->id = short_be(id); - pico_dns_fill_packet_header(hdr, 1, 0, 0, 0); /* 1 question, 0 answers */ - - return 0; -} - -static int pico_dns_client_check_header(struct pico_dns_header *pre) -{ - if (pre->qr != PICO_DNS_QR_RESPONSE || pre->opcode != PICO_DNS_OPCODE_QUERY || pre->rcode != PICO_DNS_RCODE_NO_ERROR) { - dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", pre->opcode, pre->tc, pre->rcode); - return -1; - } - - if (short_be(pre->ancount) < 1) { - dns_dbg("DNS ERROR: ancount < 1\n"); - return -1; - } - - return 0; -} - -static int pico_dns_client_check_qsuffix(struct pico_dns_question_suffix *suf, struct pico_dns_query *q) -{ - if (!suf) - return -1; - - if (short_be(suf->qtype) != q->qtype || short_be(suf->qclass) != q->qclass) { - dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->qtype), short_be(suf->qclass)); - return -1; - } - - return 0; -} - -static int pico_dns_client_check_url(struct pico_dns_header *resp, struct pico_dns_query *q) -{ - char *recv_name = (char*)(resp) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL; - char *exp_name = (char *)(q->query) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL; - if (strcasecmp(recv_name, exp_name) != 0) - return -1; - - return 0; -} - -static int pico_dns_client_check_asuffix(struct pico_dns_record_suffix *suf, struct pico_dns_query *q) -{ - if (!suf) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (short_be(suf->rtype) != q->qtype || short_be(suf->rclass) != q->qclass) { - dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->rtype), short_be(suf->rclass)); - return -1; - } - - if (long_be(suf->rttl) > PICO_DNS_MAX_TTL) { - dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(suf->rttl), PICO_DNS_MAX_TTL); - return -1; - } - - return 0; -} - -static char *pico_dns_client_seek_suffix(char *suf, struct pico_dns_header *pre, struct pico_dns_query *q) -{ - struct pico_dns_record_suffix *asuffix = NULL; - uint16_t comp = 0, compression = 0; - uint16_t i = 0; - - if (!suf) - return NULL; - - while (i++ < short_be(pre->ancount)) { - comp = short_from(suf); - compression = short_be(comp); - switch (compression >> 14) - { - case PICO_DNS_POINTER: - while (compression >> 14 == PICO_DNS_POINTER) { - dns_dbg("DNS: pointer\n"); - suf += sizeof(uint16_t); - comp = short_from(suf); - compression = short_be(comp); - } - break; - - case PICO_DNS_LABEL: - dns_dbg("DNS: label\n"); - suf = pico_dns_client_seek(suf); - break; - - default: - dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression); - return NULL; - } - - asuffix = (struct pico_dns_record_suffix *)suf; - if (!asuffix) - break; - - if (pico_dns_client_check_asuffix(asuffix, q) < 0) { - suf += (sizeof(struct pico_dns_record_suffix) + short_be(asuffix->rdlength)); - continue; - } - - return suf; - } - return NULL; -} - -static int pico_dns_client_send(struct pico_dns_query *q) -{ - uint16_t *paramID = PICO_ZALLOC(sizeof(uint16_t)); - if (!paramID) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - dns_dbg("DNS: sending query to %08X\n", q->q_ns.ns.addr); - if (!q->s) - goto failure; - - if (pico_socket_connect(q->s, &q->q_ns.ns, short_be(PICO_DNS_NS_PORT)) < 0) - goto failure; - - pico_socket_send(q->s, q->query, q->len); - *paramID = q->id; - pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, paramID); - - return 0; - -failure: - PICO_FREE(paramID); - return -1; -} - -static void pico_dns_client_retransmission(pico_time now, void *arg) -{ - struct pico_dns_query *q = NULL; - struct pico_dns_query dummy; - IGNORE_PARAMETER(now); - - if(!arg) - return; - - /* search for the dns query and free used space */ - dummy.id = *(uint16_t *)arg; - q = (struct pico_dns_query *)pico_tree_findKey(&DNSTable, &dummy); - PICO_FREE(arg); - - /* dns query successful? */ - if (!q) { - return; - } - - q->retrans++; - if (q->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) { - q->q_ns = pico_dns_client_next_ns(&q->q_ns.ns); - pico_dns_client_send(q); - } else { - pico_err = PICO_ERR_EIO; - q->callback(NULL, q->arg); - pico_dns_client_del_query(q->id); - } -} - -static int pico_dns_client_user_callback(struct pico_dns_record_suffix *asuffix, struct pico_dns_query *q) -{ - uint32_t ip = 0; - char *str = NULL; - char *rdata = (char *) asuffix + sizeof(struct pico_dns_record_suffix); - - switch (q->qtype) - { - case PICO_DNS_TYPE_A: - ip = long_from(rdata); - str = PICO_ZALLOC(PICO_DNS_IPV4_ADDR_LEN); - pico_ipv4_to_string(str, ip); - break; -#ifdef PICO_SUPPORT_IPV6 - case PICO_DNS_TYPE_AAAA: - { - struct pico_ip6 ip6; - memcpy(&ip6.addr, rdata, sizeof(struct pico_ip6)); - str = PICO_ZALLOC(PICO_DNS_IPV6_ADDR_LEN); - pico_ipv6_to_string(str, ip6.addr); - break; - } -#endif - case PICO_DNS_TYPE_PTR: - /* TODO: check for decompression / rdlength vs. decompressed length */ - pico_dns_notation_to_name(rdata, short_be(asuffix->rdlength)); - str = PICO_ZALLOC((size_t)(short_be(asuffix->rdlength) - - PICO_DNS_LABEL_INITIAL)); - if (!str) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - memcpy(str, rdata + PICO_DNS_LABEL_INITIAL, short_be(asuffix->rdlength) - PICO_DNS_LABEL_INITIAL); - break; - - default: - dns_dbg("DNS ERROR: incorrect qtype (%u)\n", q->qtype); - break; - } - - if (q->retrans) { - q->callback(str, q->arg); - q->retrans = 0; - pico_dns_client_del_query(q->id); - } - - if (str) - PICO_FREE(str); - - return 0; -} - -static char dns_response[PICO_IP_MRU] = { - 0 -}; - -static void pico_dns_try_fallback_cname(struct pico_dns_query *q, struct pico_dns_header *h, struct pico_dns_question_suffix *qsuffix) -{ - uint16_t type = q->qtype; - uint16_t proto = PICO_PROTO_IPV4; - struct pico_dns_record_suffix *asuffix = NULL; - char *p_asuffix = NULL; - char *cname_orig = NULL; - char *cname = NULL; - uint16_t cname_len; - - /* Try to use CNAME only if A or AAAA query is ongoing */ - if (type != PICO_DNS_TYPE_A && type != PICO_DNS_TYPE_AAAA) - return; - - if (type == PICO_DNS_TYPE_AAAA) - proto = PICO_PROTO_IPV6; - - q->qtype = PICO_DNS_TYPE_CNAME; - p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix); - p_asuffix = pico_dns_client_seek_suffix(p_asuffix, h, q); - if (!p_asuffix) { - return; - } - - /* Found CNAME response. Re-initiating query. */ - asuffix = (struct pico_dns_record_suffix *)p_asuffix; - cname = pico_dns_decompress_name((char *)asuffix + sizeof(struct pico_dns_record_suffix), (pico_dns_packet *)h); /* allocates memory! */ - cname_orig = cname; /* to free later */ - - if (cname == NULL) - return; - - cname_len = (uint16_t)(pico_dns_strlen(cname) + 1); - - pico_dns_notation_to_name(cname, cname_len); - if (cname[0] == '.') - cname++; - - dns_dbg("Restarting query for name '%s'\n", cname); - pico_dns_client_getaddr_init(cname, proto, q->callback, q->arg); - PICO_FREE(cname_orig); - pico_dns_client_del_query(q->id); -} - -static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s) -{ - struct pico_dns_header *header = NULL; - char *domain; - struct pico_dns_question_suffix *qsuffix = NULL; - struct pico_dns_record_suffix *asuffix = NULL; - struct pico_dns_query *q = NULL; - char *p_asuffix = NULL; - - if (ev == PICO_SOCK_EV_ERR) { - dns_dbg("DNS: socket error received\n"); - return; - } - - if (ev & PICO_SOCK_EV_RD) { - if (pico_socket_read(s, dns_response, PICO_IP_MRU) < 0) - return; - } - - header = (struct pico_dns_header *)dns_response; - domain = (char *)header + sizeof(struct pico_dns_header); - qsuffix = (struct pico_dns_question_suffix *)pico_dns_client_seek(domain); - /* valid asuffix is determined dynamically later on */ - - if (pico_dns_client_check_header(header) < 0) - return; - - q = pico_dns_client_find_query(short_be(header->id)); - if (!q) - return; - - if (pico_dns_client_check_qsuffix(qsuffix, q) < 0) - return; - - if (pico_dns_client_check_url(header, q) < 0) - return; - - p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix); - p_asuffix = pico_dns_client_seek_suffix(p_asuffix, header, q); - if (!p_asuffix) { - pico_dns_try_fallback_cname(q, header, qsuffix); - return; - } - - asuffix = (struct pico_dns_record_suffix *)p_asuffix; - pico_dns_client_user_callback(asuffix, q); - - return; -} - -static int pico_dns_create_message(struct pico_dns_header **header, struct pico_dns_question_suffix **qsuffix, enum pico_dns_arpa arpa, const char *url, uint16_t *urlen, uint16_t *hdrlen) -{ - char *domain; - char inaddr_arpa[14]; - uint16_t strlen = 0, arpalen = 0; - - if (!url) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if(arpa == PICO_DNS_ARPA4) { - strcpy(inaddr_arpa, ".in-addr.arpa"); - strlen = pico_dns_strlen(url); - } - -#ifdef PICO_SUPPORT_IPV6 - else if (arpa == PICO_DNS_ARPA6) { - strcpy(inaddr_arpa, ".IP6.ARPA"); - strlen = STRLEN_PTR_IP6; - } -#endif - else { - strcpy(inaddr_arpa, ""); - strlen = pico_dns_strlen(url); - } - - arpalen = pico_dns_strlen(inaddr_arpa); - *urlen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + arpalen + PICO_DNS_LABEL_ROOT); - *hdrlen = (uint16_t)(sizeof(struct pico_dns_header) + *urlen + sizeof(struct pico_dns_question_suffix)); - *header = PICO_ZALLOC(*hdrlen); - if (!*header) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - *header = (struct pico_dns_header *)*header; - domain = (char *) *header + sizeof(struct pico_dns_header); - *qsuffix = (struct pico_dns_question_suffix *)(domain + *urlen); - - if(arpa == PICO_DNS_ARPA4) { - memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen); - pico_dns_mirror_addr(domain + PICO_DNS_LABEL_INITIAL); - memcpy(domain + PICO_DNS_LABEL_INITIAL + strlen, inaddr_arpa, arpalen); - } - -#ifdef PICO_SUPPORT_IPV6 - else if (arpa == PICO_DNS_ARPA6) { - pico_dns_ipv6_set_ptr(url, domain + PICO_DNS_LABEL_INITIAL); - memcpy(domain + PICO_DNS_LABEL_INITIAL + STRLEN_PTR_IP6, inaddr_arpa, arpalen); - } -#endif - else { - memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen); - } - - /* assemble dns message */ - pico_dns_client_query_header(*header); - pico_dns_name_to_dns_notation(domain, strlen); - - return 0; -} - -static int pico_dns_client_addr_label_check_len(const char *url) -{ - const char *p, *label; - int count; - label = url; - p = label; - - while(*p != (char) 0) { - count = 0; - while((*p != (char)0)) { - if (*p == '.') { - label = ++p; - break; - } - - count++; - p++; - if (count > PICO_DNS_MAX_QUERY_LABEL_LEN) - return -1; - } - } - return 0; -} - -static int pico_dns_client_getaddr_check(const char *url, void (*callback)(char *, void *)) -{ - if (!url || !callback) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (strlen(url) > PICO_DNS_MAX_QUERY_LEN) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (pico_dns_client_addr_label_check_len(url) < 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return 0; -} - -static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg) -{ - struct pico_dns_header *header = NULL; - struct pico_dns_question_suffix *qsuffix = NULL; - struct pico_dns_query *q = NULL; - uint16_t len = 0, lblen = 0; - (void)proto; - - if (pico_dns_client_getaddr_check(url, callback) < 0) - return -1; - - if(pico_dns_create_message(&header, &qsuffix, PICO_DNS_NO_ARPA, url, &lblen, &len) != 0) - return -1; - -#ifdef PICO_SUPPORT_IPV6 - if (proto == PICO_PROTO_IPV6) { - pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN); - } else -#endif - pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN); - - q = pico_dns_client_add_query(header, len, qsuffix, callback, arg); - if (!q) { - PICO_FREE(header); - return -1; - } - - if (pico_dns_client_send(q) < 0) { - pico_dns_client_del_query(q->id); /* frees msg */ - return -1; - } - - return 0; -} - -int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg) -{ - return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV4, callback, arg); -} - -int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg) -{ - return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV6, callback, arg); -} - -static int pico_dns_getname_univ(const char *ip, void (*callback)(char *, void *), void *arg, enum pico_dns_arpa arpa) -{ - struct pico_dns_header *header = NULL; - struct pico_dns_question_suffix *qsuffix = NULL; - struct pico_dns_query *q = NULL; - uint16_t len = 0, lblen = 0; - - if (!ip || !callback) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if(pico_dns_create_message(&header, &qsuffix, arpa, ip, &lblen, &len) != 0) - return -1; - - pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN); - q = pico_dns_client_add_query(header, len, qsuffix, callback, arg); - if (!q) { - PICO_FREE(header); - return -1; - } - - if (pico_dns_client_send(q) < 0) { - pico_dns_client_del_query(q->id); /* frees header */ - return -1; - } - - return 0; -} - -int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg) -{ - return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA4); -} - - -int pico_dns_client_getname6(const char *ip, void (*callback)(char *, void *), void *arg) -{ - return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA6); -} - -int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag) -{ - if (!ns) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (flag) - { - case PICO_DNS_NS_ADD: - if (!pico_dns_client_add_ns(ns)) - return -1; - - break; - - case PICO_DNS_NS_DEL: - if (pico_dns_client_del_ns(ns) < 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - break; - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - return 0; -} - -int pico_dns_client_init(void) -{ - struct pico_ip4 default_ns = { - 0 - }; - - if (pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&default_ns.addr) < 0) - return -1; - - return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD); -} - -#else - -int pico_dns_client_init(void) -{ - dbg("ERROR Trying to initialize DNS module: IPv4 not supported in this build.\n"); - return -1; -} -#endif /* PICO_SUPPORT_IPV4 */ - - -#endif /* PICO_SUPPORT_DNS_CLIENT */ - diff --git a/ext/picotcp/modules/pico_dns_client.h b/ext/picotcp/modules/pico_dns_client.h deleted file mode 100644 index 910cc92..0000000 --- a/ext/picotcp/modules/pico_dns_client.h +++ /dev/null @@ -1,46 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Kristof Roelants - *********************************************************************/ - -#ifndef INCLUDE_PICO_DNS_CLIENT -#define INCLUDE_PICO_DNS_CLIENT - -#define PICO_DNS_NS_DEL 0 -#define PICO_DNS_NS_ADD 1 -#include "pico_config.h" - -/* Compression values */ -#define PICO_DNS_LABEL 0 -#define PICO_DNS_POINTER 3 - -/* Label len */ -#define PICO_DNS_LABEL_INITIAL 1u -#define PICO_DNS_LABEL_ROOT 1 - -/* TTL values */ -#define PICO_DNS_MAX_TTL 604800 /* one week */ - -/* Len of an IPv4 address string */ -#define PICO_DNS_IPV4_ADDR_LEN 16 -#define PICO_DNS_IPV6_ADDR_LEN 54 - -/* Default nameservers + port */ -#define PICO_DNS_NS_DEFAULT "208.67.222.222" -#define PICO_DNS_NS_PORT 53 - -int pico_dns_client_init(void); -/* flag is PICO_DNS_NS_DEL or PICO_DNS_NS_ADD */ -int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag); -int pico_dns_client_getaddr(const char *url, void (*callback)(char *ip, void *arg), void *arg); -int pico_dns_client_getname(const char *ip, void (*callback)(char *url, void *arg), void *arg); -#ifdef PICO_SUPPORT_IPV6 -int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg); -int pico_dns_client_getname6(const char *url, void (*callback)(char *, void *), void *arg); -#endif - -#endif /* _INCLUDE_PICO_DNS_CLIENT */ diff --git a/ext/picotcp/modules/pico_dns_common.c b/ext/picotcp/modules/pico_dns_common.c deleted file mode 100644 index 0c0250e..0000000 --- a/ext/picotcp/modules/pico_dns_common.c +++ /dev/null @@ -1,1773 +0,0 @@ -/* **************************************************************************** - * PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - * See LICENSE and COPYING for usage. - * . - * Authors: Toon Stegen, Jelle De Vleeschouwer - * ****************************************************************************/ -#include "pico_config.h" -#include "pico_protocol.h" -#include "pico_stack.h" -#include "pico_addressing.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_dns_common.h" -#include "pico_tree.h" - -#define dns_dbg(...) do {} while(0) -//#define dns_dbg dbg - -/* MARK: v NAME & IP FUNCTIONS */ -#define dns_name_foreach_label_safe(label, name, next, maxlen) \ - for ((label) = (name), (next) = (char *)((name) + *(name) + 1); \ - (*(label) != '\0') && ((uint16_t)((label) - (name)) < (maxlen)); \ - (label) = (next), (next) = (char *)((next) + *(next) + 1)) - -/* **************************************************************************** - * Checks if the DNS name doesn't exceed 256 bytes including zero-byte. - * - * @param namelen Length of the DNS name-string including zero-byte - * @return 0 when the length is correct - * ****************************************************************************/ -int -pico_dns_check_namelen( uint16_t namelen ) -{ - return ((namelen > 2u) && (namelen < 256u)) ? (0) : (-1); -} - -/* **************************************************************************** - * Returns the length of a name in a DNS-packet as if DNS name compression - * would be applied to the packet. If there's no compression present - * - * @param name Compressed name you want the calculate the strlen from - * @return Returns strlen of a compressed name, takes the first byte of compr- - * ession pointer into account but not the second byte, which acts - * like a trailing zero-byte - * ****************************************************************************/ -uint16_t -pico_dns_namelen_comp( char *name ) -{ - uint16_t len = 0; - char *label = NULL, *next = NULL; - - /* Check params */ - if (!name) { - pico_err = PICO_ERR_EINVAL; - return 0; - } - - /* Just count until the zero-byte or a pointer */ - dns_name_foreach_label_safe(label, name, next, 255) { - if ((0xC0 & *label)) - break; - } - - /* Calculate the length */ - len = (uint16_t)(label - name); - if(*label != '\0') - len++; - - return len; -} - -/* **************************************************************************** - * Returns the uncompressed name in DNS name format when DNS name compression - * is applied to the packet-buffer. - * - * @param name Compressed name, should be in the bounds of the actual packet - * @param packet Packet that contains the compressed name - * @return Returns the decompressed name, NULL on failure. - * ****************************************************************************/ -char * -pico_dns_decompress_name( char *name, pico_dns_packet *packet ) -{ - char decompressed_name[PICO_DNS_NAMEBUF_SIZE] = { - 0 - }; - char *return_name = NULL; - uint8_t *dest_iterator = NULL; - uint8_t *iterator = NULL; - uint16_t ptr = 0, nslen = 0; - - /* Initialise iterators */ - iterator = (uint8_t *) name; - dest_iterator = (uint8_t *) decompressed_name; - while (*iterator != '\0') { - if ((*iterator) & 0xC0) { - /* We have a pointer */ - ptr = (uint16_t)((((uint16_t) *iterator) & 0x003F) << 8); - ptr = (uint16_t)(ptr | (uint16_t) *(iterator + 1)); - iterator = (uint8_t *)((uint8_t *)packet + ptr); - } else { - /* We want to keep the label lengths */ - *dest_iterator = (uint8_t) *iterator; - /* Copy the label */ - memcpy(dest_iterator + 1, iterator + 1, *iterator); - /* Move to next length label */ - dest_iterator += (*iterator) + 1; - iterator += (*iterator) + 1; - } - } - /* Append final zero-byte */ - *dest_iterator = (uint8_t) '\0'; - - /* Provide storage for the name to return */ - nslen = (uint16_t)(pico_dns_strlen(decompressed_name) + 1); - if(!(return_name = PICO_ZALLOC((size_t)nslen))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - memcpy((void *)return_name, (void *)decompressed_name, (size_t)nslen); - - return return_name; -} - -/* **************************************************************************** - * Determines the length of a given url as if it where a DNS name in reverse - * resolution format. - * - * @param url URL wanted to create a reverse resolution name from. - * @param arpalen Will get filled with the length of the ARPA-suffix depending - * on the proto-parameter. - * @param proto The protocol to create a ARPA-suffix for. Can be either - * 'PICO_PROTO_IPV4' or 'PICO_PROTO_IPV6' - * @return Returns the length of the reverse name - * ****************************************************************************/ -static uint16_t -pico_dns_url_get_reverse_len( const char *url, - uint16_t *arpalen, - uint16_t proto ) -{ - uint16_t slen = (uint16_t)(pico_dns_strlen(url) + 2u); - - /* Check if pointers given are not NULL */ - if (pico_dns_check_namelen(slen) && !arpalen) { - pico_err = PICO_ERR_EINVAL; - return 0; - } - - /* Get the length of arpa-suffix if needed */ - if (proto == PICO_PROTO_IPV4) - *arpalen = (uint16_t) pico_dns_strlen(PICO_ARPA_IPV4_SUFFIX); - -#ifdef PICO_SUPPORT_IPV6 - else if (proto == PICO_PROTO_IPV6) - { - *arpalen = (uint16_t) pico_dns_strlen(PICO_ARPA_IPV6_SUFFIX); - slen = STRLEN_PTR_IP6 + 2u; - } -#endif - return slen; -} - -/* **************************************************************************** - * Converts a DNS name in URL format to a reverse name in DNS name format. - * Provides space for the DNS name as well. PICO_FREE() should be called on the - * returned string buffer that contains the reverse DNS name. - * - * @param url DNS name in URL format to convert to reverse name - * @param proto Depending on the protocol given the ARPA-suffix will be added. - * @return Returns a pointer to a string-buffer with the reverse DNS name. - * ****************************************************************************/ -static char * -pico_dns_url_to_reverse_qname( const char *url, uint8_t proto ) -{ - char *reverse_qname = NULL; - uint16_t arpalen = 0; - uint16_t slen = pico_dns_url_get_reverse_len(url, &arpalen, proto); - - /* Check namelen */ - if (pico_dns_check_namelen(slen)) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Provide space for the reverse name */ - if (!(reverse_qname = PICO_ZALLOC((size_t)(slen + arpalen)))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* If reverse IPv4 address resolving, convert to IPv4 arpa-format */ - if (PICO_PROTO_IPV4 == proto) { - memcpy(reverse_qname + 1u, url, slen - 1u); - pico_dns_mirror_addr(reverse_qname + 1u); - memcpy(reverse_qname + slen - 1, PICO_ARPA_IPV4_SUFFIX, arpalen); - } - - /* If reverse IPv6 address resolving, convert to IPv6 arpa-format */ -#ifdef PICO_SUPPORT_IPV6 - else if (proto == PICO_PROTO_IPV6) { - pico_dns_ipv6_set_ptr(url, reverse_qname + 1u); - memcpy(reverse_qname + 1u + STRLEN_PTR_IP6, - PICO_ARPA_IPV6_SUFFIX, arpalen); - } -#endif - else { /* This shouldn't happen */ - PICO_FREE(reverse_qname); - return NULL; - } - - pico_dns_name_to_dns_notation(reverse_qname, (unsigned int)(slen + arpalen)); - return reverse_qname; -} - -/* **************************************************************************** - * Converts a DNS name in DNS name format to a name in URL format. Provides - * space for the name in URL format as well. PICO_FREE() should be called on - * the returned string buffer that contains the name in URL format. - * - * @param qname DNS name in DNS name format to convert - * @return Returns a pointer to a string-buffer with the URL name on success. - * ****************************************************************************/ -char * -pico_dns_qname_to_url( const char *qname ) -{ - char *url = NULL; - char temp[256] = { - 0 - }; - uint16_t namelen = pico_dns_strlen(qname); - - /* Check if qname is not a NULL-pointer and if the length is OK */ - if (pico_dns_check_namelen(namelen)) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Provide space for the URL */ - if (!(url = PICO_ZALLOC(namelen))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Convert qname to an URL */ - memcpy(temp, qname, namelen); - pico_dns_notation_to_name(temp, namelen); - memcpy((void *)url, (void *)(temp + 1), (size_t)(namelen - 1)); - - return url; -} - -/* **************************************************************************** - * Converts a DNS name in URL format to a name in DNS name format. Provides - * space for the DNS name as well. PICO_FREE() should be called on the returned - * string buffer that contains the DNS name. - * - * @param url DNS name in URL format to convert - * @return Returns a pointer to a string-buffer with the DNS name on success. - * ****************************************************************************/ -char * -pico_dns_url_to_qname( const char *url ) -{ - char *qname = NULL; - uint16_t namelen = (uint16_t)(pico_dns_strlen(url) + 2u); - - /* Check if url or qname_addr is not a NULL-pointer */ - if (pico_dns_check_namelen(namelen)) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Provide space for the qname */ - if (!(qname = PICO_ZALLOC(namelen))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Copy in the URL (+1 to leave space for leading '.') */ - memcpy(qname + 1, url, (size_t)(namelen - 1)); - pico_dns_name_to_dns_notation(qname, namelen); - return qname; -} - -/* **************************************************************************** - * @param url String-buffer - * @return Length of string-buffer in an uint16_t - * ****************************************************************************/ -uint16_t -pico_dns_strlen( const char *url ) -{ - if (!url) - return 0; - - return (uint16_t) strlen(url); -} - -/* **************************************************************************** - * Replaces .'s in a DNS name in URL format by the label lengths. So it - * actually converts a name in URL format to a name in DNS name format. - * f.e. "*www.google.be" => "3www6google2be0" - * - * @param url Location to buffer with name in URL format. The URL needs to - * be +1 byte offset in the actual buffer. Size is should be - * pico_dns_strlen(url) + 2. - * @param maxlen Maximum length of buffer so it doesn't cause a buffer overflow - * @return 0 on success, something else on failure. - * ****************************************************************************/ -int pico_dns_name_to_dns_notation( char *url, unsigned int maxlen ) -{ - char c = '\0'; - char *lbl = url, *i = url; - - /* Check params */ - if (!url || pico_dns_check_namelen((uint16_t)maxlen)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Iterate over url */ - while ((c = *++i) != '\0') { - if ('.' == c) { - *lbl = (char)(i - lbl - 1); - lbl = i; - } - - if ((uint16_t)(i - url) > (uint16_t)maxlen) break; - } - *lbl = (char)(i - lbl - 1); - - return 0; -} - -/* **************************************************************************** - * Replaces the label lengths in a DNS-name by .'s. So it actually converts a - * name in DNS format to a name in URL format. - * f.e. 3www6google2be0 => .www.google.be - * - * @param ptr Location to buffer with name in DNS name format - * @param maxlen Maximum length of buffer so it doesn't cause a buffer overflow - * @return 0 on success, something else on failure. - * ****************************************************************************/ -int pico_dns_notation_to_name( char *ptr, unsigned int maxlen ) -{ - char *label = NULL, *next = NULL; - - /* Iterate safely over the labels and update each label */ - dns_name_foreach_label_safe(label, ptr, next, (uint16_t)maxlen) { - *label = '.'; - } - - return 0; -} - -/* **************************************************************************** - * Determines the length of the first label of a DNS name in URL-format - * - * @param url DNS name in URL-format - * @return Length of the first label of DNS name in URL-format - * ****************************************************************************/ -uint16_t -pico_dns_first_label_length( const char *url ) -{ - const char *i = NULL; - uint16_t len = 0; - - /* Check params */ - if (!url) return 0; - - /* Count */ - i = url; - while (*i != '.' && *i != '\0') { - ++i; - ++len; - } - return len; -} - -/* **************************************************************************** - * Mirrors a dotted IPv4-address string. - * f.e. 192.168.0.1 => 1.0.168.192 - * - * @param ptr - * @return 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_mirror_addr( char *ip ) -{ - uint32_t addr = 0; - - /* Convert IPv4-string to network-order 32-bit number */ - if (pico_string_to_ipv4(ip, &addr) < 0) - return -1; - - /* Mirror the 32-bit number */ - addr = (uint32_t)((uint32_t)((addr & (uint32_t)0xFF000000u) >> 24) | - (uint32_t)((addr & (uint32_t)0xFF0000u) >> 8) | - (uint32_t)((addr & (uint32_t)0xFF00u) << 8) | - (uint32_t)((addr & (uint32_t)0xFFu) << 24)); - - return pico_ipv4_to_string(ip, addr); -} - -#ifdef PICO_SUPPORT_IPV6 -/* **************************************************************************** - * Get the ASCII value of the Most Significant Nibble of a byte - * - * @param byte Byte you want to extract the MSN from. - * @return The ASCII value of the Most Significant Nibble of the byte - * ****************************************************************************/ -static inline char -dns_ptr_ip6_nibble_lo( uint8_t byte ) -{ - uint8_t nibble = byte & 0x0f; - if (nibble < 10) - return (char)(nibble + '0'); - else - return (char)(nibble - 0xa + 'a'); -} - -/* **************************************************************************** - * Get the ASCII value of the Least Significant Nibble of a byte - * - * @param byte Byte you want to extract the LSN from. - * @return The ASCII value of the Least Significant Nibble of the byte - * ****************************************************************************/ -static inline char -dns_ptr_ip6_nibble_hi( uint8_t byte ) -{ - uint8_t nibble = (byte & 0xf0u) >> 4u; - if (nibble < 10u) - return (char)(nibble + '0'); - else - return (char)(nibble - 0xa + 'a'); -} - -/* **************************************************************************** - * Convert an IPv6-address in string-format to a IPv6-address in nibble-format. - * Doesn't add a IPv6 ARPA-suffix though. - * - * @param ip IPv6-address stored as a string - * @param dst Destination to store IPv6-address in nibble-format - * ****************************************************************************/ -void -pico_dns_ipv6_set_ptr( const char *ip, char *dst ) -{ - int i = 0, j = 0; - struct pico_ip6 ip6; - memset(&ip6, 0, sizeof(struct pico_ip6)); - pico_string_to_ipv6(ip, ip6.addr); - for (i = 15; i >= 0; i--) { - if ((j + 3) > 64) return; /* Don't want j to go out of bounds */ - - dst[j++] = dns_ptr_ip6_nibble_lo(ip6.addr[i]); - dst[j++] = '.'; - dst[j++] = dns_ptr_ip6_nibble_hi(ip6.addr[i]); - dst[j++] = '.'; - } -} -#endif - -/* MARK: ^ NAME & IP FUNCTIONS */ -/* MARK: v QUESTION FUNCTIONS */ - -/* **************************************************************************** - * Calculates the size of a single DNS Question. Void-pointer allows this - * function to be used with pico_tree_size. - * - * @param question Void-point to DNS Question - * @return Size in bytes of single DNS Question if it was copied flat. - * ****************************************************************************/ -static uint16_t pico_dns_question_size( void *question ) -{ - uint16_t size = 0; - struct pico_dns_question *q = (struct pico_dns_question *)question; - if (!q) - return 0; - - size = q->qname_length; - size = (uint16_t)(size + sizeof(struct pico_dns_question_suffix)); - return size; -} - -/* **************************************************************************** - * Deletes a single DNS Question. - * - * @param question Void-pointer to DNS Question. Can be used with pico_tree_- - * destroy. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_question_delete( void **question ) -{ - struct pico_dns_question **q = (struct pico_dns_question **)question; - - /* Check params */ - if ((!q) || !(*q)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if ((*q)->qname) - PICO_FREE(((*q)->qname)); - - if ((*q)->qsuffix) - PICO_FREE((*q)->qsuffix); - - PICO_FREE((*q)); - *question = NULL; - - return 0; -} - -/* **************************************************************************** - * Fills in the DNS question suffix-fields with the correct values. - * - * todo: Update pico_dns_client to make the same mechanism possible like with - * filling DNS Resource Record-suffixes. - * - * @param suf Pointer to the suffix member of the DNS question. - * @param qtype DNS type of the DNS question to be. - * @param qclass DNS class of the DNS question to be. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_question_fill_suffix( struct pico_dns_question_suffix *suf, - uint16_t qtype, - uint16_t qclass ) -{ - if (!suf) - return -1; - - suf->qtype = short_be(qtype); - suf->qclass = short_be(qclass); - return 0; -} - -/* **************************************************************************** - * Fills in the name of the DNS question. - * - * @param qname Pointer-pointer to the name-member of the DNS-question - * @param url Name in URL format you want to convert to a name in DNS name - * format. When reverse resolving, only the IP, either IPV4 or - * IPV6, should be given in string format. - * f.e. => for IPv4: "192.168.2.1" - * => for IPv6: "2001:0db8:85a3:0042:1000:8a2e:0370:7334" - * @param qtype DNS type type of the DNS question to be. - * @param proto When reverse is true the reverse resolution name will be - * generated depending on the protocol. Can be either - * PICO_PROTO_IPV4 or PICO_PROTO_IPV6. - * @param reverse When this is true a reverse resolution name will be generated - * from the URL. - * @return The eventual length of the generated name, 0 on failure. - * ****************************************************************************/ -static uint16_t -pico_dns_question_fill_name( char **qname, - const char *url, - uint16_t qtype, - uint8_t proto, - uint8_t reverse ) -{ - uint16_t slen = 0; - - /* Try to convert the URL to an FQDN */ - if (reverse && qtype == PICO_DNS_TYPE_PTR) - *qname = pico_dns_url_to_reverse_qname(url, proto); - else { - (*qname) = pico_dns_url_to_qname(url); - } - - if (!(*qname)) { - return 0; - } - - slen = (uint16_t)(pico_dns_strlen(*qname) + 1u); - return (pico_dns_check_namelen(slen)) ? ((uint16_t)0) : (slen); -} - -/* **************************************************************************** - * Creates a standalone DNS Question with a given name and type. - * - * @param url DNS question name in URL format. Will be converted to DNS - * name notation format. - * @param len Will be filled with the total length of the DNS question. - * @param proto Protocol for which you want to create a question. Can be - * either PICO_PROTO_IPV4 or PICO_PROTO_IPV6. - * @param qtype DNS type of the question to be. - * @param qclass DNS class of the question to be. - * @param reverse When this is true, a reverse resolution name will be gene- - * from the URL - * @return Returns pointer to the created DNS Question on success, NULL on - * failure. - * ****************************************************************************/ -struct pico_dns_question * -pico_dns_question_create( const char *url, - uint16_t *len, - uint8_t proto, - uint16_t qtype, - uint16_t qclass, - uint8_t reverse ) -{ - struct pico_dns_question *question = NULL; - uint16_t slen = 0; - int ret = 0; - - /* Check if valid arguments are provided */ - if (!url || !len) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Allocate space for the question and the subfields */ - if (!(question = PICO_ZALLOC(sizeof(struct pico_dns_question)))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Fill name field */ - slen = pico_dns_question_fill_name(&(question->qname), url, - qtype, proto, reverse); - question->qname_length = (uint8_t)(slen); - question->proto = proto; - - /* Provide space for the question suffix & try to fill in */ - question->qsuffix = PICO_ZALLOC(sizeof(struct pico_dns_question_suffix)); - ret = pico_dns_question_fill_suffix(question->qsuffix, qtype, qclass); - if (ret || pico_dns_check_namelen(slen)) { - pico_dns_question_delete((void **)&question); - return NULL; - } - - /* Determine the entire length of the question */ - *len = (uint16_t)(slen + (uint16_t)sizeof(struct pico_dns_question_suffix)); - - return question; -} - -/* **************************************************************************** - * Decompresses the name of a single DNS question. - * - * @param question Question you want to decompress the name of - * @param packet Packet in which the DNS question is contained. - * @return Pointer to original name of the DNS question before decompressing. - * ****************************************************************************/ -char * -pico_dns_question_decompress( struct pico_dns_question *question, - pico_dns_packet *packet ) -{ - char *qname_original = question->qname; - - /* Try to decompress the question name */ - if (!(question->qname = pico_dns_decompress_name(question->qname, packet))) { - question->qname = qname_original; - } - - return qname_original; -} - - -/* MARK: ^ QUESTION FUNCTIONS */ -/* MARK: v RESOURCE RECORD FUNCTIONS */ - -/* **************************************************************************** - * Copies the contents of DNS Resource Record to a single flat memory-buffer. - * - * @param record Pointer to DNS record you want to copy flat. - * @param destination Pointer-pointer to flat memory buffer to copy DNS record - * to. When function returns, this will point to location - * right after the flat copied DNS Resource Record. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -static int -pico_dns_record_copy_flat( struct pico_dns_record *record, - uint8_t **destination ) -{ - char *dest_rname = NULL; /* rname destination location */ - struct pico_dns_record_suffix *dest_rsuffix = NULL; /* rsuffix destin. */ - uint8_t *dest_rdata = NULL; /* rdata destination location */ - - /* Check if there are no NULL-pointers given */ - if (!record || !destination || !(*destination)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Initialise the destination pointers to the right locations */ - dest_rname = (char *) *destination; - dest_rsuffix = (struct pico_dns_record_suffix *) - (dest_rname + record->rname_length); - dest_rdata = ((uint8_t *)dest_rsuffix + - sizeof(struct pico_dns_record_suffix)); - - /* Copy the rname of the resource record into the flat location */ - strcpy(dest_rname, record->rname); - - /* Copy the question suffix fields */ - dest_rsuffix->rtype = record->rsuffix->rtype; - dest_rsuffix->rclass = record->rsuffix->rclass; - dest_rsuffix->rttl = record->rsuffix->rttl; - dest_rsuffix->rdlength = record->rsuffix->rdlength; - - /* Copy the rdata of the resource */ - memcpy(dest_rdata, record->rdata, short_be(dest_rsuffix->rdlength)); - - /* Point to location right after flat resource record */ - *destination = (uint8_t *)(dest_rdata + - short_be(record->rsuffix->rdlength)); - return 0; -} - -/* **************************************************************************** - * Calculates the size of a single DNS Resource Record. Void-pointer allows - * this function to be used with pico_tree_size. - * - * @param record void-pointer to DNS record you want to know the size of. - * @return Size of single DNS record if it was copied flat. - * ****************************************************************************/ -static uint16_t -pico_dns_record_size( void *record ) -{ - uint16_t size = 0; - struct pico_dns_record *rr = (struct pico_dns_record *)record; - - if (!rr || !(rr->rsuffix)) - return 0; - - size = rr->rname_length; - size = (uint16_t)(size + sizeof(struct pico_dns_record_suffix)); - size = (uint16_t)(size + short_be(rr->rsuffix->rdlength)); - return size; -} - -/* **************************************************************************** - * Deletes a single DNS resource record. Void-pointer-pointer allows this - * function to be used with pico_tree_destroy. - * - * @param record void-pointer-pointer to DNS record you want to delete. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_record_delete( void **record ) -{ - struct pico_dns_record **rr = (struct pico_dns_record **)record; - - if ((!rr) || !(*rr)) - return 0; - - if ((*rr)->rname) - PICO_FREE((*rr)->rname); - - if ((*rr)->rsuffix) - PICO_FREE((*rr)->rsuffix); - - if ((*rr)->rdata) - PICO_FREE((*rr)->rdata); - - PICO_FREE((*rr)); - *record = NULL; - - return 0; -} - -/* **************************************************************************** - * Just copies a resource record hard. - * - * @param record DNS record you want to copy - * @return Pointer to copy of DNS record. - * ****************************************************************************/ -struct pico_dns_record * -pico_dns_record_copy( struct pico_dns_record *record ) -{ - struct pico_dns_record *copy = NULL; - - /* Check params */ - if (!record || !(record->rname) || !(record->rdata) || !(record->rsuffix)) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Provide space for the copy */ - if (!(copy = PICO_ZALLOC(sizeof(struct pico_dns_record)))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Provide space for the subfields */ - copy->rname = PICO_ZALLOC((size_t)record->rname_length); - copy->rsuffix = PICO_ZALLOC(sizeof(struct pico_dns_record_suffix)); - copy->rdata = PICO_ZALLOC((size_t)short_be(record->rsuffix->rdlength)); - if (!(copy->rname) || !(copy->rsuffix) || !(copy->rdata)) { - pico_dns_record_delete((void **)©); - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Fill in the rname field */ - memcpy((void *)(copy->rname), (void *)(record->rname), - (size_t)(record->rname_length)); - copy->rname_length = record->rname_length; - - /* Fill in the rsuffix fields */ - copy->rsuffix->rtype = record->rsuffix->rtype; - copy->rsuffix->rclass = record->rsuffix->rclass; - copy->rsuffix->rttl = record->rsuffix->rttl; - copy->rsuffix->rdlength = record->rsuffix->rdlength; - - /* Fill in the rdata field */ - memcpy(copy->rdata, record->rdata, short_be(record->rsuffix->rdlength)); - - return copy; -} - -/* **************************************************************************** - * Fills in the DNS resource record suffix-fields with the correct values. - * - * @param suf Pointer-pointer to rsuffix-member of struct pico_dns_record. - * @param rtype DNS type of the resource record to be. - * @param rclass DNS class of the resource record to be. - * @param rttl DNS ttl of the resource record to be. - * @param rdlength DNS rdlength of the resource record to be. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -static int -pico_dns_record_fill_suffix( struct pico_dns_record_suffix **suf, - uint16_t rtype, - uint16_t rclass, - uint32_t rttl, - uint16_t rdlength ) -{ - /* Try to provide space for the rsuffix */ - if (!(*suf = PICO_ZALLOC(sizeof(struct pico_dns_record_suffix)))) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - /* Fill in the fields */ - (*suf)->rtype = short_be(rtype); - (*suf)->rclass = short_be(rclass); - (*suf)->rttl = long_be(rttl); - (*suf)->rdlength = short_be(rdlength); - - return 0; -} - -/* **************************************************************************** - * Fills the data-buffer of a DNS resource record. - * - * @param rdata Pointer-pointer to rdata-member of struct pico_dns_record. - * @param _rdata Memory buffer with data to insert in the resource record. If - * data should contain a DNS name, the name in the databuffer - * needs to be in URL-format. - * @param datalen The exact length in bytes of the _rdata-buffer. If data of - * record should contain a DNS name, datalen needs to be - * pico_dns_strlen(_rdata). - * @param rtype DNS type of the resource record to be - * @return Returns 0 on failure, length of filled in rdata-member on success. - * Can differ from datalen-param because of URL to DNS Name conversion. - * ****************************************************************************/ -static uint16_t -pico_dns_record_fill_rdata( uint8_t **rdata, - void *_rdata, - uint16_t datalen, - uint16_t rtype ) -{ - uint16_t _datalen = 0; - - /* If type is PTR, rdata will be a DNS name in URL format */ - if (rtype == PICO_DNS_TYPE_PTR) { - _datalen = (uint16_t)(datalen + 2u); - if (!(*rdata = (uint8_t *)pico_dns_url_to_qname(_rdata))) { - pico_err = PICO_ERR_ENOMEM; - return 0; - } - } else { - /* Otherwise just copy in the databuffer */ - if (datalen == 0) { - return datalen; - } - _datalen = datalen; - if (!(*rdata = (uint8_t *)PICO_ZALLOC((size_t)datalen))) { - pico_err = PICO_ERR_ENOMEM; - return 0; - } - - memcpy((void *)*rdata, (void *)_rdata, datalen); - } - - return _datalen; -} - -/* **************************************************************************** - * Create a standalone DNS Resource Record with a given name. - * - * @param url DNS rrecord name in URL format. Will be converted to DNS - * name notation format. - * @param _rdata Memory buffer with data to insert in the resource record. If - * data should contain a DNS name, the name in the databuffer - * needs to be in URL-format. - * @param datalen The exact length in bytes of the _rdata-buffer. If data of - * record should contain a DNS name, datalen needs to be - * pico_dns_strlen(_rdata). - * @param len Will be filled with the total length of the DNS rrecord. - * @param rtype DNS type of the resource record to be. - * @param rclass DNS class of the resource record to be. - * @param rttl DNS ttl of the resource record to be. - * @return Returns pointer to the created DNS Resource Record - * ****************************************************************************/ -struct pico_dns_record * -pico_dns_record_create( const char *url, - void *_rdata, - uint16_t datalen, - uint16_t *len, - uint16_t rtype, - uint16_t rclass, - uint32_t rttl ) -{ - struct pico_dns_record *record = NULL; - uint16_t slen = (uint16_t)(pico_dns_strlen(url) + 2u); - int ret = 0; - - /* Check params */ - if (pico_dns_check_namelen(slen) || !_rdata || !len) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Allocate space for the record and subfields */ - if (!(record = PICO_ZALLOC(sizeof(struct pico_dns_record)))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Provide space and convert the URL to a DNS name */ - record->rname = pico_dns_url_to_qname(url); - record->rname_length = slen; - - /* Provide space & fill in the rdata field */ - datalen = pico_dns_record_fill_rdata(&(record->rdata), _rdata, - datalen, rtype); - - /* Provide space & fill in the rsuffix */ - ret = pico_dns_record_fill_suffix(&(record->rsuffix), rtype, rclass, rttl, - datalen); - - /* Check if everything succeeded */ - if (!(record->rname) || ret) { - pico_dns_record_delete((void **)&record); - return NULL; - } - - /* Determine the complete length of resource record */ - *len = (uint16_t)(slen + sizeof(struct pico_dns_record_suffix) + datalen); - return record; -} - -/* **************************************************************************** - * Decompresses the name of single DNS record. - * - * @param record DNS record to decompress the name of. - * @param packet Packet in which is DNS record is present - * @return Pointer to original name of the DNS record before decompressing. - * ****************************************************************************/ -char * -pico_dns_record_decompress( struct pico_dns_record *record, - pico_dns_packet *packet ) -{ - char *rname_original = record->rname; - - /* Try to decompress the record name */ - if (!(record->rname = pico_dns_decompress_name(record->rname, packet))) { - record->rname = rname_original; - } - - return rname_original; -} - -static int pico_tolower(int c) -{ - if ((c >= 'A') && (c <= 'Z')) - c += 'a' - 'A'; - return c; -} - -/* MARK: ^ RESOURCE RECORD FUNCTIONS */ -/* MARK: v COMPARING */ - -/* **************************************************************************** - * Compares two databuffers against each other. - * - * @param a 1st Memory buffer to compare - * @param b 2nd Memory buffer to compare - * @param rdlength_a Length of 1st memory buffer - * @param rdlength_b Length of 2nd memory buffer - * @param caseinsensitive Whether or not the bytes are compared - * case-insensitive - * @return 0 when the buffers are equal, returns difference when they're not. - * ****************************************************************************/ -int -pico_dns_rdata_cmp( uint8_t *a, uint8_t *b, - uint16_t rdlength_a, uint16_t rdlength_b, uint8_t caseinsensitive ) -{ - uint16_t i = 0; - uint16_t slen = 0; - int dif = 0; - - /* Check params */ - if (!a || !b) { - if (!a && !b) - return 0; - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Determine the smallest length */ - slen = rdlength_a; - if (rdlength_b < slen) - slen = rdlength_b; - - /* loop over slen */ - if(caseinsensitive){ - for (i = 0; i < slen; i++) { - if ((dif = pico_tolower((int)a[i]) - pico_tolower((int)b[i]))) { - return dif; - } - } - }else{ - for (i = 0; i < slen; i++) { - if ((dif = (int)a[i] - (int)b[i])){ - return dif; - } - } - } - - /* Return difference of buffer lengths */ - return (int)((int)rdlength_a - (int)rdlength_b); -} - -/* **************************************************************************** - * Compares 2 DNS questions - * - * @param qa DNS question A as a void-pointer (for pico_tree) - * @param qb DNS question A as a void-pointer (for pico_tree) - * @return 0 when questions are equal, returns difference when they're not. - * ****************************************************************************/ -int -pico_dns_question_cmp( void *qa, - void *qb ) -{ - int dif = 0; - uint16_t at = 0, bt = 0; - struct pico_dns_question *a = (struct pico_dns_question *)qa; - struct pico_dns_question *b = (struct pico_dns_question *)qb; - - /* Check params */ - if (!a || !b) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* First, compare the qtypes */ - at = short_be(a->qsuffix->qtype); - bt = short_be(b->qsuffix->qtype); - if ((dif = (int)((int)at - (int)bt))) - return dif; - - /* Then compare qnames */ - return pico_dns_rdata_cmp((uint8_t *)a->qname, (uint8_t *)b->qname, - pico_dns_strlen(a->qname), - pico_dns_strlen(b->qname), 1); -} - -/* **************************************************************************** - * Compares 2 DNS records by type and name only - * - * @param ra DNS record A as a void-pointer (for pico_tree) - * @param rb DNS record B as a void-pointer (for pico_tree) - * @return 0 when name and type of records are equal, returns difference when - * they're not. - * ****************************************************************************/ -int -pico_dns_record_cmp_name_type( void *ra, - void *rb ) -{ - int dif; - uint16_t at = 0, bt = 0; - struct pico_dns_record *a = (struct pico_dns_record *)ra; - struct pico_dns_record *b = (struct pico_dns_record *)rb; - - /* Check params */ - if (!a || !b) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* First, compare the rrtypes */ - at = short_be(a->rsuffix->rtype); - bt = short_be(b->rsuffix->rtype); - if ((dif = (int)((int)at - (int)bt))) - return dif; - - /* Then compare names */ - return pico_dns_rdata_cmp((uint8_t *)(a->rname), (uint8_t *)(b->rname), - (uint16_t)strlen(a->rname), - (uint16_t)strlen(b->rname), 1); -} - -/* **************************************************************************** - * Compares 2 DNS records by type, name AND rdata for a truly unique result - * - * @param ra DNS record A as a void-pointer (for pico_tree) - * @param rb DNS record B as a void-pointer (for pico_tree) - * @return 0 when records are equal, returns difference when they're not - * ****************************************************************************/ -int -pico_dns_record_cmp( void *ra, - void *rb ) -{ - int dif = 0; - struct pico_dns_record *a = (struct pico_dns_record *)ra; - struct pico_dns_record *b = (struct pico_dns_record *)rb; - - /* Check params */ - if (!a || !b) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Compare type and name */ - if ((dif = pico_dns_record_cmp_name_type(a, b))) - return dif; - - /* Then compare rdata */ - return pico_dns_rdata_cmp(a->rdata, b->rdata, - short_be(a->rsuffix->rdlength), - short_be(b->rsuffix->rdlength), 0); -} - -/* MARK: ^ COMPARING */ -/* MARK: v PICO_TREE */ - -/* **************************************************************************** - * Erases a pico_tree entirely. - * - * @param tree Pointer to a pico_tree-instance - * @param node_delete Helper-function for type-specific deleting. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_tree_destroy( struct pico_tree *tree, int (*node_delete)(void **)) -{ - struct pico_tree_node *node = NULL, *next = NULL; - void *item = NULL; - - /* Check params */ - if (!tree) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - pico_tree_foreach_safe(node, tree, next) { - item = node->keyValue; - pico_tree_delete(tree, node->keyValue); - if (item && node_delete) { - node_delete((void **)&item); - } - } - - return 0; -} - -/* **************************************************************************** - * Calculates the size in bytes of all the nodes contained in the tree summed - * up. And gets the amount of items in the tree as well. - * - * @param tree Pointer to pico_tree-instance - * @param size Will get filled with the size of all the nodes summed up. - * Make sure you clear out (set to 0) this param before you - * call this function because it doesn't happen inside and - * each size will be added to the initial value. - * @param node_size Helper-function for type-specific size-determination - * @return Amount of items in the tree. - * ****************************************************************************/ -static uint16_t -pico_tree_size( struct pico_tree *tree, - uint16_t *size, - uint16_t (*node_size)(void *)) -{ - struct pico_tree_node *node = NULL; - void *node_item = NULL; - uint16_t count = 0; - - /* Check params */ - if (!tree || !size) { - pico_err = PICO_ERR_EINVAL; - return 0; - } - - /* Add up the node sizes */ - pico_tree_foreach(node, tree) { - if ((node_item = node->keyValue)) { - *size = (uint16_t)((*size) + node_size(node_item)); - count++; - } - } - - return count; -} - -/* **************************************************************************** - * Determines the amount of nodes in a pico_tere - * - * @param tree Pointer to pico_tree-instance - * @return Amount of items in the tree. - * ****************************************************************************/ -uint16_t -pico_tree_count( struct pico_tree *tree ) -{ - struct pico_tree_node *node = NULL; - uint16_t count = 0; - - pico_tree_foreach(node, tree) { - if (node->keyValue) - count++; - } - - return count; -} - -/* **************************************************************************** - * Deletes all the questions with given DNS name from a pico_tree - * - * @param qtree Pointer to pico_tree-instance which contains DNS questions - * @param name Name of the questions you want to delete - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_qtree_del_name( struct pico_tree *qtree, - const char *name ) -{ - struct pico_tree_node *node = NULL, *next = NULL; - struct pico_dns_question *question = NULL; - - /* Check params */ - if (!qtree || !name) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Iterate over tree and delete every node with given name */ - pico_tree_foreach_safe(node, qtree, next) { - question = (struct pico_dns_question *)node->keyValue; - if ((question) && (strcasecmp(question->qname, name) == 0)) { - question = pico_tree_delete(qtree, (void *)question); - pico_dns_question_delete((void **)&question); - } - } - - return 0; -} - -/* **************************************************************************** - * Checks whether a question with given name is in the tree or not. - * - * @param qtree Pointer to pico_tree-instance which contains DNS questions - * @param name Name you want to check for - * @return 1 when the name is present in the qtree, 0 when it's not. - * ****************************************************************************/ -int -pico_dns_qtree_find_name( struct pico_tree *qtree, - const char *name ) -{ - struct pico_tree_node *node = NULL; - struct pico_dns_question *question = NULL; - - /* Check params */ - if (!qtree || !name) { - pico_err = PICO_ERR_EINVAL; - return 0; - } - - /* Iterate over tree and compare names */ - pico_tree_foreach(node, qtree) { - question = (struct pico_dns_question *)node->keyValue; - if ((question) && (strcasecmp(question->qname, name) == 0)) - return 1; - } - - return 0; -} - -/* MARK: ^ PICO_TREE */ -/* MARK: v DNS PACKET FUNCTIONS */ - -/* **************************************************************************** - * Fills the header section of a DNS packet with the correct flags and section - * -counts. - * - * @param hdr Header to fill in. - * @param qdcount Amount of questions added to the packet - * @param ancount Amount of answer records added to the packet - * @param nscount Amount of authority records added to the packet - * @param arcount Amount of additional records added to the packet - * ****************************************************************************/ -void -pico_dns_fill_packet_header( struct pico_dns_header *hdr, - uint16_t qdcount, - uint16_t ancount, - uint16_t nscount, - uint16_t arcount ) -{ - /* ID should be filled by caller */ - - if(qdcount > 0) { /* Questions present? Make it a query */ - hdr->qr = PICO_DNS_QR_QUERY; - hdr->aa = PICO_DNS_AA_NO_AUTHORITY; - } else { /* No questions present? Make it an answer*/ - hdr->qr = PICO_DNS_QR_RESPONSE; - hdr->aa = PICO_DNS_AA_IS_AUTHORITY; - } - - /* Fill in the flags and the fields */ - hdr->opcode = PICO_DNS_OPCODE_QUERY; - hdr->tc = PICO_DNS_TC_NO_TRUNCATION; - hdr->rd = PICO_DNS_RD_IS_DESIRED; - hdr->ra = PICO_DNS_RA_NO_SUPPORT; - hdr->z = 0; /* Z, AD, CD are 0 */ - hdr->rcode = PICO_DNS_RCODE_NO_ERROR; - hdr->qdcount = short_be(qdcount); - hdr->ancount = short_be(ancount); - hdr->nscount = short_be(nscount); - hdr->arcount = short_be(arcount); -} - -/* **************************************************************************** - * Fills a single DNS resource record section of a DNS packet. - * - * @param rtree Tree that contains the DNS resource records. - * @param dest Pointer-pointer to location where you want to insert records. - * Will point to location after current section on return. - * @return 0 on success, something else on failure. - * ****************************************************************************/ -static int -pico_dns_fill_packet_rr_section( struct pico_tree *rtree, - uint8_t **dest ) -{ - struct pico_tree_node *node = NULL; - struct pico_dns_record *record = NULL; - - pico_tree_foreach(node, rtree) { - record = node->keyValue; - if ((record) && pico_dns_record_copy_flat(record, dest)) { - dns_dbg("Could not copy record into Answer Section!\n"); - return -1; - } - } - return 0; -} - -/* **************************************************************************** - * Fills the resource record sections of a DNS packet with provided record- - * trees. - * - * @param packet Packet you want to fill - * @param qtree Question tree to determine where the rrsections begin. - * @param antree DNS records to put in Answer section - * @param nstree DNS records to put in Authority section - * @param artree DNS records to put in Additional section - * @return 0 on success, something else on failure. - * ****************************************************************************/ -static int -pico_dns_fill_packet_rr_sections( pico_dns_packet *packet, - struct pico_tree *qtree, - struct pico_tree *antree, - struct pico_tree *nstree, - struct pico_tree *artree ) -{ - int anret = 0, nsret = 0, arret = 0; - uint16_t temp = 0; - uint8_t *destination = NULL; - - /* Check params */ - if (!packet || !qtree || !antree || !nstree || !artree) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Initialise the destination pointers before iterating */ - destination = (uint8_t *)packet + sizeof(struct pico_dns_header); - pico_tree_size(qtree, &temp, &pico_dns_question_size); - destination = destination + temp; - - /* Iterate over ANSWERS */ - anret = pico_dns_fill_packet_rr_section(antree, &destination); - - /* Iterate over AUTHORITIES */ - nsret = pico_dns_fill_packet_rr_section(nstree, &destination); - - /* Iterate over ADDITIONALS */ - arret = pico_dns_fill_packet_rr_section(artree, &destination); - - if (anret || nsret || arret) - return -1; - - return 0; -} - -/* **************************************************************************** - * Fills the question section of a DNS packet with provided questions in the - * tree. - * - * @param packet Packet you want to fill - * @param qtree Question tree with question you want to insert - * @return 0 on success, something else on failure. - * ****************************************************************************/ -static int -pico_dns_fill_packet_question_section( pico_dns_packet *packet, - struct pico_tree *qtree ) -{ - struct pico_tree_node *node = NULL; - struct pico_dns_question *question = NULL; - struct pico_dns_question_suffix *dest_qsuffix = NULL; - char *dest_qname = NULL; - - /* Check params */ - if (!packet || !qtree) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Initialise pointer */ - dest_qname = (char *)((char *)packet + sizeof(struct pico_dns_header)); - - pico_tree_foreach(node, qtree) { - question = node->keyValue; - if (question) { - /* Copy the name */ - memcpy(dest_qname, question->qname, question->qname_length); - - /* Copy the suffix */ - dest_qsuffix = (struct pico_dns_question_suffix *) - (dest_qname + question->qname_length); - dest_qsuffix->qtype = question->qsuffix->qtype; - dest_qsuffix->qclass = question->qsuffix->qclass; - - /* Move to next question */ - dest_qname = (char *)((char *)dest_qsuffix + - sizeof(struct pico_dns_question_suffix)); - } - } - return 0; -} - -/* **************************************************************************** - * Looks for a name somewhere else in packet, more specifically between the - * beginning of the data buffer and the name itself. - * ****************************************************************************/ -static uint8_t * -pico_dns_packet_compress_find_ptr( uint8_t *name, - uint8_t *data, - uint16_t len ) -{ - uint8_t *iterator = NULL; - - /* Check params */ - if (!name || !data || !len) - return NULL; - - if ((name < data) || (name > (data + len))) - return NULL; - - iterator = data; - - /* Iterate from the beginning of data up until the name-ptr */ - while (iterator < name) { - /* Compare in each iteration of current name is equal to a section of - the DNS packet and if so return the pointer to that section */ - if (memcmp((void *)iterator++, (void *)name, - pico_dns_strlen((char *)name) + 1u) == 0) - return (iterator - 1); - } - return NULL; -} - -/* **************************************************************************** - * Compresses a single name by looking for the same name somewhere else in the - * packet-buffer. - * ****************************************************************************/ -static int -pico_dns_packet_compress_name( uint8_t *name, - uint8_t *packet, - uint16_t *len) -{ - uint8_t *lbl_iterator = NULL; /* To iterate over labels */ - uint8_t *compression_ptr = NULL; /* PTR to somewhere else in the packet */ - uint8_t *offset = NULL; /* PTR after compression pointer */ - uint8_t *ptr_after_str = NULL; - uint8_t *last_byte = NULL; - uint8_t *i = NULL; - uint16_t ptr = 0; - uint16_t difference = 0; - - /* Check params */ - if (!name || !packet || !len) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if ((name < packet) || (name > (packet + *len))) { - dns_dbg("Name ptr OOB. name: %p max: %p\n", name, packet + *len); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Try to compress name */ - lbl_iterator = name; - while (lbl_iterator != '\0') { - /* Try to find a compression pointer with current name */ - compression_ptr = pico_dns_packet_compress_find_ptr(lbl_iterator, - packet + 12, *len); - /* If name can be compressed */ - if (compression_ptr) { - /* Point to place after current string */ - ptr_after_str = lbl_iterator + strlen((char *)lbl_iterator) + 1u; - - /* Calculate the compression pointer value */ - ptr = (uint16_t)(compression_ptr - packet); - - /* Set the compression pointer in the packet */ - *lbl_iterator = (uint8_t)(0xC0 | (uint8_t)(ptr >> 8)); - *(lbl_iterator + 1) = (uint8_t)(ptr & 0xFF); - - /* Move up the rest of the packet data to right after the pointer */ - offset = lbl_iterator + 2; - - /* Move up left over data */ - difference = (uint16_t)(ptr_after_str - offset); - last_byte = packet + *len; - for (i = ptr_after_str; i < last_byte; i++) - *((uint8_t *)(i - difference)) = *i; - /* Update length */ - *len = (uint16_t)(*len - difference); - break; - } - - /* Move to next length label */ - lbl_iterator = lbl_iterator + *(lbl_iterator) + 1; - } - return 0; -} - -/* **************************************************************************** - * Utility function compress a record section - * ****************************************************************************/ -static int -pico_dns_compress_record_sections( uint16_t qdcount, uint16_t count, - uint8_t *buf, uint8_t **iterator, - uint16_t *len ) -{ - struct pico_dns_record_suffix *rsuffix = NULL; - uint8_t *_iterator = NULL; - uint16_t i = 0; - - /* Check params */ - if (!iterator || !(*iterator) || !buf || !len) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - _iterator = *iterator; - - for (i = 0; i < count; i++) { - if (qdcount || i) - pico_dns_packet_compress_name(_iterator, buf, len); - - /* To get rdlength */ - rsuffix = (struct pico_dns_record_suffix *) - (_iterator + pico_dns_namelen_comp((char *)_iterator) + 1u); - - /* Move to next res record */ - _iterator = ((uint8_t *)rsuffix + - sizeof(struct pico_dns_record_suffix) + - short_be(rsuffix->rdlength)); - } - *iterator = _iterator; - return 0; -} - -/* **************************************************************************** - * Applies DNS name compression to an entire DNS packet - * ****************************************************************************/ -static int -pico_dns_packet_compress( pico_dns_packet *packet, uint16_t *len ) -{ - uint8_t *packet_buf = NULL; - uint8_t *iterator = NULL; - uint16_t qdcount = 0, rcount = 0, i = 0; - - /* Check params */ - if (!packet || !len) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - packet_buf = (uint8_t *)packet; - - /* Temporarily store the question & record counts */ - qdcount = short_be(packet->qdcount); - rcount = (uint16_t)(rcount + short_be(packet->ancount)); - rcount = (uint16_t)(rcount + short_be(packet->nscount)); - rcount = (uint16_t)(rcount + short_be(packet->arcount)); - - /* Move past the DNS packet header */ - iterator = (uint8_t *)((uint8_t *) packet + 12u); - - /* Start with the questions */ - for (i = 0; i < qdcount; i++) { - if (i) /* First question can't be compressed */ - pico_dns_packet_compress_name(iterator, packet_buf, len); - - /* Move to next question */ - iterator = (uint8_t *)(iterator + - pico_dns_namelen_comp((char *)iterator) + - sizeof(struct pico_dns_question_suffix) + 1u); - } - /* Then onto the answers */ - pico_dns_compress_record_sections(qdcount, rcount, packet_buf, &iterator, - len); - return 0; -} - -/* **************************************************************************** - * Calculates how big a packet needs be in order to store all the question & - * records in the tree. Also determines the amount of questions and records. - * - * @param qtree Tree with Questions. - * @param antree Tree with Answer Records. - * @param nstree Tree with Authority Records. - * @param artree Tree with Additional Records. - * @param qdcount Pointer to var to store amount of questions - * @param ancount Pointer to var to store amount of answers. - * @param nscount Pointer to var to store amount of authorities. - * @param arcount Pointer to var to store amount of additionals. - * @return Returns the total length that the DNS packet needs to be. - * ****************************************************************************/ -static uint16_t -pico_dns_packet_len( struct pico_tree *qtree, - struct pico_tree *antree, - struct pico_tree *nstree, - struct pico_tree *artree, - uint8_t *qdcount, uint8_t *ancount, - uint8_t *nscount, uint8_t *arcount ) -{ - uint16_t len = (uint16_t) sizeof(pico_dns_packet); - - /* Check params */ - if (!qtree || !antree || !nstree || !artree) { - pico_err = PICO_ERR_EINVAL; - return 0; - } - - *qdcount = (uint8_t)pico_tree_size(qtree, &len, &pico_dns_question_size); - *ancount = (uint8_t)pico_tree_size(antree, &len, &pico_dns_record_size); - *nscount = (uint8_t)pico_tree_size(nstree, &len, &pico_dns_record_size); - *arcount = (uint8_t)pico_tree_size(artree, &len, &pico_dns_record_size); - return len; -} - -/* **************************************************************************** - * Generic packet creation utility that just creates a DNS packet with given - * questions and resource records to put in the Resource Record Sections. If a - * NULL-pointer is provided for a certain tree, no records will be added to - * that particular section of the packet. - * - * @param qtree DNS Questions to put in the Question Section. - * @param antree DNS Records to put in the Answer Section. - * @param nstree DNS Records to put in the Authority Section. - * @param artree DNS Records to put in the Additional Section. - * @param len Will get fill with the entire size of the packet - * @return Pointer to created DNS packet - * ****************************************************************************/ -static pico_dns_packet * -pico_dns_packet_create( struct pico_tree *qtree, - struct pico_tree *antree, - struct pico_tree *nstree, - struct pico_tree *artree, - uint16_t *len ) -{ - PICO_DNS_QTREE_DECLARE(_qtree); - PICO_DNS_RTREE_DECLARE(_antree); - PICO_DNS_RTREE_DECLARE(_nstree); - PICO_DNS_RTREE_DECLARE(_artree); - pico_dns_packet *packet = NULL; - uint8_t qdcount = 0, ancount = 0, nscount = 0, arcount = 0; - - /* Set default vector, if arguments are NULL-pointers */ - _qtree = (qtree) ? (*qtree) : (_qtree); - _antree = (antree) ? (*antree) : (_antree); - _nstree = (nstree) ? (*nstree) : (_nstree); - _artree = (artree) ? (*artree) : (_artree); - - /* Get the size of the entire packet and determine the header counters */ - *len = pico_dns_packet_len(&_qtree, &_antree, &_nstree, &_artree, - &qdcount, &ancount, &nscount, &arcount); - - /* Provide space for the entire packet */ - if (!(packet = PICO_ZALLOC(*len))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Fill the Question Section with questions */ - if (qtree && pico_tree_count(&_qtree) != 0) { - if (pico_dns_fill_packet_question_section(packet, &_qtree)) { - dns_dbg("Could not fill Question Section correctly!\n"); - return NULL; - } - } - - /* Fill the Resource Record Sections with resource records */ - if (pico_dns_fill_packet_rr_sections(packet, &_qtree, &_antree, - &_nstree, &_artree)) { - dns_dbg("Could not fill Resource Record Sections correctly!\n"); - return NULL; - } - - /* Fill the DNS packet header and try to compress */ - pico_dns_fill_packet_header(packet, qdcount, ancount, nscount, arcount); - pico_dns_packet_compress(packet, len); - - return packet; -} - -/* **************************************************************************** - * Creates a DNS Query packet with given question and resource records to put - * the Resource Record Sections. If a NULL-pointer is provided for a certain - * tree, no records will be added to that particular section of the packet. - * - * @param qtree DNS Questions to put in the Question Section - * @param antree DNS Records to put in the Answer Section - * @param nstree DNS Records to put in the Authority Section - * @param artree DNS Records to put in the Additional Section - * @param len Will get filled with the entire size of the packet - * @return Pointer to created DNS packet - * ****************************************************************************/ -pico_dns_packet * -pico_dns_query_create( struct pico_tree *qtree, - struct pico_tree *antree, - struct pico_tree *nstree, - struct pico_tree *artree, - uint16_t *len ) -{ - return pico_dns_packet_create(qtree, antree, nstree, artree, len); -} - -/* **************************************************************************** - * Creates a DNS Answer packet with given resource records to put in the - * Resource Record Sections. If a NULL-pointer is provided for a certain tree, - * no records will be added to that particular section of the packet. - * - * @param antree DNS Records to put in the Answer Section - * @param nstree DNS Records to put in the Authority Section - * @param artree DNS Records to put in the Additional Section - * @param len Will get filled with the entire size of the packet - * @return Pointer to created DNS packet. - * ****************************************************************************/ -pico_dns_packet * -pico_dns_answer_create( struct pico_tree *antree, - struct pico_tree *nstree, - struct pico_tree *artree, - uint16_t *len ) -{ - return pico_dns_packet_create(NULL, antree, nstree, artree, len); -} -/* MARK: ^ DNS PACKET FUNCTIONS */ diff --git a/ext/picotcp/modules/pico_dns_common.h b/ext/picotcp/modules/pico_dns_common.h deleted file mode 100644 index 32a1a1d..0000000 --- a/ext/picotcp/modules/pico_dns_common.h +++ /dev/null @@ -1,523 +0,0 @@ - -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See LICENSE and COPYING for usage. - . - Authors: Toon Stegen, Jelle De Vleeschouwer - *********************************************************************/ - -#ifndef INCLUDE_PICO_DNS_COMMON -#define INCLUDE_PICO_DNS_COMMON - -#include "pico_config.h" -#include "pico_tree.h" - -/* TYPE values */ -#define PICO_DNS_TYPE_A 1 -#define PICO_DNS_TYPE_CNAME 5 -#define PICO_DNS_TYPE_PTR 12 -#define PICO_DNS_TYPE_TXT 16 -#define PICO_DNS_TYPE_AAAA 28 -#define PICO_DNS_TYPE_SRV 33 -#define PICO_DNS_TYPE_NSEC 47 -#define PICO_DNS_TYPE_ANY 255 - -/* CLASS values */ -#define PICO_DNS_CLASS_IN 1 - -/* FLAG values */ -#define PICO_DNS_QR_QUERY 0 -#define PICO_DNS_QR_RESPONSE 1 -#define PICO_DNS_OPCODE_QUERY 0 -#define PICO_DNS_OPCODE_IQUERY 1 -#define PICO_DNS_OPCODE_STATUS 2 -#define PICO_DNS_AA_NO_AUTHORITY 0 -#define PICO_DNS_AA_IS_AUTHORITY 1 -#define PICO_DNS_TC_NO_TRUNCATION 0 -#define PICO_DNS_TC_IS_TRUNCATED 1 -#define PICO_DNS_RD_NO_DESIRE 0 -#define PICO_DNS_RD_IS_DESIRED 1 -#define PICO_DNS_RA_NO_SUPPORT 0 -#define PICO_DNS_RA_IS_SUPPORTED 1 -#define PICO_DNS_RCODE_NO_ERROR 0 -#define PICO_DNS_RCODE_EFORMAT 1 -#define PICO_DNS_RCODE_ESERVER 2 -#define PICO_DNS_RCODE_ENAME 3 -#define PICO_DNS_RCODE_ENOIMP 4 -#define PICO_DNS_RCODE_EREFUSED 5 - -#define PICO_ARPA_IPV4_SUFFIX ".in-addr.arpa" - -#ifdef PICO_SUPPORT_IPV6 -#define STRLEN_PTR_IP6 63 -#define PICO_ARPA_IPV6_SUFFIX ".IP6.ARPA" -#endif - -#define PICO_DNS_NAMEBUF_SIZE (256) - -enum pico_dns_arpa -{ - PICO_DNS_ARPA4, - PICO_DNS_ARPA6, - PICO_DNS_NO_ARPA, -}; - -/* flags split in 2x uint8 due to endianness */ -PACKED_STRUCT_DEF pico_dns_header -{ - uint16_t id; /* Packet id */ - uint8_t rd : 1; /* Recursion Desired */ - uint8_t tc : 1; /* TrunCation */ - uint8_t aa : 1; /* Authoritative Answer */ - uint8_t opcode : 4; /* Opcode */ - uint8_t qr : 1; /* Query/Response */ - uint8_t rcode : 4; /* Response code */ - uint8_t z : 3; /* Zero */ - uint8_t ra : 1; /* Recursion Available */ - uint16_t qdcount; /* Question count */ - uint16_t ancount; /* Answer count */ - uint16_t nscount; /* Authority count */ - uint16_t arcount; /* Additional count */ -}; -typedef struct pico_dns_header pico_dns_packet; - -/* Question fixed-sized fields */ -PACKED_STRUCT_DEF pico_dns_question_suffix -{ - uint16_t qtype; - uint16_t qclass; -}; - -/* Resource record fixed-sized fields */ -PACKED_STRUCT_DEF pico_dns_record_suffix -{ - uint16_t rtype; - uint16_t rclass; - uint32_t rttl; - uint16_t rdlength; -}; - -/* DNS QUESTION */ -struct pico_dns_question -{ - char *qname; - struct pico_dns_question_suffix *qsuffix; - uint16_t qname_length; - uint8_t proto; -}; - -/* DNS RECORD */ -struct pico_dns_record -{ - char *rname; - struct pico_dns_record_suffix *rsuffix; - uint8_t *rdata; - uint16_t rname_length; -}; - -/* MARK: v NAME & IP FUNCTIONS */ - -/* **************************************************************************** - * Checks if the DNS name doesn't exceed 256 bytes including zero-byte. - * - * @param namelen Length of the DNS name-string including zero-byte - * @return 0 when the length is correct - * ****************************************************************************/ -int -pico_dns_check_namelen( uint16_t namelen ); - -/* **************************************************************************** - * Returns the length of a name in a DNS-packet as if DNS name compression - * would be applied to the packet. If there's no compression present this - * returns the strlen. If there's compression present this returns the length - * until the compression-pointer + 1. - * - * @param name Compressed name you want the calculate the strlen from - * @return Returns strlen of a compressed name, takes the first byte of compr- - * ession pointer into account but not the second byte, which acts - * like a trailing zero-byte. - * ****************************************************************************/ -uint16_t -pico_dns_namelen_comp( char *name ); - -/* **************************************************************************** - * Returns the uncompressed name in DNS name format when DNS name compression - * is applied to the packet-buffer. - * - * @param name Compressed name, should be in the bounds of the actual packet - * @param packet Packet that contains the compressed name - * @return Returns the decompressed name, NULL on failure. - * ****************************************************************************/ -char * -pico_dns_decompress_name( char *name, pico_dns_packet *packet ); - -/* **************************************************************************** - * Converts a DNS name in DNS name format to a name in URL format. Provides - * space for the name in URL format as well. PICO_FREE() should be called on - * the returned string buffer that contains the name in URL format. - * - * @param qname DNS name in DNS name format to convert - * @return Returns a pointer to a string-buffer with the URL name on success. - * ****************************************************************************/ -char * -pico_dns_qname_to_url( const char *qname ); - -/* **************************************************************************** - * Converts a DNS name in URL format to name in DNS name format. Provides - * space for the DNS name as well. PICO_FREE() should be called on the returned - * string buffer that contains the DNS name. - * - * @param url DNS name in URL format to convert - * @return Returns a pointer to a string-buffer with the DNS name on success. - * ****************************************************************************/ -char * -pico_dns_url_to_qname( const char *url ); - -/* **************************************************************************** - * @param url String-buffer - * @return Length of string-buffer in an uint16_t - * ****************************************************************************/ -uint16_t -pico_dns_strlen( const char *url ); - -/* **************************************************************************** - * Replaces .'s in a DNS name in URL format by the label lengths. So it - * actually converts a name in URL format to a name in DNS name format. - * f.e. "*www.google.be" => "3www6google2be0" - * - * @param url Location to buffer with name in URL format. The URL needs to - * be +1 byte offset in the actual buffer. Size is should be - * strlen(url) + 2. - * @param maxlen Maximum length of buffer so it doesn't cause a buffer overflow - * @return 0 on success, something else on failure. - * ****************************************************************************/ -int pico_dns_name_to_dns_notation( char *url, unsigned int maxlen ); - -/* **************************************************************************** - * Replaces the label lengths in a DNS-name by .'s. So it actually converts a - * name in DNS format to a name in URL format. - * f.e. 3www6google2be0 => .www.google.be - * - * @param ptr Location to buffer with name in DNS name format - * @param maxlen Maximum length of buffer so it doesn't cause a buffer overflow - * @return 0 on success, something else on failure. - * ****************************************************************************/ -int pico_dns_notation_to_name( char *ptr, unsigned int maxlen ); - -/* **************************************************************************** - * Determines the length of the first label of a DNS name in URL-format - * - * @param url DNS name in URL-format - * @return Length of the first label of DNS name in URL-format - * ****************************************************************************/ -uint16_t -pico_dns_first_label_length( const char *url ); - -/* **************************************************************************** - * Mirrors a dotted IPv4-address string. - * f.e. 192.168.0.1 => 1.0.168.192 - * - * @param ptr - * @return 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_mirror_addr( char *ptr ); - -/* **************************************************************************** - * Convert an IPv6-address in string-format to a IPv6-address in nibble-format. - * Doesn't add a IPv6 ARPA-suffix though. - * - * @param ip IPv6-address stored as a string - * @param dst Destination to store IPv6-address in nibble-format - * ****************************************************************************/ -void -pico_dns_ipv6_set_ptr( const char *ip, char *dst ); - -/* MARK: QUESTION FUNCTIONS */ - -/* **************************************************************************** - * Deletes a single DNS Question. - * - * @param question Void-pointer to DNS Question. Can be used with pico_tree_- - * destroy. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_question_delete( void **question); - -/* **************************************************************************** - * Fills in the DNS question suffix-fields with the correct values. - * - * todo: Update pico_dns_client to make the same mechanism possible as with - * filling DNS Resource Record-suffixes. This function shouldn't be an - * API-function. - * - * @param suf Pointer to the suffix member of the DNS question. - * @param qtype DNS type of the DNS question to be. - * @param qclass DNS class of the DNS question to be. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_question_fill_suffix( struct pico_dns_question_suffix *suf, - uint16_t qtype, - uint16_t qclass ); - -/* **************************************************************************** - * Creates a standalone DNS Question with a given name and type. - * - * @param url DNS question name in URL format. Will be converted to DNS - * name notation format. - * @param len Will be filled with the total length of the DNS question. - * @param proto Protocol for which you want to create a question. Can be - * either PICO_PROTO_IPV4 or PICO_PROTO_IPV6. - * @param qtype DNS type of the question to be. - * @param qclass DNS class of the question to be. - * @param reverse When this is true, a reverse resolution name will be gene- - * from the URL - * @return Returns pointer to the created DNS Question on success, NULL on - * failure. - * ****************************************************************************/ -struct pico_dns_question * -pico_dns_question_create( const char *url, - uint16_t *len, - uint8_t proto, - uint16_t qtype, - uint16_t qclass, - uint8_t reverse ); - -/* **************************************************************************** - * Decompresses the name of a single DNS question. - * - * @param question Question you want to decompress the name of - * @param packet Packet in which the DNS question is contained. - * @return Pointer to original name of the DNS question before decompressing. - * ****************************************************************************/ -char * -pico_dns_question_decompress( struct pico_dns_question *question, - pico_dns_packet *packet ); - -/* MARK: RESOURCE RECORD FUNCTIONS */ - -/* **************************************************************************** - * Deletes a single DNS resource record. - * - * @param record Void-pointer to DNS record. Can be used with pico_tree_destroy - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_record_delete( void **record ); - -/* **************************************************************************** - * Just makes a hardcopy from a single DNS Resource Record - * - * @param record DNS record you want to copy - * @return Pointer to copy of DNS record. - * ****************************************************************************/ -struct pico_dns_record * -pico_dns_record_copy( struct pico_dns_record *record ); - -/* **************************************************************************** - * Create a standalone DNS Resource Record with given name, type and data. - * - * @param url DNS rrecord name in URL format. Will be converted to DNS - * name notation format. - * @param _rdata Memory buffer with data to insert in the resource record. If - * data of record should contain a DNS name, the name in the - * databuffer needs to be in URL-format. - * @param datalen The exact length in bytes of the _rdata-buffer. If data of - * record should contain a DNS name, datalen needs to be - * pico_dns_strlen(_rdata). - * @param len Will be filled with the total length of the DNS rrecord. - * @param rtype DNS type of the resource record to be. - * @param rclass DNS class of the resource record to be. - * @param rttl DNS ttl of the resource record to be. - * @return Returns pointer to the created DNS Resource Record - * ****************************************************************************/ -struct pico_dns_record * -pico_dns_record_create( const char *url, - void *_rdata, - uint16_t datalen, - uint16_t *len, - uint16_t rtype, - uint16_t rclass, - uint32_t rttl ); - -/* **************************************************************************** - * Decompresses the name of single DNS record. - * - * @param record DNS record to decompress the name of. - * @param packet Packet in which is DNS record is present - * @return Pointer to original name of the DNS record before decompressing. - * ****************************************************************************/ -char * -pico_dns_record_decompress( struct pico_dns_record *record, - pico_dns_packet *packet ); - -/* MARK: COMPARING */ - -/* **************************************************************************** - * Compares two databuffers against each other. - * - * @param a 1st Memory buffer to compare - * @param b 2nd Memory buffer to compare - * @param rdlength_a Length of 1st memory buffer - * @param rdlength_b Length of 2nd memory buffer - * @param caseinsensitive Whether or not the bytes are compared - * case-insensitive - * @return 0 when the buffers are equal, returns difference when they're not. - * ****************************************************************************/ -int -pico_dns_rdata_cmp( uint8_t *a, uint8_t *b, - uint16_t rdlength_a, uint16_t rdlength_b, uint8_t caseinsensitive ); - -/* **************************************************************************** - * Compares 2 DNS questions - * - * @param qa DNS question A as a void-pointer (for pico_tree) - * @param qb DNS question A as a void-pointer (for pico_tree) - * @return 0 when questions are equal, returns difference when they're not. - * ****************************************************************************/ -int -pico_dns_question_cmp( void *qa, - void *qb ); - -/* **************************************************************************** - * Compares 2 DNS records by type and name only - * - * @param ra DNS record A as a void-pointer (for pico_tree) - * @param rb DNS record B as a void-pointer (for pico_tree) - * @return 0 when name and type of records are equal, returns difference when - * they're not. - * ****************************************************************************/ -int -pico_dns_record_cmp_name_type( void *ra, - void *rb ); - -/* **************************************************************************** - * Compares 2 DNS records by type, name AND rdata for a truly unique result - * - * @param ra DNS record A as a void-pointer (for pico_tree) - * @param rb DNS record B as a void-pointer (for pico_tree) - * @return 0 when records are equal, returns difference when they're not - * ****************************************************************************/ -int -pico_dns_record_cmp( void *ra, - void *rb ); - -/* MARK: PICO_TREE */ - -/* **************************************************************************** - * Erases a pico_tree entirely. - * - * @param tree Pointer to a pico_tree-instance - * @param node_delete Helper-function for type-specific deleting. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_tree_destroy( struct pico_tree *tree, int (*node_delete)(void **)); - -/* **************************************************************************** - * Determines the amount of nodes in a pico_tree - * - * @param tree Pointer to pico_tree-instance - * @return Amount of items in the tree. - * ****************************************************************************/ -uint16_t -pico_tree_count( struct pico_tree *tree ); - -/* **************************************************************************** - * Definition of DNS question tree - * ****************************************************************************/ -typedef struct pico_tree pico_dns_qtree; -#define PICO_DNS_QTREE_DECLARE(name) \ - pico_dns_qtree (name) = {&LEAF, pico_dns_question_cmp} -#define PICO_DNS_QTREE_DESTROY(qtree) \ - pico_tree_destroy(qtree, pico_dns_question_delete) - -/* **************************************************************************** - * Deletes all the questions with given DNS name from a pico_tree - * - * @param qtree Pointer to pico_tree-instance which contains DNS questions - * @param name Name of the questions you want to delete - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_qtree_del_name( struct pico_tree *qtree, - const char *name ); - -/* **************************************************************************** - * Checks whether a question with given name is in the tree or not. - * - * @param qtree Pointer to pico_tree-instance which contains DNS questions - * @param name Name you want to check for - * @return 1 when the name is present in the qtree, 0 when it's not. - * ****************************************************************************/ -int -pico_dns_qtree_find_name( struct pico_tree *qtree, - const char *name ); - -/* **************************************************************************** - * Definition of DNS record tree - * ****************************************************************************/ -typedef struct pico_tree pico_dns_rtree; -#define PICO_DNS_RTREE_DECLARE(name) \ - pico_dns_rtree (name) = {&LEAF, pico_dns_record_cmp} -#define PICO_DNS_RTREE_DESTROY(rtree) \ - pico_tree_destroy((rtree), pico_dns_record_delete) - -/* MARK: DNS PACKET FUNCTIONS */ - -/* **************************************************************************** - * Fills the header section of a DNS packet with the correct flags and section - * -counts. - * - * @param hdr Header to fill in. - * @param qdcount Amount of questions added to the packet - * @param ancount Amount of answer records added to the packet - * @param nscount Amount of authority records added to the packet - * @param arcount Amount of additional records added to the packet - * ****************************************************************************/ -void -pico_dns_fill_packet_header( struct pico_dns_header *hdr, - uint16_t qdcount, - uint16_t ancount, - uint16_t authcount, - uint16_t addcount ); - -/* **************************************************************************** - * Creates a DNS Query packet with given question and resource records to put - * the Resource Record Sections. If a NULL-pointer is provided for a certain - * tree, no records will be added to that particular section of the packet. - * - * @param qtree DNS Questions to put in the Question Section - * @param antree DNS Records to put in the Answer Section - * @param nstree DNS Records to put in the Authority Section - * @param artree DNS Records to put in the Additional Section - * @param len Will get filled with the entire size of the packet - * @return Pointer to created DNS packet - * ****************************************************************************/ -pico_dns_packet * -pico_dns_query_create( struct pico_tree *qtree, - struct pico_tree *antree, - struct pico_tree *nstree, - struct pico_tree *artree, - uint16_t *len ); - -/* **************************************************************************** - * Creates a DNS Answer packet with given resource records to put in the - * Resource Record Sections. If a NULL-pointer is provided for a certain tree, - * no records will be added to that particular section of the packet. - * - * @param antree DNS Records to put in the Answer Section - * @param nstree DNS Records to put in the Authority Section - * @param artree DNS Records to put in the Additional Section - * @param len Will get filled with the entire size of the packet - * @return Pointer to created DNS packet. - * ****************************************************************************/ -pico_dns_packet * -pico_dns_answer_create( struct pico_tree *antree, - struct pico_tree *nstree, - struct pico_tree *artree, - uint16_t *len ); - -#endif /* _INCLUDE_PICO_DNS_COMMON */ diff --git a/ext/picotcp/modules/pico_dns_sd.c b/ext/picotcp/modules/pico_dns_sd.c deleted file mode 100644 index 1a60c2a..0000000 --- a/ext/picotcp/modules/pico_dns_sd.c +++ /dev/null @@ -1,549 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - . - Author: Jelle De Vleeschouwer - *********************************************************************/ - -#include "pico_dns_sd.h" - -#ifdef PICO_SUPPORT_DNS_SD - -/* --- Debugging --- */ -#define dns_sd_dbg(...) do {} while(0) -//#define dns_sd_dbg dbg - -/* --- PROTOTYPES --- */ -key_value_pair_t * -pico_dns_sd_kv_vector_get( kv_vector *vector, uint16_t index ); -int -pico_dns_sd_kv_vector_erase( kv_vector *vector ); -/* ------------------- */ - -typedef PACKED_STRUCT_DEF pico_dns_srv_record_prefix -{ - uint16_t priority; - uint16_t weight; - uint16_t port; -} pico_dns_srv_record; - -/* **************************************************************************** - * Determines the length of the resulting string when a string would be - * created from a key-value pair vector. - * - * @param vector Key-Value pair vector to determine the length of. - * @return The length of the key-value pair vector in bytes as if it would be - * converted to a string. - * ****************************************************************************/ -static uint16_t -pico_dns_sd_kv_vector_strlen( kv_vector *vector ) -{ - key_value_pair_t *iterator = NULL; - uint16_t i = 0, len = 0; - - /* Check params */ - if (!vector) { - pico_err = PICO_ERR_EINVAL; - return 0; - } - - /* Iterate over the key-value pairs */ - for (i = 0; i < vector->count; i++) { - iterator = pico_dns_sd_kv_vector_get(vector, i); - len = (uint16_t) (len + 1u + /* Length byte */ - strlen(iterator->key) /* Length of the key */); - if (iterator->value) - len = (uint16_t) (len + 1u /* '=' char */ + - strlen(iterator->value) /* Length of value */); - } - return len; -} - -/* **************************************************************************** - * Creates an mDNS record with the SRV record format. - * - * @param url Name of the SRV record in URL format. - * @param priority Priority, should be 0. - * @param weight Weight, should be 0. - * @param port Port to register the service on. - * @param target_url Hostname of the service-target, in URL-format - * @param ttl TTL of the SRV Record - * @param flags mDNS record flags to set specifications of the record. - * @return Pointer to newly created record on success, NULL on failure. - * ****************************************************************************/ -static struct pico_mdns_record * -pico_dns_sd_srv_record_create( const char *url, - uint16_t priority, - uint16_t weight, - uint16_t port, - const char *target_url, - uint32_t ttl, - uint8_t flags ) -{ - struct pico_mdns_record *record = NULL; - pico_dns_srv_record *srv_data = NULL; - char *target_rname = NULL; - uint16_t srv_length = 0; - - /* Check params */ - if (!url || !target_url) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Determine the length the rdata buf needs to be */ - srv_length = (uint16_t) (6u + strlen(target_url) + 2u); - - /* Provide space for the data-buf */ - if (!(srv_data = (pico_dns_srv_record *) PICO_ZALLOC(srv_length))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Set the fields */ - srv_data->priority = short_be(priority); - srv_data->weight = short_be(weight); - srv_data->port = short_be(port); - - /* Copy in the URL and convert to DNS notation */ - if (!(target_rname = pico_dns_url_to_qname(target_url))) { - dns_sd_dbg("Could not convert URL to qname!\n"); - PICO_FREE(srv_data); - return NULL; - } - - strcpy((char *)srv_data + 6u, target_rname); - PICO_FREE(target_rname); - - /* Create and return new mDNS record */ - record = pico_mdns_record_create(url, srv_data, srv_length, - PICO_DNS_TYPE_SRV, - ttl, flags); - PICO_FREE(srv_data); - return record; -} - -/* **************************************************************************** - * Creates an mDNS record with the TXT record format. - * - * @param url Name of the TXT record in URL format. - * @param key_value_pairs Key-Value pair vector to generate the data from. - * @param ttl TTL of the TXT record. - * @param flags mDNS record flags to set specifications of the record - * @return Pointer to newly created record on success, NULL on failure. - * ****************************************************************************/ -static struct pico_mdns_record * -pico_dns_sd_txt_record_create( const char *url, - kv_vector key_value_pairs, - uint32_t ttl, - uint8_t flags ) -{ - struct pico_mdns_record *record = NULL; - key_value_pair_t *iterator = NULL; - char *txt = NULL; - uint16_t i = 0, txt_i = 0, pair_len = 0, key_len = 0, value_len = 0; - - /* Determine the length of the string to fit in all pairs */ - uint16_t len = (uint16_t)(pico_dns_sd_kv_vector_strlen(&key_value_pairs) + 1u); - - /* If kv-vector is empty don't bother to create a TXT record */ - if (len <= 1) - return NULL; - - /* Provide space for the txt buf */ - if (!(txt = (char *)PICO_ZALLOC(len))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Iterate over all the key-value pairs */ - for (i = 0; i < key_value_pairs.count; i++) { - iterator = pico_dns_sd_kv_vector_get(&key_value_pairs, i); - - /* Determine the length of the key */ - key_len = (uint16_t) strlen(iterator->key); - pair_len = key_len; - - /* If value is not a NULL-ptr */ - if (iterator->value) { - value_len = (uint16_t) strlen(iterator->value); - pair_len = (uint16_t) (pair_len + 1u + value_len); - } - - /* Set the pair length label */ - txt[txt_i] = (char)pair_len; - - /* Copy the key */ - strcpy(txt + txt_i + 1u, iterator->key); - - /* Copy the value if it is not a NULL-ptr */ - if (iterator->value) { - strcpy(txt + txt_i + 1u + key_len, "="); - strcpy(txt + txt_i + 2u + key_len, iterator->value); - txt_i = (uint16_t) (txt_i + 2u + key_len + value_len); - } else { - txt_i = (uint16_t) (txt_i + 1u + key_len); - } - } - record = pico_mdns_record_create(url, txt, (uint16_t)(len - 1u), PICO_DNS_TYPE_TXT, ttl, flags); - PICO_FREE(txt); - - return record; -} - -/* **************************************************************************** - * Deletes a single key-value pair instance - * - * @param kv_pair Pointer-pointer to to delete instance - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -static int -pico_dns_sd_kv_delete( key_value_pair_t **kv_pair ) -{ - /* Check params */ - if (!kv_pair || !(*kv_pair)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Delete the fields */ - if ((*kv_pair)->key) - PICO_FREE((*kv_pair)->key); - - if ((*kv_pair)->value) - PICO_FREE((*kv_pair)->value); - - PICO_FREE(*kv_pair); - *kv_pair = NULL; - kv_pair = NULL; - - return 0; -} - -/* **************************************************************************** - * Creates a single key-value pair-instance - * - * @param key Key of the pair, cannot be NULL. - * @param value Value of the pair, can be NULL, empty ("") or filled ("qkejq") - * @return Pointer to newly created KV-instance on success, NULL on failure. - * ****************************************************************************/ -static key_value_pair_t * -pico_dns_sd_kv_create( const char *key, const char *value ) -{ - key_value_pair_t *kv_pair = NULL; - - /* Check params */ - if (!key || !(kv_pair = PICO_ZALLOC(sizeof(key_value_pair_t)))) { - pico_dns_sd_kv_delete(&kv_pair); - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Provide space to copy the values */ - if (!(kv_pair->key = PICO_ZALLOC((size_t)(strlen(key) + 1)))) { - pico_err = PICO_ERR_ENOMEM; - pico_dns_sd_kv_delete(&kv_pair); - return NULL; - } - - strcpy(kv_pair->key, key); - - if (value) { - if (!(kv_pair->value = PICO_ZALLOC((size_t)(strlen(value) + 1)))) { - pico_err = PICO_ERR_ENOMEM; - pico_dns_sd_kv_delete(&kv_pair); - return NULL; - } - - strcpy(kv_pair->value, value); - } else - kv_pair->value = NULL; - - return kv_pair; -} - -/* **************************************************************************** - * Checks whether the type is correctly formatted ant it's label length are - * between the allowed boundaries. - * - * @param type Servicetype to check the format of. - * @return Returns 0 when the type is correctly formatted, something else when - * it's not. - * ****************************************************************************/ -static int -pico_dns_sd_check_type_format( const char *type ) -{ - uint16_t first_lbl = 0; - int8_t subtype_present = 0; - - /* Check params */ - if (!(first_lbl = pico_dns_first_label_length(type))) - return -1; - - subtype_present = !memcmp(type + first_lbl + 1, "_sub", 4); - - /* Check if there is a subtype present */ - if (subtype_present && (first_lbl > 63)) - return -1; - else if (subtype_present) - /* Get the length of the service name */ - first_lbl = pico_dns_first_label_length(type + first_lbl + 6); - else { - /* Check if type is not greater then 21 bytes (22 - 1, since the length - byte of the service name isn't included yet) */ - if (strlen(type) > (size_t) 21) - return -1; - } - - /* Check if the service name is not greater then 16 bytes (17 - 1) */ - return (first_lbl > ((uint16_t) 16u)); -} - -/* **************************************************************************** - * Checks whether the service instance name is correctly formatted and it's - * label length falls between the allowed boundaries. - * - * @param name Instance name to check the format of. - * @return Returns 0 when the name is correctly formatted, something else when - * it's not. - * ****************************************************************************/ -static int -pico_dns_sd_check_instance_name_format( const char *name ) -{ - /* First of all check if the total length is larger than 63 bytes */ - if (pico_dns_strlen(name) > 63 || !pico_dns_strlen(name)) - return -1; - - return 0; -} - -/* **************************************************************************** - * Append the instance name adn service type to create a '.local' service SIN. - * - * @param name Instance Name of the service, f.e. "Printer 2nd Floor". - * @param type ServiceType of the service, f.e. "_http._tcp". - * @return Pointer to newly created SIN on success, NULL on failure. - * ****************************************************************************/ -static char * -pico_dns_sd_create_service_url( const char *name, - const char *type ) -{ - char *url = NULL; - uint16_t len = 0, namelen = 0, typelen = 0; - - if (pico_dns_sd_check_type_format(type)) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - if (pico_dns_sd_check_instance_name_format(name)) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - namelen = (uint16_t)strlen(name); - typelen = (uint16_t)strlen(type); - - /* Determine the length that the URL needs to be */ - len = (uint16_t)(namelen + 1u /* for '.'*/ + - typelen + 7u /* for '.local\0' */); - url = (char *)PICO_ZALLOC(len); - if (!url) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Append the parts together */ - strcpy(url, name); - strcpy(url + namelen, "."); - strcpy(url + namelen + 1, type); - strcpy(url + namelen + 1 + typelen, ".local"); - - return url; -} - -/* **************************************************************************** - * This function actually does exactly the same as pico_mdns_init(); - * ****************************************************************************/ -int -pico_dns_sd_init( const char *_hostname, - struct pico_ip4 address, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ - return pico_mdns_init(_hostname, address, callback, arg); -} - -/* **************************************************************************** - * Just calls pico_mdns_init in it's turn to initialise the mDNS-module. - * See pico_mdns.h for description. - * ****************************************************************************/ -int -pico_dns_sd_register_service( const char *name, - const char *type, - uint16_t port, - kv_vector *txt_data, - uint16_t ttl, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg) -{ - PICO_MDNS_RTREE_DECLARE(rtree); - struct pico_mdns_record *srv_record = NULL; - struct pico_mdns_record *txt_record = NULL; - const char *hostname = pico_mdns_get_hostname(); - char *url = NULL; - - /* Try to create a service URL to create records with */ - if (!(url = pico_dns_sd_create_service_url(name, type)) || !txt_data || !hostname) { - if (url) - PICO_FREE(url); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - dns_sd_dbg("\n>>>>>>>>>> Target: %s <<<<<<<<<<\n\n", hostname); - - /* Create the SRV record */ - srv_record = pico_dns_sd_srv_record_create(url, 0, 0, port, hostname, ttl, PICO_MDNS_RECORD_UNIQUE); - if (!srv_record) { - PICO_FREE(url); - return -1; - } - - /* Create the TXT record */ - txt_record = pico_dns_sd_txt_record_create(url, *txt_data, ttl, PICO_MDNS_RECORD_UNIQUE); - PICO_FREE(url); - - /* Erase the key-value pair vector, it's no longer needed */ - pico_dns_sd_kv_vector_erase(txt_data); - - if (txt_record) - pico_tree_insert(&rtree, txt_record); - - pico_tree_insert(&rtree, srv_record); - - if (pico_mdns_claim(rtree, callback, arg)) { - PICO_MDNS_RTREE_DESTROY(&rtree); - return -1; - } - pico_tree_destroy(&rtree, NULL); - return 0; -} - -/* **************************************************************************** - * Does nothing for now. - * - * @param type Type to browse for. - * @param callback Callback to call when something particular happens. - * @return When the module successfully started browsing the servicetype. - * ****************************************************************************/ -int -pico_dns_sd_browse_service( const char *type, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ - IGNORE_PARAMETER(type); - IGNORE_PARAMETER(callback); - IGNORE_PARAMETER(arg); - return 0; -} - -/* **************************************************************************** - * Add a key-value pair the a key-value pair vector. - * - * @param vector Vector to add the pair to. - * @param key Key of the pair, cannot be NULL. - * @param value Value of the pair, can be NULL, empty ("") or filled ("qkejq") - * @return Returns 0 when the pair is added successfully, something else on - * failure. - * ****************************************************************************/ -int -pico_dns_sd_kv_vector_add( kv_vector *vector, char *key, char *value ) -{ - key_value_pair_t *kv_pair = NULL; - key_value_pair_t **new_pairs = NULL; - uint16_t i = 0; - - /* Check params */ - if (!vector || !key || !(kv_pair = pico_dns_sd_kv_create(key, value))) { - pico_err = PICO_ERR_EINVAL; - pico_dns_sd_kv_delete(&kv_pair); - return -1; - } - - /* Provide enough space for the new pair pointers */ - if (!(new_pairs = PICO_ZALLOC(sizeof(key_value_pair_t *) * - (vector->count + 1u)))) { - pico_err = PICO_ERR_ENOMEM; - pico_dns_sd_kv_delete(&kv_pair); - return -1; - } - - /* Copy previous pairs and add new one */ - for (i = 0; i < vector->count; i++) - new_pairs[i] = vector->pairs[i]; - new_pairs[i] = kv_pair; - - /* Free the previous array */ - if (vector->pairs) - PICO_FREE(vector->pairs); - - vector->pairs = new_pairs; - vector->count++; - - return 0; -} - -/* **************************************************************************** - * Gets a single key-value pair form a Key-Value pair vector @ certain index. - * - * @param vector Vector to get KV-pair from. - * @param index Index of the KV-pair. - * @return key_value_pair_t* on success, NULL on failure. - * ****************************************************************************/ -key_value_pair_t * -pico_dns_sd_kv_vector_get( kv_vector *vector, uint16_t index ) -{ - /* Check params */ - if (!vector) - return NULL; - - /* Return record with conditioned index */ - if (index < vector->count) - return vector->pairs[index]; - - return NULL; -} - -/* **************************************************************************** - * Erase all the contents of a key-value pair vector. - * - * @param vector Key-Value pair vector. - * @return 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_dns_sd_kv_vector_erase( kv_vector *vector ) -{ - uint16_t i = 0; - - /* Iterate over each key-value pair */ - for (i = 0; i < vector->count; i++) { - if (pico_dns_sd_kv_delete(&(vector->pairs[i])) < 0) { - dns_sd_dbg("Could not delete key-value pairs from vector"); - return -1; - } - } - PICO_FREE(vector->pairs); - vector->pairs = NULL; - vector->count = 0; - - return 0; -} - -#endif diff --git a/ext/picotcp/modules/pico_dns_sd.h b/ext/picotcp/modules/pico_dns_sd.h deleted file mode 100644 index b93d599..0000000 --- a/ext/picotcp/modules/pico_dns_sd.h +++ /dev/null @@ -1,91 +0,0 @@ -/* **************************************************************************** - * PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved. - * See LICENSE and COPYING for usage. - * . - * Author: Jelle De Vleeschouwer - * ****************************************************************************/ -#ifndef INCLUDE_PICO_DNS_SD -#define INCLUDE_PICO_DNS_SD - -#include "pico_mdns.h" - -typedef struct -{ - char *key; - char *value; -} key_value_pair_t; - -typedef struct -{ - key_value_pair_t **pairs; - uint16_t count; -} kv_vector; - -#define PICO_DNS_SD_KV_VECTOR_DECLARE(name) \ - kv_vector (name) = {0} - -/* **************************************************************************** - * Just calls pico_mdns_init in it's turn to initialise the mDNS-module. - * See pico_mdns.h for description. - * ****************************************************************************/ -int -pico_dns_sd_init( const char *_hostname, - struct pico_ip4 address, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ); - -/* **************************************************************************** - * Register a DNS-SD service via Multicast DNS on the local network. - * - * @param name Instance Name of the service, f.e. "Printer 2nd Floor". - * @param type ServiceType of the service, f.e. "_http._tcp". - * @param port Port number on which the service runs. - * @param txt_data TXT data to create TXT record with, need kv_vector-type, - * Declare such a type with PICO_DNS_SD_KV_VECTOR_DECLARE(*) & - * add key-value pairs with pico_dns_sd_kv_vector_add(). - * @param ttl TTL - * @param callback Callback-function to call when the service is registered. - * @return - * ****************************************************************************/ -int -pico_dns_sd_register_service( const char *name, - const char *type, - uint16_t port, - kv_vector *txt_data, - uint16_t ttl, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg); - -/* **************************************************************************** - * Does nothing for now. - * - * @param type Type to browse for. - * @param callback Callback to call when something particular happens. - * @return When the module successfully started browsing the servicetype. - * ****************************************************************************/ -int -pico_dns_sd_browse_service( const char *type, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ); - -/* **************************************************************************** - * Add a key-value pair the a key-value pair vector. - * - * @param vector Vector to add the pair to. - * @param key Key of the pair, cannot be NULL. - * @param value Value of the pair, can be NULL, empty ("") or filled ("qkejq") - * @return Returns 0 when the pair is added successfully, something else on - * failure. - * ****************************************************************************/ -int -pico_dns_sd_kv_vector_add( kv_vector *vector, char *key, char *value ); - - -#endif /* _INCLUDE_PICO_DNS_SD */ - diff --git a/ext/picotcp/modules/pico_fragments.c b/ext/picotcp/modules/pico_fragments.c deleted file mode 100644 index 33e69ca..0000000 --- a/ext/picotcp/modules/pico_fragments.c +++ /dev/null @@ -1,391 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Laurens Miers, Daniele Lacamera - *********************************************************************/ - - -#include "pico_config.h" -#ifdef PICO_SUPPORT_IPV6 -#include "pico_ipv6.h" -#include "pico_icmp6.h" -#endif -#ifdef PICO_SUPPORT_IPV4 -#include "pico_ipv4.h" -#include "pico_icmp4.h" -#endif -#include "pico_stack.h" -#include "pico_eth.h" -#include "pico_udp.h" -#include "pico_tcp.h" -#include "pico_socket.h" -#include "pico_device.h" -#include "pico_tree.h" -#include "pico_constants.h" -#include "pico_fragments.h" - -#define frag_dbg(...) do {} while(0) - -#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG) -#define IP6_FRAG_OFF(x) ((x & 0xFFF8u)) -#define IP6_FRAG_MORE(x) ((x & 0x0001)) -#define IP6_FRAG_ID(x) ((uint32_t)((x->ext.frag.id[0] << 24) + (x->ext.frag.id[1] << 16) + \ - (x->ext.frag.id[2] << 8) + x->ext.frag.id[3])) -#else -#define IP6_FRAG_OFF(x) (0) -#define IP6_FRAG_MORE(x) (0) -#define IP6_FRAG_ID(x) (0) -#endif - -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) -#define IP4_FRAG_OFF(frag) (((uint32_t)frag & PICO_IPV4_FRAG_MASK) << 3ul) -#define IP4_FRAG_MORE(frag) ((frag & PICO_IPV4_MOREFRAG) ? 1 : 0) -#define IP4_FRAG_ID(hdr) (hdr->id) -#else -#define IP4_FRAG_OFF(frag) (0) -#define IP4_FRAG_MORE(frag) (0) -#define IP4_FRAG_ID(hdr) (0) -#endif - -#define FRAG_OFF(net, frag) ((net == PICO_PROTO_IPV4) ? (IP4_FRAG_OFF(frag)) : (IP6_FRAG_OFF(frag))) -#define FRAG_MORE(net, frag) ((net == PICO_PROTO_IPV4) ? (IP4_FRAG_MORE(frag)) : (IP6_FRAG_MORE(frag))) - -#define PICO_IPV6_FRAG_TIMEOUT 60000 -#define PICO_IPV4_FRAG_TIMEOUT 15000 - -static void pico_frag_expire(pico_time now, void *arg); -static void pico_fragments_complete(unsigned int bookmark, uint8_t proto, uint8_t net); -static int pico_fragments_check_complete(uint8_t proto, uint8_t net); - -#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG) -static uint32_t ipv6_cur_frag_id = 0u; -uint32_t ipv6_fragments_timer = 0u; - -static int pico_ipv6_frag_compare(void *ka, void *kb) -{ - struct pico_frame *a = ka, *b = kb; - if (IP6_FRAG_OFF(a->frag) > IP6_FRAG_OFF(b->frag)) - return 1; - - if (IP6_FRAG_OFF(a->frag) < IP6_FRAG_OFF(b->frag)) - return -1; - - return 0; -} -PICO_TREE_DECLARE(ipv6_fragments, pico_ipv6_frag_compare); - -static void pico_ipv6_fragments_complete(unsigned int len, uint8_t proto) -{ - struct pico_tree_node *index, *tmp; - struct pico_frame *f; - unsigned int bookmark = 0; - struct pico_frame *full = NULL; - struct pico_frame *first = pico_tree_first(&ipv6_fragments); - - full = pico_frame_alloc((uint16_t)(PICO_SIZE_IP6HDR + len)); - if (full) { - full->net_hdr = full->buffer; - full->net_len = PICO_SIZE_IP6HDR; - memcpy(full->net_hdr, first->net_hdr, full->net_len); - full->transport_hdr = full->net_hdr + full->net_len; - full->transport_len = (uint16_t)len; - full->dev = first->dev; - pico_tree_foreach_safe(index, &ipv6_fragments, tmp) { - f = index->keyValue; - memcpy(full->transport_hdr + bookmark, f->transport_hdr, f->transport_len); - bookmark += f->transport_len; - pico_tree_delete(&ipv6_fragments, f); - pico_frame_discard(f); - } - if (pico_transport_receive(full, proto) == -1) - { - pico_frame_discard(full); - } - pico_timer_cancel(ipv6_fragments_timer); - ipv6_fragments_timer = 0; - } -} - -static void pico_ipv6_frag_timer_on(void) -{ - ipv6_fragments_timer = pico_timer_add(PICO_IPV6_FRAG_TIMEOUT, pico_frag_expire, &ipv6_fragments); -} - -static int pico_ipv6_frag_match(struct pico_frame *a, struct pico_frame *b) -{ - struct pico_ipv6_hdr *ha, *hb; - if (!a || !b) - return 0; - - ha = (struct pico_ipv6_hdr *)a->net_hdr; - hb = (struct pico_ipv6_hdr *)b->net_hdr; - if (!ha || !hb) - return 0; - - if (memcmp(ha->src.addr, hb->src.addr, PICO_SIZE_IP6) != 0) - return 0; - - if (memcmp(ha->dst.addr, hb->dst.addr, PICO_SIZE_IP6) != 0) - return 0; - - return 1; -} -#endif - -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) -static uint32_t ipv4_cur_frag_id = 0u; -uint32_t ipv4_fragments_timer = 0u; - -static int pico_ipv4_frag_compare(void *ka, void *kb) -{ - struct pico_frame *a = ka, *b = kb; - if (IP4_FRAG_OFF(a->frag) > IP4_FRAG_OFF(b->frag)) - return 1; - - if (IP4_FRAG_OFF(a->frag) < IP4_FRAG_OFF(b->frag)) - return -1; - - return 0; -} -PICO_TREE_DECLARE(ipv4_fragments, pico_ipv4_frag_compare); - -static void pico_ipv4_fragments_complete(unsigned int len, uint8_t proto) -{ - struct pico_tree_node *index, *tmp; - struct pico_frame *f; - unsigned int bookmark = 0; - struct pico_frame *full = NULL; - struct pico_frame *first = pico_tree_first(&ipv4_fragments); - - full = pico_frame_alloc((uint16_t)(PICO_SIZE_IP4HDR + len)); - if (full) { - full->net_hdr = full->buffer; - full->net_len = PICO_SIZE_IP4HDR; - memcpy(full->net_hdr, first->net_hdr, full->net_len); - full->transport_hdr = full->net_hdr + full->net_len; - full->transport_len = (uint16_t)len; - full->dev = first->dev; - pico_tree_foreach_safe(index, &ipv4_fragments, tmp) { - f = index->keyValue; - memcpy(full->transport_hdr + bookmark, f->transport_hdr, f->transport_len); - bookmark += f->transport_len; - pico_tree_delete(&ipv4_fragments, f); - pico_frame_discard(f); - } - ipv4_cur_frag_id = 0; - if (pico_transport_receive(full, proto) == -1) - { - pico_frame_discard(full); - } - pico_timer_cancel(ipv4_fragments_timer); - ipv4_fragments_timer = 0; - } -} - -static void pico_ipv4_frag_timer_on(void) -{ - ipv4_fragments_timer = pico_timer_add( PICO_IPV4_FRAG_TIMEOUT, pico_frag_expire, &ipv4_fragments); -} - -static int pico_ipv4_frag_match(struct pico_frame *a, struct pico_frame *b) -{ - struct pico_ipv4_hdr *ha, *hb; - if (!a || !b) - return 0; - - ha = (struct pico_ipv4_hdr *)a->net_hdr; - hb = (struct pico_ipv4_hdr *)b->net_hdr; - if (!ha || !hb) - return 0; - - if (memcmp(&(ha->src.addr), &(hb->src.addr), PICO_SIZE_IP4) != 0) - return 0; - - if (memcmp(&(ha->dst.addr), &(hb->dst.addr), PICO_SIZE_IP4) != 0) - return 0; - - return 1; -} -#endif - -static void pico_fragments_complete(unsigned int bookmark, uint8_t proto, uint8_t net) -{ - if (0) {} - -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) - else if (net == PICO_PROTO_IPV4) - { - pico_ipv4_fragments_complete(bookmark, proto); - } -#endif -#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG) - else if (net == PICO_PROTO_IPV6) - { - pico_ipv6_fragments_complete(bookmark, proto); - } -#endif -} - -static int pico_fragments_check_complete(uint8_t proto, uint8_t net) -{ - struct pico_tree_node *index, *temp; - struct pico_frame *cur; - unsigned int bookmark = 0; - struct pico_tree *tree = NULL; - -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) - if (net == PICO_PROTO_IPV4) - { - tree = &ipv4_fragments; - } -#endif -#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG) - if (net == PICO_PROTO_IPV6) - { - tree = &ipv6_fragments; - } -#endif - - pico_tree_foreach_safe(index, tree, temp) { - cur = index->keyValue; - if (FRAG_OFF(net, cur->frag) != bookmark) - return 0; - - bookmark += cur->transport_len; - if (!FRAG_MORE(net, cur->frag)) { - pico_fragments_complete(bookmark, proto, net); - return 1; - } - } - return 0; -} - -static void pico_frag_expire(pico_time now, void *arg) -{ - struct pico_tree_node *index, *tmp; - struct pico_frame *f = NULL; - struct pico_tree *tree = (struct pico_tree *) arg; - struct pico_frame *first = NULL; - uint8_t net = 0; - (void)now; - - if (!tree) - { - frag_dbg("Expired packet but no tree supplied!\n"); - return; - } - - first = pico_tree_first(tree); - - if (!first) { - frag_dbg("not first - not sending notify\n"); - return; - } - -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) - if (IS_IPV4(first)) - { - net = PICO_PROTO_IPV4; - frag_dbg("Packet expired! ID:%hu\n", ipv4_cur_frag_id); - } -#endif -#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG) - if (IS_IPV6(first)) - { - net = PICO_PROTO_IPV6; - frag_dbg("Packet expired! ID:%hu\n", ipv6_cur_frag_id); - } -#endif - - /* Empty the tree */ - pico_tree_foreach_safe(index, tree, tmp) { - f = index->keyValue; - pico_tree_delete(tree, f); - if (f != first) - pico_frame_discard(f); /* Later, after ICMP notification...*/ - - } - - if (((FRAG_OFF(net, first->frag) == 0) && (pico_frame_dst_is_unicast(first)))) - { - frag_dbg("sending notify\n"); - pico_notify_frag_expired(first); - } - - if (f) - pico_tree_delete(tree, f); - - pico_frame_discard(first); -} - -void pico_ipv6_process_frag(struct pico_ipv6_exthdr *frag, struct pico_frame *f, uint8_t proto) -{ -#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG) - struct pico_frame *first = pico_tree_first(&ipv6_fragments); - - if (!first) { - if (ipv6_cur_frag_id && (IP6_FRAG_ID(frag) == ipv6_cur_frag_id)) { - /* Discard late arrivals, without firing the timer. */ - frag_dbg("discarded late arrival, exp:%hu found:%hu\n", ipv6_cur_frag_id, IP6_FRAG_ID(frag)); - return; - } - - pico_ipv6_frag_timer_on(); - ipv6_cur_frag_id = IP6_FRAG_ID(frag); - frag_dbg("Started new reassembly, ID:%hu\n", ipv6_cur_frag_id); - } - - if (!first || (pico_ipv6_frag_match(f, first) && (IP6_FRAG_ID(frag) == ipv6_cur_frag_id))) { - pico_tree_insert(&ipv6_fragments, pico_frame_copy(f)); - } - - pico_fragments_check_complete(proto, PICO_PROTO_IPV6); -#else - IGNORE_PARAMETER(frag); - IGNORE_PARAMETER(f); - IGNORE_PARAMETER(proto); -#endif -} - -void pico_ipv4_process_frag(struct pico_ipv4_hdr *hdr, struct pico_frame *f, uint8_t proto) -{ -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) - struct pico_frame *first = pico_tree_first(&ipv4_fragments); - - /* fragments from old packets still in tree, and new first fragment ? */ - if (first && (IP4_FRAG_ID(hdr) != ipv4_cur_frag_id) && (IP4_FRAG_OFF(f->frag) == 0)) - { - /* Empty the tree */ - struct pico_tree_node *index, *tmp; - pico_tree_foreach_safe(index, &ipv4_fragments, tmp) { - struct pico_frame * old = index->keyValue; - pico_tree_delete(&ipv4_fragments, old); - pico_frame_discard(old); - } - first = NULL; - ipv4_cur_frag_id = 0; - } - - f->frag = short_be(hdr->frag); - if (!first) { - if (ipv4_cur_frag_id && (IP4_FRAG_ID(hdr) == ipv4_cur_frag_id)) { - /* Discard late arrivals, without firing the timer */ - return; - } - - pico_ipv4_frag_timer_on(); - ipv4_cur_frag_id = IP4_FRAG_ID(hdr); - } - - if (!first || (pico_ipv4_frag_match(f, first) && (IP4_FRAG_ID(hdr) == ipv4_cur_frag_id))) { - pico_tree_insert(&ipv4_fragments, pico_frame_copy(f)); - } - - pico_fragments_check_complete(proto, PICO_PROTO_IPV4); -#else - IGNORE_PARAMETER(hdr); - IGNORE_PARAMETER(f); - IGNORE_PARAMETER(proto); -#endif -} diff --git a/ext/picotcp/modules/pico_fragments.h b/ext/picotcp/modules/pico_fragments.h deleted file mode 100644 index e51ec44..0000000 --- a/ext/picotcp/modules/pico_fragments.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef PICO_FRAGMENTS_H -#define PICO_FRAGMENTS_H -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_addressing.h" -#include "pico_frame.h" - -void pico_ipv6_process_frag(struct pico_ipv6_exthdr *frag, struct pico_frame *f, uint8_t proto); -void pico_ipv4_process_frag(struct pico_ipv4_hdr *hdr, struct pico_frame *f, uint8_t proto); - -#endif diff --git a/ext/picotcp/modules/pico_hotplug_detection.c b/ext/picotcp/modules/pico_hotplug_detection.c deleted file mode 100644 index 732b4d7..0000000 --- a/ext/picotcp/modules/pico_hotplug_detection.c +++ /dev/null @@ -1,134 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Frederik Van Slycken - *********************************************************************/ -#include "pico_protocol.h" -#include "pico_hotplug_detection.h" -#include "pico_tree.h" -#include "pico_device.h" - -struct pico_hotplug_device{ - struct pico_device *dev; - int prev_state; - struct pico_tree callbacks; -}; - -uint32_t timer_id = 0; - -static int pico_hotplug_dev_cmp(void *ka, void *kb) -{ - struct pico_hotplug_device *a = ka, *b = kb; - if (a->dev->hash < b->dev->hash) - return -1; - - if (a->dev->hash > b->dev->hash) - return 1; - - return 0; -} - -static int callback_compare(void *ka, void *kb) -{ - if (ka < kb) - return -1; - if (ka > kb) - return 1; - return 0; -} - -PICO_TREE_DECLARE(Hotplug_device_tree, pico_hotplug_dev_cmp); - -static void timer_cb(__attribute__((unused)) pico_time t, __attribute__((unused)) void* v) -{ - struct pico_tree_node *node = NULL, *safe = NULL, *cb_node = NULL, *cb_safe = NULL; - int new_state, event; - struct pico_hotplug_device *hpdev = NULL; - void (*cb)(struct pico_device *dev, int event); - - //we don't know if one of the callbacks might deregister, so be safe - pico_tree_foreach_safe(node, &Hotplug_device_tree, safe) - { - hpdev = node->keyValue; - new_state = hpdev->dev->link_state(hpdev->dev); - if (new_state != hpdev->prev_state) - { - if (new_state == 1){ - event = PICO_HOTPLUG_EVENT_UP; - } else { - event = PICO_HOTPLUG_EVENT_DOWN; - } - //we don't know if one of the callbacks might deregister, so be safe - pico_tree_foreach_safe(cb_node, &(hpdev->callbacks), cb_safe) - { - cb = cb_node->keyValue; - cb(hpdev->dev, event); - } - hpdev->prev_state = new_state; - } - } - - timer_id = pico_timer_add(PICO_HOTPLUG_INTERVAL, &timer_cb, NULL); -} - - -int pico_hotplug_register(struct pico_device *dev, void (*cb)(struct pico_device *dev, int event)) -{ - struct pico_hotplug_device *hotplug_dev; - struct pico_hotplug_device search = {.dev = dev}; - - if (dev->link_state == NULL){ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - } - - hotplug_dev = (struct pico_hotplug_device*)pico_tree_findKey(&Hotplug_device_tree, &search); - if (! hotplug_dev ) - { - hotplug_dev = PICO_ZALLOC(sizeof(struct pico_hotplug_device)); - if (!hotplug_dev) - { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - hotplug_dev->dev = dev; - hotplug_dev->prev_state = dev->link_state(hotplug_dev->dev); - hotplug_dev->callbacks.root = &LEAF; - hotplug_dev->callbacks.compare = &callback_compare; - pico_tree_insert(&Hotplug_device_tree, hotplug_dev); - } - pico_tree_insert(&(hotplug_dev->callbacks), cb); - - if (timer_id == 0) - { - timer_id = pico_timer_add(PICO_HOTPLUG_INTERVAL, &timer_cb, NULL); - } - - return 0; -} - -int pico_hotplug_deregister(struct pico_device *dev, void (*cb)(struct pico_device *dev, int event)) -{ - struct pico_hotplug_device* hotplug_dev; - struct pico_hotplug_device search = {.dev = dev}; - - hotplug_dev = (struct pico_hotplug_device*)pico_tree_findKey(&Hotplug_device_tree, &search); - if (!hotplug_dev) - //wasn't registered - return 0; - pico_tree_delete(&hotplug_dev->callbacks, cb); - if (pico_tree_empty(&hotplug_dev->callbacks)) - { - pico_tree_delete(&Hotplug_device_tree, hotplug_dev); - PICO_FREE(hotplug_dev); - } - - if (pico_tree_empty(&Hotplug_device_tree) && timer_id != 0) - { - pico_timer_cancel(timer_id); - timer_id = 0; - } - return 0; -} - diff --git a/ext/picotcp/modules/pico_hotplug_detection.h b/ext/picotcp/modules/pico_hotplug_detection.h deleted file mode 100644 index 19319b4..0000000 --- a/ext/picotcp/modules/pico_hotplug_detection.h +++ /dev/null @@ -1,20 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Frederik Van Slycken - *********************************************************************/ -#ifndef INCLUDE_PICO_SUPPORT_HOTPLUG -#define INCLUDE_PICO_SUPPORT_HOTPLUG -#include "pico_stack.h" - -#define PICO_HOTPLUG_EVENT_UP 1 /* link went up */ -#define PICO_HOTPLUG_EVENT_DOWN 2 /* link went down */ - -#define PICO_HOTPLUG_INTERVAL 100 - -int pico_hotplug_register(struct pico_device *dev, void (*cb)(struct pico_device *dev, int event)); -int pico_hotplug_deregister(struct pico_device *dev, void (*cb)(struct pico_device *dev, int event)); - -#endif /* _INCLUDE_PICO_SUPPORT_HOTPLUG */ - diff --git a/ext/picotcp/modules/pico_icmp4.c b/ext/picotcp/modules/pico_icmp4.c deleted file mode 100644 index da3d89c..0000000 --- a/ext/picotcp/modules/pico_icmp4.c +++ /dev/null @@ -1,395 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include "pico_icmp4.h" -#include "pico_config.h" -#include "pico_ipv4.h" -#include "pico_eth.h" -#include "pico_device.h" -#include "pico_stack.h" -#include "pico_tree.h" - -/* Queues */ -static struct pico_queue icmp_in = { - 0 -}; -static struct pico_queue icmp_out = { - 0 -}; - - -/* Functions */ - -static int pico_icmp4_checksum(struct pico_frame *f) -{ - struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr; - if (!hdr) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - hdr->crc = 0; - hdr->crc = short_be(pico_checksum(hdr, f->transport_len)); - return 0; -} - -#ifdef PICO_SUPPORT_PING -static void ping_recv_reply(struct pico_frame *f); -#endif - -static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr; - static int firstpkt = 1; - static uint16_t last_id = 0; - static uint16_t last_seq = 0; - IGNORE_PARAMETER(self); - - if (hdr->type == PICO_ICMP_ECHO) { - hdr->type = PICO_ICMP_ECHOREPLY; - /* outgoing frames require a f->len without the ethernet header len */ - if (f->dev && f->dev->eth) - f->len -= PICO_SIZE_ETHHDR; - - if (!firstpkt && (hdr->hun.ih_idseq.idseq_id == last_id) && (last_seq == hdr->hun.ih_idseq.idseq_seq)) { - /* The network duplicated the echo. Do not reply. */ - pico_frame_discard(f); - return 0; - } - - firstpkt = 0; - last_id = hdr->hun.ih_idseq.idseq_id; - last_seq = hdr->hun.ih_idseq.idseq_seq; - pico_icmp4_checksum(f); - pico_ipv4_rebound(f); - } else if (hdr->type == PICO_ICMP_UNREACH) { - f->net_hdr = f->transport_hdr + PICO_ICMPHDR_UN_SIZE; - pico_ipv4_unreachable(f, hdr->code); - } else if (hdr->type == PICO_ICMP_ECHOREPLY) { -#ifdef PICO_SUPPORT_PING - ping_recv_reply(f); -#endif - pico_frame_discard(f); - } else { - pico_frame_discard(f); - } - - return 0; -} - -static int pico_icmp4_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - IGNORE_PARAMETER(self); - IGNORE_PARAMETER(f); - dbg("Called %s\n", __FUNCTION__); - return 0; -} - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_icmp4 = { - .name = "icmp4", - .proto_number = PICO_PROTO_ICMP4, - .layer = PICO_LAYER_TRANSPORT, - .process_in = pico_icmp4_process_in, - .process_out = pico_icmp4_process_out, - .q_in = &icmp_in, - .q_out = &icmp_out, -}; - -static int pico_icmp4_notify(struct pico_frame *f, uint8_t type, uint8_t code) -{ - struct pico_frame *reply; - struct pico_icmp4_hdr *hdr; - struct pico_ipv4_hdr *info; - uint16_t f_tot_len; - - f_tot_len = short_be(((struct pico_ipv4_hdr *)f->net_hdr)->len); - - if (f_tot_len < (sizeof(struct pico_ipv4_hdr))) - return -1; - - /* Truncate tot len to be at most 8 bytes + iphdr */ - if (f_tot_len > (sizeof(struct pico_ipv4_hdr) + 8u)) { - f_tot_len = (sizeof(struct pico_ipv4_hdr) + 8u); - } - - if (f == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - reply = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t) (f_tot_len + PICO_ICMPHDR_UN_SIZE)); - info = (struct pico_ipv4_hdr*)(f->net_hdr); - hdr = (struct pico_icmp4_hdr *) reply->transport_hdr; - hdr->type = type; - hdr->code = code; - hdr->hun.ih_pmtu.ipm_nmtu = short_be(1500); - hdr->hun.ih_pmtu.ipm_void = 0; - reply->transport_len = (uint16_t)(f_tot_len + PICO_ICMPHDR_UN_SIZE); - reply->payload = reply->transport_hdr + PICO_ICMPHDR_UN_SIZE; - memcpy(reply->payload, f->net_hdr, f_tot_len); - pico_icmp4_checksum(reply); - pico_ipv4_frame_push(reply, &info->src, PICO_PROTO_ICMP4); - return 0; -} - -int pico_icmp4_port_unreachable(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PORT); -} - -int pico_icmp4_proto_unreachable(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PROTOCOL); -} - -int pico_icmp4_dest_unreachable(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_HOST); -} - -int pico_icmp4_ttl_expired(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_INTRANS); -} - -MOCKABLE int pico_icmp4_frag_expired(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_REASS); -} - -int pico_icmp4_mtu_exceeded(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_NEEDFRAG); -} - -int pico_icmp4_packet_filtered(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - /*Packet Filtered: type 3, code 13 (Communication Administratively Prohibited)*/ - return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_FILTER_PROHIB); -} - -int pico_icmp4_param_problem(struct pico_frame *f, uint8_t code) -{ - return pico_icmp4_notify(f, PICO_ICMP_PARAMPROB, code); -} - -/***********************/ -/* Ping implementation */ -/***********************/ -/***********************/ -/***********************/ -/***********************/ - - -#ifdef PICO_SUPPORT_PING - - -struct pico_icmp4_ping_cookie -{ - struct pico_ip4 dst; - uint16_t err; - uint16_t id; - uint16_t seq; - uint16_t size; - int count; - pico_time timestamp; - int interval; - int timeout; - void (*cb)(struct pico_icmp4_stats*); -}; - -static int cookie_compare(void *ka, void *kb) -{ - struct pico_icmp4_ping_cookie *a = ka, *b = kb; - if (a->id < b->id) - return -1; - - if (a->id > b->id) - return 1; - - return (a->seq - b->seq); -} - -PICO_TREE_DECLARE(Pings, cookie_compare); - -static int8_t pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie) -{ - struct pico_frame *echo = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size)); - struct pico_icmp4_hdr *hdr; - if (!echo) { - return -1; - } - - hdr = (struct pico_icmp4_hdr *) echo->transport_hdr; - - hdr->type = PICO_ICMP_ECHO; - hdr->code = 0; - hdr->hun.ih_idseq.idseq_id = short_be(cookie->id); - hdr->hun.ih_idseq.idseq_seq = short_be(cookie->seq); - echo->transport_len = (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size); - echo->payload = echo->transport_hdr + PICO_ICMPHDR_UN_SIZE; - echo->payload_len = cookie->size; - /* XXX: Fill payload */ - pico_icmp4_checksum(echo); - pico_ipv4_frame_push(echo, &cookie->dst, PICO_PROTO_ICMP4); - return 0; -} - - -static void ping_timeout(pico_time now, void *arg) -{ - struct pico_icmp4_ping_cookie *cookie = (struct pico_icmp4_ping_cookie *)arg; - IGNORE_PARAMETER(now); - - if(pico_tree_findKey(&Pings, cookie)) { - if (cookie->err == PICO_PING_ERR_PENDING) { - struct pico_icmp4_stats stats; - stats.dst = cookie->dst; - stats.seq = cookie->seq; - stats.time = 0; - stats.size = cookie->size; - stats.err = PICO_PING_ERR_TIMEOUT; - dbg(" ---- Ping timeout!!!\n"); - cookie->cb(&stats); - } - - pico_tree_delete(&Pings, cookie); - PICO_FREE(cookie); - } -} - -static void next_ping(pico_time now, void *arg); -static inline void send_ping(struct pico_icmp4_ping_cookie *cookie) -{ - pico_icmp4_send_echo(cookie); - cookie->timestamp = pico_tick; - pico_timer_add((uint32_t)cookie->timeout, ping_timeout, cookie); - if (cookie->seq < (uint16_t)cookie->count) - pico_timer_add((uint32_t)cookie->interval, next_ping, cookie); -} - -static void next_ping(pico_time now, void *arg) -{ - struct pico_icmp4_ping_cookie *newcookie, *cookie = (struct pico_icmp4_ping_cookie *)arg; - IGNORE_PARAMETER(now); - - if(pico_tree_findKey(&Pings, cookie)) { - if (cookie->err == PICO_PING_ERR_ABORTED) - return; - - if (cookie->seq < (uint16_t)cookie->count) { - newcookie = PICO_ZALLOC(sizeof(struct pico_icmp4_ping_cookie)); - if (!newcookie) - return; - - memcpy(newcookie, cookie, sizeof(struct pico_icmp4_ping_cookie)); - newcookie->seq++; - - pico_tree_insert(&Pings, newcookie); - send_ping(newcookie); - } - } -} - - -static void ping_recv_reply(struct pico_frame *f) -{ - struct pico_icmp4_ping_cookie test, *cookie; - struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr; - test.id = short_be(hdr->hun.ih_idseq.idseq_id ); - test.seq = short_be(hdr->hun.ih_idseq.idseq_seq); - - cookie = pico_tree_findKey(&Pings, &test); - if (cookie) { - struct pico_icmp4_stats stats; - if (cookie->err == PICO_PING_ERR_ABORTED) - return; - - cookie->err = PICO_PING_ERR_REPLIED; - stats.dst = ((struct pico_ipv4_hdr *)f->net_hdr)->src; - stats.seq = cookie->seq; - stats.size = cookie->size; - stats.time = pico_tick - cookie->timestamp; - stats.err = cookie->err; - stats.ttl = ((struct pico_ipv4_hdr *)f->net_hdr)->ttl; - if(cookie->cb != NULL) - cookie->cb(&stats); - } else { - dbg("Reply for seq=%d, not found.\n", test.seq); - } -} - -int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *)) -{ - static uint16_t next_id = 0x91c0; - struct pico_icmp4_ping_cookie *cookie; - - if((dst == NULL) || (interval == 0) || (timeout == 0) || (count == 0)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - cookie = PICO_ZALLOC(sizeof(struct pico_icmp4_ping_cookie)); - if (!cookie) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if (pico_string_to_ipv4(dst, (uint32_t *)&cookie->dst.addr) < 0) { - pico_err = PICO_ERR_EINVAL; - PICO_FREE(cookie); - return -1; - } - - cookie->seq = 1; - cookie->id = next_id++; - cookie->err = PICO_PING_ERR_PENDING; - cookie->size = (uint16_t)size; - cookie->interval = interval; - cookie->timeout = timeout; - cookie->cb = cb; - cookie->count = count; - - pico_tree_insert(&Pings, cookie); - send_ping(cookie); - - return cookie->id; - -} - -int pico_icmp4_ping_abort(int id) -{ - struct pico_tree_node *node; - int found = 0; - pico_tree_foreach(node, &Pings) - { - struct pico_icmp4_ping_cookie *ck = - (struct pico_icmp4_ping_cookie *) node->keyValue; - if (ck->id == (uint16_t)id) { - ck->err = PICO_PING_ERR_ABORTED; - found++; - } - } - if (found > 0) - return 0; /* OK if at least one pending ping has been canceled */ - - pico_err = PICO_ERR_ENOENT; - return -1; -} - -#endif diff --git a/ext/picotcp/modules/pico_icmp4.h b/ext/picotcp/modules/pico_icmp4.h deleted file mode 100644 index 45f0a62..0000000 --- a/ext/picotcp/modules/pico_icmp4.h +++ /dev/null @@ -1,162 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - *********************************************************************/ -#ifndef INCLUDE_PICO_ICMP4 -#define INCLUDE_PICO_ICMP4 -#include "pico_defines.h" -#include "pico_addressing.h" -#include "pico_protocol.h" - - -extern struct pico_protocol pico_proto_icmp4; - -PACKED_STRUCT_DEF pico_icmp4_hdr { - uint8_t type; - uint8_t code; - uint16_t crc; - - /* hun */ - PACKED_UNION_DEF hun_u { - uint8_t ih_pptr; - struct pico_ip4 ih_gwaddr; - PEDANTIC_STRUCT_DEF ih_idseq_s { - uint16_t idseq_id; - uint16_t idseq_seq; - } ih_idseq; - uint32_t ih_void; - PEDANTIC_STRUCT_DEF ih_pmtu_s { - uint16_t ipm_void; - uint16_t ipm_nmtu; - } ih_pmtu; - PEDANTIC_STRUCT_DEF ih_rta_s { - uint8_t rta_numgw; - uint8_t rta_wpa; - uint16_t rta_lifetime; - } ih_rta; - } hun; - - /* dun */ - PACKED_UNION_DEF dun_u { - PEDANTIC_STRUCT_DEF id_ts_s { - uint32_t ts_otime; - uint32_t ts_rtime; - uint32_t ts_ttime; - } id_ts; - PEDANTIC_STRUCT_DEF id_ip_s { - uint32_t ip_options; - uint32_t ip_data_hi; - uint32_t ip_data_lo; - } id_ip; - PEDANTIC_STRUCT_DEF id_ra_s { - uint32_t ira_addr; - uint32_t ira_pref; - } id_ra; - uint32_t id_mask; - uint8_t id_data[1]; - } dun; -}; - -#define PICO_ICMPHDR_DRY_SIZE 4 -#define PICO_ICMPHDR_UN_SIZE 8u - -#define PICO_ICMP_ECHOREPLY 0 -#define PICO_ICMP_DEST_UNREACH 3 -#define PICO_ICMP_SOURCE_QUENCH 4 -#define PICO_ICMP_REDIRECT 5 -#define PICO_ICMP_ECHO 8 -#define PICO_ICMP_TIME_EXCEEDED 11 -#define PICO_ICMP_PARAMETERPROB 12 -#define PICO_ICMP_TIMESTAMP 13 -#define PICO_ICMP_TIMESTAMPREPLY 14 -#define PICO_ICMP_INFO_REQUEST 15 -#define PICO_ICMP_INFO_REPLY 16 -#define PICO_ICMP_ADDRESS 17 -#define PICO_ICMP_ADDRESSREPLY 18 - - -#define PICO_ICMP_UNREACH 3 -#define PICO_ICMP_SOURCEQUENCH 4 -#define PICO_ICMP_ROUTERADVERT 9 -#define PICO_ICMP_ROUTERSOLICIT 10 -#define PICO_ICMP_TIMXCEED 11 -#define PICO_ICMP_PARAMPROB 12 -#define PICO_ICMP_TSTAMP 13 -#define PICO_ICMP_TSTAMPREPLY 14 -#define PICO_ICMP_IREQ 15 -#define PICO_ICMP_IREQREPLY 16 -#define PICO_ICMP_MASKREQ 17 -#define PICO_ICMP_MASKREPLY 18 - -#define PICO_ICMP_MAXTYPE 18 - - -#define PICO_ICMP_UNREACH_NET 0 -#define PICO_ICMP_UNREACH_HOST 1 -#define PICO_ICMP_UNREACH_PROTOCOL 2 -#define PICO_ICMP_UNREACH_PORT 3 -#define PICO_ICMP_UNREACH_NEEDFRAG 4 -#define PICO_ICMP_UNREACH_SRCFAIL 5 -#define PICO_ICMP_UNREACH_NET_UNKNOWN 6 -#define PICO_ICMP_UNREACH_HOST_UNKNOWN 7 -#define PICO_ICMP_UNREACH_ISOLATED 8 -#define PICO_ICMP_UNREACH_NET_PROHIB 9 -#define PICO_ICMP_UNREACH_HOST_PROHIB 10 -#define PICO_ICMP_UNREACH_TOSNET 11 -#define PICO_ICMP_UNREACH_TOSHOST 12 -#define PICO_ICMP_UNREACH_FILTER_PROHIB 13 -#define PICO_ICMP_UNREACH_HOST_PRECEDENCE 14 -#define PICO_ICMP_UNREACH_PRECEDENCE_CUTOFF 15 - - -#define PICO_ICMP_REDIRECT_NET 0 -#define PICO_ICMP_REDIRECT_HOST 1 -#define PICO_ICMP_REDIRECT_TOSNET 2 -#define PICO_ICMP_REDIRECT_TOSHOST 3 - - -#define PICO_ICMP_TIMXCEED_INTRANS 0 -#define PICO_ICMP_TIMXCEED_REASS 1 - - -#define PICO_ICMP_PARAMPROB_OPTABSENT 1 - -#define PICO_SIZE_ICMP4HDR ((sizeof(struct pico_icmp4_hdr))) - -struct pico_icmp4_stats -{ - struct pico_ip4 dst; - unsigned long size; - unsigned long seq; - pico_time time; - unsigned long ttl; - int err; -}; - -int pico_icmp4_port_unreachable(struct pico_frame *f); -int pico_icmp4_proto_unreachable(struct pico_frame *f); -int pico_icmp4_dest_unreachable(struct pico_frame *f); -int pico_icmp4_mtu_exceeded(struct pico_frame *f); -int pico_icmp4_ttl_expired(struct pico_frame *f); -int pico_icmp4_frag_expired(struct pico_frame *f); -int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *)); -int pico_icmp4_ping_abort(int id); - -#ifdef PICO_SUPPORT_ICMP4 -int pico_icmp4_packet_filtered(struct pico_frame *f); -int pico_icmp4_param_problem(struct pico_frame *f, uint8_t code); -#else -# define pico_icmp4_packet_filtered(f) (-1) -# define pico_icmp4_param_problem(f, c) (-1) -#endif /* PICO_SUPPORT_ICMP4 */ - -#define PICO_PING_ERR_REPLIED 0 -#define PICO_PING_ERR_TIMEOUT 1 -#define PICO_PING_ERR_UNREACH 2 -#define PICO_PING_ERR_ABORTED 3 -#define PICO_PING_ERR_PENDING 0xFFFF - -#endif diff --git a/ext/picotcp/modules/pico_icmp6.c b/ext/picotcp/modules/pico_icmp6.c deleted file mode 100644 index 3c46e7e..0000000 --- a/ext/picotcp/modules/pico_icmp6.c +++ /dev/null @@ -1,698 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Kristof Roelants, Daniele Lacamera - *********************************************************************/ - -#include "pico_config.h" -#include "pico_icmp6.h" -#include "pico_ipv6_nd.h" -#include "pico_eth.h" -#include "pico_device.h" -#include "pico_stack.h" -#include "pico_tree.h" -#include "pico_socket.h" -#include "pico_mld.h" -#define icmp6_dbg(...) do { }while(0); - -static struct pico_queue icmp6_in; -static struct pico_queue icmp6_out; - -uint16_t pico_icmp6_checksum(struct pico_frame *f) -{ - struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; - - struct pico_icmp6_hdr *icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - struct pico_ipv6_pseudo_hdr pseudo; - - pseudo.src = ipv6_hdr->src; - pseudo.dst = ipv6_hdr->dst; - pseudo.len = long_be(f->transport_len); - pseudo.nxthdr = PICO_PROTO_ICMP6; - - pseudo.zero[0] = 0; - pseudo.zero[1] = 0; - pseudo.zero[2] = 0; - - return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv6_pseudo_hdr), icmp6_hdr, f->transport_len); -} - -#ifdef PICO_SUPPORT_PING -static void pico_icmp6_ping_recv_reply(struct pico_frame *f); -#endif - -static int pico_icmp6_send_echoreply(struct pico_frame *echo) -{ - struct pico_frame *reply = NULL; - struct pico_icmp6_hdr *ehdr = NULL, *rhdr = NULL; - struct pico_ip6 src; - struct pico_ip6 dst; - - reply = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(echo->transport_len)); - if (!reply) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE; - reply->payload = reply->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE; - reply->payload_len = echo->transport_len; - reply->dev = echo->dev; - - ehdr = (struct pico_icmp6_hdr *)echo->transport_hdr; - rhdr = (struct pico_icmp6_hdr *)reply->transport_hdr; - rhdr->type = PICO_ICMP6_ECHO_REPLY; - rhdr->code = 0; - rhdr->msg.info.echo_reply.id = ehdr->msg.info.echo_reply.id; - rhdr->msg.info.echo_reply.seq = ehdr->msg.info.echo_request.seq; - memcpy(reply->payload, echo->payload, (uint32_t)(echo->transport_len - PICO_ICMP6HDR_ECHO_REQUEST_SIZE)); - rhdr->crc = 0; - rhdr->crc = short_be(pico_icmp6_checksum(reply)); - /* Get destination and source swapped */ - memcpy(dst.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, PICO_SIZE_IP6); - memcpy(src.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, PICO_SIZE_IP6); - pico_ipv6_frame_push(reply, &src, &dst, PICO_PROTO_ICMP6, 0); - return 0; -} - -static int pico_icmp6_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_icmp6_hdr *hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - - IGNORE_PARAMETER(self); - - icmp6_dbg("Process IN, type = %d\n", hdr->type); - - switch (hdr->type) - { - case PICO_ICMP6_DEST_UNREACH: - pico_ipv6_unreachable(f, hdr->code); - break; - - case PICO_ICMP6_ECHO_REQUEST: - icmp6_dbg("ICMP6: Received ECHO REQ\n"); - f->transport_len = (uint16_t)(f->len - f->net_len - (uint16_t)(f->net_hdr - f->buffer)); - pico_icmp6_send_echoreply(f); - pico_frame_discard(f); - break; - - case PICO_ICMP6_ECHO_REPLY: -#ifdef PICO_SUPPORT_PING - pico_icmp6_ping_recv_reply(f); -#endif - pico_frame_discard(f); - break; -#ifdef PICO_SUPPORT_MCAST - case PICO_MLD_QUERY: - case PICO_MLD_REPORT: - case PICO_MLD_DONE: - case PICO_MLD_REPORTV2: - pico_mld_process_in(f); - break; -#endif - default: - return pico_ipv6_nd_recv(f); /* CAUTION -- Implies: pico_frame_discard in any case, keep in the default! */ - } - return -1; -} - -static int pico_icmp6_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - IGNORE_PARAMETER(self); - IGNORE_PARAMETER(f); - return 0; -} - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_icmp6 = { - .name = "icmp6", - .proto_number = PICO_PROTO_ICMP6, - .layer = PICO_LAYER_TRANSPORT, - .process_in = pico_icmp6_process_in, - .process_out = pico_icmp6_process_out, - .q_in = &icmp6_in, - .q_out = &icmp6_out, -}; - -static int pico_icmp6_notify(struct pico_frame *f, uint8_t type, uint8_t code, uint32_t ptr) -{ - struct pico_frame *notice = NULL; - struct pico_ipv6_hdr *ipv6_hdr = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - uint16_t len = 0; - - if (!f) - return -1; - - ipv6_hdr = (struct pico_ipv6_hdr *)(f->net_hdr); - len = (uint16_t)(short_be(ipv6_hdr->len) + PICO_SIZE_IP6HDR); - switch (type) - { - case PICO_ICMP6_DEST_UNREACH: - /* as much of invoking packet as possible without exceeding the minimum IPv6 MTU */ - if (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_DEST_UNREACH_SIZE + len > PICO_IPV6_MIN_MTU) - len = PICO_IPV6_MIN_MTU - (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_DEST_UNREACH_SIZE); - - notice = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(PICO_ICMP6HDR_DEST_UNREACH_SIZE + len)); - if (!notice) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - notice->payload = notice->transport_hdr + PICO_ICMP6HDR_DEST_UNREACH_SIZE; - notice->payload_len = len; - icmp6_hdr = (struct pico_icmp6_hdr *)notice->transport_hdr; - icmp6_hdr->msg.err.dest_unreach.unused = 0; - break; - - case PICO_ICMP6_TIME_EXCEEDED: - /* as much of invoking packet as possible without exceeding the minimum IPv6 MTU */ - if (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_TIME_XCEEDED_SIZE + len > PICO_IPV6_MIN_MTU) - len = PICO_IPV6_MIN_MTU - (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_TIME_XCEEDED_SIZE); - - notice = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(PICO_ICMP6HDR_TIME_XCEEDED_SIZE + len)); - if (!notice) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - notice->payload = notice->transport_hdr + PICO_ICMP6HDR_TIME_XCEEDED_SIZE; - notice->payload_len = len; - icmp6_hdr = (struct pico_icmp6_hdr *)notice->transport_hdr; - icmp6_hdr->msg.err.time_exceeded.unused = 0; - break; - - case PICO_ICMP6_PARAM_PROBLEM: - if (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_PARAM_PROBLEM_SIZE + len > PICO_IPV6_MIN_MTU) - len = PICO_IPV6_MIN_MTU - (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_PARAM_PROBLEM_SIZE); - - notice = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(PICO_ICMP6HDR_PARAM_PROBLEM_SIZE + len)); - if (!notice) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - notice->payload = notice->transport_hdr + PICO_ICMP6HDR_PARAM_PROBLEM_SIZE; - notice->payload_len = len; - icmp6_hdr = (struct pico_icmp6_hdr *)notice->transport_hdr; - icmp6_hdr->msg.err.param_problem.ptr = long_be(ptr); - break; - - default: - return -1; - } - - icmp6_hdr->type = type; - icmp6_hdr->code = code; - memcpy(notice->payload, f->net_hdr, notice->payload_len); - notice->dev = f->dev; - /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(notice, NULL, &ipv6_hdr->src, PICO_PROTO_ICMP6, 0); - return 0; -} - -int pico_icmp6_port_unreachable(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - - return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_PORT, 0); -} - -int pico_icmp6_proto_unreachable(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - - return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_ADDR, 0); -} - -int pico_icmp6_dest_unreachable(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - - return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_ADDR, 0); -} - -int pico_icmp6_ttl_expired(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - - return pico_icmp6_notify(f, PICO_ICMP6_TIME_EXCEEDED, PICO_ICMP6_TIMXCEED_INTRANS, 0); -} - -int pico_icmp6_pkt_too_big(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - - return pico_icmp6_notify(f, PICO_ICMP6_PKT_TOO_BIG, 0, 0); -} - -#ifdef PICO_SUPPORT_IPFILTER -int pico_icmp6_packet_filtered(struct pico_frame *f) -{ - return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_ADMIN, 0); -} -#endif - -int pico_icmp6_parameter_problem(struct pico_frame *f, uint8_t problem, uint32_t ptr) -{ - return pico_icmp6_notify(f, PICO_ICMP6_PARAM_PROBLEM, problem, ptr); -} - -MOCKABLE int pico_icmp6_frag_expired(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - - return pico_icmp6_notify(f, PICO_ICMP6_TIME_EXCEEDED, PICO_ICMP6_TIMXCEED_REASS, 0); -} - -/* RFC 4861 $7.2.2: sending neighbor solicitations */ -int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *dst, uint8_t type) -{ - struct pico_frame *sol = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_icmp6_opt_lladdr *opt = NULL; - struct pico_ip6 daddr = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00 }}; - uint8_t i = 0; - uint16_t len = 0; - - if (pico_ipv6_is_multicast(dst->addr)) - return -1; - - len = PICO_ICMP6HDR_NEIGH_SOL_SIZE; - if (type != PICO_ICMP6_ND_DAD) - len = (uint16_t)(len + 8); - - sol = pico_proto_ipv6.alloc(&pico_proto_ipv6, len); - if (!sol) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - sol->payload = sol->transport_hdr + len; - sol->payload_len = 0; - - icmp6_hdr = (struct pico_icmp6_hdr *)sol->transport_hdr; - icmp6_hdr->type = PICO_ICMP6_NEIGH_SOL; - icmp6_hdr->code = 0; - icmp6_hdr->msg.info.neigh_sol.unused = 0; - icmp6_hdr->msg.info.neigh_sol.target = *dst; - - if (type != PICO_ICMP6_ND_DAD) { - opt = (struct pico_icmp6_opt_lladdr *)(((uint8_t *)&icmp6_hdr->msg.info.neigh_sol) + sizeof(struct neigh_sol_s)); - opt->type = PICO_ND_OPT_LLADDR_SRC; - opt->len = 1; - memcpy(opt->addr.mac.addr, dev->eth->mac.addr, PICO_SIZE_ETH); - } - - if (type == PICO_ICMP6_ND_SOLICITED || type == PICO_ICMP6_ND_DAD) { - for (i = 1; i <= 3; ++i) { - daddr.addr[PICO_SIZE_IP6 - i] = dst->addr[PICO_SIZE_IP6 - i]; - } - } else { - daddr = *dst; - } - - sol->dev = dev; - - /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(sol, NULL, &daddr, PICO_PROTO_ICMP6, (type == PICO_ICMP6_ND_DAD)); - return 0; -} - -/* RFC 4861 $7.2.4: sending solicited neighbor advertisements */ -int pico_icmp6_neighbor_advertisement(struct pico_frame *f, struct pico_ip6 *target) -{ - struct pico_frame *adv = NULL; - struct pico_ipv6_hdr *ipv6_hdr = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_icmp6_opt_lladdr *opt = NULL; - struct pico_ip6 dst = {{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}; - - ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; - adv = pico_proto_ipv6.alloc(&pico_proto_ipv6, PICO_ICMP6HDR_NEIGH_ADV_SIZE + 8); - if (!adv) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - adv->payload = adv->transport_hdr + PICO_ICMP6HDR_NEIGH_ADV_SIZE + 8; - adv->payload_len = 0; - - icmp6_hdr = (struct pico_icmp6_hdr *)adv->transport_hdr; - icmp6_hdr->type = PICO_ICMP6_NEIGH_ADV; - icmp6_hdr->code = 0; - icmp6_hdr->msg.info.neigh_adv.target = *target; - icmp6_hdr->msg.info.neigh_adv.rsor = long_be(0x60000000); /* !router && solicited && override */ - if (pico_ipv6_is_unspecified(ipv6_hdr->src.addr)) { - /* solicited = clear && dst = all-nodes address (scope link-local) */ - icmp6_hdr->msg.info.neigh_adv.rsor ^= long_be(0x40000000); - } else { - /* solicited = set && dst = source of solicitation */ - dst = ipv6_hdr->src; - } - - /* XXX if the target address is either an anycast address or a unicast - * address for which the node is providing proxy service, or the target - * link-layer Address option is not included, the Override flag SHOULD - * be set to zero. - */ - - /* XXX if the target address is an anycast address, the sender SHOULD delay - * sending a response for a random time between 0 and MAX_ANYCAST_DELAY_TIME seconds. - */ - - opt = (struct pico_icmp6_opt_lladdr *)(((uint8_t *)&icmp6_hdr->msg.info.neigh_adv) + sizeof(struct neigh_adv_s)); - opt->type = PICO_ND_OPT_LLADDR_TGT; - opt->len = 1; - memcpy(opt->addr.mac.addr, f->dev->eth->mac.addr, PICO_SIZE_ETH); - adv->dev = f->dev; - - /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(adv, NULL, &dst, PICO_PROTO_ICMP6, 0); - return 0; -} - -/* RFC 4861 $6.3.7: sending router solicitations */ -int pico_icmp6_router_solicitation(struct pico_device *dev, struct pico_ip6 *src) -{ - struct pico_frame *sol = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_icmp6_opt_lladdr *lladdr = NULL; - uint16_t len = 0; - struct pico_ip6 daddr = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}; - - len = PICO_ICMP6HDR_ROUTER_SOL_SIZE; - if (!pico_ipv6_is_unspecified(src->addr)) - len = (uint16_t)(len + 8); - - sol = pico_proto_ipv6.alloc(&pico_proto_ipv6, len); - if (!sol) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - sol->payload = sol->transport_hdr + len; - sol->payload_len = 0; - - icmp6_hdr = (struct pico_icmp6_hdr *)sol->transport_hdr; - icmp6_hdr->type = PICO_ICMP6_ROUTER_SOL; - icmp6_hdr->code = 0; - - if (!pico_ipv6_is_unspecified(src->addr)) { - lladdr = (struct pico_icmp6_opt_lladdr *)(((uint8_t *)&icmp6_hdr->msg.info.router_sol) + sizeof(struct router_sol_s)); - lladdr->type = PICO_ND_OPT_LLADDR_SRC; - lladdr->len = 1; - memcpy(lladdr->addr.mac.addr, dev->eth->mac.addr, PICO_SIZE_ETH); - } - - sol->dev = dev; - - /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(sol, NULL, &daddr, PICO_PROTO_ICMP6, 0); - return 0; -} - -#define PICO_RADV_VAL_LIFETIME (long_be(86400)) -#define PICO_RADV_PREF_LIFETIME (long_be(14400)) - -/* RFC 4861: sending router advertisements */ -int pico_icmp6_router_advertisement(struct pico_device *dev, struct pico_ip6 *dst) -{ - struct pico_frame *adv = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_icmp6_opt_lladdr *lladdr; - struct pico_icmp6_opt_prefix *prefix; - uint16_t len = 0; - struct pico_ip6 dst_mcast = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}; - uint8_t *nxt_opt; - - len = PICO_ICMP6HDR_ROUTER_ADV_SIZE + PICO_ICMP6_OPT_LLADDR_SIZE + sizeof(struct pico_icmp6_opt_prefix); - - adv = pico_proto_ipv6.alloc(&pico_proto_ipv6, len); - if (!adv) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - adv->payload = adv->transport_hdr + len; - adv->payload_len = 0; - adv->dev = dev; - - icmp6_hdr = (struct pico_icmp6_hdr *)adv->transport_hdr; - icmp6_hdr->type = PICO_ICMP6_ROUTER_ADV; - icmp6_hdr->code = 0; - icmp6_hdr->msg.info.router_adv.life_time = short_be(45); - icmp6_hdr->msg.info.router_adv.hop = 64; - nxt_opt = (uint8_t *)&icmp6_hdr->msg.info.router_adv + sizeof(struct router_adv_s); - - prefix = (struct pico_icmp6_opt_prefix *)nxt_opt; - prefix->type = PICO_ND_OPT_PREFIX; - prefix->len = sizeof(struct pico_icmp6_opt_prefix) >> 3; - prefix->prefix_len = 64; /* Only /64 are forwarded */ - prefix->aac = 1; - prefix->onlink = 1; - prefix->val_lifetime = PICO_RADV_VAL_LIFETIME; - prefix->pref_lifetime = PICO_RADV_PREF_LIFETIME; - memcpy(&prefix->prefix, dst, sizeof(struct pico_ip6)); - - nxt_opt += (sizeof (struct pico_icmp6_opt_prefix)); - lladdr = (struct pico_icmp6_opt_lladdr *)nxt_opt; - lladdr->type = PICO_ND_OPT_LLADDR_SRC; - lladdr->len = 1; - memcpy(lladdr->addr.mac.addr, dev->eth->mac.addr, PICO_SIZE_ETH); - icmp6_hdr->crc = 0; - icmp6_hdr->crc = short_be(pico_icmp6_checksum(adv)); - /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(adv, NULL, &dst_mcast, PICO_PROTO_ICMP6, 0); - return 0; -} - -/***********************/ -/* Ping implementation */ -/***********************/ - -#ifdef PICO_SUPPORT_PING -struct pico_icmp6_ping_cookie -{ - uint16_t id; - uint16_t seq; - uint16_t size; - uint16_t err; - int count; - int interval; - int timeout; - pico_time timestamp; - struct pico_ip6 dst; - struct pico_device *dev; - void (*cb)(struct pico_icmp6_stats*); -}; - -static int icmp6_cookie_compare(void *ka, void *kb) -{ - struct pico_icmp6_ping_cookie *a = ka, *b = kb; - if (a->id < b->id) - return -1; - - if (a->id > b->id) - return 1; - - return (a->seq - b->seq); -} -PICO_TREE_DECLARE(IPV6Pings, icmp6_cookie_compare); - -static int pico_icmp6_send_echo(struct pico_icmp6_ping_cookie *cookie) -{ - struct pico_frame *echo = NULL; - struct pico_icmp6_hdr *hdr = NULL; - - echo = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(PICO_ICMP6HDR_ECHO_REQUEST_SIZE + cookie->size)); - if (!echo) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE; - echo->payload_len = cookie->size; - - hdr = (struct pico_icmp6_hdr *)echo->transport_hdr; - hdr->type = PICO_ICMP6_ECHO_REQUEST; - hdr->code = 0; - hdr->msg.info.echo_request.id = short_be(cookie->id); - hdr->msg.info.echo_request.seq = short_be(cookie->seq); - /* XXX: Fill payload */ - hdr->crc = 0; - hdr->crc = short_be(pico_icmp6_checksum(echo)); - echo->dev = cookie->dev; - pico_ipv6_frame_push(echo, NULL, &cookie->dst, PICO_PROTO_ICMP6, 0); - return 0; -} - - -static void pico_icmp6_ping_timeout(pico_time now, void *arg) -{ - struct pico_icmp6_ping_cookie *cookie = NULL; - - IGNORE_PARAMETER(now); - - cookie = (struct pico_icmp6_ping_cookie *)arg; - if (pico_tree_findKey(&IPV6Pings, cookie)) { - if (cookie->err == PICO_PING6_ERR_PENDING) { - struct pico_icmp6_stats stats = { - 0 - }; - stats.dst = cookie->dst; - stats.seq = cookie->seq; - stats.time = 0; - stats.size = cookie->size; - stats.err = PICO_PING6_ERR_TIMEOUT; - dbg(" ---- Ping6 timeout!!!\n"); - if (cookie->cb) - cookie->cb(&stats); - } - - pico_tree_delete(&IPV6Pings, cookie); - PICO_FREE(cookie); - } -} - -static void pico_icmp6_next_ping(pico_time now, void *arg); -static inline void pico_icmp6_send_ping(struct pico_icmp6_ping_cookie *cookie) -{ - pico_icmp6_send_echo(cookie); - cookie->timestamp = pico_tick; - pico_timer_add((pico_time)(cookie->interval), pico_icmp6_next_ping, cookie); - pico_timer_add((pico_time)(cookie->timeout), pico_icmp6_ping_timeout, cookie); -} - -static void pico_icmp6_next_ping(pico_time now, void *arg) -{ - struct pico_icmp6_ping_cookie *cookie = NULL, *new = NULL; - - IGNORE_PARAMETER(now); - - cookie = (struct pico_icmp6_ping_cookie *)arg; - if (pico_tree_findKey(&IPV6Pings, cookie)) { - if (cookie->err == PICO_PING6_ERR_ABORTED) - return; - - if (cookie->seq < (uint16_t)cookie->count) { - new = PICO_ZALLOC(sizeof(struct pico_icmp6_ping_cookie)); - if (!new) { - pico_err = PICO_ERR_ENOMEM; - return; - } - - memcpy(new, cookie, sizeof(struct pico_icmp6_ping_cookie)); - new->seq++; - - pico_tree_insert(&IPV6Pings, new); - pico_icmp6_send_ping(new); - } - } -} - -static void pico_icmp6_ping_recv_reply(struct pico_frame *f) -{ - struct pico_icmp6_ping_cookie *cookie = NULL, test = { - 0 - }; - struct pico_icmp6_hdr *hdr = NULL; - - hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - test.id = short_be(hdr->msg.info.echo_reply.id); - test.seq = short_be(hdr->msg.info.echo_reply.seq); - cookie = pico_tree_findKey(&IPV6Pings, &test); - if (cookie) { - struct pico_icmp6_stats stats = { - 0 - }; - if (cookie->err == PICO_PING6_ERR_ABORTED) - return; - - cookie->err = PICO_PING6_ERR_REPLIED; - stats.dst = cookie->dst; - stats.seq = cookie->seq; - stats.size = cookie->size; - stats.time = pico_tick - cookie->timestamp; - stats.err = cookie->err; - stats.ttl = ((struct pico_ipv6_hdr *)f->net_hdr)->hop; - if(cookie->cb) - cookie->cb(&stats); - } else { - dbg("Reply for seq=%d, not found.\n", test.seq); - } -} - -int pico_icmp6_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp6_stats *), struct pico_device *dev) -{ - static uint16_t next_id = 0x91c0; - struct pico_icmp6_ping_cookie *cookie = NULL; - - if(!dst || !count || !interval || !timeout) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - cookie = PICO_ZALLOC(sizeof(struct pico_icmp6_ping_cookie)); - if (!cookie) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if (pico_string_to_ipv6(dst, cookie->dst.addr) < 0) { - pico_err = PICO_ERR_EINVAL; - PICO_FREE(cookie); - return -1; - } - - cookie->seq = 1; - cookie->id = next_id++; - cookie->err = PICO_PING6_ERR_PENDING; - cookie->size = (uint16_t)size; - cookie->interval = interval; - cookie->timeout = timeout; - cookie->cb = cb; - cookie->count = count; - cookie->dev = dev; - - pico_tree_insert(&IPV6Pings, cookie); - pico_icmp6_send_ping(cookie); - return (int)cookie->id; -} - -int pico_icmp6_ping_abort(int id) -{ - struct pico_tree_node *node; - int found = 0; - pico_tree_foreach(node, &IPV6Pings) - { - struct pico_icmp6_ping_cookie *ck = - (struct pico_icmp6_ping_cookie *) node->keyValue; - if (ck->id == (uint16_t)id) { - ck->err = PICO_PING6_ERR_ABORTED; - found++; - } - } - if (found > 0) - return 0; /* OK if at least one pending ping has been canceled */ - - pico_err = PICO_ERR_ENOENT; - return -1; -} - -#endif diff --git a/ext/picotcp/modules/pico_icmp6.h b/ext/picotcp/modules/pico_icmp6.h deleted file mode 100644 index 7734060..0000000 --- a/ext/picotcp/modules/pico_icmp6.h +++ /dev/null @@ -1,256 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - *********************************************************************/ -#ifndef _INCLUDE_PICO_ICMP6 -#define _INCLUDE_PICO_ICMP6 -#include "pico_addressing.h" -#include "pico_protocol.h" -#include "pico_mld.h" -/* ICMP header sizes */ -#define PICO_ICMP6HDR_DRY_SIZE 4 -#define PICO_ICMP6HDR_ECHO_REQUEST_SIZE 8 -#define PICO_ICMP6HDR_DEST_UNREACH_SIZE 8 -#define PICO_ICMP6HDR_TIME_XCEEDED_SIZE 8 -#define PICO_ICMP6HDR_PARAM_PROBLEM_SIZE 8 -#define PICO_ICMP6HDR_NEIGH_SOL_SIZE 24 -#define PICO_ICMP6HDR_NEIGH_ADV_SIZE 24 -#define PICO_ICMP6HDR_ROUTER_SOL_SIZE 8 -#define PICO_ICMP6HDR_ROUTER_ADV_SIZE 16 -#define PICO_ICMP6HDR_REDIRECT_SIZE 40 - -/* ICMP types */ -#define PICO_ICMP6_DEST_UNREACH 1 -#define PICO_ICMP6_PKT_TOO_BIG 2 -#define PICO_ICMP6_TIME_EXCEEDED 3 -#define PICO_ICMP6_PARAM_PROBLEM 4 -#define PICO_ICMP6_ECHO_REQUEST 128 -#define PICO_ICMP6_ECHO_REPLY 129 -#define PICO_ICMP6_ROUTER_SOL 133 -#define PICO_ICMP6_ROUTER_ADV 134 -#define PICO_ICMP6_NEIGH_SOL 135 -#define PICO_ICMP6_NEIGH_ADV 136 -#define PICO_ICMP6_REDIRECT 137 - -/* destination unreachable codes */ -#define PICO_ICMP6_UNREACH_NOROUTE 0 -#define PICO_ICMP6_UNREACH_ADMIN 1 -#define PICO_ICMP6_UNREACH_SRCSCOPE 2 -#define PICO_ICMP6_UNREACH_ADDR 3 -#define PICO_ICMP6_UNREACH_PORT 4 -#define PICO_ICMP6_UNREACH_SRCFILTER 5 -#define PICO_ICMP6_UNREACH_REJROUTE 6 - -/* time exceeded codes */ -#define PICO_ICMP6_TIMXCEED_INTRANS 0 -#define PICO_ICMP6_TIMXCEED_REASS 1 - -/* parameter problem codes */ -#define PICO_ICMP6_PARAMPROB_HDRFIELD 0 -#define PICO_ICMP6_PARAMPROB_NXTHDR 1 -#define PICO_ICMP6_PARAMPROB_IPV6OPT 2 - -/* ping error codes */ -#define PICO_PING6_ERR_REPLIED 0 -#define PICO_PING6_ERR_TIMEOUT 1 -#define PICO_PING6_ERR_UNREACH 2 -#define PICO_PING6_ERR_ABORTED 3 -#define PICO_PING6_ERR_PENDING 0xFFFF - -/* ND configuration */ -#define PICO_ND_MAX_FRAMES_QUEUED 4 /* max frames queued while awaiting address resolution */ - -/* ND RFC constants */ -#define PICO_ND_MAX_SOLICIT 3 -#define PICO_ND_MAX_NEIGHBOR_ADVERT 3 -#define PICO_ND_DELAY_INCOMPLETE 1000 /* msec */ -#define PICO_ND_DELAY_FIRST_PROBE_TIME 5000 /* msec */ - -/* neighbor discovery options */ -#define PICO_ND_OPT_LLADDR_SRC 1 -#define PICO_ND_OPT_LLADDR_TGT 2 -#define PICO_ND_OPT_PREFIX 3 -#define PICO_ND_OPT_REDIRECT 4 -#define PICO_ND_OPT_MTU 5 -#define PICO_ND_OPT_RDNSS 25 /* RFC 5006 */ - -/* ND advertisement flags */ -#define PICO_ND_ROUTER 0x80000000 -#define PICO_ND_SOLICITED 0x40000000 -#define PICO_ND_OVERRIDE 0x20000000 -#define IS_ROUTER(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_ROUTER)) /* router flag set? */ -#define IS_SOLICITED(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_SOLICITED)) /* solicited flag set? */ -#define IS_OVERRIDE(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_OVERRIDE)) /* override flag set? */ - -#define PICO_ND_PREFIX_LIFETIME_INF 0xFFFFFFFFu -/* #define PICO_ND_DESTINATION_LRU_TIME 600000u / * msecs (10min) * / */ - -/* custom defines */ -#define PICO_ICMP6_ND_UNICAST 0 -#define PICO_ICMP6_ND_ANYCAST 1 -#define PICO_ICMP6_ND_SOLICITED 2 -#define PICO_ICMP6_ND_DAD 3 - -#define PICO_ICMP6_MAX_RTR_SOL_DELAY 1000 - -#define PICO_SIZE_ICMP6HDR ((sizeof(struct pico_icmp6_hdr))) -#define PICO_ICMP6_OPT_LLADDR_SIZE (8) - -extern struct pico_protocol pico_proto_icmp6; - -PACKED_STRUCT_DEF pico_icmp6_hdr { - uint8_t type; - uint8_t code; - uint16_t crc; - - PACKED_UNION_DEF icmp6_msg_u { - /* error messages */ - PACKED_UNION_DEF icmp6_err_u { - PEDANTIC_STRUCT_DEF dest_unreach_s { - uint32_t unused; - } dest_unreach; - PEDANTIC_STRUCT_DEF pkt_too_big_s { - uint32_t mtu; - } pkt_too_big; - PEDANTIC_STRUCT_DEF time_exceeded_s { - uint32_t unused; - } time_exceeded; - PEDANTIC_STRUCT_DEF param_problem_s { - uint32_t ptr; - } param_problem; - } err; - - /* informational messages */ - PACKED_UNION_DEF icmp6_info_u { - PEDANTIC_STRUCT_DEF echo_request_s { - uint16_t id; - uint16_t seq; - } echo_request; - PEDANTIC_STRUCT_DEF echo_reply_s { - uint16_t id; - uint16_t seq; - } echo_reply; - PEDANTIC_STRUCT_DEF router_sol_s { - uint32_t unused; - } router_sol; - PEDANTIC_STRUCT_DEF router_adv_s { - uint8_t hop; - uint8_t mor; - uint16_t life_time; - uint32_t reachable_time; - uint32_t retrans_time; - } router_adv; - PEDANTIC_STRUCT_DEF neigh_sol_s { - uint32_t unused; - struct pico_ip6 target; - } neigh_sol; - PEDANTIC_STRUCT_DEF neigh_adv_s { - uint32_t rsor; - struct pico_ip6 target; - } neigh_adv; - PEDANTIC_STRUCT_DEF redirect_s { - uint32_t reserved; - struct pico_ip6 target; - struct pico_ip6 dest; - } redirect; - PEDANTIC_STRUCT_DEF mld_s { - uint16_t max_resp_time; - uint16_t reserved; - struct pico_ip6 mmcast_group; - /*MLDv2*/ - uint8_t reserverd; // With S and QRV - uint8_t QQIC; - uint16_t nbr_src; - struct pico_ip6 src[0]; - } mld; - } info; - } msg; -}; - -PACKED_STRUCT_DEF pico_icmp6_opt_lladdr -{ - uint8_t type; - uint8_t len; - PACKED_UNION_DEF icmp6_opt_hw_addr_u { - struct pico_eth mac; - } addr; -}; - -PACKED_STRUCT_DEF pico_icmp6_opt_prefix -{ - uint8_t type; - uint8_t len; - uint8_t prefix_len; - uint8_t res : 6; - uint8_t aac : 1; - uint8_t onlink : 1; - uint32_t val_lifetime; - uint32_t pref_lifetime; - uint32_t reserved; - struct pico_ip6 prefix; -}; - -PACKED_STRUCT_DEF pico_icmp6_opt_mtu -{ - uint8_t type; - uint8_t len; - uint16_t res; - uint32_t mtu; -}; - -PACKED_STRUCT_DEF pico_icmp6_opt_redirect -{ - uint8_t type; - uint8_t len; - uint16_t res0; - uint32_t res1; -}; - -PACKED_STRUCT_DEF pico_icmp6_opt_rdnss -{ - uint8_t type; - uint8_t len; - uint16_t res0; - uint32_t lifetime; - struct pico_ip6 *addr; -}; - -PACKED_STRUCT_DEF pico_icmp6_opt_na -{ - uint8_t type; - uint8_t len; -}; - -struct pico_icmp6_stats -{ - unsigned long size; - unsigned long seq; - pico_time time; - unsigned long ttl; - int err; - struct pico_ip6 dst; -}; - -int pico_icmp6_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp6_stats *), struct pico_device *dev); -int pico_icmp6_ping_abort(int id); - -int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *dst, uint8_t type); -int pico_icmp6_neighbor_advertisement(struct pico_frame *f, struct pico_ip6 *target); -int pico_icmp6_router_solicitation(struct pico_device *dev, struct pico_ip6 *src); - -int pico_icmp6_port_unreachable(struct pico_frame *f); -int pico_icmp6_proto_unreachable(struct pico_frame *f); -int pico_icmp6_dest_unreachable(struct pico_frame *f); -int pico_icmp6_ttl_expired(struct pico_frame *f); -int pico_icmp6_packet_filtered(struct pico_frame *f); -int pico_icmp6_parameter_problem(struct pico_frame *f, uint8_t problem, uint32_t ptr); -int pico_icmp6_pkt_too_big(struct pico_frame *f); -int pico_icmp6_frag_expired(struct pico_frame *f); - -uint16_t pico_icmp6_checksum(struct pico_frame *f); -int pico_icmp6_router_advertisement(struct pico_device *dev, struct pico_ip6 *dst); - -#endif diff --git a/ext/picotcp/modules/pico_igmp.c b/ext/picotcp/modules/pico_igmp.c deleted file mode 100644 index 2d2fc08..0000000 --- a/ext/picotcp/modules/pico_igmp.c +++ /dev/null @@ -1,1276 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - RFC 1112, 2236, 3376, 3569, 3678, 4607 - - Authors: Kristof Roelants (IGMPv3), Simon Maes, Brecht Van Cauwenberghe - *********************************************************************/ - -#include "pico_stack.h" -#include "pico_ipv4.h" -#include "pico_igmp.h" -#include "pico_config.h" -#include "pico_eth.h" -#include "pico_addressing.h" -#include "pico_frame.h" -#include "pico_tree.h" -#include "pico_device.h" -#include "pico_socket.h" - -#if defined(PICO_SUPPORT_IGMP) && defined(PICO_SUPPORT_MCAST) - -#define igmp_dbg(...) do {} while(0) -/* #define igmp_dbg dbg */ - -/* membership states */ -#define IGMP_STATE_NON_MEMBER (0x0) -#define IGMP_STATE_DELAYING_MEMBER (0x1) -#define IGMP_STATE_IDLE_MEMBER (0x2) - -/* events */ -#define IGMP_EVENT_DELETE_GROUP (0x0) -#define IGMP_EVENT_CREATE_GROUP (0x1) -#define IGMP_EVENT_UPDATE_GROUP (0x2) -#define IGMP_EVENT_QUERY_RECV (0x3) -#define IGMP_EVENT_REPORT_RECV (0x4) -#define IGMP_EVENT_TIMER_EXPIRED (0x5) - -/* message types */ -#define IGMP_TYPE_MEM_QUERY (0x11) -#define IGMP_TYPE_MEM_REPORT_V1 (0x12) -#define IGMP_TYPE_MEM_REPORT_V2 (0x16) -#define IGMP_TYPE_LEAVE_GROUP (0x17) -#define IGMP_TYPE_MEM_REPORT_V3 (0x22) - -/* group record types */ -#define IGMP_MODE_IS_INCLUDE (1) -#define IGMP_MODE_IS_EXCLUDE (2) -#define IGMP_CHANGE_TO_INCLUDE_MODE (3) -#define IGMP_CHANGE_TO_EXCLUDE_MODE (4) -#define IGMP_ALLOW_NEW_SOURCES (5) -#define IGMP_BLOCK_OLD_SOURCES (6) - -/* host flag */ -#define IGMP_HOST_LAST (0x1) -#define IGMP_HOST_NOT_LAST (0x0) - -/* list of timers, counters and their default values */ -#define IGMP_ROBUSTNESS (2u) -#define IGMP_QUERY_INTERVAL (125) /* secs */ -#define IGMP_QUERY_RESPONSE_INTERVAL (10u) /* secs */ -#define IGMP_STARTUP_QUERY_INTERVAL (IGMPV3_QUERY_INTERVAL / 4) -#define IGMP_STARTUP_QUERY_COUNT (IGMPV3_ROBUSTNESS) -#define IGMP_LAST_MEMBER_QUERY_INTERVAL (1) /* secs */ -#define IGMP_LAST_MEMBER_QUERY_COUNT (IGMPV3_ROBUSTNESS) -#define IGMP_UNSOLICITED_REPORT_INTERVAL (1) /* secs */ -#define IGMP_DEFAULT_MAX_RESPONSE_TIME (100) - -/* custom timers types */ -#define IGMP_TIMER_GROUP_REPORT (1) -#define IGMP_TIMER_V1_QUERIER (2) -#define IGMP_TIMER_V2_QUERIER (3) - -/* IGMP groups */ -#define IGMP_ALL_HOST_GROUP long_be(0xE0000001) /* 224.0.0.1 */ -#define IGMP_ALL_ROUTER_GROUP long_be(0xE0000002) /* 224.0.0.2 */ -#define IGMPV3_ALL_ROUTER_GROUP long_be(0xE0000016) /* 224.0.0.22 */ - -/* misc */ -#define IGMP_TIMER_STOPPED (1) -#define IP_OPTION_ROUTER_ALERT_LEN (4u) -#define IGMP_MAX_GROUPS (32) /* max 255 */ - -PACKED_STRUCT_DEF igmp_message { - uint8_t type; - uint8_t max_resp_time; - uint16_t crc; - uint32_t mcast_group; -}; - -PACKED_STRUCT_DEF igmpv3_query { - uint8_t type; - uint8_t max_resp_time; - uint16_t crc; - uint32_t mcast_group; - uint8_t rsq; - uint8_t qqic; - uint16_t sources; -}; - -PACKED_STRUCT_DEF igmpv3_group_record { - uint8_t type; - uint8_t aux; - uint16_t sources; - uint32_t mcast_group; -}; - -PACKED_STRUCT_DEF igmpv3_report { - uint8_t type; - uint8_t res0; - uint16_t crc; - uint16_t res1; - uint16_t groups; -}; - -struct igmp_parameters { - uint8_t event; - uint8_t state; - uint8_t last_host; - uint8_t filter_mode; - uint8_t max_resp_time; - struct pico_ip4 mcast_link; - struct pico_ip4 mcast_group; - struct pico_tree *MCASTFilter; - struct pico_frame *f; -}; - -struct igmp_timer { - uint8_t type; - uint8_t stopped; - pico_time start; - pico_time delay; - struct pico_ip4 mcast_link; - struct pico_ip4 mcast_group; - struct pico_frame *f; - void (*callback)(struct igmp_timer *t); -}; - -/* queues */ -static struct pico_queue igmp_in = { - 0 -}; -static struct pico_queue igmp_out = { - 0 -}; - -/* finite state machine caller */ -static int pico_igmp_process_event(struct igmp_parameters *p); - -/* state callback prototype */ -typedef int (*callback)(struct igmp_parameters *); - -static inline int igmpt_type_compare(struct igmp_timer *a, struct igmp_timer *b) -{ - if (a->type < b->type) - return -1; - - if (a->type > b->type) - return 1; - - return 0; -} - - -static inline int igmpt_group_compare(struct igmp_timer *a, struct igmp_timer *b) -{ - return pico_ipv4_compare(&a->mcast_group, &b->mcast_group); -} - -static inline int igmpt_link_compare(struct igmp_timer *a, struct igmp_timer *b) -{ - return pico_ipv4_compare(&a->mcast_link, &b->mcast_link); -} - -/* redblack trees */ -static int igmp_timer_cmp(void *ka, void *kb) -{ - struct igmp_timer *a = ka, *b = kb; - int cmp = igmpt_type_compare(a, b); - if (cmp) - return cmp; - - cmp = igmpt_group_compare(a, b); - if (cmp) - return cmp; - - return igmpt_link_compare(a, b); - -} -PICO_TREE_DECLARE(IGMPTimers, igmp_timer_cmp); - -static inline int igmpparm_group_compare(struct igmp_parameters *a, struct igmp_parameters *b) -{ - return pico_ipv4_compare(&a->mcast_group, &b->mcast_group); -} - -static inline int igmpparm_link_compare(struct igmp_parameters *a, struct igmp_parameters *b) -{ - return pico_ipv4_compare(&a->mcast_link, &b->mcast_link); -} - -static int igmp_parameters_cmp(void *ka, void *kb) -{ - struct igmp_parameters *a = ka, *b = kb; - int cmp = igmpparm_group_compare(a, b); - if (cmp) - return cmp; - - return igmpparm_link_compare(a, b); -} -PICO_TREE_DECLARE(IGMPParameters, igmp_parameters_cmp); - -static int igmp_sources_cmp(void *ka, void *kb) -{ - struct pico_ip4 *a = ka, *b = kb; - return pico_ipv4_compare(a, b); -} -PICO_TREE_DECLARE(IGMPAllow, igmp_sources_cmp); -PICO_TREE_DECLARE(IGMPBlock, igmp_sources_cmp); - -static struct igmp_parameters *pico_igmp_find_parameter(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group) -{ - struct igmp_parameters test = { - 0 - }; - if (!mcast_link || !mcast_group) - return NULL; - - test.mcast_link.addr = mcast_link->addr; - test.mcast_group.addr = mcast_group->addr; - return pico_tree_findKey(&IGMPParameters, &test); -} - -static int pico_igmp_delete_parameter(struct igmp_parameters *p) -{ - if (pico_tree_delete(&IGMPParameters, p)) - PICO_FREE(p); - else - return -1; - - return 0; -} - -static void pico_igmp_timer_expired(pico_time now, void *arg) -{ - struct igmp_timer *t = NULL, *timer = NULL, test = { - 0 - }; - - IGNORE_PARAMETER(now); - t = (struct igmp_timer *)arg; - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - igmp_dbg("IGMP: timer expired for %08X link %08X type %u, delay %lu\n", t->mcast_group.addr, t->mcast_link.addr, t->type, t->delay); - timer = pico_tree_findKey(&IGMPTimers, &test); - if (!timer) { - return; - } - - if (timer->stopped == IGMP_TIMER_STOPPED) { - pico_tree_delete(&IGMPTimers, timer); - PICO_FREE(t); - return; - } - - if (timer->start + timer->delay < PICO_TIME_MS()) { - pico_tree_delete(&IGMPTimers, timer); - if (timer->callback) - timer->callback(timer); - - PICO_FREE(timer); - } else { - igmp_dbg("IGMP: restart timer for %08X, delay %lu, new delay %lu\n", t->mcast_group.addr, t->delay, (timer->start + timer->delay) - PICO_TIME_MS()); - pico_timer_add((timer->start + timer->delay) - PICO_TIME_MS(), &pico_igmp_timer_expired, timer); - } - - return; -} - -static int pico_igmp_timer_reset(struct igmp_timer *t) -{ - struct igmp_timer *timer = NULL, test = { - 0 - }; - - igmp_dbg("IGMP: reset timer for %08X, delay %lu\n", t->mcast_group.addr, t->delay); - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&IGMPTimers, &test); - if (!timer) - return -1; - - *timer = *t; - timer->start = PICO_TIME_MS(); - return 0; -} - -static int pico_igmp_timer_start(struct igmp_timer *t) -{ - struct igmp_timer *timer = NULL, test = { - 0 - }; - - igmp_dbg("IGMP: start timer for %08X link %08X type %u, delay %lu\n", t->mcast_group.addr, t->mcast_link.addr, t->type, t->delay); - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&IGMPTimers, &test); - if (timer) - return pico_igmp_timer_reset(t); - - timer = PICO_ZALLOC(sizeof(struct igmp_timer)); - if (!timer) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - *timer = *t; - timer->start = PICO_TIME_MS(); - - pico_tree_insert(&IGMPTimers, timer); - pico_timer_add(timer->delay, &pico_igmp_timer_expired, timer); - return 0; -} - -static int pico_igmp_timer_stop(struct igmp_timer *t) -{ - struct igmp_timer *timer = NULL, test = { - 0 - }; - - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&IGMPTimers, &test); - if (!timer) - return -1; - - igmp_dbg("IGMP: stop timer for %08X, delay %lu\n", timer->mcast_group.addr, timer->delay); - timer->stopped = IGMP_TIMER_STOPPED; - return 0; -} - -static int pico_igmp_timer_is_running(struct igmp_timer *t) -{ - struct igmp_timer *timer = NULL, test = { - 0 - }; - - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&IGMPTimers, &test); - if (timer) - return 1; - - return 0; -} - -static struct igmp_timer *pico_igmp_find_timer(uint8_t type, struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group) -{ - struct igmp_timer test = { - 0 - }; - - test.type = type; - test.mcast_link = *mcast_link; - test.mcast_group = *mcast_group; - return pico_tree_findKey(&IGMPTimers, &test); -} - -static void pico_igmp_report_expired(struct igmp_timer *t) -{ - struct igmp_parameters *p = NULL; - - p = pico_igmp_find_parameter(&t->mcast_link, &t->mcast_group); - if (!p) - return; - - p->event = IGMP_EVENT_TIMER_EXPIRED; - pico_igmp_process_event(p); -} - -static void pico_igmp_v2querier_expired(struct igmp_timer *t) -{ - struct pico_ipv4_link *link = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL; - - link = pico_ipv4_link_by_dev(t->f->dev); - if (!link) - return; - - /* When changing compatibility mode, cancel all pending response - * and retransmission timers. - */ - pico_tree_foreach_safe(index, &IGMPTimers, _tmp) - { - ((struct igmp_timer *)index->keyValue)->stopped = IGMP_TIMER_STOPPED; - pico_tree_delete(&IGMPTimers, index->keyValue); - } - igmp_dbg("IGMP: switch to compatibility mode IGMPv3\n"); - link->mcast_compatibility = PICO_IGMPV3; - return; -} - -static int pico_igmp_is_checksum_valid(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = NULL; - uint8_t ihl = 24, datalen = 0; - - hdr = (struct pico_ipv4_hdr *)f->net_hdr; - ihl = (uint8_t)((hdr->vhl & 0x0F) * 4); /* IHL is in 32bit words */ - datalen = (uint8_t)(short_be(hdr->len) - ihl); - - if (short_be(pico_checksum(f->transport_hdr, datalen)) == 0) - return 1; - - igmp_dbg("IGMP: invalid checksum\n"); - return 0; -} - -/* RFC 3376 $7.1 */ -static int pico_igmp_compatibility_mode(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = NULL; - struct pico_ipv4_link *link = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct igmp_timer t = { - 0 - }; - uint8_t ihl = 24, datalen = 0; - - link = pico_ipv4_link_by_dev(f->dev); - if (!link) - return -1; - - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - ihl = (uint8_t)((hdr->vhl & 0x0F) * 4); /* IHL is in 32bit words */ - datalen = (uint8_t)(short_be(hdr->len) - ihl); - igmp_dbg("IGMP: IHL = %u, LEN = %u, OCTETS = %u\n", ihl, short_be(hdr->len), datalen); - - if (datalen >= 12) { - /* IGMPv3 query */ - t.type = IGMP_TIMER_V2_QUERIER; - if (pico_igmp_timer_is_running(&t)) { /* IGMPv2 querier present timer still running */ - igmp_dbg("Timer is already running\n"); - return -1; - } else { - link->mcast_compatibility = PICO_IGMPV3; - igmp_dbg("IGMP Compatibility: v3\n"); - return 0; - } - } else if (datalen == 8) { - struct igmp_message *query = (struct igmp_message *)f->transport_hdr; - if (query->max_resp_time != 0) { - /* IGMPv2 query */ - /* When changing compatibility mode, cancel all pending response - * and retransmission timers. - */ - pico_tree_foreach_safe(index, &IGMPTimers, _tmp) - { - ((struct igmp_timer *)index->keyValue)->stopped = IGMP_TIMER_STOPPED; - pico_tree_delete(&IGMPTimers, index->keyValue); - } - igmp_dbg("IGMP: switch to compatibility mode IGMPv2\n"); - link->mcast_compatibility = PICO_IGMPV2; - t.type = IGMP_TIMER_V2_QUERIER; - t.delay = ((IGMP_ROBUSTNESS * link->mcast_last_query_interval) + IGMP_QUERY_RESPONSE_INTERVAL) * 1000; - t.f = f; - t.callback = pico_igmp_v2querier_expired; - /* only one of this type of timer may exist! */ - pico_igmp_timer_start(&t); - } else { - /* IGMPv1 query, not supported */ - return -1; - } - } else { - /* invalid query, silently ignored */ - return -1; - } - - return 0; -} - -static struct igmp_parameters *pico_igmp_analyse_packet(struct pico_frame *f) -{ - struct igmp_message *message = NULL; - struct igmp_parameters *p = NULL; - struct pico_ipv4_link *link = NULL; - struct pico_ip4 mcast_group = { - 0 - }; - - link = pico_ipv4_link_by_dev(f->dev); - if (!link) - return NULL; - - /* IGMPv2 and IGMPv3 have a similar structure for the first 8 bytes */ - message = (struct igmp_message *)f->transport_hdr; - mcast_group.addr = message->mcast_group; - p = pico_igmp_find_parameter(&link->address, &mcast_group); - if (!p && mcast_group.addr == 0) { /* general query */ - p = PICO_ZALLOC(sizeof(struct igmp_parameters)); - if (!p) - return NULL; - - p->state = IGMP_STATE_NON_MEMBER; - p->mcast_link.addr = link->address.addr; - p->mcast_group.addr = mcast_group.addr; - pico_tree_insert(&IGMPParameters, p); - } else if (!p) { - return NULL; - } - - switch (message->type) { - case IGMP_TYPE_MEM_QUERY: - p->event = IGMP_EVENT_QUERY_RECV; - break; - case IGMP_TYPE_MEM_REPORT_V1: - p->event = IGMP_EVENT_REPORT_RECV; - break; - case IGMP_TYPE_MEM_REPORT_V2: - p->event = IGMP_EVENT_REPORT_RECV; - break; - case IGMP_TYPE_MEM_REPORT_V3: - p->event = IGMP_EVENT_REPORT_RECV; - break; - default: - return NULL; - } - p->max_resp_time = message->max_resp_time; /* if IGMPv3 report this will be 0 (res0 field) */ - p->f = f; - - return p; -} - -static int pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - struct igmp_parameters *p = NULL; - IGNORE_PARAMETER(self); - - if (!pico_igmp_is_checksum_valid(f)) - goto out; - - if (pico_igmp_compatibility_mode(f) < 0) - goto out; - - p = pico_igmp_analyse_packet(f); - if (!p) - goto out; - - return pico_igmp_process_event(p); - -out: - pico_frame_discard(f); - return 0; -} - -static int pico_igmp_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - /* packets are directly transferred to the IP layer by calling pico_ipv4_frame_push */ - IGNORE_PARAMETER(self); - IGNORE_PARAMETER(f); - return 0; -} - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_igmp = { - .name = "igmp", - .proto_number = PICO_PROTO_IGMP, - .layer = PICO_LAYER_TRANSPORT, - .process_in = pico_igmp_process_in, - .process_out = pico_igmp_process_out, - .q_in = &igmp_in, - .q_out = &igmp_out, -}; - -int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state) -{ - struct igmp_parameters *p = NULL; - - if (mcast_group->addr == IGMP_ALL_HOST_GROUP) - return 0; - - p = pico_igmp_find_parameter(mcast_link, mcast_group); - if (!p && state == PICO_IGMP_STATE_CREATE) { - p = PICO_ZALLOC(sizeof(struct igmp_parameters)); - if (!p) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if (!mcast_link || !mcast_group) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - p->state = IGMP_STATE_NON_MEMBER; - p->mcast_link = *mcast_link; - p->mcast_group = *mcast_group; - pico_tree_insert(&IGMPParameters, p); - } else if (!p) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (state) { - case PICO_IGMP_STATE_CREATE: - p->event = IGMP_EVENT_CREATE_GROUP; - break; - - case PICO_IGMP_STATE_UPDATE: - p->event = IGMP_EVENT_UPDATE_GROUP; - break; - - case PICO_IGMP_STATE_DELETE: - p->event = IGMP_EVENT_DELETE_GROUP; - break; - - default: - return -1; - } - p->filter_mode = filter_mode; - p->MCASTFilter = _MCASTFilter; - - return pico_igmp_process_event(p); -} - -static int pico_igmp_send_report(struct igmp_parameters *p, struct pico_frame *f) -{ - struct pico_ip4 dst = { - 0 - }; - struct pico_ip4 mcast_group = { - 0 - }; - struct pico_ipv4_link *link = NULL; - - link = pico_ipv4_link_get(&p->mcast_link); - if (!link) - return -1; - - mcast_group.addr = p->mcast_group.addr; - switch (link->mcast_compatibility) { - case PICO_IGMPV2: - if (p->event == IGMP_EVENT_DELETE_GROUP) - dst.addr = IGMP_ALL_ROUTER_GROUP; - else - dst.addr = mcast_group.addr; - - break; - - case PICO_IGMPV3: - dst.addr = IGMPV3_ALL_ROUTER_GROUP; - break; - - default: - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - } - - igmp_dbg("IGMP: send membership report on group %08X to %08X\n", mcast_group.addr, dst.addr); - pico_ipv4_frame_push(f, &dst, PICO_PROTO_IGMP); - return 0; -} - -static int8_t pico_igmp_generate_report(struct igmp_parameters *p) -{ - struct pico_ipv4_link *link = NULL; - int i = 0; - - link = pico_ipv4_link_get(&p->mcast_link); - if (!link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (link->mcast_compatibility) { - case PICO_IGMPV1: - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - - case PICO_IGMPV2: - { - struct igmp_message *report = NULL; - uint8_t report_type = IGMP_TYPE_MEM_REPORT_V2; - if (p->event == IGMP_EVENT_DELETE_GROUP) - report_type = IGMP_TYPE_LEAVE_GROUP; - - p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, IP_OPTION_ROUTER_ALERT_LEN + sizeof(struct igmp_message)); - p->f->net_len = (uint16_t)(p->f->net_len + IP_OPTION_ROUTER_ALERT_LEN); - p->f->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN; - p->f->transport_len = (uint16_t)(p->f->transport_len - IP_OPTION_ROUTER_ALERT_LEN); - p->f->dev = pico_ipv4_link_find(&p->mcast_link); - /* p->f->len is correctly set by alloc */ - - report = (struct igmp_message *)p->f->transport_hdr; - report->type = report_type; - report->max_resp_time = IGMP_DEFAULT_MAX_RESPONSE_TIME; - report->mcast_group = p->mcast_group.addr; - - report->crc = 0; - report->crc = short_be(pico_checksum(report, sizeof(struct igmp_message))); - break; - } - case PICO_IGMPV3: - { - struct igmpv3_report *report = NULL; - struct igmpv3_group_record *record = NULL; - struct pico_mcast_group *g = NULL, test = { - 0 - }; - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_tree *IGMPFilter = NULL; - struct pico_ip4 *source = NULL; - uint8_t record_type = 0; - uint8_t sources = 0; - uint16_t len = 0; - - test.mcast_addr = p->mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (!g) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (p->event == IGMP_EVENT_DELETE_GROUP) { /* "non-existent" state of filter mode INCLUDE and empty source list */ - p->filter_mode = PICO_IP_MULTICAST_INCLUDE; - p->MCASTFilter = NULL; - } - - if (p->event == IGMP_EVENT_QUERY_RECV) { - goto igmp3_report; - } - - - /* cleanup filters */ - pico_tree_foreach_safe(index, &IGMPAllow, _tmp) - { - pico_tree_delete(&IGMPAllow, index->keyValue); - } - pico_tree_foreach_safe(index, &IGMPBlock, _tmp) - { - pico_tree_delete(&IGMPBlock, index->keyValue); - } - - switch (g->filter_mode) { - - case PICO_IP_MULTICAST_INCLUDE: - switch (p->filter_mode) { - case PICO_IP_MULTICAST_INCLUDE: - if (p->event == IGMP_EVENT_DELETE_GROUP) { /* all ADD_SOURCE_MEMBERSHIP had an equivalent DROP_SOURCE_MEMBERSHIP */ - /* TO_IN (B) */ - record_type = IGMP_CHANGE_TO_INCLUDE_MODE; - IGMPFilter = &IGMPAllow; - if (p->MCASTFilter) { - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&IGMPAllow, index->keyValue); - sources++; - } - } /* else { IGMPAllow stays empty } */ - - break; - } - - /* ALLOW (B-A) */ - /* if event is CREATE A will be empty, thus only ALLOW (B-A) has sense */ - if (p->event == IGMP_EVENT_CREATE_GROUP) /* first ADD_SOURCE_MEMBERSHIP */ - record_type = IGMP_CHANGE_TO_INCLUDE_MODE; - else - record_type = IGMP_ALLOW_NEW_SOURCES; - - IGMPFilter = &IGMPAllow; - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&IGMPAllow, index->keyValue); - sources++; - } - pico_tree_foreach(index, &g->MCASTSources) /* A */ - { - source = pico_tree_findKey(&IGMPAllow, index->keyValue); - if (source) { - pico_tree_delete(&IGMPAllow, source); - sources--; - } - } - if (!pico_tree_empty(&IGMPAllow)) /* record type is ALLOW */ - break; - - /* BLOCK (A-B) */ - record_type = IGMP_BLOCK_OLD_SOURCES; - IGMPFilter = &IGMPBlock; - pico_tree_foreach(index, &g->MCASTSources) /* A */ - { - pico_tree_insert(&IGMPBlock, index->keyValue); - sources++; - } - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - source = pico_tree_findKey(&IGMPBlock, index->keyValue); - if (source) { - pico_tree_delete(&IGMPBlock, source); - sources--; - } - } - if (!pico_tree_empty(&IGMPBlock)) /* record type is BLOCK */ - break; - - /* ALLOW (B-A) and BLOCK (A-B) are empty: do not send report (RFC 3376 $5.1) */ - p->f = NULL; - return 0; - - case PICO_IP_MULTICAST_EXCLUDE: - /* TO_EX (B) */ - record_type = IGMP_CHANGE_TO_EXCLUDE_MODE; - IGMPFilter = &IGMPBlock; - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&IGMPBlock, index->keyValue); - sources++; - } - break; - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - break; - - case PICO_IP_MULTICAST_EXCLUDE: - switch (p->filter_mode) { - case PICO_IP_MULTICAST_INCLUDE: - /* TO_IN (B) */ - record_type = IGMP_CHANGE_TO_INCLUDE_MODE; - IGMPFilter = &IGMPAllow; - if (p->MCASTFilter) { - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&IGMPAllow, index->keyValue); - sources++; - } - } /* else { IGMPAllow stays empty } */ - - break; - - case PICO_IP_MULTICAST_EXCLUDE: - /* BLOCK (B-A) */ - record_type = IGMP_BLOCK_OLD_SOURCES; - IGMPFilter = &IGMPBlock; - pico_tree_foreach(index, p->MCASTFilter) - { - pico_tree_insert(&IGMPBlock, index->keyValue); - sources++; - } - pico_tree_foreach(index, &g->MCASTSources) /* A */ - { - source = pico_tree_findKey(&IGMPBlock, index->keyValue); /* B */ - if (source) { - pico_tree_delete(&IGMPBlock, source); - sources--; - } - } - if (!pico_tree_empty(&IGMPBlock)) /* record type is BLOCK */ - break; - - /* ALLOW (A-B) */ - record_type = IGMP_ALLOW_NEW_SOURCES; - IGMPFilter = &IGMPAllow; - pico_tree_foreach(index, &g->MCASTSources) - { - pico_tree_insert(&IGMPAllow, index->keyValue); - sources++; - } - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - source = pico_tree_findKey(&IGMPAllow, index->keyValue); /* A */ - if (source) { - pico_tree_delete(&IGMPAllow, source); - sources--; - } - } - if (!pico_tree_empty(&IGMPAllow)) /* record type is ALLOW */ - break; - - /* BLOCK (B-A) and ALLOW (A-B) are empty: do not send report (RFC 3376 $5.1) */ - p->f = NULL; - return 0; - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - break; - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - -igmp3_report: - len = (uint16_t)(sizeof(struct igmpv3_report) + sizeof(struct igmpv3_group_record) + (sources * sizeof(struct pico_ip4))); - p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t)(IP_OPTION_ROUTER_ALERT_LEN + len)); - p->f->net_len = (uint16_t)(p->f->net_len + IP_OPTION_ROUTER_ALERT_LEN); - p->f->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN; - p->f->transport_len = (uint16_t)(p->f->transport_len - IP_OPTION_ROUTER_ALERT_LEN); - p->f->dev = pico_ipv4_link_find(&p->mcast_link); - /* p->f->len is correctly set by alloc */ - - report = (struct igmpv3_report *)p->f->transport_hdr; - report->type = IGMP_TYPE_MEM_REPORT_V3; - report->res0 = 0; - report->crc = 0; - report->res1 = 0; - report->groups = short_be(1); - - record = (struct igmpv3_group_record *)(((uint8_t *)report) + sizeof(struct igmpv3_report)); - record->type = record_type; - record->aux = 0; - record->sources = short_be(sources); - record->mcast_group = p->mcast_group.addr; - if (IGMPFilter && !pico_tree_empty(IGMPFilter)) { - uint32_t *source_addr = (uint32_t *)((void *)((uint8_t *)record + sizeof(struct igmpv3_group_record))); - i = 0; - pico_tree_foreach(index, IGMPFilter) - { - source_addr[i] = ((struct pico_ip4 *)index->keyValue)->addr; - i++; - } - } - - report->crc = short_be(pico_checksum(report, len)); - break; - } - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - return 0; -} - -/* stop timer, send leave if flag set */ -static int stslifs(struct igmp_parameters *p) -{ - struct igmp_timer t = { - 0 - }; - - igmp_dbg("IGMP: event = leave group | action = stop timer, send leave if flag set\n"); - - t.type = IGMP_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - if (pico_igmp_timer_stop(&t) < 0) - return -1; - - /* always send leave, even if not last host */ - if (pico_igmp_send_report(p, p->f) < 0) - return -1; - - pico_igmp_delete_parameter(p); - igmp_dbg("IGMP: new state = non-member\n"); - return 0; -} - -/* send report, set flag, start timer */ -static int srsfst(struct igmp_parameters *p) -{ - struct igmp_timer t = { - 0 - }; - struct pico_frame *copy_frame = NULL; - - igmp_dbg("IGMP: event = join group | action = send report, set flag, start timer\n"); - - p->last_host = IGMP_HOST_LAST; - - if (pico_igmp_generate_report(p) < 0) - return -1; - - if (!p->f) - return 0; - - copy_frame = pico_frame_copy(p->f); - if (!copy_frame) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if (pico_igmp_send_report(p, copy_frame) < 0) - return -1; - - t.type = IGMP_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - t.delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); - t.f = p->f; - t.callback = pico_igmp_report_expired; - pico_igmp_timer_start(&t); - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -/* merge report, send report, reset timer (IGMPv3 only) */ -static int mrsrrt(struct igmp_parameters *p) -{ - struct igmp_timer *t = NULL; - struct pico_frame *copy_frame = NULL; - struct pico_ipv4_link *link = NULL; - - igmp_dbg("IGMP: event = update group | action = merge report, send report, reset timer (IGMPv3 only)\n"); - - link = pico_ipv4_link_get(&p->mcast_link); - if (!link) - return -1; - - if (link->mcast_compatibility != PICO_IGMPV3) { - igmp_dbg("IGMP: no IGMPv3 compatible router on network\n"); - return -1; - } - - /* XXX: merge with pending report rfc 3376 $5.1 */ - - copy_frame = pico_frame_copy(p->f); - if (!copy_frame) - return -1; - - if (pico_igmp_send_report(p, copy_frame) < 0) - return -1; - - t = pico_igmp_find_timer(IGMP_TIMER_GROUP_REPORT, &p->mcast_link, &p->mcast_group); - if (!t) - return -1; - - t->delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); - pico_igmp_timer_reset(t); - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -/* send report, start timer (IGMPv3 only) */ -static int srst(struct igmp_parameters *p) -{ - struct igmp_timer t = { - 0 - }; - struct pico_frame *copy_frame = NULL; - struct pico_ipv4_link *link = NULL; - - igmp_dbg("IGMP: event = update group | action = send report, start timer (IGMPv3 only)\n"); - - link = pico_ipv4_link_get(&p->mcast_link); - if (!link) - return -1; - - if (link->mcast_compatibility != PICO_IGMPV3) { - igmp_dbg("IGMP: no IGMPv3 compatible router on network\n"); - return -1; - } - - if (pico_igmp_generate_report(p) < 0) - return -1; - - if (!p->f) - return 0; - - copy_frame = pico_frame_copy(p->f); - if (!copy_frame) - return -1; - - if (pico_igmp_send_report(p, copy_frame) < 0) - return -1; - - t.type = IGMP_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - t.delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); - t.f = p->f; - t.callback = pico_igmp_report_expired; - pico_igmp_timer_start(&t); - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -/* send leave if flag set */ -static int slifs(struct igmp_parameters *p) -{ - igmp_dbg("IGMP: event = leave group | action = send leave if flag set\n"); - - /* always send leave, even if not last host */ - if (pico_igmp_send_report(p, p->f) < 0) - return -1; - - pico_igmp_delete_parameter(p); - igmp_dbg("IGMP: new state = non-member\n"); - return 0; -} - -/* start timer */ -static int st(struct igmp_parameters *p) -{ - struct igmp_timer t = { - 0 - }; - - igmp_dbg("IGMP: event = query received | action = start timer\n"); - - if (pico_igmp_generate_report(p) < 0) { - igmp_dbg("Failed to generate report\n"); - return -1; - } - - if (!p->f) { - igmp_dbg("No pending frame\n"); - return -1; - } - - t.type = IGMP_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - t.delay = (pico_rand() % ((1u + p->max_resp_time) * 100u)); - t.f = p->f; - t.callback = pico_igmp_report_expired; - pico_igmp_timer_start(&t); - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -/* stop timer, clear flag */ -static int stcl(struct igmp_parameters *p) -{ - struct igmp_timer t = { - 0 - }; - - igmp_dbg("IGMP: event = report received | action = stop timer, clear flag\n"); - - t.type = IGMP_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - if (pico_igmp_timer_stop(&t) < 0) - return -1; - - p->last_host = IGMP_HOST_NOT_LAST; - p->state = IGMP_STATE_IDLE_MEMBER; - igmp_dbg("IGMP: new state = idle member\n"); - return 0; -} - -/* send report, set flag */ -static int srsf(struct igmp_parameters *p) -{ - igmp_dbg("IGMP: event = timer expired | action = send report, set flag\n"); - - if (pico_igmp_send_report(p, p->f) < 0) - return -1; - - p->state = IGMP_STATE_IDLE_MEMBER; - igmp_dbg("IGMP: new state = idle member\n"); - return 0; -} - -/* reset timer if max response time < current timer */ -static int rtimrtct(struct igmp_parameters *p) -{ - struct igmp_timer *t = NULL; - uint32_t time_to_run = 0; - - igmp_dbg("IGMP: event = query received | action = reset timer if max response time < current timer\n"); - - t = pico_igmp_find_timer(IGMP_TIMER_GROUP_REPORT, &p->mcast_link, &p->mcast_group); - if (!t) - return -1; - - time_to_run = (uint32_t)(t->start + t->delay - PICO_TIME_MS()); - if ((p->max_resp_time * 100u) < time_to_run) { /* max_resp_time in units of 1/10 seconds */ - t->delay = pico_rand() % ((1u + p->max_resp_time) * 100u); - pico_igmp_timer_reset(t); - } - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -static int discard(struct igmp_parameters *p) -{ - igmp_dbg("IGMP: ignore and discard frame\n"); - pico_frame_discard(p->f); - return 0; -} - -/* finite state machine table */ -const callback host_membership_diagram_table[3][6] = -{ /* event |Delete Group |Create Group |Update Group |Query Received |Report Received |Timer Expired */ -/* state Non-Member */ - { discard, srsfst, srsfst, discard, discard, discard }, -/* state Delaying Member */ { stslifs, mrsrrt, mrsrrt, rtimrtct, stcl, srsf }, -/* state Idle Member */ { slifs, srst, srst, st, discard, discard } -}; - -static int pico_igmp_process_event(struct igmp_parameters *p) -{ - struct pico_tree_node *index = NULL; - struct igmp_parameters *_p = NULL; - - igmp_dbg("IGMP: process event on group address %08X\n", p->mcast_group.addr); - if (p->event == IGMP_EVENT_QUERY_RECV && p->mcast_group.addr == 0) { /* general query */ - pico_tree_foreach(index, &IGMPParameters) { - _p = index->keyValue; - _p->max_resp_time = p->max_resp_time; - _p->event = IGMP_EVENT_QUERY_RECV; - igmp_dbg("IGMP: for each mcast_group = %08X | state = %u\n", _p->mcast_group.addr, _p->state); - host_membership_diagram_table[_p->state][_p->event](_p); - } - } else { - igmp_dbg("IGMP: state = %u (0: non-member - 1: delaying member - 2: idle member)\n", p->state); - host_membership_diagram_table[p->state][p->event](p); - } - - return 0; -} - -#else -static struct pico_queue igmp_in = { - 0 -}; -static struct pico_queue igmp_out = { - 0 -}; - -static int pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f) { - IGNORE_PARAMETER(self); - IGNORE_PARAMETER(f); - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static int pico_igmp_process_out(struct pico_protocol *self, struct pico_frame *f) { - IGNORE_PARAMETER(self); - IGNORE_PARAMETER(f); - return -1; -} - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_igmp = { - .name = "igmp", - .proto_number = PICO_PROTO_IGMP, - .layer = PICO_LAYER_TRANSPORT, - .process_in = pico_igmp_process_in, - .process_out = pico_igmp_process_out, - .q_in = &igmp_in, - .q_out = &igmp_out, -}; - -int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state) { - IGNORE_PARAMETER(mcast_link); - IGNORE_PARAMETER(mcast_group); - IGNORE_PARAMETER(filter_mode); - IGNORE_PARAMETER(_MCASTFilter); - IGNORE_PARAMETER(state); - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} -#endif diff --git a/ext/picotcp/modules/pico_igmp.h b/ext/picotcp/modules/pico_igmp.h deleted file mode 100644 index 6f8d74e..0000000 --- a/ext/picotcp/modules/pico_igmp.h +++ /dev/null @@ -1,26 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Kristof Roelants, Simon Maes, Brecht Van Cauwenberghe - *********************************************************************/ - -#ifndef INCLUDE_PICO_IGMP -#define INCLUDE_PICO_IGMP - -#define PICO_IGMPV1 1 -#define PICO_IGMPV2 2 -#define PICO_IGMPV3 3 - -#define PICO_IGMP_STATE_CREATE 1 -#define PICO_IGMP_STATE_UPDATE 2 -#define PICO_IGMP_STATE_DELETE 3 - -#define PICO_IGMP_QUERY_INTERVAL 125 - -extern struct pico_protocol pico_proto_igmp; - -int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state); -#endif /* _INCLUDE_PICO_IGMP */ diff --git a/ext/picotcp/modules/pico_ipfilter.c b/ext/picotcp/modules/pico_ipfilter.c deleted file mode 100644 index 64ee349..0000000 --- a/ext/picotcp/modules/pico_ipfilter.c +++ /dev/null @@ -1,458 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Andrei Carp - Simon Maes - *********************************************************************/ - -#include "pico_ipv4.h" -#include "pico_config.h" -#include "pico_icmp4.h" -#include "pico_stack.h" -#include "pico_eth.h" -#include "pico_socket.h" -#include "pico_device.h" -#include "pico_ipfilter.h" -#include "pico_tcp.h" -#include "pico_udp.h" -#include "pico_tree.h" - -/**************** LOCAL MACROS ****************/ -#define MAX_PRIORITY (10) -#define MIN_PRIORITY (-10) - -#define ipf_dbg(...) do {} while(0) - -/**************** LOCAL DECLARATIONS ****************/ -struct filter_node; -static int filter_compare(void *filterA, void *filterB); - -/**************** FILTER TREE ****************/ - -struct filter_node { - struct pico_device *fdev; - /* output address */ - uint32_t out_addr; - uint32_t out_addr_netmask; - /* input address */ - uint32_t in_addr; - uint32_t in_addr_netmask; - /* transport */ - uint16_t out_port; - uint16_t in_port; - /* filter details */ - uint8_t proto; - int8_t priority; - uint8_t tos; - uint32_t filter_id; - int (*function_ptr)(struct filter_node *filter, struct pico_frame *f); -}; - -PICO_TREE_DECLARE(filter_tree, &filter_compare); - -static inline int ipfilter_uint32_cmp(uint32_t a, uint32_t b) -{ - if (a < b) - return -1; - - if (b < a) - return 1; - - return 0; -} - -static inline int ipfilter_uint16_cmp(uint16_t a, uint16_t b) -{ - if (a < b) - return -1; - - if (b < a) - return 1; - - return 0; -} - -static inline int ipfilter_uint8_cmp(uint8_t a, uint8_t b) -{ - if (a < b) - return -1; - - if (b < a) - return 1; - - return 0; -} - -static inline int ipfilter_ptr_cmp(void *a, void *b) -{ - if (a < b) - return -1; - - if (b < a) - return 1; - - return 0; -} - - - -static inline int filter_compare_ports(struct filter_node *a, struct filter_node *b) -{ - int cmp; - cmp = ipfilter_uint16_cmp(a->in_port, b->in_port); - if (cmp) - return cmp; - - cmp = ipfilter_uint16_cmp(a->out_port, b->out_port); - return cmp; -} - -static inline int filter_compare_addresses(struct filter_node *a, struct filter_node *b) -{ - int cmp; - /* Compare source address */ - cmp = ipfilter_uint32_cmp((a->in_addr & a->in_addr_netmask), (b->in_addr & b->in_addr_netmask)); - if (cmp) - return cmp; - - /* Compare destination address */ - cmp = ipfilter_uint32_cmp((a->out_addr & a->out_addr_netmask), (b->out_addr & b->out_addr_netmask)); - return cmp; -} - -static inline int filter_compare_proto(struct filter_node *a, struct filter_node *b) -{ - return ipfilter_uint8_cmp(a->proto, b->proto); -} - -static inline int filter_compare_address_port(struct filter_node *a, struct filter_node *b) -{ - int cmp; - cmp = filter_compare_addresses(a, b); - if (cmp) - return cmp; - - return filter_compare_ports(a, b); -} - -static inline int filter_match_packet_dev(struct filter_node *a, struct filter_node *b, struct filter_node *rule) -{ - int cmp; - /* 1. Compare devices */ - if (rule->fdev) { - cmp = ipfilter_ptr_cmp(a->fdev, b->fdev); - if (cmp) - return cmp; - } - - return 0; - -} - -static inline int filter_match_packet_proto(struct filter_node *a, struct filter_node *b, struct filter_node *rule) -{ - int cmp; - /* 2. Compare protocol */ - if (rule->proto) { - cmp = filter_compare_proto(a, b); - if (cmp) - return cmp; - } - - return 0; - -} -static inline int filter_match_packet_addr_in(struct filter_node *a, struct filter_node *b, struct filter_node *rule) -{ - int cmp; - /* 3. Compare addresses order: in, out */ - if (rule->in_addr_netmask) { - cmp = ipfilter_uint32_cmp(a->in_addr & rule->in_addr_netmask, b->in_addr & rule->in_addr_netmask); - if (cmp) - return cmp; - } - - return 0; -} -static inline int filter_match_packet_addr_out(struct filter_node *a, struct filter_node *b, struct filter_node *rule) -{ - int cmp; - if (rule->out_addr_netmask) { - cmp = ipfilter_uint32_cmp(a->out_addr & rule->out_addr_netmask, b->out_addr & rule->out_addr_netmask); - if (cmp) { - return cmp; - } - } - - return 0; -} -static inline int filter_match_packet_port_in(struct filter_node *a, struct filter_node *b, struct filter_node *rule) -{ - int cmp; - /* 4. Compare ports order: in, out */ - if (rule->in_port) { - cmp = ipfilter_uint16_cmp(a->in_port, b->in_port); - if (cmp) - return cmp; - } - - return 0; -} -static inline int filter_match_packet_port_out(struct filter_node *a, struct filter_node *b, struct filter_node *rule) -{ - int cmp; - if (rule->out_port) { - cmp = ipfilter_uint16_cmp(a->out_port, b->out_port); - if (cmp) - return cmp; - } - - return 0; -} - -static inline int filter_match_packet_dev_and_proto(struct filter_node *a, struct filter_node *b, struct filter_node *rule) -{ - int cmp = filter_match_packet_dev(a, b, rule); - if (cmp) - return cmp; - - return filter_match_packet_proto(a, b, rule); -} - -static inline int filter_match_packet_addr(struct filter_node *a, struct filter_node *b, struct filter_node *rule) -{ - int cmp = filter_match_packet_addr_in(a, b, rule); - if (cmp) - return cmp; - - return filter_match_packet_addr_out(a, b, rule); - -} - -static inline int filter_match_packet_port(struct filter_node *a, struct filter_node *b, struct filter_node *rule) -{ - int cmp = filter_match_packet_port_in(a, b, rule); - if (cmp) - return cmp; - - return filter_match_packet_port_out(a, b, rule); -} - -static inline struct filter_node *filter_match_packet_find_rule(struct filter_node *a, struct filter_node *b) -{ - if (!a->filter_id) - return b; - - return a; -} - -static inline int filter_match_packet(struct filter_node *a, struct filter_node *b) -{ - struct filter_node *rule; - int cmp = 0; - rule = filter_match_packet_find_rule(a, b); - - cmp = filter_match_packet_dev_and_proto(a, b, rule); - if (cmp) - return cmp; - - cmp = filter_match_packet_addr(a, b, rule); - if (cmp) - return cmp; - - cmp = filter_match_packet_port(a, b, rule); - if (cmp) - return cmp; - - return 0; -} - - -int filter_compare(void *filterA, void *filterB) -{ - - struct filter_node *a = (struct filter_node *)filterA; - struct filter_node *b = (struct filter_node *)filterB; - int cmp = 0; - if (a->filter_id == 0 || b->filter_id == 0) { - return filter_match_packet(a, b); - } - - /* improve the search */ - if(a->filter_id == b->filter_id) - return 0; - - /* 1. Compare devices */ - cmp = ipfilter_ptr_cmp(a->fdev, a->fdev); - if (cmp) - return cmp; - - /* 2. Compare protocol */ - cmp = filter_compare_proto(a, b); - if(cmp) - return cmp; - - /* 3. Compare addresses order: in, out */ - /* 4. Compare ports order: in, out */ - cmp = filter_compare_address_port(a, b); - - return cmp; -} - -/**************** FILTER CALLBACKS ****************/ - -static int fp_priority(struct filter_node *filter, struct pico_frame *f) -{ - /* TODO do priority-stuff */ - IGNORE_PARAMETER(filter); - IGNORE_PARAMETER(f); - return 0; -} - -static int fp_reject(struct filter_node *filter, struct pico_frame *f) -{ -/* TODO check first if sender is pico itself or not */ - IGNORE_PARAMETER(filter); - ipf_dbg("ipfilter> reject\n"); - (void)pico_icmp4_packet_filtered(f); - pico_frame_discard(f); - return 1; -} - -static int fp_drop(struct filter_node *filter, struct pico_frame *f) -{ - IGNORE_PARAMETER(filter); - ipf_dbg("ipfilter> drop\n"); - pico_frame_discard(f); - return 1; -} - -struct fp_function { - int (*fn)(struct filter_node *filter, struct pico_frame *f); -}; - - -static const struct fp_function fp_function[FILTER_COUNT] = -{ - {&fp_priority}, - {&fp_reject}, - {&fp_drop} -}; - -static int pico_ipv4_filter_add_validate(int8_t priority, enum filter_action action) -{ - if ( priority > MAX_PRIORITY || priority < MIN_PRIORITY) { - return -1; - } - - if (action >= FILTER_COUNT) { - return -1; - } - - return 0; -} - - -/**************** FILTER API's ****************/ -uint32_t pico_ipv4_filter_add(struct pico_device *dev, uint8_t proto, - struct pico_ip4 *out_addr, struct pico_ip4 *out_addr_netmask, - struct pico_ip4 *in_addr, struct pico_ip4 *in_addr_netmask, - uint16_t out_port, uint16_t in_port, int8_t priority, - uint8_t tos, enum filter_action action) -{ - static uint32_t filter_id = 1u; /* 0 is a special value used in the binary-tree search for packets being processed */ - struct filter_node *new_filter; - - if (pico_ipv4_filter_add_validate(priority, action) < 0) { - pico_err = PICO_ERR_EINVAL; - return 0; - } - - new_filter = PICO_ZALLOC(sizeof(struct filter_node)); - if (!new_filter) { - pico_err = PICO_ERR_ENOMEM; - return 0; - } - - new_filter->fdev = dev; - new_filter->proto = proto; - new_filter->out_addr = (!out_addr) ? (0U) : (out_addr->addr); - new_filter->out_addr_netmask = (!out_addr_netmask) ? (0U) : (out_addr_netmask->addr); - new_filter->in_addr = (!in_addr) ? (0U) : (in_addr->addr); - new_filter->in_addr_netmask = (!in_addr_netmask) ? (0U) : (in_addr_netmask->addr); - new_filter->out_port = out_port; - new_filter->in_port = in_port; - new_filter->priority = priority; - new_filter->tos = tos; - new_filter->filter_id = filter_id++; - new_filter->function_ptr = fp_function[action].fn; - - if(pico_tree_insert(&filter_tree, new_filter)) - { - PICO_FREE(new_filter); - filter_id--; - return 0; - } - - return new_filter->filter_id; -} - -int pico_ipv4_filter_del(uint32_t filter_id) -{ - struct filter_node *node = NULL; - struct filter_node dummy = { 0 }; - - dummy.filter_id = filter_id; - if((node = pico_tree_delete(&filter_tree, &dummy)) == NULL) - { - ipf_dbg("ipfilter> failed to delete filter :%d\n", filter_id); - return -1; - } - - PICO_FREE(node); - return 0; -} - -static int ipfilter_apply_filter(struct pico_frame *f, struct filter_node *pkt) -{ - struct filter_node *filter_frame = NULL; - filter_frame = pico_tree_findKey(&filter_tree, pkt); - if(filter_frame) - { - filter_frame->function_ptr(filter_frame, f); - return 1; - } - - return 0; -} - -int ipfilter(struct pico_frame *f) -{ - struct filter_node temp; - struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_trans *trans; - struct pico_icmp4_hdr *icmp_hdr; - - memset(&temp, 0u, sizeof(struct filter_node)); - - temp.fdev = f->dev; - temp.out_addr = ipv4_hdr->dst.addr; - temp.in_addr = ipv4_hdr->src.addr; - if ((ipv4_hdr->proto == PICO_PROTO_TCP) || (ipv4_hdr->proto == PICO_PROTO_UDP)) { - trans = (struct pico_trans *) f->transport_hdr; - temp.out_port = short_be(trans->dport); - temp.in_port = short_be(trans->sport); - } - else if(ipv4_hdr->proto == PICO_PROTO_ICMP4) { - icmp_hdr = (struct pico_icmp4_hdr *) f->transport_hdr; - if(icmp_hdr->type == PICO_ICMP_UNREACH && icmp_hdr->type == PICO_ICMP_UNREACH_FILTER_PROHIB) - return 0; - } - - temp.proto = ipv4_hdr->proto; - temp.priority = f->priority; - temp.tos = ipv4_hdr->tos; - return ipfilter_apply_filter(f, &temp); -} - diff --git a/ext/picotcp/modules/pico_ipfilter.h b/ext/picotcp/modules/pico_ipfilter.h deleted file mode 100644 index fb92e67..0000000 --- a/ext/picotcp/modules/pico_ipfilter.h +++ /dev/null @@ -1,29 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Simon Maes - *********************************************************************/ -#ifndef INCLUDE_PICO_IPFILTER -#define INCLUDE_PICO_IPFILTER - -#include "pico_device.h" - -enum filter_action { - FILTER_PRIORITY = 0, - FILTER_REJECT, - FILTER_DROP, - FILTER_COUNT -}; - -uint32_t pico_ipv4_filter_add(struct pico_device *dev, uint8_t proto, - struct pico_ip4 *out_addr, struct pico_ip4 *out_addr_netmask, struct pico_ip4 *in_addr, - struct pico_ip4 *in_addr_netmask, uint16_t out_port, uint16_t in_port, - int8_t priority, uint8_t tos, enum filter_action action); - -int pico_ipv4_filter_del(uint32_t filter_id); - -int ipfilter(struct pico_frame *f); - -#endif /* _INCLUDE_PICO_IPFILTER */ - diff --git a/ext/picotcp/modules/pico_ipv4.c b/ext/picotcp/modules/pico_ipv4.c deleted file mode 100644 index 7159549..0000000 --- a/ext/picotcp/modules/pico_ipv4.c +++ /dev/null @@ -1,1585 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera, Markian Yskout - *********************************************************************/ - - -#include "pico_config.h" -#include "pico_ipfilter.h" -#include "pico_ipv4.h" -#include "pico_icmp4.h" -#include "pico_stack.h" -#include "pico_eth.h" -#include "pico_udp.h" -#include "pico_tcp.h" -#include "pico_socket.h" -#include "pico_device.h" -#include "pico_nat.h" -#include "pico_igmp.h" -#include "pico_tree.h" -#include "pico_aodv.h" -#include "pico_socket_multicast.h" -#include "pico_fragments.h" - -#ifdef PICO_SUPPORT_IPV4 - -#ifdef PICO_SUPPORT_MCAST -# define ip_mcast_dbg(...) do {} while(0) /* so_mcast_dbg in pico_socket.c */ -/* #define ip_mcast_dbg dbg */ -# define PICO_MCAST_ALL_HOSTS long_be(0xE0000001) /* 224.0.0.1 */ -/* Default network interface for multicast transmission */ -static struct pico_ipv4_link *mcast_default_link = NULL; -#endif -#ifdef PICO_SUPPORT_IPV4FRAG -/* # define reassembly_dbg dbg */ -# define reassembly_dbg(...) do {} while(0) -#endif - -/* Queues */ -static struct pico_queue in = { - 0 -}; -static struct pico_queue out = { - 0 -}; - -/* Functions */ -static int ipv4_route_compare(void *ka, void *kb); -static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, uint16_t size); - - -int pico_ipv4_compare(struct pico_ip4 *a, struct pico_ip4 *b) -{ - if (a->addr < b->addr) - return -1; - - if (a->addr > b->addr) - return 1; - - return 0; -} - -int pico_ipv4_to_string(char *ipbuf, const uint32_t ip) -{ - const unsigned char *addr = (const unsigned char *) &ip; - int i; - - if (!ipbuf) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - for(i = 0; i < 4; i++) - { - if (addr[i] > 99) { - *ipbuf++ = (char)('0' + (addr[i] / 100)); - *ipbuf++ = (char)('0' + ((addr[i] % 100) / 10)); - *ipbuf++ = (char)('0' + ((addr[i] % 100) % 10)); - } else if (addr[i] > 9) { - *ipbuf++ = (char)('0' + (addr[i] / 10)); - *ipbuf++ = (char)('0' + (addr[i] % 10)); - } else { - *ipbuf++ = (char)('0' + addr[i]); - } - - if (i < 3) - *ipbuf++ = '.'; - } - *ipbuf = '\0'; - - return 0; -} - -static int pico_string_check_null_args(const char *ipstr, uint32_t *ip) -{ - - if (!ipstr || !ip) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return 0; - -} - -int pico_string_to_ipv4(const char *ipstr, uint32_t *ip) -{ - unsigned char buf[PICO_SIZE_IP4] = { - 0 - }; - int cnt = 0; - char p; - - if (pico_string_check_null_args(ipstr, ip) < 0) - return -1; - - while((p = *ipstr++) != 0 && cnt < PICO_SIZE_IP4) - { - if (pico_is_digit(p)) { - buf[cnt] = (uint8_t)((10 * buf[cnt]) + (p - '0')); - } else if (p == '.') { - cnt++; - } else { - return -1; - } - } - /* Handle short notation */ - if (cnt == 1) { - buf[3] = buf[1]; - buf[1] = 0; - buf[2] = 0; - } else if (cnt == 2) { - buf[3] = buf[2]; - buf[2] = 0; - } else if (cnt != 3) { - /* String could not be parsed, return error */ - return -1; - } - - *ip = long_from(buf); - - return 0; -} - -int pico_ipv4_valid_netmask(uint32_t mask) -{ - int cnt = 0; - int end = 0; - int i; - uint32_t mask_swap = long_be(mask); - - /* - * Swap bytes for convenient parsing - * e.g. 0x..f8ff will become 0xfff8.. - * Then, we count the consecutive bits - * - * */ - - for(i = 0; i < 32; i++) { - if ((mask_swap << i) & 0x80000000) { - if (end) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - cnt++; - } else { - end = 1; - } - } - return cnt; -} - -int pico_ipv4_is_unicast(uint32_t address) -{ - const unsigned char *addr = (unsigned char *) &address; - if ((addr[0] & 0xe0) == 0xe0) - return 0; /* multicast */ - - return 1; -} - -int pico_ipv4_is_multicast(uint32_t address) -{ - const unsigned char *addr = (unsigned char *) &address; - if ((addr[0] != 0xff) && ((addr[0] & 0xe0) == 0xe0)) - return 1; /* multicast */ - - return 0; -} - -int pico_ipv4_is_loopback(uint32_t address) -{ - const unsigned char *addr = (unsigned char *) &address; - if (addr[0] == 0x7f) - return 1; - - return 0; -} - -static int pico_ipv4_is_invalid_loopback(uint32_t address, struct pico_device *dev) -{ - return pico_ipv4_is_loopback(address) && ((!dev) || strcmp(dev->name, "loop")); -} - -int pico_ipv4_is_valid_src(uint32_t address, struct pico_device *dev) -{ - if (pico_ipv4_is_broadcast(address)) { - dbg("Source is a broadcast address, discard packet\n"); - return 0; - } else if ( pico_ipv4_is_multicast(address)) { - dbg("Source is a multicast address, discard packet\n"); - return 0; - } else if (pico_ipv4_is_invalid_loopback(address, dev)) { - dbg("Source is a loopback address, discard packet\n"); - return 0; - } else { -#ifdef PICO_SUPPORT_AODV - union pico_address src; - src.ip4.addr = address; - pico_aodv_refresh(&src); -#endif - return 1; - } -} - -static int pico_ipv4_checksum(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - if (!hdr) - return -1; - - hdr->crc = 0; - hdr->crc = short_be(pico_checksum(hdr, f->net_len)); - return 0; -} - - -#ifdef PICO_SUPPORT_CRC -static inline int pico_ipv4_crc_check(struct pico_frame *f) -{ - uint16_t checksum_invalid = 1; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - - checksum_invalid = short_be(pico_checksum(hdr, f->net_len)); - if (checksum_invalid) { - dbg("IP: checksum failed!\n"); - pico_frame_discard(f); - return 0; - } - - return 1; -} -#else -static inline int pico_ipv4_crc_check(struct pico_frame *f) -{ - IGNORE_PARAMETER(f); - return 1; -} -#endif /* PICO_SUPPORT_CRC */ - -static int pico_ipv4_forward(struct pico_frame *f); -#ifdef PICO_SUPPORT_MCAST -static int pico_ipv4_mcast_filter(struct pico_frame *f); -#endif - -static int ipv4_link_compare(void *ka, void *kb) -{ - struct pico_ipv4_link *a = ka, *b = kb; - int cmp = pico_ipv4_compare(&a->address, &b->address); - if (cmp) - return cmp; - - /* zero can be assigned multiple times (e.g. for DHCP) */ - if (a->dev != NULL && b->dev != NULL && a->address.addr == PICO_IP4_ANY && b->address.addr == PICO_IP4_ANY) { - if (a->dev < b->dev) - return -1; - - if (a->dev > b->dev) - return 1; - } - - return 0; -} - -PICO_TREE_DECLARE(Tree_dev_link, ipv4_link_compare); - -static int pico_ipv4_process_bcast_in(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; -#ifdef PICO_SUPPORT_UDP - if (pico_ipv4_is_broadcast(hdr->dst.addr) && (hdr->proto == PICO_PROTO_UDP)) { - /* Receiving UDP broadcast datagram */ - f->flags |= PICO_FRAME_FLAG_BCAST; - pico_enqueue(pico_proto_udp.q_in, f); - return 1; - } - -#endif - -#ifdef PICO_SUPPORT_ICMP4 - if (pico_ipv4_is_broadcast(hdr->dst.addr) && (hdr->proto == PICO_PROTO_ICMP4)) { - /* Receiving ICMP4 bcast packet */ - f->flags |= PICO_FRAME_FLAG_BCAST; - pico_enqueue(pico_proto_icmp4.q_in, f); - return 1; - } - -#endif - return 0; -} - -static int pico_ipv4_process_mcast_in(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - if (pico_ipv4_is_multicast(hdr->dst.addr)) { -#ifdef PICO_SUPPORT_IGMP - /* Receiving UDP multicast datagram TODO set f->flags? */ - if (hdr->proto == PICO_PROTO_IGMP) { - ip_mcast_dbg("MCAST: received IGMP message\n"); - pico_transport_receive(f, PICO_PROTO_IGMP); - return 1; - } else if ((pico_ipv4_mcast_filter(f) == 0) && (hdr->proto == PICO_PROTO_UDP)) { - pico_enqueue(pico_proto_udp.q_in, f); - return 1; - } - -#endif - pico_frame_discard(f); - return 1; - } - - return 0; -} - -static int pico_ipv4_process_local_unicast_in(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_ipv4_link test = { - .address = {.addr = PICO_IP4_ANY}, .dev = NULL - }; - if (pico_ipv4_link_find(&hdr->dst)) { - if (pico_ipv4_nat_inbound(f, &hdr->dst) == 0) - pico_enqueue(pico_proto_ipv4.q_in, f); /* dst changed, reprocess */ - else - pico_transport_receive(f, hdr->proto); - - return 1; - } else if (pico_tree_findKey(&Tree_dev_link, &test)) { -#ifdef PICO_SUPPORT_UDP - /* address of this device is apparently 0.0.0.0; might be a DHCP packet */ - /* XXX KRO: is obsolete. Broadcast flag is set on outgoing DHCP messages. - * incomming DHCP messages are to be broadcasted. Our current DHCP server - * implementation does not take this flag into account yet though ... */ - pico_enqueue(pico_proto_udp.q_in, f); - return 1; -#endif - } - - return 0; -} - -static void pico_ipv4_process_finally_try_forward(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - if ((pico_ipv4_is_broadcast(hdr->dst.addr)) || ((f->flags & PICO_FRAME_FLAG_BCAST)!= 0)) { - /* don't forward broadcast frame, discard! */ - pico_frame_discard(f); - } else if (pico_ipv4_forward(f) != 0) { - pico_frame_discard(f); - /* dbg("Forward failed.\n"); */ - } -} - - - -static int pico_ipv4_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - uint8_t option_len = 0; - int ret = 0; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - uint16_t max_allowed = (uint16_t) ((int)f->buffer_len - (f->net_hdr - f->buffer) - (int)PICO_SIZE_IP4HDR); - uint16_t flag = short_be(hdr->frag); - - (void)self; - - if (!hdr) - return -1; - /* NAT needs transport header information */ - if (((hdr->vhl) & 0x0F) > 5) { - option_len = (uint8_t)(4 * (((hdr->vhl) & 0x0F) - 5)); - } - - f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR + option_len; - f->transport_len = (uint16_t)(short_be(hdr->len) - PICO_SIZE_IP4HDR - option_len); - f->net_len = (uint16_t)(PICO_SIZE_IP4HDR + option_len); - - if (f->transport_len > max_allowed) { - pico_frame_discard(f); - return 0; /* Packet is discarded due to unfeasible length */ - } - -#ifdef PICO_SUPPORT_IPFILTER - if (ipfilter(f)) { - /*pico_frame is discarded as result of the filtering*/ - return 0; - } - -#endif - - - /* ret == 1 indicates to continue the function */ - ret = pico_ipv4_crc_check(f); - if (ret < 1) - return ret; - - /* Validate source IP address. Discard quietly if invalid */ - if (!pico_ipv4_is_valid_src(hdr->src.addr, f->dev)) { - pico_frame_discard(f); - return 0; - } - - if (hdr->frag & short_be(PICO_IPV4_EVIL)) { - (void)pico_icmp4_param_problem(f, 0); - pico_frame_discard(f); /* RFC 3514 */ - return 0; - } - - if ((hdr->vhl & 0x0f) < 5) { - /* RFC 791: IHL minimum value is 5 */ - (void)pico_icmp4_param_problem(f, 0); - pico_frame_discard(f); - return 0; - } - - if (flag & (PICO_IPV4_MOREFRAG | PICO_IPV4_FRAG_MASK)) - { -#ifdef PICO_SUPPORT_IPV4FRAG - pico_ipv4_process_frag(hdr, f, hdr ? hdr->proto : 0 ); - /* Frame can be discarded, frag will handle its own copy */ -#endif - /* We do not support fragmentation, discard quietly */ - pico_frame_discard(f); - return 0; - } - - if (pico_ipv4_process_bcast_in(f) > 0) - return 0; - - if (pico_ipv4_process_mcast_in(f) > 0) - return 0; - - if (pico_ipv4_process_local_unicast_in(f) > 0) - return 0; - - pico_ipv4_process_finally_try_forward(f); - - return 0; -} - -PICO_TREE_DECLARE(Routes, ipv4_route_compare); - - -static int pico_ipv4_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - IGNORE_PARAMETER(self); - f->start = (uint8_t*) f->net_hdr; -#ifdef PICO_SUPPORT_IPFILTER - if (ipfilter(f)) { - /*pico_frame is discarded as result of the filtering*/ - return 0; - } - -#endif - return pico_sendto_dev(f); -} - - -static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, uint16_t size) -{ - struct pico_frame *f = pico_frame_alloc(size + PICO_SIZE_IP4HDR + PICO_SIZE_ETHHDR); - IGNORE_PARAMETER(self); - - if (!f) - return NULL; - - f->datalink_hdr = f->buffer; - f->net_hdr = f->buffer + PICO_SIZE_ETHHDR; - f->net_len = PICO_SIZE_IP4HDR; - f->transport_hdr = f->net_hdr + PICO_SIZE_IP4HDR; - f->transport_len = size; - f->len = size + PICO_SIZE_IP4HDR; - return f; -} - -static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f); - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_ipv4 = { - .name = "ipv4", - .proto_number = PICO_PROTO_IPV4, - .layer = PICO_LAYER_NETWORK, - .alloc = pico_ipv4_alloc, - .process_in = pico_ipv4_process_in, - .process_out = pico_ipv4_process_out, - .push = pico_ipv4_frame_sock_push, - .q_in = &in, - .q_out = &out, -}; - - -static int ipv4_route_compare(void *ka, void *kb) -{ - struct pico_ipv4_route *a = ka, *b = kb; - uint32_t a_nm, b_nm; - int cmp; - - a_nm = long_be(a->netmask.addr); - b_nm = long_be(b->netmask.addr); - - /* Routes are sorted by (host side) netmask len, then by addr, then by metric. */ - if (a_nm < b_nm) - return -1; - - if (b_nm < a_nm) - return 1; - - cmp = pico_ipv4_compare(&a->dest, &b->dest); - if (cmp) - return cmp; - - if (a->metric < b->metric) - return -1; - - if (a->metric > b->metric) - return 1; - - return 0; -} - - -static struct pico_ipv4_route default_bcast_route = { - .dest = {PICO_IP4_BCAST}, - .netmask = {PICO_IP4_BCAST}, - .gateway = { 0 }, - .link = NULL, - .metric = 1000 -}; - -static struct pico_ipv4_route *route_find_default_bcast(void) -{ - return &default_bcast_route; -} - - -static struct pico_ipv4_route *route_find(const struct pico_ip4 *addr) -{ - struct pico_ipv4_route *r; - struct pico_tree_node *index; - - if (addr->addr != PICO_IP4_BCAST) { - pico_tree_foreach_reverse(index, &Routes) { - r = index->keyValue; - if ((addr->addr & (r->netmask.addr)) == (r->dest.addr)) { - return r; - } - } - return NULL; - } - - return route_find_default_bcast(); -} - -struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr) -{ - struct pico_ip4 nullip; - struct pico_ipv4_route *route; - nullip.addr = 0U; - - if (!addr) { - pico_err = PICO_ERR_EINVAL; - return nullip; - } - - route = route_find(addr); - if (!route) { - pico_err = PICO_ERR_EHOSTUNREACH; - return nullip; - } - else - return route->gateway; -} - -struct pico_ip4 *pico_ipv4_source_find(const struct pico_ip4 *dst) -{ - struct pico_ip4 *myself = NULL; - struct pico_ipv4_route *rt; -#ifdef PICO_SUPPORT_AODV - union pico_address node_address; - node_address.ip4.addr = dst->addr; - if (dst->addr && pico_ipv4_is_unicast(dst->addr)) - pico_aodv_lookup(&node_address); - -#endif - - if (!dst) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - rt = route_find(dst); - if (rt && rt->link) { - myself = &rt->link->address; - } else { - pico_err = PICO_ERR_EHOSTUNREACH; - } - - return myself; -} - -struct pico_device *pico_ipv4_source_dev_find(const struct pico_ip4 *dst) -{ - struct pico_device *dev = NULL; - struct pico_ipv4_route *rt; - - if (!dst) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - rt = route_find(dst); - if (rt && rt->link) { - dev = rt->link->dev; - } else { - pico_err = PICO_ERR_EHOSTUNREACH; - } - - return dev; -} - - -#ifdef PICO_SUPPORT_MCAST -/* link - * | - * MCASTGroups - * | | | - * ------------ | ------------ - * | | | - * MCASTSources MCASTSources MCASTSources - * | | | | | | | | | | | | - * S S S S S S S S S S S S - * - * MCASTGroups: RBTree(mcast_group) - * MCASTSources: RBTree(source) - */ -static int ipv4_mcast_groups_cmp(void *ka, void *kb) -{ - struct pico_mcast_group *a = ka, *b = kb; - return pico_ipv4_compare(&a->mcast_addr, &b->mcast_addr); -} - -static int ipv4_mcast_sources_cmp(void *ka, void *kb) -{ - struct pico_ip4 *a = ka, *b = kb; - return pico_ipv4_compare(a, b); -} - -static void pico_ipv4_mcast_print_groups(struct pico_ipv4_link *mcast_link) -{ - uint16_t i = 0; - struct pico_mcast_group *g = NULL; - struct pico_ip4 *source = NULL; - struct pico_tree_node *index = NULL, *index2 = NULL; - (void) source; - - ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); - ip_mcast_dbg("+ MULTICAST list interface %-16s +\n", mcast_link->dev->name); - ip_mcast_dbg("+---------------------------------------------------------------------------------+\n"); - ip_mcast_dbg("+ nr | interface | host group | reference count | filter mode | source +\n"); - ip_mcast_dbg("+---------------------------------------------------------------------------------+\n"); - - pico_tree_foreach(index, mcast_link->MCASTGroups) { - g = index->keyValue; - ip_mcast_dbg("+ %04d | %16s | %08X | %05u | %u | %8s +\n", i, mcast_link->dev->name, g->mcast_addr.addr, g->reference_count, g->filter_mode, ""); - pico_tree_foreach(index2, &g->MCASTSources) { - source = index2->keyValue; - ip_mcast_dbg("+ %4s | %16s | %8s | %5s | %s | %08X +\n", "", "", "", "", "", source->addr); - } - i++; - } - ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); -} - -static int mcast_group_update(struct pico_mcast_group *g, struct pico_tree *MCASTFilter, uint8_t filter_mode) -{ - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ip4 *source = NULL; - /* cleanup filter */ - pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) { - source = index->keyValue; - pico_tree_delete(&g->MCASTSources, source); - PICO_FREE(source); - } - /* insert new filter */ - if (MCASTFilter) { - pico_tree_foreach(index, MCASTFilter) { - if (index->keyValue) { - source = PICO_ZALLOC(sizeof(struct pico_ip4)); - if (!source) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - source->addr = ((struct pico_ip4 *)index->keyValue)->addr; - pico_tree_insert(&g->MCASTSources, source); - } - } - } - - g->filter_mode = filter_mode; - return 0; -} - -int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) -{ - struct pico_mcast_group *g = NULL, test = { - 0 - }; - struct pico_ipv4_link *link = NULL; - - if (mcast_link) - link = pico_ipv4_link_get(mcast_link); - - if (!link) - link = mcast_default_link; - - test.mcast_addr = *mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (g) { - if (reference_count) - g->reference_count++; - - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE); - } else { - g = PICO_ZALLOC(sizeof(struct pico_mcast_group)); - if (!g) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - /* "non-existent" state of filter mode INCLUDE and empty source list */ - g->filter_mode = PICO_IP_MULTICAST_INCLUDE; - g->reference_count = 1; - g->mcast_addr = *mcast_group; - g->MCASTSources.root = &LEAF; - g->MCASTSources.compare = ipv4_mcast_sources_cmp; - pico_tree_insert(link->MCASTGroups, g); - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_CREATE); - } - - if (mcast_group_update(g, MCASTFilter, filter_mode) < 0) { - dbg("Error in mcast_group update\n"); - return -1; - } - - pico_ipv4_mcast_print_groups(link); - return 0; -} - -int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) -{ - - struct pico_mcast_group *g = NULL, test = { - 0 - }; - struct pico_ipv4_link *link = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ip4 *source = NULL; - - if (mcast_link) - link = pico_ipv4_link_get(mcast_link); - - if (!link) - link = mcast_default_link; - - if (!link) - return -1; - - test.mcast_addr = *mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (!g) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - if (reference_count && (--(g->reference_count) < 1)) { - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_DELETE); - /* cleanup filter */ - pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) { - source = index->keyValue; - pico_tree_delete(&g->MCASTSources, source); - PICO_FREE(source); - } - pico_tree_delete(link->MCASTGroups, g); - PICO_FREE(g); - } else { - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE); - if (mcast_group_update(g, MCASTFilter, filter_mode) < 0) - return -1; - } - } - - pico_ipv4_mcast_print_groups(link); - return 0; -} - -struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void) -{ - return mcast_default_link; -} - -static int pico_ipv4_mcast_filter(struct pico_frame *f) -{ - struct pico_ipv4_link *link = NULL; - struct pico_tree_node *index = NULL, *index2 = NULL; - struct pico_mcast_group *g = NULL, test = { - 0 - }; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - - test.mcast_addr = hdr->dst; - - pico_tree_foreach(index, &Tree_dev_link) { - link = index->keyValue; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (g) { - if (f->dev == link->dev) { - ip_mcast_dbg("MCAST: IP %08X is group member of current link %s\n", hdr->dst.addr, f->dev->name); - /* perform source filtering */ - switch (g->filter_mode) { - case PICO_IP_MULTICAST_INCLUDE: - pico_tree_foreach(index2, &g->MCASTSources) { - if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) { - ip_mcast_dbg("MCAST: IP %08X in included interface source list\n", hdr->src.addr); - return 0; - } - } - ip_mcast_dbg("MCAST: IP %08X NOT in included interface source list\n", hdr->src.addr); - return -1; - - case PICO_IP_MULTICAST_EXCLUDE: - pico_tree_foreach(index2, &g->MCASTSources) { - if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) { - ip_mcast_dbg("MCAST: IP %08X in excluded interface source list\n", hdr->src.addr); - return -1; - } - } - ip_mcast_dbg("MCAST: IP %08X NOT in excluded interface source list\n", hdr->src.addr); - return 0; - - default: - return -1; - } - } else { - ip_mcast_dbg("MCAST: IP %08X is group member of different link %s\n", hdr->dst.addr, link->dev->name); - } - } else { - ip_mcast_dbg("MCAST: IP %08X is not a group member of link %s\n", hdr->dst.addr, f->dev->name); - } - } - return -1; -} - -#else - -int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return NULL; -} -#endif /* PICO_SUPPORT_MCAST */ - -/* #define DEBUG_ROUTE */ -#ifdef DEBUG_ROUTE -void dbg_route(void) -{ - struct pico_ipv4_route *r; - struct pico_tree_node *index; - int count_hosts = 0; - dbg("==== ROUTING TABLE =====\n"); - pico_tree_foreach(index, &Routes) { - r = index->keyValue; - dbg("Route to %08x/%08x, gw %08x, dev: %s, metric: %d\n", r->dest.addr, r->netmask.addr, r->gateway.addr, r->link->dev->name, r->metric); - if (r->netmask.addr == 0xFFFFFFFF) - count_hosts++; - } - dbg("================ total HOST nodes: %d ======\n\n\n", count_hosts); -} -#else -#define dbg_route() do { } while(0) -#endif - -int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t proto) -{ - - struct pico_ipv4_route *route; - struct pico_ipv4_link *link; - struct pico_ipv4_hdr *hdr; - uint8_t ttl = PICO_IPV4_DEFAULT_TTL; - uint8_t vhl = 0x45; /* version 4, header length 20 */ - static uint16_t ipv4_progressive_id = 0x91c0; -#ifdef PICO_SUPPORT_MCAST - struct pico_tree_node *index; -#endif - - if (!f || !dst) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - if (!hdr) { - dbg("IP header error\n"); - pico_err = PICO_ERR_EINVAL; - goto drop; - } - - if (dst->addr == 0) { - dbg("IP destination addr error\n"); - pico_err = PICO_ERR_EINVAL; - goto drop; - } - - route = route_find(dst); - if (!route) { - /* dbg("Route to %08x not found.\n", long_be(dst->addr)); */ - - - pico_err = PICO_ERR_EHOSTUNREACH; - goto drop; - } else { - link = route->link; -#ifdef PICO_SUPPORT_MCAST - if (pico_ipv4_is_multicast(dst->addr)) { /* if multicast */ - switch (proto) { - case PICO_PROTO_UDP: - if (pico_udp_get_mc_ttl(f->sock, &ttl) < 0) - ttl = PICO_IP_DEFAULT_MULTICAST_TTL; - - break; -#ifdef PICO_SUPPORT_IGMP - case PICO_PROTO_IGMP: - vhl = 0x46; /* header length 24 */ - ttl = 1; - /* router alert (RFC 2113) */ - hdr->options[0] = 0x94; - hdr->options[1] = 0x04; - hdr->options[2] = 0x00; - hdr->options[3] = 0x00; - if (f->dev && link->dev != f->dev) { /* default link is not requested link */ - pico_tree_foreach(index, &Tree_dev_link) { - link = index->keyValue; - if (link->dev == f->dev) - break; - } - } - - break; -#endif - default: - ttl = PICO_IPV4_DEFAULT_TTL; - } - } - -#endif - } - - hdr->vhl = vhl; - hdr->len = short_be((uint16_t)(f->transport_len + f->net_len)); - hdr->id = short_be(ipv4_progressive_id); - - if ( -#ifdef PICO_SUPPORT_IPV4FRAG - (0 == (f->frag & PICO_IPV4_MOREFRAG)) && -#endif - 1 ) - ipv4_progressive_id++; - - if (f->send_ttl > 0) { - ttl = f->send_ttl; - } - - hdr->dst.addr = dst->addr; - hdr->src.addr = link->address.addr; - hdr->ttl = ttl; - hdr->tos = f->send_tos; - hdr->proto = proto; - hdr->frag = short_be(PICO_IPV4_DONTFRAG); - -#ifdef PICO_SUPPORT_IPV4FRAG -# ifdef PICO_SUPPORT_UDP - if (proto == PICO_PROTO_UDP) { - /* first fragment, can not use transport_len to calculate IP length */ - if (f->transport_hdr != f->payload) - hdr->len = short_be((uint16_t)(f->payload_len + sizeof(struct pico_udp_hdr) + f->net_len)); - - /* set fragmentation flags and offset calculated in socket layer */ - hdr->frag = short_be(f->frag); - } - - if (proto == PICO_PROTO_ICMP4) - { - hdr->frag = short_be(f->frag); - } - -# endif -#endif /* PICO_SUPPORT_IPV4FRAG */ - pico_ipv4_checksum(f); - - if (f->sock && f->sock->dev) { - /* if the socket has its device set, use that (currently used for DHCP) */ - f->dev = f->sock->dev; - } else { - f->dev = link->dev; - if (f->sock) - f->sock->dev = f->dev; - } - -#ifdef PICO_SUPPORT_MCAST - if (pico_ipv4_is_multicast(hdr->dst.addr)) { - struct pico_frame *cpy; - /* Sending UDP multicast datagram, am I member? If so, loopback copy */ - if ((proto != PICO_PROTO_IGMP) && (pico_ipv4_mcast_filter(f) == 0)) { - ip_mcast_dbg("MCAST: sender is member of group, loopback copy\n"); - cpy = pico_frame_copy(f); - pico_enqueue(&in, cpy); - } - } - -#endif - -/* #ifdef PICO_SUPPORT_AODV */ -#if 0 - { - union pico_address node_address; - node_address.ip4.addr = hdr->dst.addr; - if(hdr->dst.addr && pico_ipv4_is_unicast(hdr->dst.addr)) - pico_aodv_lookup(&node_address); - } -#endif - - if (pico_ipv4_link_get(&hdr->dst)) { - /* it's our own IP */ - return pico_enqueue(&in, f); - } else{ - /* TODO: Check if there are members subscribed here */ - return pico_enqueue(&out, f); - } - -drop: - pico_frame_discard(f); - return -1; -} - - -static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_ip4 *dst; - struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *) f->info; - IGNORE_PARAMETER(self); - - if (!f->sock) { - pico_frame_discard(f); - return -1; - } - - if (remote_endpoint) { - dst = &remote_endpoint->remote_addr.ip4; - } else { - dst = &f->sock->remote_addr.ip4; - } - - return pico_ipv4_frame_push(f, dst, (uint8_t)f->sock->proto->proto_number); -} - - -int MOCKABLE pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) -{ - struct pico_ipv4_route test, *new; - test.dest.addr = address.addr; - test.netmask.addr = netmask.addr; - test.metric = (uint32_t)metric; - - if (pico_tree_findKey(&Routes, &test)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - new = PICO_ZALLOC(sizeof(struct pico_ipv4_route)); - if (!new) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - new->dest.addr = address.addr; - new->netmask.addr = netmask.addr; - new->gateway.addr = gateway.addr; - new->metric = (uint32_t)metric; - if (gateway.addr == 0) { - /* No gateway provided, use the link */ - new->link = link; - } else { - struct pico_ipv4_route *r = route_find(&gateway); - if (!r ) { /* Specified Gateway is unreachable */ - pico_err = PICO_ERR_EHOSTUNREACH; - PICO_FREE(new); - return -1; - } - - if (r->gateway.addr) { /* Specified Gateway is not a neighbor */ - pico_err = PICO_ERR_ENETUNREACH; - PICO_FREE(new); - return -1; - } - - new->link = r->link; - } - - if (!new->link) { - pico_err = PICO_ERR_EINVAL; - PICO_FREE(new); - return -1; - } - - pico_tree_insert(&Routes, new); - dbg_route(); - return 0; -} - -int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, int metric) -{ - struct pico_ipv4_route test, *found; - - test.dest.addr = address.addr; - test.netmask.addr = netmask.addr; - test.metric = (uint32_t)metric; - - found = pico_tree_findKey(&Routes, &test); - if (found) { - - pico_tree_delete(&Routes, found); - PICO_FREE(found); - - dbg_route(); - return 0; - } - - pico_err = PICO_ERR_EINVAL; - return -1; -} - - -int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask) -{ - struct pico_ipv4_link test, *new; - struct pico_ip4 network, gateway; - char ipstr[30]; - - if (!dev) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - test.address.addr = address.addr; - test.netmask.addr = netmask.addr; - test.dev = dev; - /** XXX: Valid netmask / unicast address test **/ - - if (pico_tree_findKey(&Tree_dev_link, &test)) { - pico_err = PICO_ERR_EADDRINUSE; - return -1; - } - - /** XXX: Check for network already in use (e.g. trying to assign 10.0.0.1/24 where 10.1.0.1/8 is in use) **/ - new = PICO_ZALLOC(sizeof(struct pico_ipv4_link)); - if (!new) { - dbg("IPv4: Out of memory!\n"); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - new->address.addr = address.addr; - new->netmask.addr = netmask.addr; - new->dev = dev; -#ifdef PICO_SUPPORT_MCAST - new->MCASTGroups = PICO_ZALLOC(sizeof(struct pico_tree)); - if (!new->MCASTGroups) { - PICO_FREE(new); - dbg("IPv4: Out of memory!\n"); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - new->MCASTGroups->root = &LEAF; - new->MCASTGroups->compare = ipv4_mcast_groups_cmp; -#ifdef PICO_SUPPORT_IGMP - new->mcast_compatibility = PICO_IGMPV3; /* default RFC 3376 $7.2.1 */ - new->mcast_last_query_interval = PICO_IGMP_QUERY_INTERVAL; -#endif -#endif - - pico_tree_insert(&Tree_dev_link, new); -#ifdef PICO_SUPPORT_MCAST - do { - struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm, mcast_gw; - if (!mcast_default_link) { - mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */ - mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */ - mcast_gw.addr = long_be(0x00000000); - mcast_default_link = new; - pico_ipv4_route_add(mcast_addr, mcast_nm, mcast_gw, 1, new); - } - - mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS; - pico_ipv4_mcast_join(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL); - } while(0); -#endif - - network.addr = address.addr & netmask.addr; - gateway.addr = 0U; - pico_ipv4_route_add(network, netmask, gateway, 1, new); - pico_ipv4_to_string(ipstr, new->address.addr); - dbg("Assigned ipv4 %s to device %s\n", ipstr, new->dev->name); - if (default_bcast_route.link == NULL) - default_bcast_route.link = new; - - return 0; -} - -static int pico_ipv4_cleanup_routes(struct pico_ipv4_link *link) -{ - struct pico_tree_node *index = NULL, *tmp = NULL; - struct pico_ipv4_route *route = NULL; - - pico_tree_foreach_safe(index, &Routes, tmp) { - route = index->keyValue; - if (link == route->link) - pico_ipv4_route_del(route->dest, route->netmask, (int)route->metric); - } - return 0; -} - -void MOCKABLE pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link) -{ - if (link) - default_bcast_route.link = link; -} - -int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address) -{ - struct pico_ipv4_link test, *found; - - if (!dev) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - test.address.addr = address.addr; - test.dev = dev; - found = pico_tree_findKey(&Tree_dev_link, &test); - if (!found) { - pico_err = PICO_ERR_ENXIO; - return -1; - } - -#ifdef PICO_SUPPORT_MCAST - do { - struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm; - struct pico_mcast_group *g = NULL; - struct pico_tree_node *index, *_tmp; - if (found == mcast_default_link) { - mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */ - mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */ - mcast_default_link = NULL; - pico_ipv4_route_del(mcast_addr, mcast_nm, 1); - } - - mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS; - pico_ipv4_mcast_leave(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL); - pico_tree_foreach_safe(index, found->MCASTGroups, _tmp) { - g = index->keyValue; - pico_tree_delete(found->MCASTGroups, g); - PICO_FREE(g); - } - } while(0); - PICO_FREE(found->MCASTGroups); -#endif - - pico_ipv4_cleanup_routes(found); - pico_tree_delete(&Tree_dev_link, found); - if (default_bcast_route.link == found) - default_bcast_route.link = NULL; - - PICO_FREE(found); - - return 0; -} - - -struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address) -{ - struct pico_ipv4_link test = { - 0 - }, *found = NULL; - test.address.addr = address->addr; - - found = pico_tree_findKey(&Tree_dev_link, &test); - if (!found) - return NULL; - else - return found; -} - -struct pico_ipv4_link *MOCKABLE pico_ipv4_link_by_dev(struct pico_device *dev) -{ - struct pico_tree_node *index = NULL; - struct pico_ipv4_link *link = NULL; - - pico_tree_foreach(index, &Tree_dev_link) { - link = index->keyValue; - if (link->dev == dev) - return link; - } - return NULL; -} - -struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struct pico_ipv4_link *last) -{ - struct pico_tree_node *index = NULL; - struct pico_ipv4_link *link = NULL; - int valid = 0; - - if (last == NULL) - valid = 1; - - pico_tree_foreach(index, &Tree_dev_link) { - link = index->keyValue; - if (link->dev == dev) { - if (last == link) - valid = 1; - else if (valid > 0) - return link; - } - } - return NULL; -} - -struct pico_device *MOCKABLE pico_ipv4_link_find(struct pico_ip4 *address) -{ - struct pico_ipv4_link test, *found; - if (!address) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - test.dev = NULL; - test.address.addr = address->addr; - found = pico_tree_findKey(&Tree_dev_link, &test); - if (!found) { - pico_err = PICO_ERR_ENXIO; - return NULL; - } - - return found->dev; -} - - -static int pico_ipv4_rebound_large(struct pico_frame *f) -{ -#ifdef PICO_SUPPORT_IPV4FRAG - uint16_t total_payload_written = 0; - uint32_t len = f->transport_len; - struct pico_frame *fr; - struct pico_ip4 dst; - struct pico_ipv4_hdr *hdr; - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - dst.addr = hdr->src.addr; - - while(total_payload_written < len) { - uint32_t space = (uint32_t)len - total_payload_written; - if (space > PICO_IPV4_MAXPAYLOAD) - space = PICO_IPV4_MAXPAYLOAD; - - fr = pico_ipv4_alloc(&pico_proto_ipv4, (uint16_t)space); - if (!fr) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if (space + total_payload_written < len) - { - fr->frag |= PICO_IPV4_MOREFRAG; - } - else - { - fr->frag &= PICO_IPV4_FRAG_MASK; - } - - fr->frag = (((total_payload_written) >> 3u) & 0xffffu) | fr->frag; - - memcpy(fr->transport_hdr, f->transport_hdr + total_payload_written, fr->transport_len); - if (pico_ipv4_frame_push(fr, &dst, hdr->proto) > 0) { - total_payload_written = (uint16_t)((uint16_t)fr->transport_len + total_payload_written); - } else { - pico_frame_discard(fr); - break; - } - } /* while() */ - return (int)total_payload_written; -#else - (void)f; - return -1; -#endif -} - -int pico_ipv4_rebound(struct pico_frame *f) -{ - struct pico_ip4 dst; - struct pico_ipv4_hdr *hdr; - if (!f) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - if (!hdr) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - dst.addr = hdr->src.addr; - if (f->transport_len > PICO_IPV4_MAXPAYLOAD) { - return pico_ipv4_rebound_large(f); - } - - return pico_ipv4_frame_push(f, &dst, hdr->proto); -} - -static int pico_ipv4_pre_forward_checks(struct pico_frame *f) -{ - static uint16_t last_id = 0; - static uint16_t last_proto = 0; - static struct pico_ip4 last_src = { - 0 - }; - static struct pico_ip4 last_dst = { - 0 - }; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; - - /* Decrease TTL, check if expired */ - hdr->ttl = (uint8_t)(hdr->ttl - 1); - if (hdr->ttl < 1) { - pico_notify_ttl_expired(f); - dbg(" ------------------- TTL EXPIRED\n"); - return -1; - } - - /* HACK: increase crc to compensate decreased TTL */ - hdr->crc++; - - /* If source is local, discard anyway (packets bouncing back and forth) */ - if (pico_ipv4_link_get(&hdr->src)) - return -1; - - /* If this was the last forwarded packet, silently discard to prevent duplications */ - if ((last_src.addr == hdr->src.addr) && (last_id == hdr->id) - && (last_dst.addr == hdr->dst.addr) && (last_proto == hdr->proto)) { - return -1; - } else { - last_src.addr = hdr->src.addr; - last_dst.addr = hdr->dst.addr; - last_id = hdr->id; - last_proto = hdr->proto; - } - - return 0; -} - -static int pico_ipv4_forward_check_dev(struct pico_frame *f) -{ - if (f->dev->eth != NULL) - f->len -= PICO_SIZE_ETHHDR; - - if (f->len > f->dev->mtu) { - pico_notify_pkt_too_big(f); - return -1; - } - - return 0; -} - -static int pico_ipv4_forward(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; - struct pico_ipv4_route *rt; - if (!hdr) { - return -1; - } - - rt = route_find(&hdr->dst); - if (!rt) { - pico_notify_dest_unreachable(f); - return -1; - } - - f->dev = rt->link->dev; - - if (pico_ipv4_pre_forward_checks(f) < 0) - return -1; - - pico_ipv4_nat_outbound(f, &rt->link->address); - - f->start = f->net_hdr; - - if (pico_ipv4_forward_check_dev(f) < 0) - return -1; - - pico_sendto_dev(f); - return 0; - -} - -int pico_ipv4_is_broadcast(uint32_t addr) -{ - struct pico_ipv4_link *link; - struct pico_tree_node *index; - if (addr == PICO_IP4_BCAST) - return 1; - - pico_tree_foreach(index, &Tree_dev_link) { - link = index->keyValue; - if ((link->address.addr | (~link->netmask.addr)) == addr) - return 1; - } - return 0; -} - -void pico_ipv4_unreachable(struct pico_frame *f, int err) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; -#if defined PICO_SUPPORT_TCP || defined PICO_SUPPORT_UDP - f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR; - pico_transport_error(f, hdr->proto, err); -#endif -} - -int pico_ipv4_cleanup_links(struct pico_device *dev) -{ - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ipv4_link *link = NULL; - - pico_tree_foreach_safe(index, &Tree_dev_link, _tmp) { - link = index->keyValue; - if (dev == link->dev) - pico_ipv4_link_del(dev, link->address); - } - return 0; -} - - -#endif diff --git a/ext/picotcp/modules/pico_ipv4.h b/ext/picotcp/modules/pico_ipv4.h deleted file mode 100644 index 2429815..0000000 --- a/ext/picotcp/modules/pico_ipv4.h +++ /dev/null @@ -1,124 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - *********************************************************************/ -#ifndef INCLUDE_PICO_IPV4 -#define INCLUDE_PICO_IPV4 -#include "pico_addressing.h" -#include "pico_protocol.h" -#include "pico_tree.h" -#include "pico_device.h" - -#define PICO_IPV4_INADDR_ANY 0x00000000U - -#define PICO_IPV4_MTU (1500u) -#define PICO_SIZE_IP4HDR (uint32_t)((sizeof(struct pico_ipv4_hdr))) -#define PICO_IPV4_MAXPAYLOAD (PICO_IPV4_MTU - PICO_SIZE_IP4HDR) -#define PICO_IPV4_DONTFRAG 0x4000U -#define PICO_IPV4_MOREFRAG 0x2000U -#define PICO_IPV4_EVIL 0x8000U -#define PICO_IPV4_FRAG_MASK 0x1FFFU -#define PICO_IPV4_DEFAULT_TTL 64 -#ifndef MBED - #define PICO_IPV4_FRAG_MAX_SIZE (uint32_t)(63 * 1024) -#else - #define PICO_IPV4_FRAG_MAX_SIZE PICO_DEFAULT_SOCKETQ -#endif - -extern struct pico_protocol pico_proto_ipv4; - -PACKED_STRUCT_DEF pico_ipv4_hdr { - uint8_t vhl; - uint8_t tos; - uint16_t len; - uint16_t id; - uint16_t frag; - uint8_t ttl; - uint8_t proto; - uint16_t crc; - struct pico_ip4 src; - struct pico_ip4 dst; - uint8_t options[]; -}; - -PACKED_STRUCT_DEF pico_ipv4_pseudo_hdr -{ - struct pico_ip4 src; - struct pico_ip4 dst; - uint8_t zeros; - uint8_t proto; - uint16_t len; -}; - -/* Interface: link to device */ -struct pico_mcast_list; - -struct pico_ipv4_link -{ - struct pico_device *dev; - struct pico_ip4 address; - struct pico_ip4 netmask; -#ifdef PICO_SUPPORT_MCAST - struct pico_tree *MCASTGroups; - uint8_t mcast_compatibility; - uint8_t mcast_last_query_interval; -#endif -}; - -#ifdef PICO_SUPPORT_MCAST -struct pico_mcast_group { - uint8_t filter_mode; - uint16_t reference_count; - struct pico_ip4 mcast_addr; - struct pico_tree MCASTSources; -}; -#endif - -struct pico_ipv4_route -{ - struct pico_ip4 dest; - struct pico_ip4 netmask; - struct pico_ip4 gateway; - struct pico_ipv4_link *link; - uint32_t metric; -}; - -extern struct pico_tree Routes; - - -int pico_ipv4_compare(struct pico_ip4 *a, struct pico_ip4 *b); -int pico_ipv4_to_string(char *ipbuf, const uint32_t ip); -int pico_string_to_ipv4(const char *ipstr, uint32_t *ip); -int pico_ipv4_valid_netmask(uint32_t mask); -int pico_ipv4_is_unicast(uint32_t address); -int pico_ipv4_is_multicast(uint32_t address); -int pico_ipv4_is_broadcast(uint32_t addr); -int pico_ipv4_is_loopback(uint32_t addr); -int pico_ipv4_is_valid_src(uint32_t addr, struct pico_device *dev); - -int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask); -int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address); -int pico_ipv4_rebound(struct pico_frame *f); - -int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t proto); -struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address); -struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev); -struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struct pico_ipv4_link *last); -struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address); -struct pico_ip4 *pico_ipv4_source_find(const struct pico_ip4 *dst); -struct pico_device *pico_ipv4_source_dev_find(const struct pico_ip4 *dst); -int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link); -int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, int metric); -struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr); -void pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link); -void pico_ipv4_unreachable(struct pico_frame *f, int err); - -int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter); -int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter); -struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void); -int pico_ipv4_cleanup_links(struct pico_device *dev); - -#endif /* _INCLUDE_PICO_IPV4 */ diff --git a/ext/picotcp/modules/pico_ipv6.c b/ext/picotcp/modules/pico_ipv6.c deleted file mode 100644 index 3d532cf..0000000 --- a/ext/picotcp/modules/pico_ipv6.c +++ /dev/null @@ -1,1921 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera, Kristof Roelants - *********************************************************************/ - - -#include "pico_ipv6.h" -#include "pico_icmp6.h" -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_eth.h" -#include "pico_udp.h" -#include "pico_tcp.h" -#include "pico_socket.h" -#include "pico_device.h" -#include "pico_tree.h" -#include "pico_fragments.h" -#include "pico_mld.h" - -#ifdef PICO_SUPPORT_IPV6 - - -#define PICO_IPV6_EXTHDR_OPT_PAD1 0 -#define PICO_IPV6_EXTHDR_OPT_PADN 1 -#define PICO_IPV6_EXTHDR_OPT_SRCADDR 201 - -#define PICO_IPV6_EXTHDR_OPT_ACTION_MASK 0xC0 /* highest-order two bits */ -#define PICO_IPV6_EXTHDR_OPT_ACTION_SKIP 0x00 /* skip and continue processing */ -#define PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD 0x40 /* discard packet */ -#define PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD_SI 0x80 /* discard and send ICMP parameter problem */ -#define PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD_SINM 0xC0 /* discard and send ICMP parameter problem if not multicast */ - -#define PICO_IPV6_MAX_RTR_SOLICITATION_DELAY 1000 -#define PICO_IPV6_DEFAULT_DAD_RETRANS 1 - -#define ipv6_dbg(...) do { }while(0); -#define ipv6_mcast_dbg do{ }while(0); -static struct pico_ipv6_link *mcast_default_link_ipv6 = NULL; - -/* queues */ -static struct pico_queue ipv6_in; -static struct pico_queue ipv6_out; - -const uint8_t PICO_IP6_ANY[PICO_SIZE_IP6] = { - 0 -}; -#ifdef PICO_SUPPORT_MCAST -static int pico_ipv6_mcast_filter(struct pico_frame *f); -#endif - - -int pico_ipv6_compare(struct pico_ip6 *a, struct pico_ip6 *b) -{ - uint32_t i; - for (i = 0; i < sizeof(struct pico_ip6); i++) { - if (a->addr[i] < b->addr[i]) - return -1; - - if (a->addr[i] > b->addr[i]) - return 1; - } - return 0; -} - -static int ipv6_link_compare(void *ka, void *kb) -{ - struct pico_ipv6_link *a = ka, *b = kb; - struct pico_ip6 *a_addr, *b_addr; - int ret; - a_addr = &a->address; - b_addr = &b->address; - - ret = pico_ipv6_compare(a_addr, b_addr); - if (ret) - return ret; - - /* zero can be assigned multiple times (e.g. for DHCP) */ - if (a->dev != NULL && b->dev != NULL && !memcmp(a->address.addr, PICO_IP6_ANY, PICO_SIZE_IP6) && !memcmp(b->address.addr, PICO_IP6_ANY, PICO_SIZE_IP6)) { - /* XXX change PICO_IP6_ANY */ - if (a->dev < b->dev) - return -1; - - if (a->dev > b->dev) - return 1; - } - - return 0; -} - -static inline int ipv6_compare_metric(struct pico_ipv6_route *a, struct pico_ipv6_route *b) -{ - if (a->metric < b->metric) - return -1; - - if (a->metric > b->metric) - return 1; - - return 0; -} - -static int ipv6_route_compare(void *ka, void *kb) -{ - struct pico_ipv6_route *a = ka, *b = kb; - int ret; - - /* Routes are sorted by (host side) netmask len, then by addr, then by metric. */ - ret = pico_ipv6_compare(&a->netmask, &b->netmask); - if (ret) - return ret; - - ret = pico_ipv6_compare(&a->dest, &b->dest); - if (ret) - return ret; - - return ipv6_compare_metric(a, b); - -} - -PICO_TREE_DECLARE(Tree_dev_ip6_link, ipv6_link_compare); -PICO_TREE_DECLARE(IPV6Routes, ipv6_route_compare); -PICO_TREE_DECLARE(IPV6Links, ipv6_link_compare); - -static char pico_ipv6_dec_to_char(uint8_t u) -{ - if (u < 10) - return (char)('0' + u); - else if (u < 16) - return (char)('a' + (u - 10)); - else - return '0'; -} - -static int pico_ipv6_hex_to_dec(char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'a' && c <= 'f') - return 10 + (c - 'a'); - - if (c >= 'A' && c <= 'F') - return 10 + (c - 'A'); - - return 0; -} - -int pico_ipv6_to_string(char *ipbuf, const uint8_t ip[PICO_SIZE_IP6]) -{ - uint8_t dec = 0, i = 0; - - if (!ipbuf || !ip) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* every nibble is one char */ - for (i = 0; i < ((uint8_t)PICO_SIZE_IP6) * 2u; ++i) { - if (i % 4 == 0 && i != 0) - *ipbuf++ = ':'; - - if (i % 2 == 0) { /* upper nibble */ - dec = ip[i / 2] >> 4; - } else { /* lower nibble */ - dec = ip[i / 2] & 0x0F; - } - - *ipbuf++ = pico_ipv6_dec_to_char(dec); - } - *ipbuf = '\0'; - - return 0; -} - -int pico_string_to_ipv6(const char *ipstr, uint8_t *ip) -{ - uint8_t buf[PICO_SIZE_IP6] = { - 0 - }; - uint8_t doublecolon = 0, byte = 0; - char p = 0; - int i = 0, diff = 0, nibble = 0, hex = 0, colons = 0; - int zeros = 0, shift = 0; - - pico_err = PICO_ERR_EINVAL; - if (!ipstr || !ip) - return -1; - - memset(ip, 0, PICO_SIZE_IP6); - - while((p = *ipstr++) != 0) - { - if (pico_is_hex(p) || (p == ':') || *ipstr == '\0') { /* valid signs */ - if (pico_is_hex(p)) { - buf[byte] = (uint8_t)((buf[byte] << 4) + pico_ipv6_hex_to_dec(p)); - if (++nibble % 2 == 0) - ++byte; - } - - if (p == ':' || *ipstr == '\0') { /* account for leftout leading zeros */ - ++hex; - if (p == ':') - ++colons; - - diff = (hex * 4) - nibble; - nibble += diff; - switch (diff) { - case 0: - /* 16-bit hex block ok f.e. 1db8 */ - break; - case 1: - /* one zero f.e. db8: byte = 1, buf[byte-1] = 0xdb, buf[byte] = 0x08 */ - buf[byte] |= (uint8_t)(buf[byte - 1] << 4); - buf[byte - 1] >>= 4; - byte++; - break; - case 2: - /* two zeros f.e. b8: byte = 1, buf[byte] = 0x00, buf[byte-1] = 0xb8 */ - buf[byte] = buf[byte - 1]; - buf[byte - 1] = 0x00; - byte++; - break; - case 3: - /* three zeros f.e. 8: byte = 0, buf[byte] = 0x08, buf[byte+1] = 0x00 */ - buf[byte + 1] = buf[byte]; - buf[byte] = 0x00; - byte = (uint8_t)(byte + 2); - break; - case 4: - /* case of :: */ - if (doublecolon && colons != 2) /* catch case x::x::x but not ::x */ - return -1; - else - doublecolon = byte; - - break; - default: - /* case of missing colons f.e. 20011db8 instead of 2001:1db8 */ - return -1; - } - } - } else { - return -1; - } - } - if (colons < 2) /* valid IPv6 has atleast two colons */ - return -1; - - /* account for leftout :: zeros */ - zeros = PICO_SIZE_IP6 - byte; - if (zeros) { - shift = PICO_SIZE_IP6 - zeros - doublecolon; - for (i = shift; i >= 0; --i) { - /* (i-1) as arrays are indexed from 0 onwards */ - if ((doublecolon + (i - 1)) >= 0) - buf[doublecolon + zeros + (i - 1)] = buf[doublecolon + (i - 1)]; - } - memset(&buf[doublecolon], 0, (size_t)zeros); - } - - memcpy(ip, buf, 16); - pico_err = PICO_ERR_NOERR; - return 0; -} - -int pico_ipv6_is_linklocal(const uint8_t addr[PICO_SIZE_IP6]) -{ - /* prefix: fe80::/10 */ - if ((addr[0] == 0xfe) && ((addr[1] >> 6) == 0x02)) - return 1; - - return 0; -} - -int pico_ipv6_is_sitelocal(const uint8_t addr[PICO_SIZE_IP6]) -{ - /* prefix: fec0::/10 */ - if ((addr[0] == 0xfe) && ((addr[1] >> 6) == 0x03)) - return 1; - - return 0; -} - -int pico_ipv6_is_uniquelocal(const uint8_t addr[PICO_SIZE_IP6]) -{ - /* prefix: fc00::/7 */ - if (((addr[0] >> 1) == 0x7e)) - return 1; - - return 0; -} - -int pico_ipv6_is_global(const uint8_t addr[PICO_SIZE_IP6]) -{ - /* prefix: 2000::/3 */ - if (((addr[0] >> 5) == 0x01)) - return 1; - - return 0; -} - -int pico_ipv6_is_localhost(const uint8_t addr[PICO_SIZE_IP6]) -{ - const uint8_t localhost[PICO_SIZE_IP6] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 - }; - if (memcmp(addr, localhost, PICO_SIZE_IP6) == 0) - return 1; - - return 0; - -} - -int pico_ipv6_is_unicast(struct pico_ip6 *a) -{ - if (pico_ipv6_is_global(a->addr)) - return 1; - else if (pico_ipv6_is_uniquelocal(a->addr)) - return 1; - else if (pico_ipv6_is_sitelocal(a->addr)) - return 1; - else if (pico_ipv6_is_linklocal(a->addr)) - return 1; - else if (pico_ipv6_is_localhost(a->addr)) - return 1; - else if(pico_ipv6_link_get(a)) - return 1; - else - return 0; - -} - -int pico_ipv6_is_multicast(const uint8_t addr[PICO_SIZE_IP6]) -{ - /* prefix: ff00::/8 */ - if ((addr[0] == 0xff)) - return 1; - - return 0; -} - -int pico_ipv6_is_allhosts_multicast(const uint8_t addr[PICO_SIZE_IP6]) -{ - struct pico_ip6 allhosts = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}; - return !memcmp(allhosts.addr, addr, PICO_SIZE_IP6); -} - -int pico_ipv6_is_solicited(const uint8_t addr[PICO_SIZE_IP6]) -{ - struct pico_ip6 solicited_node = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00 }}; - return !memcmp(solicited_node.addr, addr, 13); -} - -int pico_ipv6_is_solnode_multicast(const uint8_t addr[PICO_SIZE_IP6], struct pico_device *dev) -{ - struct pico_ipv6_link *link; - if (pico_ipv6_is_multicast(addr) == 0) - return 0; - - link = pico_ipv6_link_by_dev(dev); - while(link) { - if (pico_ipv6_is_linklocal(link->address.addr)) { - int i, match = 0; - for(i = 13; i < 16; i++) { - if (addr[i] == link->address.addr[i]) - ++match; - } - /* Solicitation: last 3 bytes match a local address. */ - if (match == 3) - return 1; - } - - link = pico_ipv6_link_by_dev_next(dev, link); - } - return 0; -} - -int pico_ipv6_is_unspecified(const uint8_t addr[PICO_SIZE_IP6]) -{ - return !memcmp(PICO_IP6_ANY, addr, PICO_SIZE_IP6); -} - -static struct pico_ipv6_route *pico_ipv6_route_find(const struct pico_ip6 *addr) -{ - struct pico_ipv6_route *r = NULL; - struct pico_tree_node *index = NULL; - int i = 0; - if (!pico_ipv6_is_localhost(addr->addr) && (pico_ipv6_is_linklocal(addr->addr) || pico_ipv6_is_sitelocal(addr->addr))) { - return NULL; - } - pico_tree_foreach_reverse(index, &IPV6Routes) - { - r = index->keyValue; - for (i = 0; i < PICO_SIZE_IP6; ++i) { - if ((addr->addr[i] & (r->netmask.addr[i])) != ((r->dest.addr[i]) & (r->netmask.addr[i]))) { - break; - } - - if (i + 1 == PICO_SIZE_IP6) { - return r; - } - } - } - return NULL; -} - -struct pico_ip6 *pico_ipv6_source_find(const struct pico_ip6 *dst) -{ - struct pico_ip6 *myself = NULL; - struct pico_ipv6_route *rt; - - if(!dst) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - rt = pico_ipv6_route_find(dst); - if (rt) { - myself = &rt->link->address; - } else - pico_err = PICO_ERR_EHOSTUNREACH; - - return myself; -} - -struct pico_device *pico_ipv6_source_dev_find(const struct pico_ip6 *dst) -{ - struct pico_device *dev = NULL; - struct pico_ipv6_route *rt; - - if(!dst) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - rt = pico_ipv6_route_find(dst); - if (rt && rt->link) { - dev = rt->link->dev; - } else - pico_err = PICO_ERR_EHOSTUNREACH; - - return dev; -} - -static int pico_ipv6_forward_check_dev(struct pico_frame *f) -{ - if(f->dev->eth != NULL) - f->len -= PICO_SIZE_ETHHDR; - - if(f->len > f->dev->mtu) { - pico_notify_pkt_too_big(f); - return -1; - } - - return 0; -} - -static int pico_ipv6_pre_forward_checks(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - - /* Decrease HOP count, check if expired */ - hdr->hop = (uint8_t)(hdr->hop - 1); - if (hdr->hop < 1) { - pico_notify_ttl_expired(f); - dbg(" ------------------- HOP COUNT EXPIRED\n"); - return -1; - } - /* If source is local, discard anyway (packets bouncing back and forth) */ - if (pico_ipv6_link_get(&hdr->src)) - return -1; - - if (pico_ipv6_forward_check_dev(f) < 0) - return -1; - - return 0; -} - -static int pico_ipv6_forward(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - struct pico_ipv6_route *rt; - if (!hdr) { - pico_frame_discard(f); - return -1; - } - - rt = pico_ipv6_route_find(&hdr->dst); - if (!rt) { - pico_notify_dest_unreachable(f); - pico_frame_discard(f); - return -1; - } - - f->dev = rt->link->dev; - - if (pico_ipv6_pre_forward_checks(f) < 0) - { - pico_frame_discard(f); - return -1; - } - - f->start = f->net_hdr; - - return pico_sendto_dev(f); -} - - -static int pico_ipv6_process_hopbyhop(struct pico_ipv6_exthdr *hbh, struct pico_frame *f) -{ - uint8_t *option = NULL; - uint8_t len = 0, optlen = 0; - uint32_t ptr = sizeof(struct pico_ipv6_hdr); - uint8_t *extensions_start = (uint8_t *)hbh; - uint8_t must_align = 1; - IGNORE_PARAMETER(f); - - option = ((uint8_t *)&hbh->ext.hopbyhop) + sizeof(struct hopbyhop_s); - len = (uint8_t)HBH_LEN(hbh); - ipv6_dbg("IPv6: hop by hop extension header length %u\n", len + 2); - while (len) { - switch (*option) - { - case PICO_IPV6_EXTHDR_OPT_PAD1: - ++option; - --len; - break; - - case PICO_IPV6_EXTHDR_OPT_PADN: - optlen = (uint8_t)((*(option + 1)) + 2); /* plus type and len byte */ - option += optlen; - len = (uint8_t)(len - optlen); - break; - case PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT: - optlen = (uint8_t)((*(option + 1)) + 2); /* plus type and len byte */ - // MLD package - if(*(option+1) == 2) - must_align = 0; - option += optlen; - len = (uint8_t)(len - optlen); - break; - default: - /* unknown option */ - optlen = (uint8_t)(*(option + 1) + 2); /* plus type and len byte */ - switch ((*option) & PICO_IPV6_EXTHDR_OPT_ACTION_MASK) { - case PICO_IPV6_EXTHDR_OPT_ACTION_SKIP: - break; - case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD: - return -1; - case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD_SI: - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, ptr + (uint32_t)(option - extensions_start)); - return -1; - case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD_SINM: - if (!pico_ipv6_is_multicast(((struct pico_ipv6_hdr *)(f->net_hdr))->dst.addr)) - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, ptr + (uint32_t)(option - extensions_start)); - - return -1; - } - ipv6_dbg("IPv6: option with type %u and length %u\n", *option, optlen); - option += optlen; - len = (uint8_t)(len - optlen); - } - } - return must_align; -} - - -static int pico_ipv6_process_routing(struct pico_ipv6_exthdr *routing, struct pico_frame *f, uint32_t ptr) -{ - IGNORE_PARAMETER(f); - - if (routing->ext.routing.segleft == 0) - return 0; - - ipv6_dbg("IPv6: routing extension header with len %u\n", routing->ext.routing.len + 2); - switch (routing->ext.routing.routtype) { - case 0x00: - /* deprecated */ - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, ptr + 2); - return -1; - case 0x02: - /* routing type for MIPv6: not supported yet */ - break; - default: - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, ptr + 2); - return -1; - } - return 0; -} - -#define IP6FRAG_MORE(x) ((x & 0x0001)) - -static int pico_ipv6_process_destopt(struct pico_ipv6_exthdr *destopt, struct pico_frame *f, uint32_t opt_ptr) -{ - uint8_t *option = NULL; - uint8_t len = 0, optlen = 0; - opt_ptr += (uint32_t)(2u); /* Skip Dest_opts header */ - IGNORE_PARAMETER(f); - option = ((uint8_t *)&destopt->ext.destopt) + sizeof(struct destopt_s); - len = (uint8_t)(((destopt->ext.destopt.len + 1) << 3) - 2); /* len in bytes, minus nxthdr and len byte */ - ipv6_dbg("IPv6: destination option extension header length %u\n", len + 2); - while (len) { - optlen = (uint8_t)(*(option + 1) + 2); - switch (*option) - { - case PICO_IPV6_EXTHDR_OPT_PAD1: - break; - - case PICO_IPV6_EXTHDR_OPT_PADN: - break; - - case PICO_IPV6_EXTHDR_OPT_SRCADDR: - ipv6_dbg("IPv6: home address option with length %u\n", optlen); - break; - - default: - ipv6_dbg("IPv6: option with type %u and length %u\n", *option, optlen); - switch (*option & PICO_IPV6_EXTHDR_OPT_ACTION_MASK) { - case PICO_IPV6_EXTHDR_OPT_ACTION_SKIP: - break; - case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD: - return -1; - case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD_SI: - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, opt_ptr); - return -1; - case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD_SINM: - if (!pico_ipv6_is_multicast(((struct pico_ipv6_hdr *)(f->net_hdr))->dst.addr)){ - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, opt_ptr); - } - return -1; - } - break; - } - opt_ptr += optlen; - option += optlen; - len = (uint8_t)(len - optlen); - } - return 0; -} - -#define IPV6_OPTLEN(x) ((uint16_t)(((x + 1) << 3))) - -static int pico_ipv6_check_headers_sequence(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - int ptr = sizeof(struct pico_ipv6_hdr); - int cur_nexthdr = 6; /* Starts with nexthdr field in ipv6 pkt */ - uint8_t nxthdr = hdr->nxthdr; - for (;; ) { - uint8_t optlen = *(f->net_hdr + ptr + 1); - switch (nxthdr) { - case PICO_IPV6_EXTHDR_DESTOPT: - case PICO_IPV6_EXTHDR_ROUTING: - case PICO_IPV6_EXTHDR_HOPBYHOP: - case PICO_IPV6_EXTHDR_ESP: - case PICO_IPV6_EXTHDR_AUTH: - optlen = (uint8_t)IPV6_OPTLEN(optlen); - break; - case PICO_IPV6_EXTHDR_FRAG: - optlen = 8; - break; - case PICO_IPV6_EXTHDR_NONE: - return 0; - - case PICO_PROTO_TCP: - case PICO_PROTO_UDP: - case PICO_PROTO_ICMP6: - return 0; - default: - /* Invalid next header */ - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_NXTHDR, (uint32_t)cur_nexthdr); - return -1; - } - cur_nexthdr = ptr; - nxthdr = *(f->net_hdr + ptr); - ptr += optlen; - } -} - -static int pico_ipv6_check_aligned(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if ((short_be(hdr->len) % 8) != 0) { - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, 4); - return -1; - } - - return 0; -} - -static int pico_ipv6_extension_headers(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - uint8_t nxthdr = hdr->nxthdr; - struct pico_ipv6_exthdr *exthdr = NULL, *frag_hdr = NULL; - uint32_t ptr = sizeof(struct pico_ipv6_hdr); - uint16_t cur_optlen; - uint32_t cur_nexthdr = 6; - int must_align = 0; - - f->net_len = sizeof(struct pico_ipv6_hdr); - - if (pico_ipv6_check_headers_sequence(f) < 0) - return -1; - for (;; ) { - exthdr = (struct pico_ipv6_exthdr *)(f->net_hdr + f->net_len); - cur_optlen = 0; - - switch (nxthdr) { - case PICO_IPV6_EXTHDR_HOPBYHOP: - if (cur_nexthdr != 6) { - /* The Hop-by-Hop Options header, - * when present, must immediately follow the IPv6 header. - */ - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_NXTHDR, cur_nexthdr); - return -1; - } - - cur_optlen = IPV6_OPTLEN(exthdr->ext.hopbyhop.len); - f->net_len = (uint16_t) (f->net_len + cur_optlen); - must_align = pico_ipv6_process_hopbyhop(exthdr, f); - if(must_align < 0) - return -1; - - break; - case PICO_IPV6_EXTHDR_ROUTING: - cur_optlen = IPV6_OPTLEN(exthdr->ext.routing.len); - f->net_len = (uint16_t) (f->net_len + cur_optlen); - if (pico_ipv6_process_routing(exthdr, f, ptr) < 0) - return -1; - - break; - case PICO_IPV6_EXTHDR_FRAG: - cur_optlen = 8u; - f->net_len = (uint16_t) (f->net_len + cur_optlen); - frag_hdr = exthdr; - f->frag = (uint16_t)((frag_hdr->ext.frag.om[0] << 8) + frag_hdr->ext.frag.om[1]); - /* If M-Flag is set, and packet is not 8B aligned, discard and alert */ - if (IP6FRAG_MORE(f->frag) && ((short_be(hdr->len) % 8) != 0)) { - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, 4); - return -1; - } - - break; - case PICO_IPV6_EXTHDR_DESTOPT: - cur_optlen = IPV6_OPTLEN(exthdr->ext.destopt.len); - f->net_len = (uint16_t) (f->net_len + cur_optlen); - must_align = 1; - if (pico_ipv6_process_destopt(exthdr, f, ptr) < 0) - return -1; - - break; - case PICO_IPV6_EXTHDR_ESP: - /* not supported, ignored. */ - return 0; - case PICO_IPV6_EXTHDR_AUTH: - /* not supported, ignored */ - return 0; - case PICO_IPV6_EXTHDR_NONE: - /* no next header */ - if (must_align && (pico_ipv6_check_aligned(f) < 0)) - return -1; - - return 0; - - case PICO_PROTO_TCP: - case PICO_PROTO_UDP: - case PICO_PROTO_ICMP6: - if (must_align && (pico_ipv6_check_aligned(f) < 0)) - return -1; - - f->transport_hdr = f->net_hdr + f->net_len; - f->transport_len = (uint16_t)(short_be(hdr->len) - (f->net_len - sizeof(struct pico_ipv6_hdr))); - if (frag_hdr) { -#ifdef PICO_SUPPORT_IPV6FRAG - pico_ipv6_process_frag(frag_hdr, f, nxthdr); -#endif - return -1; - } else { - return nxthdr; - } - - break; - default: - /* Invalid next header */ - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_NXTHDR, cur_nexthdr); - return -1; - } - nxthdr = exthdr->nxthdr; - cur_nexthdr = ptr; - ptr += cur_optlen; - } -} -static int pico_ipv6_process_mcast_in(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *) f->net_hdr; - struct pico_ipv6_exthdr *hbh = NULL; - if (pico_ipv6_is_multicast(hdr->dst.addr)) { -#ifdef PICO_SUPPORT_MCAST - /* Receiving UDP multicast datagram TODO set f->flags? */ - if(hdr->nxthdr == 0) { - hbh = (struct pico_ipv6_exthdr *) (f->transport_hdr); - } - if (hdr->nxthdr == PICO_PROTO_ICMP6 || (hbh != NULL && hbh->nxthdr == PICO_PROTO_ICMP6)) { - pico_transport_receive(f, PICO_PROTO_ICMP6); - return 1; - } else if ((pico_ipv6_mcast_filter(f) == 0) && (hdr->nxthdr == PICO_PROTO_UDP)) { - pico_enqueue(pico_proto_udp.q_in, f); - return 1; - } - -#endif - pico_frame_discard(f); - return 1; - } - - return 0; -} -static int pico_ipv6_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - int proto = 0; - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - struct pico_ipv6_exthdr *hbh; - IGNORE_PARAMETER(self); - /* forward if not local, except if router alert is set */ - if (pico_ipv6_is_unicast(&hdr->dst) && !pico_ipv6_link_get(&hdr->dst)) { - if(hdr->nxthdr == 0) { - hbh = (struct pico_ipv6_exthdr *) f->transport_hdr; - if(hbh->ext.routing.routtype == 0) - return pico_ipv6_forward(f); - } else - /* not local, try to forward. */ - return pico_ipv6_forward(f); - } - - proto = pico_ipv6_extension_headers(f); - if (proto <= 0) { - pico_frame_discard(f); - return 0; - } - - f->proto = (uint8_t)proto; - ipv6_dbg("IPv6: payload %u net_len %u nxthdr %u\n", short_be(hdr->len), f->net_len, proto); - - if (pico_ipv6_is_unicast(&hdr->dst)) { - pico_transport_receive(f, f->proto); - } else if (pico_ipv6_is_multicast(hdr->dst.addr)) { - /* XXX perform multicast filtering: solicited-node multicast address MUST BE allowed! */ - if (pico_ipv6_process_mcast_in(f) > 0) - return 0; - pico_transport_receive(f, f->proto); - } - - return 0; -} - -static int pico_ipv6_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - IGNORE_PARAMETER(self); - - f->start = (uint8_t*)f->net_hdr; - return pico_sendto_dev(f); -} - -/* allocates an IPv6 packet without extension headers. If extension headers are needed, - * include the len of the extension headers in the size parameter. Once a frame acquired - * increment net_len and transport_hdr with the len of the extension headers, decrement - * transport_len with this value. - */ -static struct pico_frame *pico_ipv6_alloc(struct pico_protocol *self, uint16_t size) -{ - struct pico_frame *f = pico_frame_alloc((uint32_t)(size + PICO_SIZE_IP6HDR + PICO_SIZE_ETHHDR)); - - IGNORE_PARAMETER(self); - - if (!f) - return NULL; - - f->datalink_hdr = f->buffer; - f->net_hdr = f->buffer + PICO_SIZE_ETHHDR; - f->net_len = PICO_SIZE_IP6HDR; - f->transport_hdr = f->net_hdr + PICO_SIZE_IP6HDR; - f->transport_len = (uint16_t)size; - /* PICO_SIZE_ETHHDR is accounted for in pico_ethernet_send */ - f->len = (uint32_t)(size + PICO_SIZE_IP6HDR); - return f; -} - -static inline int ipv6_pushed_frame_valid(struct pico_frame *f, struct pico_ip6 *dst) -{ - struct pico_ipv6_hdr *hdr = NULL; - if(!f || !dst) - return -1; - - hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (!hdr) { - dbg("IPv6: IP header error\n"); - return -1; - } - - return 0; -} -int pico_ipv6_is_null_address(struct pico_ip6 * ip6) { - struct pico_ip6 null_addr = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; - return !memcmp(ip6, &null_addr, sizeof(struct pico_ip6)); -} -#ifdef PICO_SUPPORT_MCAST -/* link - * | - * MCASTGroups - * | | | - * ------------ | ------------ - * | | | - * MCASTSources MCASTSources MCASTSources - * | | | | | | | | | | | | - * S S S S S S S S S S S S - * - * MCASTGroups: RBTree(mcast_group) - * MCASTSources: RBTree(source) - */ -static int ipv6_mcast_groups_cmp(void *ka, void *kb) -{ - struct pico_ipv6_mcast_group *a = ka, *b = kb; - return pico_ipv6_compare(&a->mcast_addr, &b->mcast_addr); -} -static int ipv6_mcast_sources_cmp(void *ka, void *kb) -{ - struct pico_ip6 *a = ka, *b = kb; - return pico_ipv6_compare(a, b); -} - -static void pico_ipv6_mcast_print_groups(struct pico_ipv6_link *mcast_link) -{ -#ifdef PICO_DEBUG_MULTICAST - uint16_t i = 0; - struct pico_ipv6_mcast_group *g = NULL; - struct pico_ip6 *source = NULL; - struct pico_tree_node *index = NULL, *index2 = NULL; - char *ipv6_addr; - (void) source; - ipv6_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); - ipv6_mcast_dbg("+ MULTICAST list interface %-16s +\n", mcast_link->dev->name); - ipv6_mcast_dbg("+------------------------------------------------------------------------------------------+\n"); - ipv6_mcast_dbg("+ nr | interface | host group | reference count | filter mode | source +\n"); - ipv6_mcast_dbg("+------------------------------------------------------------------------------------------+\n"); - ipv6_addr = PICO_ZALLOC(PICO_IPV6_STRING); - pico_tree_foreach(index, mcast_link->MCASTGroups) { - g = index->keyValue; - pico_ipv6_to_string(ipv6_addr, &g->mcast_addr.addr[0]); - ipv6_mcast_dbg("+ %04d | %16s | %s | %05u | %u | %8s +\n", i, mcast_link->dev->name, ipv6_addr, g->reference_count, g->filter_mode, ""); - pico_tree_foreach(index2, &g->MCASTSources) { - source = index2->keyValue; - pico_ipv6_to_string(ipv6_addr, source->addr); - ipv6_mcast_dbg("+ %4s | %16s | %8s | %5s | %s | %s +\n", "", "", "", "", "", ipv6_addr); - } - i++; - } - PICO_FREE(ipv6_addr); - ipv6_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); -#else - IGNORE_PARAMETER(mcast_link); -#endif - -} - -static int mcast_group_update_ipv6(struct pico_ipv6_mcast_group *g, struct pico_tree *_MCASTFilter, uint8_t filter_mode) -{ - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ip6 *source = NULL; - /* cleanup filter */ - pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) { - source = index->keyValue; - pico_tree_delete(&g->MCASTSources, source); - PICO_FREE(source); - } - /* insert new filter */ - if (_MCASTFilter) { - pico_tree_foreach(index, _MCASTFilter) { - if (index->keyValue) { - source = PICO_ZALLOC(sizeof(struct pico_ip6)); - if (!source) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - *source = *((struct pico_ip6 *)index->keyValue); - pico_tree_insert(&g->MCASTSources, source); - } - } - } - - g->filter_mode = filter_mode; - return 0; -} - -int pico_ipv6_mcast_join(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *_MCASTFilter) -{ - struct pico_ipv6_mcast_group *g = NULL, test = { - 0 - }; - struct pico_ipv6_link *link = NULL; - int res = -1; - if (mcast_link) { - link = pico_ipv6_link_get(mcast_link); - } - if (!link) { - link = mcast_default_link_ipv6; - } - test.mcast_addr = *mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (g) { - if (reference_count) - g->reference_count++; - res = pico_mld_state_change(mcast_link, mcast_group, filter_mode, _MCASTFilter, PICO_MLD_STATE_UPDATE); - } else { - g = PICO_ZALLOC(sizeof(struct pico_ipv6_mcast_group)); - if (!g) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - /* "non-existent" state of filter mode INCLUDE and empty source list */ - g->filter_mode = PICO_IP_MULTICAST_INCLUDE; - g->reference_count = 1; - g->mcast_addr = *mcast_group; - g->MCASTSources.root = &LEAF; - g->MCASTSources.compare = ipv6_mcast_sources_cmp; - pico_tree_insert(link->MCASTGroups, g); - res = pico_mld_state_change(mcast_link, mcast_group, filter_mode, _MCASTFilter, PICO_MLD_STATE_CREATE); - } - - if (mcast_group_update_ipv6(g, _MCASTFilter, filter_mode) < 0) { - dbg("Error in mcast_group update\n"); - return -1; - } - pico_ipv6_mcast_print_groups(link); - return res; -} - -int pico_ipv6_mcast_leave(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *_MCASTFilter) -{ - struct pico_ipv6_mcast_group *g = NULL, test = { - 0 - }; - struct pico_ipv6_link *link = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ip6 *source = NULL; - int res = -1; - if (mcast_link) - link = pico_ipv6_link_get(mcast_link); - - if (!link) - link = mcast_default_link_ipv6; - - test.mcast_addr = *mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (!g) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - if (reference_count && (--(g->reference_count) < 1)) { - res = pico_mld_state_change(mcast_link, mcast_group, filter_mode, _MCASTFilter, PICO_MLD_STATE_DELETE); - /* cleanup filter */ - pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) { - source = index->keyValue; - pico_tree_delete(&g->MCASTSources, source); - PICO_FREE(source); - } - pico_tree_delete(link->MCASTGroups, g); - PICO_FREE(g); - } else { - res = pico_mld_state_change(mcast_link, mcast_group, filter_mode, _MCASTFilter, PICO_MLD_STATE_UPDATE); - if (mcast_group_update_ipv6(g, _MCASTFilter, filter_mode) < 0) - return -1; - } - } - - pico_ipv6_mcast_print_groups(link); - return res; -} - -struct pico_ipv6_link *pico_ipv6_get_default_mcastlink(void) -{ - return mcast_default_link_ipv6; -} - -static int pico_ipv6_mcast_filter(struct pico_frame *f) -{ - struct pico_ipv6_link *link = NULL; - struct pico_tree_node *index = NULL, *index2 = NULL; - struct pico_ipv6_mcast_group *g = NULL, test = { - 0 - }; - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *) f->net_hdr; -#ifdef PICO_DEBUG_MULTICAST - char ipv6_addr[PICO_IPV6_STRING]; -#endif - test.mcast_addr = hdr->dst; - - pico_tree_foreach(index, &Tree_dev_ip6_link) { - link = index->keyValue; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (g) { - if (f->dev == link->dev) { -#ifdef PICO_DEBUG_MULTICAST - pico_ipv6_to_string( ipv6_addr, &hdr->dst.addr[0]); - ipv6_mcast_dbg("MCAST: IP %s is group member of current link %s\n", ipv6_addr, f->dev->name); -#endif - /* perform source filtering */ - switch (g->filter_mode) { - case PICO_IP_MULTICAST_INCLUDE: - pico_tree_foreach(index2, &g->MCASTSources) { - if (hdr->src.addr == ((struct pico_ip6 *)index2->keyValue)->addr) { -#ifdef PICO_DEBUG_MULTICAST - pico_ipv6_to_string(ipv6_addr,&hdr->src.addr[0]); - ipv6_mcast_dbg("MCAST: IP %s in included interface source list\n", ipv6_addr); -#endif - return 0; - } - } -#ifdef PICO_DEBUG_MULTICAST - pico_ipv6_to_string(ipv6_addr,&hdr->src.addr[0]); - ipv6_mcast_dbg("MCAST: IP %s NOT in included interface source list\n", ipv6_addr); -#endif - return -1; - - case PICO_IP_MULTICAST_EXCLUDE: - pico_tree_foreach(index2, &g->MCASTSources) { - if (memcmp(hdr->src.addr , (((struct pico_ip6 *)index2->keyValue)->addr) , sizeof(struct pico_ip6))== 0){ -#ifdef PICO_DEBUG_MULTICAST - pico_ipv6_to_string(ipv6_addr,&hdr->src.addr[0]); - ipv6_mcast_dbg("MCAST: IP %s in excluded interface source list\n", ipv6_addr); -#endif - return -1; - } - } -#ifdef PICO_DEBUG_MULTICAST - pico_ipv6_to_string(ipv6_addr,&hdr->src.addr[0]); - ipv6_mcast_dbg("MCAST: IP %s NOT in excluded interface source list\n", ipv6_addr); -#endif - return 0; - - default: - return -1; - } - } else { -#ifdef PICO_DEBUG_MULTICAST - pico_ipv6_to_string(ipv6_addr,&hdr->dst.addr[0]); - ipv6_mcast_dbg("MCAST: IP %s is group member of different link %s\n", ipv6_addr, link->dev->name); -#endif - } - } else { -#ifdef PICO_DEBUG_MULTICAST - pico_ipv6_to_string(ipv6_addr,&hdr->dst.addr[0]); - ipv6_mcast_dbg("MCAST: IP %s is not a group member of link %s\n", ipv6_addr, f->dev->name); -#endif - } - } - return -1; -} - -#else - -int pico_ipv6_mcast_join(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *_MCASTFilter) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -int pico_ipv6_mcast_leave(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *_MCASTFilter) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -struct pico_ipv6_link *pico_ipv6_get_default_mcastlink(void) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return NULL; -} -#endif /* PICO_SUPPORT_MCAST */ -static inline struct pico_ipv6_route *ipv6_pushed_frame_checks(struct pico_frame *f, struct pico_ip6 *dst) -{ - struct pico_ipv6_route *route = NULL; - - if (ipv6_pushed_frame_valid(f, dst) < 0) - return NULL; - - if (memcmp(dst->addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0) { - dbg("IPv6: IP destination address error\n"); - return NULL; - } - - route = pico_ipv6_route_find(dst); - if (!route && !f->dev) { - dbg("IPv6: route not found.\n"); - pico_err = PICO_ERR_EHOSTUNREACH; - return NULL; - } - - return route; -} - -static inline void ipv6_push_hdr_adjust(struct pico_frame *f, struct pico_ipv6_link *link, struct pico_ip6 *src, struct pico_ip6 *dst, uint8_t proto, int is_dad) -{ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_ipv6_hdr *hdr = NULL; - struct pico_ipv6_exthdr *hbh = NULL; - const uint8_t vtf = (uint8_t)long_be(0x60000000); /* version 6, traffic class 0, flow label 0 */ - - hdr = (struct pico_ipv6_hdr *)f->net_hdr; - hdr->vtf = vtf; - hdr->len = short_be((uint16_t)(f->transport_len + f->net_len - (uint16_t)sizeof(struct pico_ipv6_hdr))); - hdr->nxthdr = proto; - hdr->hop = f->dev->hostvars.hoplimit; - hdr->dst = *dst; - - if (!src || !pico_ipv6_is_unicast(src)) - /* Address defaults to the link information: src address selection is done via link */ - hdr->src = link->address; - else { - /* Sender protocol is forcing an IPv6 address */ - hdr->src = *src; - } - - if (f->send_ttl) { - hdr->hop = f->send_ttl; - } - - if (f->send_tos) { - hdr->vtf |= ((uint32_t)f->send_tos << 20u); - } - - /* make adjustments to defaults according to proto */ - switch (proto) - { - case 0: - { - hbh = (struct pico_ipv6_exthdr *) f->transport_hdr; - switch(hbh->nxthdr) { - case PICO_PROTO_ICMP6: - { - icmp6_hdr = (struct pico_icmp6_hdr *)(f->transport_hdr+sizeof(struct pico_ipv6_exthdr)); - if((icmp6_hdr->type >= PICO_MLD_QUERY && icmp6_hdr->type <= PICO_MLD_DONE) || icmp6_hdr->type == PICO_MLD_REPORTV2) { - hdr->hop = 1; - } - icmp6_hdr->crc = 0; - icmp6_hdr->crc = short_be(pico_mld_checksum(f)); - break; - } - } - break; - } - case PICO_PROTO_ICMP6: - { - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - if (icmp6_hdr->type == PICO_ICMP6_NEIGH_SOL || icmp6_hdr->type == PICO_ICMP6_NEIGH_ADV || icmp6_hdr->type == PICO_ICMP6_ROUTER_SOL || icmp6_hdr->type == PICO_ICMP6_ROUTER_ADV) - hdr->hop = 255; - - if ((is_dad || link->istentative) && icmp6_hdr->type == PICO_ICMP6_NEIGH_SOL){ - memcpy(hdr->src.addr, PICO_IP6_ANY, PICO_SIZE_IP6); - - } - - icmp6_hdr->crc = 0; - icmp6_hdr->crc = short_be(pico_icmp6_checksum(f)); - break; - } -#ifdef PICO_SUPPORT_UDP - case PICO_PROTO_UDP: - { - struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - udp_hdr->crc = short_be(pico_udp_checksum_ipv6(f)); - break; - } -#endif - - default: - break; - } - -} - -static int ipv6_frame_push_final(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = NULL; - hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if(pico_ipv6_link_get(&hdr->dst)) { - return pico_enqueue(&ipv6_in, f); - } - else { - return pico_enqueue(&ipv6_out, f); - } -} - -struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev); - -int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *src, struct pico_ip6 *dst, uint8_t proto, int is_dad) -{ - struct pico_ipv6_route *route = NULL; - struct pico_ipv6_link *link = NULL; - - if (pico_ipv6_is_linklocal(dst->addr) || pico_ipv6_is_multicast(dst->addr) || pico_ipv6_is_sitelocal(dst->addr)) { - if (!f->dev) { - pico_frame_discard(f); - return -1; - } - if (pico_ipv6_is_sitelocal(dst->addr)) - link = pico_ipv6_sitelocal_get(f->dev); - else - link = pico_ipv6_linklocal_get(f->dev); - - if (link) - goto push_final; - } - - if (pico_ipv6_is_localhost(dst->addr)) { - f->dev = pico_get_device("loop"); - } - - route = ipv6_pushed_frame_checks(f, dst); - if (!route) { - pico_frame_discard(f); - return -1; - } - - link = route->link; - - if (f->sock && f->sock->dev) - f->dev = f->sock->dev; - else { - f->dev = link->dev; - if (f->sock) - f->sock->dev = f->dev; - } - - - #if 0 - if (pico_ipv6_is_multicast(hdr->dst.addr)) { - /* XXX: reimplement loopback */ - } - - #endif - -push_final: - ipv6_push_hdr_adjust(f, link, src, dst, proto, is_dad); - return ipv6_frame_push_final(f); -} - -static int pico_ipv6_frame_sock_push(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_ip6 *dst = NULL; - struct pico_remote_endpoint *remote_endpoint = NULL; - - IGNORE_PARAMETER(self); - - if (!f->sock) { - pico_frame_discard(f); - return -1; - } - - remote_endpoint = (struct pico_remote_endpoint *)f->info; - if (remote_endpoint) { - dst = &remote_endpoint->remote_addr.ip6; - } else { - dst = &f->sock->remote_addr.ip6; - } - - return pico_ipv6_frame_push(f, NULL, dst, (uint8_t)f->sock->proto->proto_number, 0); -} - -/* interface: protocol definition */ -struct pico_protocol pico_proto_ipv6 = { - .name = "ipv6", - .proto_number = PICO_PROTO_IPV6, - .layer = PICO_LAYER_NETWORK, - .alloc = pico_ipv6_alloc, - .process_in = pico_ipv6_process_in, - .process_out = pico_ipv6_process_out, - .push = pico_ipv6_frame_sock_push, - .q_in = &ipv6_in, - .q_out = &ipv6_out, -}; - -#ifdef DEBUG_ROUTE -static void pico_ipv6_dbg_route(void) -{ - struct pico_ipv6_route *r; - struct pico_tree_node *index; - pico_tree_foreach(index, &Routes){ - r = index->keyValue; - dbg("Route to %08x/%08x, gw %08x, dev: %s, metric: %d\n", r->dest.addr, r->netmask.addr, r->gateway.addr, r->link->dev->name, r->metric); - } -} -#else -#define pico_ipv6_dbg_route() do { } while(0) -#endif - -static inline struct pico_ipv6_route *ipv6_route_add_link(struct pico_ip6 gateway) -{ - struct pico_ip6 zerogateway = {{0}}; - struct pico_ipv6_route *r = pico_ipv6_route_find(&gateway); - if (!r ) { /* Specified Gateway is unreachable */ - pico_err = PICO_ERR_EHOSTUNREACH; - return NULL; - } - - if (memcmp(r->gateway.addr, zerogateway.addr, PICO_SIZE_IP6) != 0) { /* Specified Gateway is not a neighbor */ - pico_err = PICO_ERR_ENETUNREACH; - return NULL; - } - - - return r; -} - -int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link) -{ - struct pico_ip6 zerogateway = {{0}}; - struct pico_ipv6_route test, *new = NULL; - test.dest = address; - test.netmask = netmask; - test.metric = (uint32_t)metric; - if (pico_tree_findKey(&IPV6Routes, &test)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - new = PICO_ZALLOC(sizeof(struct pico_ipv6_route)); - if (!new) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - ipv6_dbg("Adding IPV6 static route\n"); - new->dest = address; - new->netmask = netmask; - new->gateway = gateway; - new->metric = (uint32_t)metric; - if (memcmp(gateway.addr, zerogateway.addr, PICO_SIZE_IP6) == 0) { - /* No gateway provided, use the link */ - new->link = link; - } else { - struct pico_ipv6_route *r = ipv6_route_add_link(gateway); - if (!r) { - if (link) - new->link = link; - else { - PICO_FREE(new); - return -1; - } - } else { - new->link = r->link; - } - } - - if (new->link && (pico_ipv6_is_global(address.addr)) && (!pico_ipv6_is_global(new->link->address.addr))) { - new->link = pico_ipv6_global_get(new->link->dev); - } - - if (!new->link) { - pico_err = PICO_ERR_EINVAL; - PICO_FREE(new); - return -1; - } - - - pico_tree_insert(&IPV6Routes, new); - pico_ipv6_dbg_route(); - return 0; -} - -int pico_ipv6_route_del(struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link) -{ - struct pico_ipv6_route test, *found = NULL; - - IGNORE_PARAMETER(gateway); - - if (!link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - test.dest = address; - test.netmask = netmask; - test.metric = (uint32_t)metric; - - found = pico_tree_findKey(&IPV6Routes, &test); - if (found) { - pico_tree_delete(&IPV6Routes, found); - PICO_FREE(found); - pico_ipv6_dbg_route(); - return 0; - } - - pico_err = PICO_ERR_EINVAL; - return -1; -} - -void pico_ipv6_router_down(struct pico_ip6 *address) -{ - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ipv6_route *route = NULL; - if (!address) - return; - - pico_tree_foreach_safe(index, &IPV6Routes, _tmp) - { - route = index->keyValue; - if (pico_ipv6_compare(address, &route->gateway) == 0) - pico_ipv6_route_del(route->dest, route->netmask, route->gateway, (int)route->metric, route->link); - } -} - -#ifndef UNIT_TEST -static void pico_ipv6_nd_dad(pico_time now, void *arg) -{ - struct pico_ip6 *address = (struct pico_ip6 *)arg; - struct pico_ipv6_link *l = NULL; - struct pico_ip6 old_address; - if (!arg) - return; - - IGNORE_PARAMETER(now); - - l = pico_ipv6_link_istentative(address); - if (!l) - return; - - if (pico_device_link_state(l->dev) == 0) { - l->dad_timer = pico_timer_add(100, pico_ipv6_nd_dad, &l->address); - return; - } - - if (l->isduplicate) { - dbg("IPv6: duplicate address.\n"); - old_address = *address; - if (pico_ipv6_is_linklocal(address->addr)) { - address->addr[8] = (uint8_t)((uint8_t)(pico_rand() & 0xff) & (uint8_t)(~0x03)); - address->addr[9] = pico_rand() & 0xff; - address->addr[10] = pico_rand() & 0xff; - address->addr[11] = pico_rand() & 0xff; - address->addr[12] = pico_rand() & 0xff; - address->addr[13] = pico_rand() & 0xff; - address->addr[14] = pico_rand() & 0xff; - address->addr[15] = pico_rand() & 0xff; - pico_ipv6_link_add(l->dev, *address, l->netmask); - } - - pico_ipv6_link_del(l->dev, old_address); - } - else { - if (l->dup_detect_retrans-- == 0) { - dbg("IPv6: DAD verified valid address.\n"); - l->istentative = 0; - } else { - /* Duplicate Address Detection */ - pico_icmp6_neighbor_solicitation(l->dev, &l->address, PICO_ICMP6_ND_DAD); - l->dad_timer = pico_timer_add(PICO_ICMP6_MAX_RTR_SOL_DELAY, pico_ipv6_nd_dad, &l->address); - } - } -} -#endif - - -struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask) -{ - struct pico_ipv6_link test = { - 0 - }, *new = NULL; - struct pico_ip6 network = {{0}}, gateway = {{0}}; - struct pico_ip6 mcast_addr = {{ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; - struct pico_ip6 mcast_nm = {{ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; - struct pico_ip6 mcast_gw = {{0}}; - struct pico_ip6 all_hosts = {{ 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}; -#ifdef PICO_DEBUG_IPV6 - char ipstr[40] = { - 0 - }; -#endif - int i = 0; - if (!dev) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - test.address = address; - test.dev = dev; - /** XXX: Valid netmask / unicast address test **/ - - if (pico_tree_findKey(&IPV6Links, &test)) { - dbg("IPv6: trying to assign an invalid address (in use)\n"); - pico_err = PICO_ERR_EADDRINUSE; - return NULL; - } - - /** XXX: Check for network already in use (e.g. trying to assign 10.0.0.1/24 where 10.1.0.1/8 is in use) **/ - new = PICO_ZALLOC(sizeof(struct pico_ipv6_link)); - if (!new) { - dbg("IPv6: out of memory!\n"); - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - new->address = address; - new->netmask = netmask; - new->dev = dev; - new->istentative = 1; - new->isduplicate = 0; -#ifdef PICO_SUPPORT_MCAST - new->MCASTGroups = PICO_ZALLOC(sizeof(struct pico_tree)); - if (!new->MCASTGroups) { - PICO_FREE(new); - dbg("IPv6: Out of memory!\n"); - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - new->MCASTGroups->root = &LEAF; - new->MCASTGroups->compare = ipv6_mcast_groups_cmp; - new->mcast_compatibility = PICO_MLDV2; - new->mcast_last_query_interval = MLD_QUERY_INTERVAL; -#endif - pico_tree_insert(&IPV6Links, new); - for (i = 0; i < PICO_SIZE_IP6; ++i) { - network.addr[i] = address.addr[i] & netmask.addr[i]; - } -#ifdef PICO_SUPPORT_MCAST - do { - if (!mcast_default_link_ipv6) { - mcast_default_link_ipv6 = new; - pico_ipv6_route_add(mcast_addr, mcast_nm, mcast_gw, 1, new); - } - pico_ipv6_mcast_join(&address, &all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL); - } while(0); -#endif - pico_ipv6_route_add(network, netmask, gateway, 1, new); - pico_ipv6_route_add(mcast_addr, mcast_nm, mcast_gw, 1, new); - new->dup_detect_retrans = PICO_IPV6_DEFAULT_DAD_RETRANS; -#ifndef UNIT_TEST - /* Duplicate Address Detection */ - new->dad_timer = pico_timer_add(100, pico_ipv6_nd_dad, &new->address); -#else - new->istentative = 0; -#endif - -#ifdef PICO_DEBUG_IPV6 - pico_ipv6_to_string(ipstr, new->address.addr); - dbg("Assigned ipv6 %s to device %s\n", ipstr, new->dev->name); -#endif - return new; -} - -static int pico_ipv6_cleanup_routes(struct pico_ipv6_link *link) -{ - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ipv6_route *route = NULL; - - pico_tree_foreach_safe(index, &IPV6Routes, _tmp) - { - route = index->keyValue; - if (link == route->link) - pico_ipv6_route_del(route->dest, route->netmask, route->gateway, (int)route->metric, route->link); - } - return 0; -} - -int pico_ipv6_cleanup_links(struct pico_device *dev) -{ - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ipv6_link *link = NULL; - - pico_tree_foreach_safe(index, &IPV6Links, _tmp) - { - link = index->keyValue; - if (dev == link->dev) - pico_ipv6_link_del(dev, link->address); - } - return 0; -} - -int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address) -{ - struct pico_ipv6_link test = { - 0 - }, *found = NULL; - - if (!dev) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - test.address = address; - test.dev = dev; - found = pico_tree_findKey(&IPV6Links, &test); - if (!found) { - pico_err = PICO_ERR_ENXIO; - return -1; - } - - pico_ipv6_cleanup_routes(found); - if (found->dad_timer) - pico_timer_cancel(found->dad_timer); - - pico_tree_delete(&IPV6Links, found); - /* XXX MUST leave the solicited-node multicast address corresponding to the address (RFC 4861 $7.2.1) */ - PICO_FREE(found); - return 0; -} - -struct pico_ipv6_link *pico_ipv6_link_istentative(struct pico_ip6 *address) -{ - struct pico_ipv6_link test = { - 0 - }, *found = NULL; - test.address = *address; - - found = pico_tree_findKey(&IPV6Links, &test); - if (!found) - return NULL; - - if (found->istentative) - return found; - - return NULL; -} - -struct pico_ipv6_link *pico_ipv6_link_get(struct pico_ip6 *address) -{ - struct pico_ipv6_link test = { - 0 - }, *found = NULL; - test.address = *address; - found = pico_tree_findKey(&IPV6Links, &test); - if (!found) { - return NULL; - } - if (found->istentative) { - return NULL; - } - return found; -} - -struct pico_device *pico_ipv6_link_find(struct pico_ip6 *address) -{ - struct pico_ipv6_link test = { - 0 - }, *found = NULL; - if(!address) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - test.dev = NULL; - test.address = *address; - found = pico_tree_findKey(&IPV6Links, &test); - if (!found) { - pico_err = PICO_ERR_ENXIO; - return NULL; - } - - if (found->istentative) { - return NULL; - } - - return found->dev; -} - -struct pico_ip6 pico_ipv6_route_get_gateway(struct pico_ip6 *addr) -{ - struct pico_ip6 nullip = {{0}}; - struct pico_ipv6_route *route = NULL; - - if (!addr) { - pico_err = PICO_ERR_EINVAL; - return nullip; - } - - route = pico_ipv6_route_find(addr); - if (!route) { - pico_err = PICO_ERR_EHOSTUNREACH; - return nullip; - } - else - return route->gateway; -} - - -struct pico_ipv6_link *pico_ipv6_link_by_dev(struct pico_device *dev) -{ - struct pico_tree_node *index = NULL; - struct pico_ipv6_link *link = NULL; - - pico_tree_foreach(index, &IPV6Links) - { - link = index->keyValue; - if (dev == link->dev) - return link; - } - return NULL; -} - -struct pico_ipv6_link *pico_ipv6_link_by_dev_next(struct pico_device *dev, struct pico_ipv6_link *last) -{ - struct pico_tree_node *index = NULL; - struct pico_ipv6_link *link = NULL; - int valid = 0; - - if (last == NULL) - valid = 1; - - pico_tree_foreach(index, &IPV6Links) - { - link = index->keyValue; - if (link->dev == dev) { - if (last == link) - valid = 1; - else if (valid > 0) - return link; - } - } - return NULL; -} - -struct pico_ipv6_link *pico_ipv6_prefix_configured(struct pico_ip6 *prefix) -{ - unsigned int nm64_len = 8; - struct pico_tree_node *index = NULL; - struct pico_ipv6_link *link = NULL; - pico_tree_foreach(index, &IPV6Links) { - link = index->keyValue; - if (memcmp(link->address.addr, prefix->addr, nm64_len) == 0) - return link; - } - return NULL; -} - -struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev) -{ - struct pico_ipv6_link *link = pico_ipv6_link_by_dev(dev); - while (link && !pico_ipv6_is_linklocal(link->address.addr)) { - link = pico_ipv6_link_by_dev_next(dev, link); - } - return link; -} - -struct pico_ipv6_link *pico_ipv6_sitelocal_get(struct pico_device *dev) -{ - struct pico_ipv6_link *link = pico_ipv6_link_by_dev(dev); - while (link && !pico_ipv6_is_sitelocal(link->address.addr)) { - link = pico_ipv6_link_by_dev_next(dev, link); - } - return link; -} - -struct pico_ipv6_link *pico_ipv6_global_get(struct pico_device *dev) -{ - struct pico_ipv6_link *link = pico_ipv6_link_by_dev(dev); - while (link && !pico_ipv6_is_global(link->address.addr)) { - link = pico_ipv6_link_by_dev_next(dev, link); - } - return link; -} - -#define TWO_HOURS ((pico_time)(1000 * 60 * 60 * 2)) - -void pico_ipv6_check_lifetime_expired(pico_time now, void *arg) -{ - struct pico_tree_node *index = NULL, *temp; - struct pico_ipv6_link *link = NULL; - (void)arg; - pico_tree_foreach_safe(index, &IPV6Links, temp) { - link = index->keyValue; - if ((link->expire_time > 0) && (link->expire_time < now)) { - dbg("Warning: IPv6 address has expired.\n"); - pico_ipv6_link_del(link->dev, link->address); - } - } - pico_timer_add(1000, pico_ipv6_check_lifetime_expired, NULL); -} - -int pico_ipv6_lifetime_set(struct pico_ipv6_link *l, pico_time expire) -{ - pico_time now = PICO_TIME_MS(); - if (expire <= now) { - return -1; - } - - if (expire > 0xFFFFFFFE) { - l->expire_time = 0u; - }else if ((expire > (now + TWO_HOURS)) || (expire > l->expire_time)) { - l->expire_time = expire; - } else { - l->expire_time = now + TWO_HOURS; - } - - return 0; -} - -int pico_ipv6_dev_routing_enable(struct pico_device *dev) -{ - dev->hostvars.routing = 1; - return 0; -} - -int pico_ipv6_dev_routing_disable(struct pico_device *dev) -{ - dev->hostvars.routing = 0; - return 0; -} - -void pico_ipv6_unreachable(struct pico_frame *f, uint8_t code) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; -#if defined PICO_SUPPORT_TCP || defined PICO_SUPPORT_UDP - pico_transport_error(f, hdr->nxthdr, code); -#endif -} - - - -#endif diff --git a/ext/picotcp/modules/pico_ipv6.h b/ext/picotcp/modules/pico_ipv6.h deleted file mode 100644 index 80af525..0000000 --- a/ext/picotcp/modules/pico_ipv6.h +++ /dev/null @@ -1,175 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - *********************************************************************/ -#ifndef _INCLUDE_PICO_IPV6 -#define _INCLUDE_PICO_IPV6 -#include "pico_addressing.h" -#include "pico_protocol.h" -#include "pico_ipv4.h" -#define PICO_SIZE_IP6HDR ((uint32_t)(sizeof(struct pico_ipv6_hdr))) -#define PICO_IPV6_DEFAULT_HOP 64 -#define PICO_IPV6_MIN_MTU 1280 -#define PICO_IPV6_STRING 46 - -#define PICO_IPV6_EXTHDR_HOPBYHOP 0 -#define PICO_IPV6_EXTHDR_ROUTING 43 -#define PICO_IPV6_EXTHDR_FRAG 44 -#define PICO_IPV6_EXTHDR_ESP 50 -#define PICO_IPV6_EXTHDR_AUTH 51 -#define PICO_IPV6_EXTHDR_NONE 59 -#define PICO_IPV6_EXTHDR_DESTOPT 60 - - -#define PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT 5 -#define PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT_DATALEN 2 - -#define HBH_LEN(hbh) ((((hbh->ext.hopbyhop.len + 1) << 3) - 2)) /* len in bytes, minus nxthdr and len byte */ - -extern const uint8_t PICO_IP6_ANY[PICO_SIZE_IP6]; -extern struct pico_protocol pico_proto_ipv6; -extern struct pico_tree IPV6Routes; - -PACKED_STRUCT_DEF pico_ipv6_hdr { - uint32_t vtf; - uint16_t len; - uint8_t nxthdr; - uint8_t hop; - struct pico_ip6 src; - struct pico_ip6 dst; -}; - -PACKED_STRUCT_DEF pico_ipv6_pseudo_hdr -{ - struct pico_ip6 src; - struct pico_ip6 dst; - uint32_t len; - uint8_t zero[3]; - uint8_t nxthdr; -}; - -struct pico_ipv6_link -{ - struct pico_device *dev; - struct pico_ip6 address; - struct pico_ip6 netmask; - uint8_t istentative : 1; - uint8_t isduplicate : 1; - uint32_t dad_timer; - uint16_t dup_detect_retrans; - pico_time expire_time; -#ifdef PICO_SUPPORT_MCAST - struct pico_tree *MCASTGroups; - uint8_t mcast_compatibility; - uint8_t mcast_last_query_interval; -#endif - -}; -union pico_link { - struct pico_ipv4_link ipv4; - struct pico_ipv6_link ipv6; -}; - -struct pico_ipv6_hbhoption { - uint8_t type; - uint8_t len; -}; -#ifdef PICO_SUPPORT_MCAST -struct pico_ipv6_mcast_group { - uint8_t filter_mode; - uint16_t reference_count; - struct pico_ip6 mcast_addr; - struct pico_tree MCASTSources; -}; -#endif -struct pico_ipv6_destoption { - uint8_t type; - uint8_t len; -}; - -struct pico_ipv6_route -{ - struct pico_ip6 dest; - struct pico_ip6 netmask; - struct pico_ip6 gateway; - struct pico_ipv6_link *link; - uint32_t metric; -}; - -PACKED_STRUCT_DEF pico_ipv6_exthdr { - uint8_t nxthdr; - - PACKED_UNION_DEF ipv6_ext_u { - PEDANTIC_STRUCT_DEF hopbyhop_s { - uint8_t len; - } hopbyhop; - - PEDANTIC_STRUCT_DEF destopt_s { - uint8_t len; - } destopt; - - PEDANTIC_STRUCT_DEF routing_s { - uint8_t len; - uint8_t routtype; - uint8_t segleft; - } routing; - - PEDANTIC_STRUCT_DEF fragmentation_s { - uint8_t res; - uint8_t om[2]; - uint8_t id[4]; - } frag; - } ext; -}; - -int pico_ipv6_compare(struct pico_ip6 *a, struct pico_ip6 *b); -int pico_string_to_ipv6(const char *ipstr, uint8_t *ip); -int pico_ipv6_to_string(char *ipbuf, const uint8_t ip[PICO_SIZE_IP6]); -int pico_ipv6_is_unicast(struct pico_ip6 *a); -int pico_ipv6_is_multicast(const uint8_t addr[PICO_SIZE_IP6]); -int pico_ipv6_is_allhosts_multicast(const uint8_t addr[PICO_SIZE_IP6]); -int pico_ipv6_is_solnode_multicast(const uint8_t addr[PICO_SIZE_IP6], struct pico_device *dev); -int pico_ipv6_is_global(const uint8_t addr[PICO_SIZE_IP6]); -int pico_ipv6_is_uniquelocal(const uint8_t addr[PICO_SIZE_IP6]); -int pico_ipv6_is_sitelocal(const uint8_t addr[PICO_SIZE_IP6]); -int pico_ipv6_is_linklocal(const uint8_t addr[PICO_SIZE_IP6]); -int pico_ipv6_is_solicited(const uint8_t addr[PICO_SIZE_IP6]); -int pico_ipv6_is_unspecified(const uint8_t addr[PICO_SIZE_IP6]); -int pico_ipv6_is_localhost(const uint8_t addr[PICO_SIZE_IP6]); - -int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *src, struct pico_ip6 *dst, uint8_t proto, int is_dad); -int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link); -int pico_ipv6_route_del(struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link); -void pico_ipv6_unreachable(struct pico_frame *f, uint8_t code); - -struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask); -int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address); -int pico_ipv6_cleanup_links(struct pico_device *dev); -struct pico_ipv6_link *pico_ipv6_link_istentative(struct pico_ip6 *address); -struct pico_ipv6_link *pico_ipv6_link_get(struct pico_ip6 *address); -struct pico_device *pico_ipv6_link_find(struct pico_ip6 *address); -struct pico_ip6 pico_ipv6_route_get_gateway(struct pico_ip6 *addr); -struct pico_ip6 *pico_ipv6_source_find(const struct pico_ip6 *dst); -struct pico_device *pico_ipv6_source_dev_find(const struct pico_ip6 *dst); -struct pico_ipv6_link *pico_ipv6_link_by_dev(struct pico_device *dev); -struct pico_ipv6_link *pico_ipv6_link_by_dev_next(struct pico_device *dev, struct pico_ipv6_link *last); -struct pico_ipv6_link *pico_ipv6_global_get(struct pico_device *dev); -struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev); -struct pico_ipv6_link *pico_ipv6_sitelocal_get(struct pico_device *dev); -struct pico_ipv6_link *pico_ipv6_prefix_configured(struct pico_ip6 *prefix); -int pico_ipv6_lifetime_set(struct pico_ipv6_link *l, pico_time expire); -void pico_ipv6_check_lifetime_expired(pico_time now, void *arg); -int pico_ipv6_dev_routing_enable(struct pico_device *dev); -int pico_ipv6_dev_routing_disable(struct pico_device *dev); -void pico_ipv6_router_down(struct pico_ip6 *address); - -int pico_ipv6_mcast_join(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *_MCASTFilter); -int pico_ipv6_mcast_leave(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *_MCASTFilter); - -struct pico_ipv6_link *pico_ipv6_get_default_mcastlink(void); - -int pico_ipv6_is_null_address(struct pico_ip6 * ip6); -#endif diff --git a/ext/picotcp/modules/pico_ipv6_nd.c b/ext/picotcp/modules/pico_ipv6_nd.c deleted file mode 100644 index c1048b3..0000000 --- a/ext/picotcp/modules/pico_ipv6_nd.c +++ /dev/null @@ -1,1009 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - -#include "pico_config.h" -#include "pico_tree.h" -#include "pico_icmp6.h" -#include "pico_ipv6.h" -#include "pico_stack.h" -#include "pico_device.h" -#include "pico_eth.h" -#include "pico_addressing.h" -#include "pico_ipv6_nd.h" - -#ifdef PICO_SUPPORT_IPV6 - - -#define nd_dbg(...) do {} while(0) - -static struct pico_frame *frames_queued_v6[PICO_ND_MAX_FRAMES_QUEUED] = { 0 }; - - -enum pico_ipv6_neighbor_state { - PICO_ND_STATE_INCOMPLETE = 0, - PICO_ND_STATE_REACHABLE, - PICO_ND_STATE_STALE, - PICO_ND_STATE_DELAY, - PICO_ND_STATE_PROBE -}; - -struct pico_ipv6_neighbor { - enum pico_ipv6_neighbor_state state; - struct pico_ip6 address; - struct pico_eth mac; - struct pico_device *dev; - uint16_t is_router; - uint16_t failure_count; - pico_time expire; -}; - -static int pico_ipv6_neighbor_compare(void *ka, void *kb) -{ - struct pico_ipv6_neighbor *a = ka, *b = kb; - return pico_ipv6_compare(&a->address, &b->address); -} - - -PICO_TREE_DECLARE(NCache, pico_ipv6_neighbor_compare); - -static struct pico_ipv6_neighbor *pico_nd_find_neighbor(struct pico_ip6 *dst) -{ - struct pico_ipv6_neighbor test = { - 0 - }; - - test.address = *dst; - return pico_tree_findKey(&NCache, &test); -} - -static void pico_ipv6_nd_queued_trigger(void) -{ - int i; - struct pico_frame *f; - for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++) - { - f = frames_queued_v6[i]; - if (f) { - (void)pico_ethernet_send(f); - if(frames_queued_v6[i]) - pico_frame_discard(frames_queued_v6[i]); - frames_queued_v6[i] = NULL; - } - } -} - -static void ipv6_duplicate_detected(struct pico_ipv6_link *l) -{ - struct pico_device *dev; - int is_ll = pico_ipv6_is_linklocal(l->address.addr); - dev = l->dev; - dbg("IPV6: Duplicate address detected. Removing link.\n"); - pico_ipv6_link_del(l->dev, l->address); - if (is_ll) - pico_device_ipv6_random_ll(dev); -} - -static struct pico_ipv6_neighbor *pico_nd_add(struct pico_ip6 *addr, struct pico_device *dev) -{ - struct pico_ipv6_neighbor *n = PICO_ZALLOC(sizeof(struct pico_ipv6_neighbor)); - char address[120]; - if (!n) - return NULL; - - pico_ipv6_to_string(address, addr->addr); - nd_dbg("Adding address %s to cache...\n", address); - memcpy(&n->address, addr, sizeof(struct pico_ip6)); - n->dev = dev; - pico_tree_insert(&NCache, n); - return n; -} - -static void pico_ipv6_nd_unreachable(struct pico_ip6 *a) -{ - int i; - struct pico_frame *f; - struct pico_ipv6_hdr *hdr; - struct pico_ip6 dst; - for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++) - { - f = frames_queued_v6[i]; - if (f) { - hdr = (struct pico_ipv6_hdr *) f->net_hdr; - dst = pico_ipv6_route_get_gateway(&hdr->dst); - if (pico_ipv6_is_unspecified(dst.addr)) - dst = hdr->dst; - - if (memcmp(dst.addr, a->addr, PICO_SIZE_IP6) == 0) { - if (!pico_source_is_local(f)) { - pico_notify_dest_unreachable(f); - } - - pico_frame_discard(f); - frames_queued_v6[i] = NULL; - } - } - } -} - -static void pico_nd_new_expire_time(struct pico_ipv6_neighbor *n) -{ - if (n->state == PICO_ND_STATE_REACHABLE) - n->expire = PICO_TIME_MS() + PICO_ND_REACHABLE_TIME; - else if ((n->state == PICO_ND_STATE_DELAY) || (n->state == PICO_ND_STATE_STALE)) - n->expire = PICO_TIME_MS() + PICO_ND_DELAY_FIRST_PROBE_TIME; - else { - n->expire = n->dev->hostvars.retranstime + PICO_TIME_MS(); - } -} - -static void pico_nd_discover(struct pico_ipv6_neighbor *n) -{ - char IPADDR[64]; - if (n->expire != (pico_time)0) - return; - - pico_ipv6_to_string(IPADDR, n->address.addr); - /* dbg("Sending NS for %s\n", IPADDR); */ - if (++n->failure_count > PICO_ND_MAX_SOLICIT) - return; - - if (n->state == PICO_ND_STATE_INCOMPLETE) { - pico_icmp6_neighbor_solicitation(n->dev, &n->address, PICO_ICMP6_ND_SOLICITED); - } else { - pico_icmp6_neighbor_solicitation(n->dev, &n->address, PICO_ICMP6_ND_UNICAST); - } - - pico_nd_new_expire_time(n); -} - -static struct pico_eth *pico_nd_get_neighbor(struct pico_ip6 *addr, struct pico_ipv6_neighbor *n, struct pico_device *dev) -{ - /* dbg("Finding neighbor %02x:...:%02x, state = %d\n", addr->addr[0], addr->addr[15], n?n->state:-1); */ - - if (!n) { - n = pico_nd_add(addr, dev); - pico_nd_discover(n); - return NULL; - } - - if (n->state == PICO_ND_STATE_INCOMPLETE) { - return NULL; - } - - if (n->state == PICO_ND_STATE_STALE) { - n->state = PICO_ND_STATE_DELAY; - pico_nd_new_expire_time(n); - } - - if (n->state != PICO_ND_STATE_REACHABLE) - pico_nd_discover(n); - - return &n->mac; - -} - -static struct pico_eth *pico_nd_get(struct pico_ip6 *address, struct pico_device *dev) -{ - struct pico_ip6 gateway = {{0}}, addr = {{0}}; - - /* should we use gateway, or is dst local (gateway == 0)? */ - gateway = pico_ipv6_route_get_gateway(address); - if (memcmp(gateway.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0) - addr = *address; - else - addr = gateway; - - return pico_nd_get_neighbor(&addr, pico_nd_find_neighbor(&addr), dev); -} - -static int neigh_options(struct pico_frame *f, struct pico_icmp6_opt_lladdr *opt, uint8_t expected_opt) -{ - /* RFC 4861 $7.1.2 + $7.2.5. - * * The contents of any defined options that are not specified to be used - * * with Neighbor Advertisement messages MUST be ignored and the packet - * * processed as normal. The only defined option that may appear is the - * * Target Link-Layer Address option. - * */ - int optlen = 0; - uint8_t *option = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - int len; - uint8_t type; - int found = 0; - - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - optlen = f->transport_len - PICO_ICMP6HDR_NEIGH_ADV_SIZE; - if (optlen) - option = ((uint8_t *)&icmp6_hdr->msg.info.neigh_adv) + sizeof(struct neigh_adv_s); - - while (optlen > 0) { - type = ((struct pico_icmp6_opt_lladdr *)option)->type; - len = ((struct pico_icmp6_opt_lladdr *)option)->len; - optlen -= len << 3; /* len in units of 8 octets */ - if (len <= 0) - return -1; /* malformed option. */ - - if (type == expected_opt) { - if (found > 0) - return -1; /* malformed option: option is there twice. */ - - memcpy(opt, (struct pico_icmp6_opt_lladdr *)option, (size_t)(len << 3)); - found++; - } - - if (optlen > 0) { - option += len << 3; - } else { /* parsing options: terminated. */ - return found; - } - } - return found; -} - -static void pico_ipv6_neighbor_update(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt) -{ - memcpy(n->mac.addr, opt->addr.mac.addr, PICO_SIZE_ETH); -} - -static int pico_ipv6_neighbor_compare_stored(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt) -{ - return memcmp(n->mac.addr, opt->addr.mac.addr, PICO_SIZE_ETH); -} - -static void neigh_adv_reconfirm_router_option(struct pico_ipv6_neighbor *n, unsigned int isRouter) -{ - if (!isRouter && n->is_router) { - pico_ipv6_router_down(&n->address); - } - - if (isRouter) - n->is_router = 1; - else - n->is_router = 0; -} - - -static int neigh_adv_reconfirm_no_tlla(struct pico_ipv6_neighbor *n, struct pico_icmp6_hdr *hdr) -{ - if (IS_SOLICITED(hdr)) { - n->state = PICO_ND_STATE_REACHABLE; - n->failure_count = 0; - pico_ipv6_nd_queued_trigger(); - pico_nd_new_expire_time(n); - return 0; - } - - return -1; -} - - -static int neigh_adv_reconfirm(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt, struct pico_icmp6_hdr *hdr) -{ - - if (IS_SOLICITED(hdr) && !IS_OVERRIDE(hdr) && (pico_ipv6_neighbor_compare_stored(n, opt) == 0)) { - n->state = PICO_ND_STATE_REACHABLE; - n->failure_count = 0; - pico_ipv6_nd_queued_trigger(); - pico_nd_new_expire_time(n); - return 0; - } - - if ((n->state == PICO_ND_STATE_REACHABLE) && IS_SOLICITED(hdr) && !IS_OVERRIDE(hdr)) { - n->state = PICO_ND_STATE_STALE; - return 0; - } - - if (IS_SOLICITED(hdr) && IS_OVERRIDE(hdr)) { - pico_ipv6_neighbor_update(n, opt); - n->state = PICO_ND_STATE_REACHABLE; - n->failure_count = 0; - pico_ipv6_nd_queued_trigger(); - pico_nd_new_expire_time(n); - return 0; - } - - if (!IS_SOLICITED(hdr) && IS_OVERRIDE(hdr) && (pico_ipv6_neighbor_compare_stored(n, opt) != 0)) { - pico_ipv6_neighbor_update(n, opt); - n->state = PICO_ND_STATE_STALE; - pico_ipv6_nd_queued_trigger(); - pico_nd_new_expire_time(n); - return 0; - } - - if ((n->state == PICO_ND_STATE_REACHABLE) && (!IS_SOLICITED(hdr)) && (!IS_OVERRIDE(hdr)) && - (pico_ipv6_neighbor_compare_stored(n, opt) != 0)) { - - /* I. If the Override flag is clear and the supplied link-layer address - * differs from that in the cache, then one of two actions takes - * place: - * a. If the state of the entry is REACHABLE, set it to STALE, but - * do not update the entry in any other way. - * b. Otherwise, the received advertisement should be ignored and - * MUST NOT update the cache. - */ - n->state = PICO_ND_STATE_STALE; - pico_nd_new_expire_time(n); - return 0; - } - - return -1; -} - -static void neigh_adv_process_incomplete(struct pico_ipv6_neighbor *n, struct pico_frame *f, struct pico_icmp6_opt_lladdr *opt) -{ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - if (!n || !f) - return; - - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - - if (!icmp6_hdr) - return; - - if (IS_SOLICITED(icmp6_hdr)) { - n->state = PICO_ND_STATE_REACHABLE; - n->failure_count = 0; - pico_nd_new_expire_time(n); - } else { - n->state = PICO_ND_STATE_STALE; - } - - if (opt) - pico_ipv6_neighbor_update(n, opt); - - pico_ipv6_nd_queued_trigger(); -} - - -static int neigh_adv_process(struct pico_frame *f) -{ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_ipv6_neighbor *n = NULL; - struct pico_icmp6_opt_lladdr opt = { - 0 - }; - int optres = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_TGT); - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - - if (optres < 0) { /* Malformed packet: option field cannot be processed. */ - return -1; - } - - n = pico_nd_find_neighbor(&icmp6_hdr->msg.info.neigh_adv.target); - if (!n) { - return 0; - } - - if ((optres == 0) || IS_OVERRIDE(icmp6_hdr) || (pico_ipv6_neighbor_compare_stored(n, &opt) == 0)) { - neigh_adv_reconfirm_router_option(n, IS_ROUTER(icmp6_hdr)); - } - - if ((optres > 0) && (n->state == PICO_ND_STATE_INCOMPLETE)) { - neigh_adv_process_incomplete(n, f, &opt); - return 0; - } - - if (optres > 0) - return neigh_adv_reconfirm(n, &opt, icmp6_hdr); - else - return neigh_adv_reconfirm_no_tlla(n, icmp6_hdr); - -} - - - -static struct pico_ipv6_neighbor *pico_ipv6_neighbor_from_sol_new(struct pico_ip6 *ip, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev) -{ - struct pico_ipv6_neighbor *n = NULL; - n = pico_nd_add(ip, dev); - if (!n) - return NULL; - - memcpy(n->mac.addr, opt->addr.mac.addr, PICO_SIZE_ETH); - n->state = PICO_ND_STATE_STALE; - pico_ipv6_nd_queued_trigger(); - return n; -} - -static void pico_ipv6_neighbor_from_unsolicited(struct pico_frame *f) -{ - struct pico_ipv6_neighbor *n = NULL; - struct pico_icmp6_opt_lladdr opt = { - 0 - }; - struct pico_ipv6_hdr *ip = (struct pico_ipv6_hdr *)f->net_hdr; - int valid_lladdr = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_SRC); - - if (!pico_ipv6_is_unspecified(ip->src.addr) && (valid_lladdr > 0)) { - n = pico_nd_find_neighbor(&ip->src); - if (!n) { - n = pico_ipv6_neighbor_from_sol_new(&ip->src, &opt, f->dev); - } else if (memcmp(opt.addr.mac.addr, n->mac.addr, PICO_SIZE_ETH)) { - pico_ipv6_neighbor_update(n, &opt); - n->state = PICO_ND_STATE_STALE; - pico_ipv6_nd_queued_trigger(); - pico_nd_new_expire_time(n); - } - - if (!n) - return; - } -} - -static int neigh_sol_detect_dad(struct pico_frame *f) -{ - struct pico_ipv6_hdr *ipv6_hdr = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_ipv6_link *link = NULL; - ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - link = pico_ipv6_link_istentative(&icmp6_hdr->msg.info.neigh_adv.target); - if (link) { - if (pico_ipv6_is_unicast(&ipv6_hdr->src)) - { - /* RFC4862 5.4.3 : sender is performing address resolution, - * our address is not yet valid, discard silently. - */ - dbg("DAD:Sender performing AR\n"); - } - - else if (pico_ipv6_is_unspecified(ipv6_hdr->src.addr) && - !pico_ipv6_is_allhosts_multicast(ipv6_hdr->dst.addr)) - { - /* RFC4862 5.4.3 : sender is performing DaD */ - dbg("DAD:Sender performing DaD\n"); - ipv6_duplicate_detected(link); - } - - return 0; - } - - return -1; /* Current link is not tentative */ -} - -static int neigh_sol_process(struct pico_frame *f) -{ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_ipv6_link *link = NULL; - int valid_lladdr; - struct pico_icmp6_opt_lladdr opt = { - 0 - }; - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - - valid_lladdr = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_SRC); - pico_ipv6_neighbor_from_unsolicited(f); - - if ((valid_lladdr == 0) && (neigh_sol_detect_dad(f) == 0)) - return 0; - - if (valid_lladdr < 0) - return -1; /* Malformed packet. */ - - link = pico_ipv6_link_get(&icmp6_hdr->msg.info.neigh_adv.target); - if (!link) { /* Not for us. */ - return -1; - } - - pico_icmp6_neighbor_advertisement(f, &icmp6_hdr->msg.info.neigh_adv.target); - return 0; -} - -static int icmp6_initial_checks(struct pico_frame *f) -{ - /* Common "step 0" validation */ - struct pico_ipv6_hdr *ipv6_hdr = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - - ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - - /* RFC4861 - 7.1.2 : - * - The IP Hop Limit field has a value of 255, i.e., the packet - * could not possibly have been forwarded by a router. - * - ICMP Checksum is valid. - * - ICMP Code is 0. - */ - if (ipv6_hdr->hop != 255 || pico_icmp6_checksum(f) != 0 || icmp6_hdr->code != 0) - return -1; - - return 0; -} - -static int neigh_adv_option_len_validity_check(struct pico_frame *f) -{ - /* Step 4 validation */ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - uint8_t *opt; - int optlen = f->transport_len - PICO_ICMP6HDR_NEIGH_ADV_SIZE; - /* RFC4861 - 7.1.2 : - * - All included options have a length that is greater than zero. - */ - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - opt = ((uint8_t *)&icmp6_hdr->msg.info.neigh_adv) + sizeof(struct neigh_adv_s); - - while(optlen > 0) { - int opt_size = (opt[1] << 3); - if (opt_size == 0) - return -1; - - opt = opt + opt_size; - optlen -= opt_size; - } - return 0; -} - -static int neigh_adv_mcast_validity_check(struct pico_frame *f) -{ - /* Step 3 validation */ - struct pico_ipv6_hdr *ipv6_hdr = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - /* RFC4861 - 7.1.2 : - * - If the IP Destination Address is a multicast address the - * Solicited flag is zero. - */ - ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - if (pico_ipv6_is_multicast(ipv6_hdr->dst.addr) && IS_SOLICITED(icmp6_hdr)) - return -1; - - return neigh_adv_option_len_validity_check(f); -} - -static int neigh_adv_validity_checks(struct pico_frame *f) -{ - /* Step 2 validation */ - /* RFC4861 - 7.1.2: - * - ICMP length (derived from the IP length) is 24 or more octets. - */ - if (f->transport_len < PICO_ICMP6HDR_NEIGH_ADV_SIZE) - return -1; - - return neigh_adv_mcast_validity_check(f); -} - - -static int neigh_sol_mcast_validity_check(struct pico_frame *f) -{ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - if (pico_ipv6_is_solnode_multicast(icmp6_hdr->msg.info.neigh_sol.target.addr, f->dev) == 0) - return -1; - - return 0; -} - -static int neigh_sol_unicast_validity_check(struct pico_frame *f) -{ - struct pico_ipv6_link *link; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - - link = pico_ipv6_link_by_dev(f->dev); - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - while(link) { - if (pico_ipv6_compare(&link->address, &icmp6_hdr->msg.info.neigh_sol.target) == 0) - return 0; - - link = pico_ipv6_link_by_dev_next(f->dev, link); - } - return -1; - -} - -static int neigh_sol_validate_unspec(struct pico_frame *f) -{ - /* RFC4861, 7.1.1: - * - * - If the IP source address is the unspecified address, the IP - * destination address is a solicited-node multicast address. - * - * - If the IP source address is the unspecified address, there is no - * source link-layer address option in the message. - * - */ - - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)(f->net_hdr); - struct pico_icmp6_opt_lladdr opt = { - 0 - }; - int valid_lladdr = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_SRC); - if (pico_ipv6_is_solnode_multicast(hdr->dst.addr, f->dev) == 0) { - return -1; - } - - if (valid_lladdr) { - return -1; - } - - return 0; -} - -static int neigh_sol_validity_checks(struct pico_frame *f) -{ - /* Step 2 validation */ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)(f->net_hdr); - if (f->transport_len < PICO_ICMP6HDR_NEIGH_ADV_SIZE) - return -1; - - if ((pico_ipv6_is_unspecified(hdr->src.addr)) && (neigh_sol_validate_unspec(f) < 0)) - { - return -1; - } - - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - if (pico_ipv6_is_multicast(icmp6_hdr->msg.info.neigh_adv.target.addr)) { - return neigh_sol_mcast_validity_check(f); - } - - return neigh_sol_unicast_validity_check(f); -} - -static int router_adv_validity_checks(struct pico_frame *f) -{ - /* Step 2 validation */ - if (f->transport_len < PICO_ICMP6HDR_ROUTER_ADV_SIZE) - return -1; - - return 0; -} - -static int neigh_adv_checks(struct pico_frame *f) -{ - /* Step 1 validation */ - if (icmp6_initial_checks(f) < 0) - return -1; - - return neigh_adv_validity_checks(f); -} - - -static int pico_nd_router_sol_recv(struct pico_frame *f) -{ - pico_ipv6_neighbor_from_unsolicited(f); - /* Host only: router solicitation is discarded. */ - return 0; -} - -static int radv_process(struct pico_frame *f) -{ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - uint8_t *nxtopt, *opt_start; - struct pico_ipv6_link *link; - struct pico_ipv6_hdr *hdr; - struct pico_ip6 zero = { - .addr = {0} - }; - int optlen; - - hdr = (struct pico_ipv6_hdr *)f->net_hdr; - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - optlen = f->transport_len - PICO_ICMP6HDR_ROUTER_ADV_SIZE; - opt_start = ((uint8_t *)&icmp6_hdr->msg.info.router_adv) + sizeof(struct router_adv_s); - nxtopt = opt_start; - - while (optlen > 0) { - uint8_t *type = (uint8_t *)nxtopt; - switch (*type) { - case PICO_ND_OPT_PREFIX: - { - pico_time now = PICO_TIME_MS(); - struct pico_icmp6_opt_prefix *prefix = - (struct pico_icmp6_opt_prefix *) nxtopt; - /* RFC4862 5.5.3 */ - /* a) If the Autonomous flag is not set, silently ignore the Prefix - * Information option. - */ - if (prefix->aac == 0) - goto ignore_opt_prefix; - - /* b) If the prefix is the link-local prefix, silently ignore the - * Prefix Information option - */ - if (pico_ipv6_is_linklocal(prefix->prefix.addr)) - goto ignore_opt_prefix; - - /* c) If the preferred lifetime is greater than the valid lifetime, - * silently ignore the Prefix Information option - */ - if (long_be(prefix->pref_lifetime) > long_be(prefix->val_lifetime)) - goto ignore_opt_prefix; - - if (prefix->val_lifetime == 0) - goto ignore_opt_prefix; - - - if (prefix->prefix_len != 64) { - return -1; - } - - link = pico_ipv6_prefix_configured(&prefix->prefix); - if (link) { - pico_ipv6_lifetime_set(link, now + (pico_time)(1000 * (long_be(prefix->val_lifetime)))); - goto ignore_opt_prefix; - } - - link = pico_ipv6_link_add_local(f->dev, &prefix->prefix); - if (link) { - pico_ipv6_lifetime_set(link, now + (pico_time)(1000 * (long_be(prefix->val_lifetime)))); - pico_ipv6_route_add(zero, zero, hdr->src, 10, link); - } - -ignore_opt_prefix: - optlen -= (prefix->len << 3); - nxtopt += (prefix->len << 3); - } - break; - case PICO_ND_OPT_LLADDR_SRC: - { - struct pico_icmp6_opt_lladdr *lladdr_src = - (struct pico_icmp6_opt_lladdr *) nxtopt; - optlen -= (lladdr_src->len << 3); - nxtopt += (lladdr_src->len << 3); - } - break; - case PICO_ND_OPT_MTU: - { - struct pico_icmp6_opt_mtu *mtu = - (struct pico_icmp6_opt_mtu *) nxtopt; - /* Skip this */ - optlen -= (mtu->len << 3); - nxtopt += (mtu->len << 3); - } - break; - case PICO_ND_OPT_REDIRECT: - { - struct pico_icmp6_opt_redirect *redirect = - (struct pico_icmp6_opt_redirect *) nxtopt; - /* Skip this */ - optlen -= (redirect->len << 3); - nxtopt += (redirect->len << 3); - - } - break; - case PICO_ND_OPT_RDNSS: - { - struct pico_icmp6_opt_rdnss *rdnss = - (struct pico_icmp6_opt_rdnss *) nxtopt; - /* Skip this */ - optlen -= (rdnss->len << 3); - nxtopt += (rdnss->len << 3); - } - break; - default: - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, - (uint32_t)sizeof(struct pico_ipv6_hdr) + (uint32_t)PICO_ICMP6HDR_ROUTER_ADV_SIZE + (uint32_t)(nxtopt - opt_start)); - return -1; - } - } - if (icmp6_hdr->msg.info.router_adv.retrans_time != 0u) { - f->dev->hostvars.retranstime = long_be(icmp6_hdr->msg.info.router_adv.retrans_time); - } - - return 0; -} - - -static int pico_nd_router_adv_recv(struct pico_frame *f) -{ - if (icmp6_initial_checks(f) < 0) - return -1; - - if (router_adv_validity_checks(f) < 0) - return -1; - - pico_ipv6_neighbor_from_unsolicited(f); - return radv_process(f); -} - -static int pico_nd_neigh_sol_recv(struct pico_frame *f) -{ - if (icmp6_initial_checks(f) < 0) - return -1; - - if (neigh_sol_validity_checks(f) < 0) - return -1; - - return neigh_sol_process(f); -} - -static int pico_nd_neigh_adv_recv(struct pico_frame *f) -{ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_ipv6_link *link = NULL; - - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - if (neigh_adv_checks(f) < 0) { - return -1; - } - - link = pico_ipv6_link_istentative(&icmp6_hdr->msg.info.neigh_adv.target); - if (link) - ipv6_duplicate_detected(link); - - return neigh_adv_process(f); -} - -static int pico_nd_redirect_recv(struct pico_frame *f) -{ - pico_ipv6_neighbor_from_unsolicited(f); - /* TODO */ - return 0; -} - -static void pico_ipv6_nd_timer_elapsed(pico_time now, struct pico_ipv6_neighbor *n) -{ - (void)now; - switch(n->state) { - case PICO_ND_STATE_INCOMPLETE: - /* intentional fall through */ - case PICO_ND_STATE_PROBE: - if (n->failure_count > PICO_ND_MAX_SOLICIT) { - pico_ipv6_nd_unreachable(&n->address); - pico_tree_delete(&NCache, n); - PICO_FREE(n); - return; - } - - n->expire = 0ull; - pico_nd_discover(n); - break; - - case PICO_ND_STATE_REACHABLE: - n->state = PICO_ND_STATE_STALE; - /* dbg("IPv6_ND: neighbor expired!\n"); */ - return; - - case PICO_ND_STATE_STALE: - break; - - case PICO_ND_STATE_DELAY: - n->expire = 0ull; - n->state = PICO_ND_STATE_PROBE; - break; - default: - dbg("IPv6_ND: neighbor in wrong state!\n"); - } - pico_nd_new_expire_time(n); -} - -static void pico_ipv6_nd_timer_callback(pico_time now, void *arg) -{ - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ipv6_neighbor *n; - - (void)arg; - pico_tree_foreach_safe(index, &NCache, _tmp) - { - n = index->keyValue; - if ( now > n->expire) { - pico_ipv6_nd_timer_elapsed(now, n); - } - } - pico_timer_add(200, pico_ipv6_nd_timer_callback, NULL); -} - -#define PICO_IPV6_ND_MIN_RADV_INTERVAL (5000) -#define PICO_IPV6_ND_MAX_RADV_INTERVAL (15000) - -static void pico_ipv6_nd_ra_timer_callback(pico_time now, void *arg) -{ - struct pico_tree_node *devindex = NULL; - struct pico_tree_node *rindex = NULL; - struct pico_device *dev; - struct pico_ipv6_route *rt; - struct pico_ip6 nm64 = { {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0 } }; - pico_time next_timer_expire = 0u; - - (void)arg; - (void)now; - pico_tree_foreach(rindex, &IPV6Routes) - { - rt = rindex->keyValue; - if (pico_ipv6_compare(&nm64, &rt->netmask) == 0) { - pico_tree_foreach(devindex, &Device_tree) { - dev = devindex->keyValue; - if ((!pico_ipv6_is_linklocal(rt->dest.addr)) && dev->hostvars.routing && (rt->link) && (dev != rt->link->dev)) { - pico_icmp6_router_advertisement(dev, &rt->dest); - } - } - } - } - next_timer_expire = PICO_IPV6_ND_MIN_RADV_INTERVAL + (pico_rand() % (PICO_IPV6_ND_MAX_RADV_INTERVAL - PICO_IPV6_ND_MIN_RADV_INTERVAL)); - pico_timer_add(next_timer_expire, pico_ipv6_nd_ra_timer_callback, NULL); -} - -/* Public API */ - -struct pico_eth *pico_ipv6_get_neighbor(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = NULL; - struct pico_ipv6_link *l = NULL; - if (!f) - return NULL; - - hdr = (struct pico_ipv6_hdr *)f->net_hdr; - /* If we are still probing for Duplicate Address, abort now. */ - if (pico_ipv6_link_istentative(&hdr->src)) - return NULL; - - /* address belongs to ourselves? */ - l = pico_ipv6_link_get(&hdr->dst); - if (l) - return &l->dev->eth->mac; - - return pico_nd_get(&hdr->dst, f->dev); -} - -void pico_ipv6_nd_postpone(struct pico_frame *f) -{ - int i; - static int last_enq = -1; - struct pico_frame *cp = pico_frame_copy(f); - for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++) - { - if (!frames_queued_v6[i]) { - frames_queued_v6[i] = cp; - last_enq = i; - return; - } - } - /* Overwrite the oldest frame in the buffer */ - if (++last_enq >= PICO_ND_MAX_FRAMES_QUEUED) { - last_enq = 0; - } - - if (frames_queued_v6[last_enq]) - pico_frame_discard(frames_queued_v6[last_enq]); - - frames_queued_v6[last_enq] = cp; -} - - -int pico_ipv6_nd_recv(struct pico_frame *f) -{ - - struct pico_icmp6_hdr *hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - int ret = -1; - switch(hdr->type) { - case PICO_ICMP6_ROUTER_SOL: - nd_dbg("ICMP6: received ROUTER SOL\n"); - ret = pico_nd_router_sol_recv(f); - break; - - case PICO_ICMP6_ROUTER_ADV: - ret = pico_nd_router_adv_recv(f); - break; - - case PICO_ICMP6_NEIGH_SOL: - nd_dbg("ICMP6: received NEIGH SOL\n"); - ret = pico_nd_neigh_sol_recv(f); - break; - - case PICO_ICMP6_NEIGH_ADV: - nd_dbg("ICMP6: received NEIGH ADV\n"); - ret = pico_nd_neigh_adv_recv(f); - break; - - case PICO_ICMP6_REDIRECT: - ret = pico_nd_redirect_recv(f); - break; - } - pico_frame_discard(f); - return ret; -} - -void pico_ipv6_nd_init(void) -{ - pico_timer_add(200, pico_ipv6_nd_timer_callback, NULL); - pico_timer_add(200, pico_ipv6_nd_ra_timer_callback, NULL); - pico_timer_add(1000, pico_ipv6_check_lifetime_expired, NULL); -} - -#endif diff --git a/ext/picotcp/modules/pico_ipv6_nd.h b/ext/picotcp/modules/pico_ipv6_nd.h deleted file mode 100644 index f709b1e..0000000 --- a/ext/picotcp/modules/pico_ipv6_nd.h +++ /dev/null @@ -1,26 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef _INCLUDE_PICO_ND -#define _INCLUDE_PICO_ND -#include "pico_frame.h" - -/* RFC constants */ -#define PICO_ND_REACHABLE_TIME 30000 /* msec */ -#define PICO_ND_RETRANS_TIMER 1000 /* msec */ - -struct pico_nd_hostvars { - uint8_t routing; - uint8_t hoplimit; - pico_time basetime; - pico_time reachabletime; - pico_time retranstime; -}; - -void pico_ipv6_nd_init(void); -struct pico_eth *pico_ipv6_get_neighbor(struct pico_frame *f); -void pico_ipv6_nd_postpone(struct pico_frame *f); -int pico_ipv6_nd_recv(struct pico_frame *f); -#endif diff --git a/ext/picotcp/modules/pico_mdns.c b/ext/picotcp/modules/pico_mdns.c deleted file mode 100644 index 6b5c5e9..0000000 --- a/ext/picotcp/modules/pico_mdns.c +++ /dev/null @@ -1,3417 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - . - Author: Toon Stegen, Jelle De Vleeschouwer - *********************************************************************/ -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_addressing.h" -#include "pico_socket.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_tree.h" -#include "pico_mdns.h" - -#ifdef PICO_SUPPORT_MDNS - -/* --- Debugging --- */ -#define mdns_dbg(...) do {} while(0) -//#define mdns_dbg dbg - -#define PICO_MDNS_QUERY_TIMEOUT (10000) /* Ten seconds */ -#define PICO_MDNS_RR_TTL_TICK (1000) /* One second */ - -/* mDNS MTU size */ -#define PICO_MDNS_MAXBUF (1400u) - -/* --- Cookie flags --- */ -#define PICO_MDNS_PACKET_TYPE_ANNOUNCEMENT (0x01u) -#define PICO_MDNS_PACKET_TYPE_ANSWER (0x02u) -#define PICO_MDNS_PACKET_TYPE_QUERY (0x04u) -#define PICO_MDNS_PACKET_TYPE_PROBE (0x08u) -#define PICO_MDNS_PACKET_TYPE_QUERY_ANY (0x00u) -/* --- Cookie status --- */ -#define PICO_MDNS_COOKIE_STATUS_ACTIVE (0xffu) -#define PICO_MDNS_COOKIE_STATUS_INACTIVE (0x00u) -#define PICO_MDNS_COOKIE_STATUS_CANCELLED (0x77u) -#define PICO_MDNS_COOKIE_TIMEOUT (10u) - -#define PICO_MDNS_SECTION_ANSWERS (0) -#define PICO_MDNS_SECTION_AUTHORITIES (1) -#define PICO_MDNS_SETCTIO_ADDITIONALS (2) - -/* --- Question flags --- */ -#define PICO_MDNS_QUESTION_FLAG_PROBE (0x01u) -#define PICO_MDNS_QUESTION_FLAG_NO_PROBE (0x00u) -#define PICO_MDNS_QUESTION_FLAG_UNICAST_RES (0x02u) -#define PICO_MDNS_QUESTION_FLAG_MULTICAST_RES (0x00u) - -#define IS_QUESTION_PROBE_FLAG_SET(x) \ - (((x) & PICO_MDNS_QUESTION_FLAG_PROBE) ? (1) : (0)) -#define IS_QUESTION_UNICAST_FLAG_SET(x) \ - (((x) & PICO_MDNS_QUESTION_FLAG_UNICAST_RES) ? (1) : (0)) -#define IS_QUESTION_MULTICAST_FLAG_SET(x) \ - (((x) & PICO_MDNS_QUESTION_FLAG_UNICAST_RES) ? (0) : (1)) - -/* Resource Record flags */ -#define PICO_MDNS_RECORD_ADDITIONAL (0x08u) -#define PICO_MDNS_RECORD_SEND_UNICAST (0x10u) -#define PICO_MDNS_RECORD_CURRENTLY_PROBING (0x20u) -#define PICO_MDNS_RECORD_PROBED (0x40u) -#define PICO_MDNS_RECORD_CLAIMED (0x80u) - -#define IS_SHARED_RECORD(x) \ - ((x)->flags & PICO_MDNS_RECORD_SHARED) -#define IS_UNIQUE_RECORD(x) \ - (!((x)->flags & PICO_MDNS_RECORD_SHARED)) -#define IS_RECORD_PROBING(x) \ - ((x)->flags & PICO_MDNS_RECORD_CURRENTLY_PROBING) -#define IS_UNICAST_REQUESTED(x) \ - ((x)->flags & PICO_MDNS_RECORD_SEND_UNICAST) -#define IS_RECORD_VERIFIED(x) \ - ((x)->flags & PICO_MDNS_RECORD_PROBED) -#define IS_RECORD_CLAIMED(x) \ - ((x)->flags & PICO_MDNS_RECORD_CLAIMED) - -/* Set and clear flags */ -#define PICO_MDNS_SET_FLAG(x, b) (x = ((x) | (uint8_t)(b))) -#define PICO_MDNS_CLR_FLAG(x, b) (x = (uint8_t)(((x) & (~((uint8_t)(b)))))) - -/* Set and clear MSB of BE short */ -#define PICO_MDNS_SET_MSB(x) (x = x | (uint16_t)(0x8000u)) -#define PICO_MDNS_CLR_MSB(x) (x = x & (uint16_t)(0x7fffu)) -#define PICO_MDNS_SET_MSB_BE(x) (x = x | (uint16_t)(short_be(0x8000u))) -#define PICO_MDNS_CLR_MSB_BE(x) (x = x & (uint16_t)(short_be(0x7fffu))) -#define PICO_MDNS_IS_MSB_SET(x) ((x & 0x8000u) ? 1 : 0) - -/* **************************************************************************** - * mDNS cookie - * ****************************************************************************/ -struct pico_mdns_cookie -{ - pico_dns_qtree qtree; /* Question tree */ - pico_mdns_rtree antree; /* Answer tree */ - pico_mdns_rtree artree; /* Additional record tree */ - uint8_t count; /* Times to send the query */ - uint8_t type; /* QUERY/ANNOUNCE/PROBE/ANSWER */ - uint8_t status; /* Active status */ - uint8_t timeout; /* Timeout counter */ - uint32_t send_timer; /* For sending events */ - void (*callback)(pico_mdns_rtree *, - char *, - void *); /* Callback */ - void *arg; /* Argument to pass to callback */ -}; - -/* MARK: TREES & GLOBAL VARIABLES */ - -/* MDNS Communication variables */ -static struct pico_socket *mdns_sock_ipv4 = NULL; -static uint16_t mdns_port = 5353u; -static struct pico_ip4 inaddr_any = { - 0 -}; - -/* **************************************************************************** - * Hostname for this machine, only 1 hostname can be set. - * ****************************************************************************/ -static char *_hostname = NULL; -static void (*init_callback)(pico_mdns_rtree *, char *, void *) = 0; - -/* **************************************************************************** - * Compares 2 mDNS records by name and type only - * - * @param a mDNS record A - * @param b mDNS record B - * @return 0 when name and type of records are equal, returns difference when - * they're not. - * ****************************************************************************/ -static int -pico_mdns_record_cmp_name_type( void *a, void *b ) -{ - struct pico_mdns_record *_a = NULL, *_b = NULL; - - /* Check params */ - if (!(_a = (struct pico_mdns_record *)a) || - !(_b = (struct pico_mdns_record *)b)) { - pico_err = PICO_ERR_EINVAL; - return -1; /* Don't want a wrong result when NULL-pointers are passed */ - } - - return pico_dns_record_cmp_name_type(_a->record, _b->record); -} - -/* **************************************************************************** - * Compares 2 mDNS records by type, name AND rdata for a truly unique result - * - * @param ra mDNS record A - * @param rb mDNS record B - * @return 0 when records are equal, returns difference when they're not. - * ****************************************************************************/ -int -pico_mdns_record_cmp( void *a, void *b ) -{ - /* Check params */ - if (!a || !b) { - if (!a && !b) - return 0; - pico_err = PICO_ERR_EINVAL; - return -1; /* Don't want a wrong result when NULL-pointers are passed */ - } - - return pico_dns_record_cmp((void*)(((struct pico_mdns_record *)a)->record), - (void*)(((struct pico_mdns_record *)b)->record)); -} - -/* **************************************************************************** - * Compares 2 mDNS cookies again each other. Only compares questions since a - * only a cookie query will be added to the tree. And there shouldn't be 2 - * different cookies with the same questions in the tree. - * - * @param ka mDNS cookie A - * @param kb mDNS cookie B - * @return 0 when cookies are equal, returns difference when they're not. - * ****************************************************************************/ -static int -pico_mdns_cookie_cmp( void *ka, void *kb ) -{ - struct pico_mdns_cookie *a = (struct pico_mdns_cookie *)ka; - struct pico_mdns_cookie *b = (struct pico_mdns_cookie *)kb; - struct pico_dns_question *qa = NULL, *qb = 0; - struct pico_tree_node *na = NULL, *nb = 0; - uint16_t ca = 0, cb = 0; - int ret = 0; - - /* Check params */ - if (!a || !b) { - pico_err = PICO_ERR_EINVAL; - return -1; /* Don't want a wrong result when NULL-pointers are passed */ - } - - /* Start comparing the questions */ - for (na = pico_tree_firstNode(a->qtree.root), - nb = pico_tree_firstNode(b->qtree.root); - (na != &LEAF) && (nb != &LEAF); - na = pico_tree_next(na), - nb = pico_tree_next(nb)) { - qa = na->keyValue; - qb = nb->keyValue; - if ((qa) && (qb) && (ret = pico_dns_question_cmp(qa, qb))) - return ret; - } - /* Check for lengths difference */ - ca = pico_tree_count(&(a->qtree)); - cb = pico_tree_count(&(b->qtree)); - if (ca != cb) - return (int)((int)ca - (int)cb); - - /* Cookies contain same questions, shouldn't happen */ - return 0; -} - -#if PICO_MDNS_ALLOW_CACHING == 1 -/* Cache records from mDNS peers on the network */ -PICO_TREE_DECLARE(Cache, &pico_mdns_record_cmp); -#endif - -/* My records for which I want to have the authority */ -PICO_TREE_DECLARE(MyRecords, &pico_mdns_record_cmp_name_type); - -/* Cookie-tree */ -PICO_TREE_DECLARE(Cookies, &pico_mdns_cookie_cmp); - -/* **************************************************************************** - * MARK: PROTOTYPES */ -static int -pico_mdns_getrecord_generic( const char *url, uint16_t type, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg); - -static void -pico_mdns_send_probe_packet( pico_time now, void *arg ); - -static int -pico_mdns_reclaim( pico_mdns_rtree record_tree, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ); -/* EOF PROTOTYPES - * ****************************************************************************/ - -/* MARK: v MDNS NAMES */ - -#define IS_NUM(c) (((c) >= '0') && ((c) <= '9')) -/* **************************************************************************** - * Tries to convert the characters after '-' to a numeric value. - * - * @param opening Pointer to dash index. - * @param closing Pointer to end of label. - * @return Numeric value of suffix on success - * ****************************************************************************/ -static inline uint16_t -pico_mdns_suffix_to_uint16( char *opening, char *closing) -{ - uint16_t n = 0; - char *i = 0; - - /* Check params */ - if (!opening || !closing || - ((closing - opening) > 5) || - ((closing - opening) < 0)) - return 0; - - for (i = (char *)(opening + 1); i < closing; i++) { - if (!IS_NUM(*i)) - return 0; - - n = (uint16_t)((n * 10) + (*i - '0')); - } - return n; -} - -#define iterate_first_label_name_reverse(iterator, name) \ - for ((iterator) = \ - (*name < (char)63) ? ((char *)(name + *name)) : (name); \ - (iterator) > (name); \ - (iterator)--) - -/* **************************************************************************** - * Checks whether there is already a conflict-suffix already present in the - * first label of a name or not. - * - * @param name Name in DNS name notation you want to check for a suffix. - * @param o_i Pointer-pointer, will get filled with location to '-'-char. - * @param c_i Pointer-pointer, will get filled with end of label. - * @return Returns value of the suffix, when it's present, 0 when no correct - * suffix is present. - * ****************************************************************************/ -static uint16_t -pico_mdns_is_suffix_present( char name[], - char **o_i, - char **c_i ) -{ - char *i = NULL; - uint16_t n = 0; - - *o_i = NULL; /* Clear out indexes */ - *c_i = NULL; - - /* Find the end of label. */ - *c_i = (name + *name + 1); - - iterate_first_label_name_reverse(i, name) { - /* Find the last dash */ - if ((*c_i) && (i < *c_i) && *i == '-') { - *o_i = i; - break; - } - } - - /* Convert the string suffix to a number */ - if (!(n = pico_mdns_suffix_to_uint16(*o_i, *c_i))) { - *o_i = NULL; - *c_i = NULL; - } - - return n; -} - -/* **************************************************************************** - * Manual string to uint16_t conversion. - * - * @param n Numeric value you want to convert. - * @param s String to convert to - * @return void - * ****************************************************************************/ -static void pico_itoa( uint16_t n, char s[] ) -{ - int i = 0, j = 0; - char c = 0; - - /* Get char values */ - do { - s[i++] = (char)(n % 10 + '0'); - } while ((n /= 10) > 0); - - /* Reverse the string */ - for (i = 0, j = (int)(pico_dns_strlen(s) - 1); i < j; i++, j--) { - c = s[i]; - s[i] = s[j]; - s[j] = c; - } -} - -/* **************************************************************************** - * Generates a new name by appending a conflict resolution suffix to the first - * label of an FQDN. - * - * @param rname Name you want to append the suffix to - * @return Newly created FQDN with suffix appended to first label. - * ****************************************************************************/ -static char * -pico_mdns_resolve_name_conflict( char rname[] ) -{ - char *new_rname = NULL; - char suffix[5] = { - 0 - }, nsuffix[5] = { - 0 - }, copy_offset = 0; - char *o_i = NULL, *c_i = NULL; - uint16_t new_len = (uint16_t)(pico_dns_strlen(rname) + 1); - uint8_t nslen = 0, slen = 0, ns = 0; - - /* Check params */ - if (pico_dns_check_namelen(new_len)) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Check whether a conflict-suffix is already present in the name */ - if ((ns = (uint8_t)pico_mdns_is_suffix_present(rname, &o_i, &c_i))) { - pico_itoa(ns, suffix); - pico_itoa(++ns, nsuffix); - slen = (uint8_t)pico_dns_strlen(suffix); - nslen = (uint8_t)pico_dns_strlen(nsuffix); - new_len = (uint16_t)(new_len + nslen - slen); - } else { - /* If no suffix is present */ - c_i = (o_i = rname + *rname) + 1; - new_len = (uint16_t)(new_len + 2u); - memcpy((void *)nsuffix, "-2\0", (size_t)3); - } - - /* Provide space for the new name */ - if (!(new_rname = PICO_ZALLOC(new_len))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Assemble the new name again */ - copy_offset = (char)((o_i - rname + 1)); - memcpy(new_rname, rname, (size_t)(copy_offset)); - strcpy(new_rname + copy_offset, nsuffix); - strcpy(new_rname + copy_offset + pico_dns_strlen(nsuffix), c_i); - /* Set the first length-byte */ - new_rname[0] = (char)(new_rname[0] + new_len - pico_dns_strlen(rname) - 1); - return new_rname; -} - -/* MARK: ^ MDNS NAMES */ -/* MARK: v MDNS QUESTIONS */ - -/* **************************************************************************** - * Creates a standalone mDNS Question with a given name and type. - * - * @param url DNS question name in URL format. Will be converted to DNS - * name notation format. - * @param len Will be filled with the total length of the DNS question. - * @param proto Protocol for which you want to create a question. Can be - * either PICO_PROTO_IPV4 or PICO_PROTO_IPV6. - * @param qtype DNS type of the question to be. - * @param flags With the flags you can specify if the question should be - * a QU-question rather than a QM-question - * @param reverse When this is true, a reverse resolution name will be gene- - * from the URL - * @return Returns pointer to the created mDNS Question on success, NULL on - * failure. - * ****************************************************************************/ -static struct pico_dns_question * -pico_mdns_question_create( const char *url, - uint16_t *len, - uint8_t proto, - uint16_t qtype, - uint8_t flags, - uint8_t reverse ) -{ - uint16_t qclass = PICO_DNS_CLASS_IN; - - /* Set the MSB of the qclass field according to the mDNS format */ - if (IS_QUESTION_UNICAST_FLAG_SET(flags)) - PICO_MDNS_SET_MSB(qclass); - - /* Fill in the question suffix */ - if (IS_QUESTION_PROBE_FLAG_SET(flags)) - qtype = PICO_DNS_TYPE_ANY; - - /* Create a question as you would with plain DNS */ - return pico_dns_question_create(url, len, proto, qtype, qclass, reverse); -} - -/* MARK: ^ MDNS QUESTIONS */ -/* MARK: v MDNS RECORDS */ - -/* **************************************************************************** - * Just makes a hardcopy from a single mDNS resource record. - * - * @param record mDNS record you want to create a copy from - * @return Pointer to copied mDNS resource record - * ****************************************************************************/ -static struct pico_mdns_record * -pico_mdns_record_copy( struct pico_mdns_record *record ) -{ - struct pico_mdns_record *copy = NULL; - - /* Check params */ - if (!record) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Provide space for the copy */ - if (!(copy = PICO_ZALLOC(sizeof(struct pico_mdns_record)))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Copy the DNS record */ - if (!(copy->record = pico_dns_record_copy(record->record))) { - PICO_FREE(copy); - return NULL; - } - - /* Copy the fields */ - copy->current_ttl = record->current_ttl; - copy->flags = record->flags; - copy->claim_id = record->claim_id; - - return copy; -} - -/* **************************************************************************** - * Looks for multiple mDNS records in a tree with the same name. - * - * @param tree Tree in which you want to search. - * @param name Name you want to search for. - * @return Tree with found hits, can possibly be empty - * ****************************************************************************/ -static pico_mdns_rtree -pico_mdns_rtree_find_name( pico_mdns_rtree *tree, - const char *name, - uint8_t copy ) -{ - PICO_MDNS_RTREE_DECLARE(hits); - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL; - - /* Check params */ - if (!name || !tree) { - pico_err = PICO_ERR_EINVAL; - return hits; - } - - /* Iterate over tree */ - pico_tree_foreach(node, tree) { - record = node->keyValue; - if (record && strcasecmp(record->record->rname, name) == 0) { - if (copy) - record = pico_mdns_record_copy(record); - if (record) - pico_tree_insert(&hits, record); - } - } - - return hits; -} - -/* **************************************************************************** - * Looks for (possibly) multiple mDNS records in a tree with the same name and - * type. - * - * @param tree Tree in which you want to search. - * @param name Name you want to search for. - * @param rtype DNS type you want to search for. - * @return Tree with found hits, can possibly be empty. - * ****************************************************************************/ -static pico_mdns_rtree -pico_mdns_rtree_find_name_type( pico_mdns_rtree *tree, - char *name, - uint16_t rtype, - uint8_t copy ) -{ - PICO_MDNS_RTREE_DECLARE(hits); - - struct pico_dns_record_suffix test_dns_suffix = { 0, 1, 0, 0 }; - struct pico_dns_record test_dns_record = { 0 }; - struct pico_mdns_record test = { 0 }; - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL; - test_dns_record.rsuffix = &test_dns_suffix; - test.record = &test_dns_record; - - /* Check params */ - if (!name || !tree) { - pico_err = PICO_ERR_EINVAL; - return hits; - } - - test.record->rname = name; - test.record->rsuffix->rtype = short_be(rtype); - - /* Iterate over the tree */ - pico_tree_foreach(node, tree) { - record = node->keyValue; - if ((record) && (0 == pico_mdns_record_cmp_name_type(record, &test))) { - if (copy) - record = pico_mdns_record_copy(record); - if (record) - pico_tree_insert(&hits, record); - } - } - - return hits; -} - -/* **************************************************************************** - * Deletes multiple mDNS records in a tree with the same name. - * - * @param tree Tree from which you want to delete records by name. - * @param name Name of records you want to delete from the tree. - * @return 0 on success, something else on failure. - * ****************************************************************************/ -static int -pico_mdns_rtree_del_name( pico_mdns_rtree *tree, - const char *name ) -{ - struct pico_tree_node *node = NULL, *safe = NULL; - struct pico_mdns_record *record = NULL; - - /* Check params */ - if (!name || !tree) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Iterate over tree */ - pico_tree_foreach_safe(node, tree, safe) { - record = node->keyValue; - if (record && strcasecmp(record->record->rname, name) == 0) { - record = pico_tree_delete(tree, record); - pico_mdns_record_delete((void **)&record); - } - } - - return 0; -} - -/* **************************************************************************** - * Deletes (possibly) multiple mDNS records from a tree with same name and - * type. - * - * @param tree Tree from which you want to delete records by name and type. - * @param name Name of records you want to delete. - * @param type DNS type of records you want to delete. - * @return 0 on success, something else on failure. - * ****************************************************************************/ -#if PICO_MDNS_ALLOW_CACHING == 1 -static int -pico_mdns_rtree_del_name_type( pico_mdns_rtree *tree, - char *name, - uint16_t type ) -{ - struct pico_tree_node *node = NULL, *next = NULL; - struct pico_mdns_record *record = NULL; - struct pico_dns_record_suffix test_dns_suffix = { 0, 1, 0, 0 }; - struct pico_dns_record test_dns_record = { 0 }; - struct pico_mdns_record test = { 0 }; - - test_dns_record.rsuffix = &test_dns_suffix; - test.record = &test_dns_record; - - /* Check params */ - if (!name || !tree) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - test.record->rname = name; - test.record->rsuffix->rtype = short_be(type); - - /* Iterate over the tree */ - pico_tree_foreach_safe(node, tree, next) { - record = node->keyValue; - if ((record) && (0 == pico_mdns_record_cmp_name_type(record, &test))) { - record = pico_tree_delete(tree, record); - pico_mdns_record_delete((void **)&record); - } - } - - return 0; -} -#endif - -/* **************************************************************************** - * Makes a hardcopy from a single mDNS resource record, but sets a new name - * for the copy. - * - * @param record mDNS record you want to copy. - * @param new_rname New name you want to set the name of the record to. - * @return Pointer to the copy on success, NULL-pointer on failure. - * ****************************************************************************/ -static struct pico_mdns_record * -pico_mdns_record_copy_with_new_name( struct pico_mdns_record *record, - const char *new_rname ) -{ - struct pico_mdns_record *copy = NULL; - uint16_t slen = (uint16_t)(pico_dns_strlen(new_rname) + 1u); - - /* Check params */ - if (pico_dns_check_namelen(slen)) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Copy the record */ - if (!(copy = pico_mdns_record_copy(record))) - return NULL; - - /* Provide a new string */ - PICO_FREE(copy->record->rname); - if (!(copy->record->rname = PICO_ZALLOC(slen))) { - pico_err = PICO_ERR_ENOMEM; - pico_mdns_record_delete((void **)©); - return NULL; - } - - memcpy((void *)(copy->record->rname), new_rname, slen); - copy->record->rname_length = slen; - - return copy; -} - -/* **************************************************************************** - * Generates (copies) new records from conflicting ones with another name. - * deletes - * - * @param conflict_records mDNS record tree that contains conflicting records - * @param conflict_name Name for which the conflict occurred. This is to be - * able to delete the conflicting records from the tree - * @param new_name To generate new records from the conflicting ones, - * with this new name. - * @return A mDNS record tree that contains all the newly generated records. - * ****************************************************************************/ -static pico_mdns_rtree -pico_mdns_generate_new_records( pico_mdns_rtree *conflict_records, - char *conflict_name, - char *new_name ) -{ - PICO_MDNS_RTREE_DECLARE(new_records); - struct pico_tree_node *node = NULL, *next = NULL; - struct pico_mdns_record *record = NULL, *new_record = NULL; - - /* Delete all the conflicting records from MyRecords */ - if (pico_mdns_rtree_del_name(&MyRecords, conflict_name)) - return new_records; - - pico_tree_foreach_safe(node, conflict_records, next) { - record = node->keyValue; - if (record && strcasecmp(record->record->rname, conflict_name) == 0) { - /* Create a new record */ - new_record = pico_mdns_record_copy_with_new_name(record, new_name); - if (!new_record) { - mdns_dbg("Could not create new non-conflicting record!\n"); - return new_records; - } - - new_record->flags &= (uint8_t)(~(PICO_MDNS_RECORD_PROBED | - PICO_MDNS_RECORD_SHARED | - PICO_MDNS_RECORD_CURRENTLY_PROBING)); - - /* Add the record to the new tree */ - pico_tree_insert(&new_records, new_record); - - /* Delete the old conflicting record */ - record = pico_tree_delete(conflict_records, record); - if (pico_mdns_record_delete((void **)&record)) { - mdns_dbg("Could not delete old conflict record from tree!\n"); - return new_records; - } - } - } - - return new_records; -} - -/* **************************************************************************** - * When hosts observe an unsolicited record, no cookie is currently active - * for that, so it has to check in MyRecords if no conflict occurred for a - * record it has already registered. When this occurs the conflict should be - * resolved as with a normal cookie, just without the cookie. - * - * @param record mDNS record for which the conflict occurred. - * @param rname DNS name for which the conflict occurred in DNS name notation. - * @return 0 when the resolving is applied successfully, 1 otherwise. - * ****************************************************************************/ -static int -pico_mdns_record_resolve_conflict( struct pico_mdns_record *record, - char *rname ) -{ - int retval; - PICO_MDNS_RTREE_DECLARE(new_records); - struct pico_mdns_record *copy = NULL; - char *new_name = NULL; - - /* Check params */ - if (!record || !rname || IS_SHARED_RECORD(record)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Step 2: Create a new name depending on current name */ - if (!(new_name = pico_mdns_resolve_name_conflict(rname))) - return -1; - - copy = pico_mdns_record_copy_with_new_name(record, new_name); - PICO_FREE(new_name); - if (copy) - pico_tree_insert(&new_records, copy); - - /* Step 3: delete conflicting record from my records */ - pico_tree_delete(&MyRecords, record); - pico_mdns_record_delete((void **)&record); - - /* Step 4: Try to reclaim the newly created records */ - retval = pico_mdns_reclaim(new_records, init_callback, NULL); - pico_tree_destroy(&new_records, NULL); - return retval; -} - -/* **************************************************************************** - * Determines if my_record is lexicographically later than peer_record, returns - * positive value when this is the case. Check happens by comparing rtype first - * and then rdata as prescribed by RFC6762. - * - * @param my_record Record this hosts want to claim. - * @param peer_record Record the peer host wants to claim (the enemy!) - * @return positive value when my record is lexicographically later - * ****************************************************************************/ -static int -pico_mdns_record_am_i_lexi_later( struct pico_mdns_record *my_record, - struct pico_mdns_record *peer_record) -{ - struct pico_dns_record *my = NULL, *peer = NULL; - uint16_t mclass = 0, pclass = 0, mtype = 0, ptype = 0; - int dif = 0; - - /* Check params */ - if (!my_record || !peer_record || - !(my = my_record->record) || !(peer = peer_record->record)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* - * First compare the record class (excluding cache-flush bit described in - * section 10.2) - * The numerically greater class wins - */ - mclass = PICO_MDNS_CLR_MSB_BE(my->rsuffix->rclass); - pclass = PICO_MDNS_CLR_MSB_BE(peer->rsuffix->rclass); - if ((dif = (int)((int)mclass - (int)pclass))){ - return dif; - } - - /* Second, compare the rrtypes */ - mtype = (my->rsuffix->rtype); - ptype = (peer->rsuffix->rtype); - if ((dif = (int)((int)mtype - (int)ptype))){ - return dif; - } - - /* Third compare binary content of rdata (no regard for meaning or structure) */ - - /* When using name compression, names MUST be uncompressed before comparison. See secion 8.2 in RFC 6762 - This is already the case, but we won't check for it here. - The current execution stack to get here is: - > pico_mdns_handle_data_as_answers_generic - > > pico_dns_record_decompress - > > pico_mdns_handle_single_authority - > > > pico_mdns_cookie_apply_spt - > > > > pico_mdns_record_am_i_lexi_later - - Make sure pico_dns_record_decompress is executed before pico_mdns_record_am_i_lexi_later gets called, if problems ever arise with this function. - */ - - /* Then compare rdata */ - return pico_dns_rdata_cmp(my->rdata, peer->rdata, - short_be(my->rsuffix->rdlength), - short_be(peer->rsuffix->rdlength), 0); -} - -/* **************************************************************************** - * Deletes a single mDNS resource record. - * - * @param record Void-pointer to mDNS Resource Record. Can be used with pico_- - * tree-destroy. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_mdns_record_delete( void **record ) -{ - struct pico_mdns_record **rr = (struct pico_mdns_record **)record; - - /* Check params */ - if (!rr || !(*rr)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Delete DNS record contained */ - if (((*rr)->record)) - pico_dns_record_delete((void **)&((*rr)->record)); - - /* Delete the record itself */ - PICO_FREE(*rr); - *record = NULL; - - return 0; -} - -/* **************************************************************************** - * Set the MSB of the QCLASS field of a DNS record depending on flags. - * - * @param record DNS record you want the set or clear the class MSB for. - * @param flags Depending on this the MSB will be set or not. Can be either - * PICO_MDNS_RECORD_UNIQUE or PICO_MDNS_RECORD_SHARED - * @return 0 on success, something else on failure. - * ****************************************************************************/ -static inline int -pico_mdns_record_set_class( struct pico_dns_record *record, - uint8_t flags ) -{ - uint16_t c = PICO_DNS_CLASS_IN; - PICO_MDNS_SET_MSB(c); - c = short_be(c); - - /* Set the MSB of the rclass field according to the mDNS format */ - if (!((flags) & PICO_MDNS_RECORD_SHARED)) - record->rsuffix->rclass = c; - - return 0; -} - -/* **************************************************************************** - * Creates a single standalone mDNS resource record with given name, type and - * data. - * - * @param url DNS rrecord name in URL format. Will be converted to DNS - * name notation format. - * @param _rdata Memory buffer with data to insert in the resource record. If - * data of record should contain a DNS name, the name in the - * data buffer needs to be in URL-format. - * @param datalen The exact length in bytes of the _rdata-buffer. If data of - * record should contain a DNS name, datalen needs to be - * pico_dns_strlen(_rdata). - * @param len Will be filled with the total length of the DNS rrecord. - * @param rtype DNS type of the resource record to be. - * @param rclass DNS class of the resource record to be. - * @param rttl DNS ttl of the resource record to be. - * @param flags You can specify if the mDNS record should be a shared record - * rather than a unique record. - * @return Pointer to newly created mDNS resource record. - * ****************************************************************************/ -struct pico_mdns_record * -pico_mdns_record_create( const char *url, - void *_rdata, - uint16_t datalen, - uint16_t rtype, - uint32_t rttl, - uint8_t flags ) -{ - struct pico_mdns_record *record = NULL; - uint16_t len = 0; - - /* Check params */ - if (!url || !_rdata) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Provide space for the new mDNS resource record */ - if (!(record = PICO_ZALLOC(sizeof(struct pico_mdns_record)))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Try to create the actual DNS record */ - if (!(record->record = pico_dns_record_create(url, _rdata, datalen, - &len, rtype, - PICO_DNS_CLASS_IN, rttl))) { - mdns_dbg("Could not create DNS record for mDNS!\n"); - PICO_FREE(record); - return NULL; - } - - /* Initialise fields */ - record->current_ttl = rttl; - pico_mdns_record_set_class(record->record, flags); - record->flags = flags; - record->claim_id = 0; - - return record; -} - -/* MARK: ^ MDNS RECORDS */ -/* MARK: v MDNS COOKIES */ - -/* **************************************************************************** - * Deletes a single mDNS packet cookie and frees memory. - * - * @param cookie Void-pointer to mDNS cookie, allow to be used with pico_tree- - * destroy. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -static int -pico_mdns_cookie_delete( struct pico_mdns_cookie **c ) -{ - /* Check params */ - if (!c || !(*c)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Destroy the vectors contained */ - PICO_DNS_QTREE_DESTROY(&((*c)->qtree)); - PICO_MDNS_RTREE_DESTROY(&((*c)->antree)); - PICO_MDNS_RTREE_DESTROY(&((*c)->artree)); - - /* Delete the cookie itself */ - PICO_FREE(*c); - *c = NULL; - - return 0; -} - -/* **************************************************************************** - * Creates a single standalone mDNS cookie - * - * @param qtree DNS questions you want to insert in the cookie. - * @param antree mDNS answers/authority records you want to add to cookie. - * @param artree mDNS additional records you want to add to cookie. - * @param count Times you want to send the cookie as a packet on the wire. - * @param type Type of packet you want to create from the cookie. - * @param callback Callback when the host receives responses for the cookie. - * @return Pointer to newly create cookie, NULL on failure. - * ****************************************************************************/ -static struct pico_mdns_cookie * -pico_mdns_cookie_create( pico_dns_qtree qtree, - pico_mdns_rtree antree, - pico_mdns_rtree artree, - uint8_t count, - uint8_t type, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ - struct pico_mdns_cookie *cookie = NULL; /* Packet cookie to send */ - - /* Provide space for the mDNS packet cookie */ - cookie = PICO_ZALLOC(sizeof(struct pico_mdns_cookie)); - if (!cookie) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Fill in the fields */ - cookie->qtree = qtree; - cookie->antree = antree; - cookie->artree = artree; - cookie->count = count; - cookie->type = type; - cookie->status = PICO_MDNS_COOKIE_STATUS_INACTIVE; - cookie->timeout = PICO_MDNS_COOKIE_TIMEOUT; - cookie->callback = callback; - cookie->arg = arg; - return cookie; -} - -/* **************************************************************************** - * Apply Simultaneous Probe Tiebreakin (S.P.T.) on a probe-cookie. - * - * @param cookie Cookie which contains the record which is simult. probed. - * @param answer Authority record received from peer which is simult. probed. - * @return 0 when SPT is applied correctly, 0 otherwise. - * ****************************************************************************/ -static int -pico_mdns_cookie_apply_spt( struct pico_mdns_cookie *cookie, - struct pico_dns_record *answer) -{ - struct pico_mdns_record *my_record = NULL; - struct pico_mdns_record peer_record; - - /* Check params */ - if ((!cookie) || !answer || (cookie->type != PICO_MDNS_PACKET_TYPE_PROBE)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - cookie->status = PICO_MDNS_COOKIE_STATUS_INACTIVE; - - /* Implement Simultaneous Probe Tiebreaking */ - peer_record.record = answer; - my_record = pico_tree_findKey(&MyRecords, &peer_record); - if (!my_record || !IS_RECORD_PROBING(my_record)) { - mdns_dbg("This is weird! My record magically removed...\n"); - return -1; - } - - if (pico_mdns_record_am_i_lexi_later(my_record, &peer_record) > 0) { - mdns_dbg("My record is lexicographically later! Yay!\n"); - cookie->status = PICO_MDNS_COOKIE_STATUS_ACTIVE; - } else { - pico_timer_cancel(cookie->send_timer); - cookie->timeout = PICO_MDNS_COOKIE_TIMEOUT; - cookie->count = PICO_MDNS_PROBE_COUNT; - cookie->send_timer = pico_timer_add(1000, pico_mdns_send_probe_packet, - cookie); - mdns_dbg("Probing postponed with 1s because of S.P.T.\n"); - } - - return 0; -} - -/* **************************************************************************** - * Applies conflict resolution mechanism to a cookie, when a conflict occurs - * for a name which is present in the cookie. - * - * @param cookie Cookie on which you want to apply the conflict resolution- - * mechanism. - * @param rname Name for which the conflict occurred. A new non-conflicting - * name will be generated from this string. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -static int -pico_mdns_cookie_resolve_conflict( struct pico_mdns_cookie *cookie, - char *rname ) -{ - struct pico_tree_node *node = NULL; - struct pico_dns_question *question = NULL; - PICO_MDNS_RTREE_DECLARE(new_records); - PICO_MDNS_RTREE_DECLARE(antree); - char *new_name = NULL; - void (*callback)(pico_mdns_rtree *, char *, void *); - void *arg = NULL; - uint16_t qc = 0; - int retval; - - /* Check params */ - if ((!cookie) || !rname || (cookie->type != PICO_MDNS_PACKET_TYPE_PROBE)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Convert rname to url */ - mdns_dbg("CONFLICT for probe query with name '%s' occurred!\n", rname); - - /* DNS conflict is case-insensitive. However, we want to keep the original - * capitalisation for the new probe. */ - pico_tree_foreach(node, &(cookie->qtree)) { - question = (struct pico_dns_question *)node->keyValue; - if ((question) && (strcasecmp(question->qname, rname) == 0)) - /* Create a new name depending on current name */ - new_name = pico_mdns_resolve_name_conflict(question->qname); - } - - /* Step 1: Remove question with that name from cookie and store some - * useful information */ - pico_dns_qtree_del_name(&(cookie->qtree), rname); - antree = cookie->antree; - callback = cookie->callback; - arg = cookie->arg; - cookie->antree.root = &LEAF; - - /* Check if there are no questions left, cancel events if so and delete */ - if (!(qc = pico_tree_count(&(cookie->qtree)))) { - pico_timer_cancel(cookie->send_timer); - cookie = pico_tree_delete(&Cookies, cookie); - pico_mdns_cookie_delete(&cookie); - } - - /* Step 2: Check if the new name succeeded, if not: error. */ - if (!(new_name)) - return -1; - - /* Step 3: Create records with new name for the records with that name */ - new_records = pico_mdns_generate_new_records(&antree, rname, new_name); - PICO_FREE(new_name); - - /* Step 4: Try to reclaim the newly created records */ - retval = pico_mdns_reclaim(new_records, callback, arg); - pico_tree_destroy(&new_records, NULL); - return retval; -} - -/* **************************************************************************** - * Find a query cookie that contains a question for a specific name. - * - * @param name Name of question you want to look for. - * @return Pointer to cookie in tree when one is found, NULL on failure. - * ****************************************************************************/ -static struct pico_mdns_cookie * -pico_mdns_ctree_find_cookie( const char *name, uint8_t type ) -{ - struct pico_mdns_cookie *cookie = NULL; - struct pico_tree_node *node = NULL; - - /* Check params */ - if (!name) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Find the cookie in the tree wherein the question is present */ - pico_tree_foreach(node, &Cookies) { - if ((cookie = node->keyValue) && - pico_dns_qtree_find_name(&(cookie->qtree), name)) { - if (type == PICO_MDNS_PACKET_TYPE_QUERY_ANY) - return cookie; - else if (cookie->type == type) - return cookie; - } - } - - return NULL; -} - -/* MARK: ^ MDNS COOKIES */ -/* MARK: v MY RECORDS */ - -/* **************************************************************************** - * Adds records contained in records-tree to MyRecords. Suppresses adding of - * duplicates. - * - * @param records Tree with records to add to 'MyRecords'. - * @param reclaim If the records contained in records are claimed again. - * @return 0 on success, something else on failure. - * ****************************************************************************/ -static int -pico_mdns_my_records_add( pico_mdns_rtree *records, uint8_t reclaim ) -{ - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL; - static uint8_t claim_id_count = 0; - - if (!reclaim) - ++claim_id_count; - - /* Iterate over record vector */ - pico_tree_foreach(node, records) { - record = node->keyValue; - if (record) { - /* Set probed flag if record is a shared record */ - if (IS_SHARED_RECORD(record)) - PICO_MDNS_SET_FLAG(record->flags, PICO_MDNS_RECORD_PROBED); - - /* If record is not claimed again, set new claim-ID */ - if (!reclaim) - record->claim_id = claim_id_count; - pico_tree_insert(&MyRecords, record); - } - } - return 0; -} - -/* **************************************************************************** - * Generates a tree of all My Records for which the probe flag already has - * been set. Copies the records from MyRecords into a new tree. - * - * @return Tree with all records in MyRecords with the PROBED-flag set. - * ****************************************************************************/ -static pico_mdns_rtree -pico_mdns_my_records_find_probed( void ) -{ - PICO_MDNS_RTREE_DECLARE(probed); - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL, *copy = NULL; - - /* Iterate over MyRecords */ - pico_tree_foreach(node, &MyRecords) { - record = node->keyValue; - if (record && IS_RECORD_VERIFIED(record) && !IS_RECORD_CLAIMED(record)) { - copy = pico_mdns_record_copy(record); - if (copy && pico_tree_insert(&probed, copy)) - pico_mdns_record_delete((void **)©); - } - } - - return probed; -} - -/* **************************************************************************** - * Generates a tree of all My Records for which the probe flag has not yet - * been set. Copies the record from MyRecords into a new tree. - * - * @return Tree with all records in MyRecords with the PROBED-flag not set. - * ****************************************************************************/ -static pico_mdns_rtree -pico_mdns_my_records_find_to_probe( void ) -{ - PICO_MDNS_RTREE_DECLARE(toprobe); - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL, *copy = NULL; - - pico_tree_foreach(node, &MyRecords) { - record = node->keyValue; - /* Check if probed flag is not set of a record */ - if (record && - IS_UNIQUE_RECORD(record) && - !IS_RECORD_VERIFIED(record) && - !IS_RECORD_PROBING(record)) { - /* Set record to currently being probed status */ - record->flags |= PICO_MDNS_RECORD_CURRENTLY_PROBING; - copy = pico_mdns_record_copy(record); - if (copy && pico_tree_insert(&toprobe, copy)) - pico_mdns_record_delete((void **)©); - } - } - return toprobe; -} - -/* **************************************************************************** - * Checks whether all MyRecords with a certain claim ID are claimed or not. - * - * @param claim_id Claim ID of the records to check for already been probed. - * @param reg_records Tree in which all MyRecords with claim ID are inserted. - * @return 1 when all MyRecords with claim ID are probed, 0 when they're not. - * ****************************************************************************/ -static uint8_t -pico_mdns_my_records_claimed_id( uint8_t claim_id, - pico_mdns_rtree *reg_records ) -{ - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL; - - /* Initialise the iterator for iterating over my records */ - pico_tree_foreach(node, &MyRecords) { - record = node->keyValue; - if (record && record->claim_id == claim_id) { - if (IS_RECORD_VERIFIED(record)) { - pico_tree_insert(reg_records, record); - } else { - return 0; - } - } - } - - return 1; -} - -/* **************************************************************************** - * Marks mDNS resource records in the tree as registered. Checks MyRecords for - * for other records with the same claim ID. If all records with the same claim - * ID as the records in the tree are claimed, the callback will get called. - * - * @param rtree Tree with mDNS records that are registered. - * @param callback Callback will get called when all records are registered. - * @return Returns 0 when everything went smooth, something else otherwise. - * ****************************************************************************/ -static int -pico_mdns_my_records_claimed( pico_mdns_rtree rtree, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ - PICO_MDNS_RTREE_DECLARE(claimed_records); - struct pico_mdns_record *record = NULL, *myrecord = NULL; - struct pico_tree_node *node = NULL; - uint8_t claim_id = 0; - - /* Iterate over records and set the PROBED flag */ - pico_tree_foreach(node, &rtree) { - if ((record = node->keyValue)) { - if (!claim_id) - claim_id = record->claim_id; - } - - if ((myrecord = pico_tree_findKey(&MyRecords, record))) - PICO_MDNS_SET_FLAG(myrecord->flags, PICO_MDNS_RECORD_CLAIMED); - } - - /* If all_claimed is still true */ - if (pico_mdns_my_records_claimed_id(claim_id, &claimed_records)) - callback(&claimed_records, _hostname, arg); - pico_tree_destroy(&claimed_records, NULL); - - mdns_dbg(">>>>>> DONE - CLAIM SESSION: %d\n", claim_id); - - return 0; -} - -/* **************************************************************************** - * Makes sure the cache flush bit is set of the records which are probed, and - * set the corresponding MyRecords to 'being probed'-state. - * - * @param records mDNS records which are probed. - * ****************************************************************************/ -static void -pico_mdns_my_records_probed( pico_mdns_rtree *records ) -{ - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL, *found = NULL; - - pico_tree_foreach(node, records) { - if ((record = node->keyValue)) { - /* Set the cache flush bit again */ - PICO_MDNS_SET_MSB_BE(record->record->rsuffix->rclass); - if ((found = pico_tree_findKey(&MyRecords, record))) { - if (IS_HOSTNAME_RECORD(found)) { - if (_hostname) - PICO_FREE(_hostname); - - _hostname = pico_dns_qname_to_url(found->record->rname); - } - - PICO_MDNS_SET_FLAG(found->flags, PICO_MDNS_RECORD_PROBED); - PICO_MDNS_CLR_FLAG(found->flags, PICO_MDNS_RECORD_CURRENTLY_PROBING); - } else - mdns_dbg("Could not find my corresponding record...\n"); - } - } -} - -/* MARK: ^ MY RECORDS */ -/* MARK: v CACHE COHERENCY */ -#if PICO_MDNS_ALLOW_CACHING == 1 -/* **************************************************************************** - * Updates TTL of a cache entry. - * - * @param record Record of which you want to update the TTL of - * @param ttl TTL you want to update the TTL of the record to. - * @return void - * ****************************************************************************/ -static inline void -pico_mdns_cache_update_ttl( struct pico_mdns_record *record, - uint32_t ttl ) -{ - if(ttl > 0) { - /* Update the TTL's */ - record->record->rsuffix->rttl = long_be(ttl); - record->current_ttl = ttl; - } else { - /* TTL 0 means delete from cache but we need to wait one second */ - record->record->rsuffix->rttl = long_be(1u); - record->current_ttl = 1u; - } -} - -/* **************************************************************************** - * Adds a mDNS record to the cache. - * - * @param record mDNS record to add to the Cache. - * @return 0 when entry successfully added, something else when it all went ho- - * rribly wrong... - * ****************************************************************************/ -static int -pico_mdns_cache_add( struct pico_mdns_record *record ) -{ - struct pico_dns_record_suffix *suffix = NULL; - char *name = NULL; - uint16_t type = 0; - uint32_t rttl = 0; - - /* Check params */ - if (!record) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - suffix = record->record->rsuffix; - name = record->record->rname; - type = short_be(suffix->rtype); - rttl = long_be(suffix->rttl); - - /* Check if cache flush bit is set */ - if (PICO_MDNS_IS_MSB_SET(short_be(suffix->rclass))) { - mdns_dbg("FLUSH - Cache flush bit was set, triggered flush.\n"); - if (pico_mdns_rtree_del_name_type(&Cache, name, type)) { - mdns_dbg("Could not flush records from cache!\n"); - return -1; - } - } - - /* Check if the TTL is not 0*/ - if (!rttl) - return -1; - /* Set current TTL to the original TTL before inserting */ - record->current_ttl = rttl; - - if (pico_tree_insert(&Cache, record) != NULL) - return -1; - - mdns_dbg("RR cached. TICK TACK TICK TACK...\n"); - - return 0; -} - -/* **************************************************************************** - * Add a copy of an mDNS resource record to the cache tree. Checks whether the - * entry is already present in the Cache or not. - * - * @param record Record to add to the Cache-tree - * @return 0 on grrrreat success, something else on awkward failure. - * ****************************************************************************/ -static int -pico_mdns_cache_add_record( struct pico_mdns_record *record ) -{ - struct pico_mdns_record *found = NULL, *copy = NULL; - uint32_t rttl = 0; - - /* Check params */ - if (!record) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* See if the record is already contained in the cache */ - if ((found = pico_tree_findKey(&Cache, record))) { - rttl = long_be(record->record->rsuffix->rttl); - pico_mdns_cache_update_ttl(found, rttl); - } else if ((copy = pico_mdns_record_copy(record))) { - if (pico_mdns_cache_add(copy)) { - pico_mdns_record_delete((void **)©); - return -1; - } - } else - return -1; - - return 0; -} - -#if PICO_MDNS_CONTINUOUS_REFRESH == 1 -/* **************************************************************************** - * Determine if the current TTL is at a refreshing point. - * - * @param original Original TTL to calculate refreshing points - * @param current Current TTL to check. - * @return 1 when Current TTL is at refresh point. 0 when it's not. - * ****************************************************************************/ -static int -pico_mdns_ttl_at_refresh_time( uint32_t original, - uint32_t current ) -{ - uint32_t rnd = 0; - rnd = pico_rand() % 3; - - if (((original - current == - ((original * (80 + rnd)) / 100)) ? 1 : 0) || - ((original - current == - ((original * (85 + rnd)) / 100)) ? 1 : 0) || - ((original - current == - ((original * (90 + rnd)) / 100)) ? 1 : 0) || - ((original - current == - ((original * (95 + rnd)) / 100)) ? 1 : 0)) - return 1; - else - return 0; -} -#endif - -/* **************************************************************************** - * Utility function to update the TTL of cache entries and check for expired - * ones. When continuous refreshing is enabled the records will be reconfirmed - * @ 80%, 85%, 90% and 95% of their original TTL. - * ****************************************************************************/ -static void -pico_mdns_cache_check_expiries( void ) -{ - struct pico_tree_node *node = NULL, *next = NULL; - struct pico_mdns_record *record = NULL; -#if PICO_MDNS_CONTINUOUS_REFRESH == 1 - uint32_t current = 0, original = 0; - uint16_t type 0; - char *url = NULL; -#endif - - /* Check for expired cache records */ - pico_tree_foreach_safe(node, &Cache, next) { - if ((record = node->keyValue)) { - /* Update current ttl and delete when TTL is 0*/ - if ((--(record->current_ttl)) == 0) { - record = pico_tree_delete(&Cache, record); - pico_mdns_record_delete((void **)&record); - } - -#if PICO_MDNS_CONTINUOUS_REFRESH == 1 - /* Determine original and current ttl */ - original = long_be(record->record->rsuffix->rttl); - current = record->current_ttl; - - /* Cache refresh at 80 or 85/90/95% of TTL + 2% rnd */ - if (pico_mdns_ttl_at_refresh_time(original, current)) { - url = pico_dns_qname_to_url(record->record->rname); - type = short_be(record->record->rsuffix->rtype) - pico_mdns_getrecord_generic(url, type, NULL, NULL); - PICO_FREE(url); - } - -#endif - } - } -} -#endif /* PICO_MDNS_ALLOW_CACHING */ - -/* **************************************************************************** - * Utility function to update the TTL of cookies and check for expired - * ones. Deletes the expired ones as well. - * ****************************************************************************/ -static void -pico_mdns_cookies_check_timeouts( void ) -{ - struct pico_tree_node *node = NULL, *next = NULL; - struct pico_mdns_cookie *cookie = NULL; - - pico_tree_foreach_safe(node, &Cookies, next) { - if ((cookie = node->keyValue) && --(cookie->timeout) == 0) { - /* Call callback to allow error checking */ - if (cookie->callback) { - cookie->callback(NULL, NULL, cookie->arg); - } - - /* Delete cookie */ - cookie = pico_tree_delete(&Cookies, cookie); - pico_mdns_cookie_delete(&cookie); - - /* If the request was for a reconfirmation of a record, - flush the corresponding record after the timeout */ - } - } -} - -/* **************************************************************************** - * Global mDNS module tick-function, central point where all the timing is - * handled. - * - * @param now Ignore - * @param _arg Ignore - * ****************************************************************************/ -static void -pico_mdns_tick( pico_time now, void *_arg ) -{ - IGNORE_PARAMETER(now); - IGNORE_PARAMETER(_arg); - -#if PICO_MDNS_ALLOW_CACHING == 1 - /* Update the cache */ - pico_mdns_cache_check_expiries(); -#endif - - /* Update the cookies */ - pico_mdns_cookies_check_timeouts(); - - /* Schedule new tick */ - pico_timer_add(PICO_MDNS_RR_TTL_TICK, pico_mdns_tick, NULL); -} - -/* MARK: v MDNS PACKET UTILITIES */ - -/* **************************************************************************** - * Sends a Multicast packet on the wire to the mDNS destination port. - * - * @param packet Packet buffer in memory - * @param len Size of the packet in bytes - * @return 0 When the packet is passed successfully on to the lower layers of - * picoTCP. Doesn't mean the packet is successfully send on the wire. - * ****************************************************************************/ -static int -pico_mdns_send_packet( pico_dns_packet *packet, uint16_t len ) -{ - struct pico_ip4 dst4; - - /* Set the destination address to the mDNS multicast-address */ - pico_string_to_ipv4(PICO_MDNS_DEST_ADDR4, &dst4.addr); - - /* Send packet to IPv4 socket */ - return pico_socket_sendto(mdns_sock_ipv4, packet, (int)len, &dst4, - short_be(mdns_port)); -} - -/* **************************************************************************** - * Sends a Unicast packet on the wire to the mDNS destination port of specific - * peer in the network - * - * @param packet Packet buffer in memory - * @param len Size of the packet in bytes - * @param peer Peer in the network you want to send the packet to. - * @return 0 When the packet is passed successfully on to the lower layers of - * picoTCP. Doesn't mean the packet is successfully send on the wire. - * ****************************************************************************/ -static int -pico_mdns_send_packet_unicast( pico_dns_packet *packet, - uint16_t len, - struct pico_ip4 peer ) -{ - /* Send packet to IPv4 socket */ - return pico_socket_sendto(mdns_sock_ipv4, packet, (int)len, &peer, - short_be(mdns_port)); -} - - -/* **************************************************************************** - * Send DNS records as answers to a peer via unicast - * - * @param unicast_tree Tree with DNS records to send as answers. - * @param peer Peer IPv4-address - * @return 0 when the packet is properly send, something else otherwise. - * ****************************************************************************/ -static int -pico_mdns_unicast_reply( pico_dns_rtree *unicast_tree, - pico_dns_rtree *artree, - struct pico_ip4 peer ) -{ - union pico_address *local_addr = NULL; - pico_dns_packet *packet = NULL; - uint16_t len = 0; - - if (pico_tree_count(unicast_tree) > 0) { - /* Create response DNS packet */ - packet = pico_dns_answer_create(unicast_tree, NULL, artree, &len); - if (!packet || !len) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - packet->id = 0; - - /* Check if source address is on the local link */ - local_addr = (union pico_address *) pico_ipv4_source_find(&peer); - if (!local_addr) { - mdns_dbg("Peer not on same link!\n"); - /* Forced response via multicast */ - if (pico_mdns_send_packet(packet, len) != (int)len) { - mdns_dbg("Could not send multicast response!\n"); - return -1; - } - } else { - /* Send the packet via unicast */ - if (pico_mdns_send_packet_unicast(packet, len, peer) != (int)len) { - mdns_dbg("Could not send unicast response!\n"); - return -1; - } - - mdns_dbg("Unicast response sent successfully!\n"); - } - PICO_FREE(packet); - } - - return 0; -} - -/* **************************************************************************** - * Send DNS records as answers to mDNS peers via multicast - * - * @param multicast_tree Tree with DNS records to send as answers. - * @return 0 when the packet is properly send, something else otherwise. - * ****************************************************************************/ -static int -pico_mdns_multicast_reply( pico_dns_rtree *multicast_tree, - pico_dns_rtree *artree ) -{ - pico_dns_packet *packet = NULL; - uint16_t len = 0; - - /* If there are any multicast records */ - if (pico_tree_count(multicast_tree) > 0) { - /* Create response DNS packet */ - packet = pico_dns_answer_create(multicast_tree, NULL, artree, &len); - if (!packet || len == 0) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - packet->id = 0; - - /* Send the packet via multicast */ - if (pico_mdns_send_packet(packet, len) != (int)len) { - mdns_dbg("Could not send multicast response!\n"); - return -1; - } - - mdns_dbg("Multicast response sent successfully!\n"); - - PICO_FREE(packet); - } - - return 0; -} - -/* MARK: ^ MDNS PACKET UTILITIES */ -/* MARK: ASYNCHRONOUS MDNS RECEPTION */ - -/* **************************************************************************** - * Merges 2 pico_trees with each other. - * - * @param dest Destination tree to merge the other tree in. - * @param src Source tree to get the node from to insert into the dest-tree. - * @return Returns 0 when properly merged, or not.. - * ****************************************************************************/ -static int -pico_tree_merge( struct pico_tree *dest, struct pico_tree *src ) -{ - struct pico_tree_node *node = NULL; - - /* Check params */ - if (!dest || !src) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Insert source nodes */ - pico_tree_foreach(node, src) { - if (node->keyValue) { - pico_tree_insert(dest, node->keyValue); - } - } - - return 0; -} - -/* **************************************************************************** - * Populates an mDNS record tree with answers from MyRecords depending on name - * , qtype and qclass. - * - * @param name Name of records to look for in MyRecords - * @param qtype Type of records to look for in MyRecords - * @param qclass Whether the answer should be sent via unicast or not. - * @return mDNS record tree with possible answers from MyRecords - * ****************************************************************************/ -static pico_mdns_rtree -pico_mdns_populate_antree( char *name, uint16_t qtype, uint16_t qclass ) -{ - PICO_MDNS_RTREE_DECLARE(antree); - struct pico_tree_node *node = NULL, *next; - struct pico_mdns_record *record = NULL; - - /* Create an answer record vector */ - if (PICO_DNS_TYPE_ANY == qtype) - antree = pico_mdns_rtree_find_name(&MyRecords, name, 1); - else - antree = pico_mdns_rtree_find_name_type(&MyRecords, name, qtype, 1); - - /* Remove answers which aren't successfully registered yet */ - pico_tree_foreach_safe(node, &antree, next) { - if ((record = node->keyValue) && !IS_RECORD_VERIFIED(record)) { - pico_tree_delete(&antree, record); - } - } - - /* Check if question is a QU-question */ - if (PICO_MDNS_IS_MSB_SET(qclass)) { - /* Set all the flags of the answer accordingly */ - pico_tree_foreach(node, &antree) { - if ((record = node->keyValue)) - PICO_MDNS_SET_FLAG(record->flags, - PICO_MDNS_RECORD_SEND_UNICAST); - } - } - - return antree; -} - -/* **************************************************************************** - * Handles a single received question. - * - * @param question DNS question to parse and handle. - * @param packet Received packet in which the DNS question was present. - * @return mDNS record tree with possible answer to the question. Can possibly - * be empty. - * ****************************************************************************/ -static pico_mdns_rtree -pico_mdns_handle_single_question( struct pico_dns_question *question, - pico_dns_packet *packet ) -{ - struct pico_mdns_cookie *cookie = NULL; - PICO_MDNS_RTREE_DECLARE(antree); - char *qname_original = NULL; - uint16_t qtype = 0, qclass = 0; - - /* Check params */ - if (!question || !packet) { - pico_err = PICO_ERR_EINVAL; - return antree; - } - - /* Decompress single DNS question */ - qname_original = pico_dns_question_decompress(question, packet); - mdns_dbg("Question RCVD for '%s'\n", question->qname); - - /* Find currently active query cookie */ - if ((cookie = pico_mdns_ctree_find_cookie(question->qname, - PICO_MDNS_PACKET_TYPE_QUERY))) { - mdns_dbg("Query cookie found for question, suppress duplicate.\n"); - cookie->status = PICO_MDNS_COOKIE_STATUS_CANCELLED; - } else { - qtype = short_be(question->qsuffix->qtype); - qclass = short_be(question->qsuffix->qclass); - antree = pico_mdns_populate_antree(question->qname, qtype, qclass); - } - - PICO_FREE(question->qname); - question->qname = qname_original; - return antree; -} - -/* **************************************************************************** - * When a query-cookie is found for a RCVD answer, the cookie should be - * handled accordingly. This function does that. - * - * @param cookie Cookie that contains the question for the RCVD answer. - * @param answer RCVD answer to handle cookie with - * @return Returns 0 when handling went OK, something else when it didn't. - * ****************************************************************************/ -static int -pico_mdns_handle_cookie_with_answer( struct pico_mdns_cookie *cookie, - struct pico_mdns_record *answer ) -{ - PICO_MDNS_RTREE_DECLARE(antree); - uint8_t type = 0, status = 0; - - /* Check params */ - if (!cookie || !answer) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - type = cookie->type; - status = cookie->status; - if (PICO_MDNS_COOKIE_STATUS_ACTIVE == status) { - if (PICO_MDNS_PACKET_TYPE_PROBE == type) { - /* Conflict occurred, resolve it! */ - pico_mdns_cookie_resolve_conflict(cookie, answer->record->rname); - } else if (PICO_MDNS_PACKET_TYPE_QUERY == type) { - if (cookie->callback) { - /* RCVD Answer on query, callback with answer. Callback is - * responsible for aggregating all the received answers. */ - pico_tree_insert(&antree, answer); - cookie->callback(&antree, NULL, cookie->arg); - } - } else { /* Don't handle answer cookies with answer */ - } - } - - return 0; -} - -/* **************************************************************************** - * Handles a single received answer record. - * - * @param answer Answer mDNS record. - * @return 0 when answer is properly handled, something else when it's not. - * ****************************************************************************/ -static int -pico_mdns_handle_single_answer( struct pico_mdns_record *answer ) -{ - struct pico_mdns_cookie *found = NULL; - struct pico_mdns_record *record = NULL; - - mdns_dbg("Answer RCVD for '%s'\n", answer->record->rname); - - /* Find currently active query cookie */ - found = pico_mdns_ctree_find_cookie(answer->record->rname, - PICO_MDNS_PACKET_TYPE_QUERY_ANY); - if (found && pico_mdns_handle_cookie_with_answer(found, answer)) { - mdns_dbg("Could not handle found cookie correctly!\n"); - return -1; - } else { - mdns_dbg("RCVD an unsolicited record!\n"); - if ((record = pico_tree_findKey(&MyRecords, answer)) && - !IS_RECORD_PROBING(record)) - return pico_mdns_record_resolve_conflict(record, - answer->record->rname); - } - - return 0; -} - -/* **************************************************************************** - * Handles a single received authority record. - * - * @param answer Authority mDNS record. - * @return 0 when authority is properly handled. -1 when it's not. - * ****************************************************************************/ -static int -pico_mdns_handle_single_authority( struct pico_mdns_record *answer ) -{ - struct pico_mdns_cookie *found = NULL; - char *name = NULL; - - name = answer->record->rname; - mdns_dbg("Authority RCVD for '%s'\n", name); - - /* Find currently active probe cookie */ - if ((found = pico_mdns_ctree_find_cookie(name, PICO_MDNS_PACKET_TYPE_PROBE)) - && PICO_MDNS_COOKIE_STATUS_ACTIVE == found->status) { - mdns_dbg("Simultaneous Probing occurred, went tiebreaking...\n"); - if (pico_mdns_cookie_apply_spt(found, answer->record) < 0) { - mdns_dbg("Could not apply S.P.T. to cookie!\n"); - return -1; - } - } - - return 0; -} - -/* **************************************************************************** - * Handles a single received additional [Temporarily unused] - * - * @param answer Additional mDNS record. - * @return 0 - * ****************************************************************************/ -static int -pico_mdns_handle_single_additional( struct pico_mdns_record *answer ) -{ - /* Don't need this for now ... */ - IGNORE_PARAMETER(answer); - return 0; -} - -/* **************************************************************************** - * Handles a flat chunk of memory as if it were all questions in it. - * Generates a tree with responses if there are any questions for records for - * which host has the authority to answer. - * - * @param ptr Pointer-Pointer to location of question section of packet. - * Will point to right after the question section on return. - * @param qdcount Amount of questions contained in the packet - * @param packet DNS packet where the questions are present. - * @return Tree with possible responses on the questions. - * ****************************************************************************/ -static pico_mdns_rtree -pico_mdns_handle_data_as_questions ( uint8_t **ptr, - uint16_t qdcount, - pico_dns_packet *packet ) -{ - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(rtree); - struct pico_dns_question question; - uint16_t i = 0; - - /* Check params */ - if ((!ptr) || !packet || !(*ptr)) { - pico_err = PICO_ERR_EINVAL; - return antree; - } - - for (i = 0; i < qdcount; i++) { - /* Set qname of the question to the correct location */ - question.qname = (char *)(*ptr); - - /* Set qsuffix of the question to the correct location */ - question.qsuffix = (struct pico_dns_question_suffix *) - (question.qname + pico_dns_namelen_comp(question.qname) + 1); - - /* Handle a single question and merge the returned tree */ - rtree = pico_mdns_handle_single_question(&question, packet); - pico_tree_merge(&antree, &rtree); - pico_tree_destroy(&rtree, NULL); - - /* Move to next question */ - *ptr = (uint8_t *)question.qsuffix + - sizeof(struct pico_dns_question_suffix); - } - if (pico_tree_count(&antree) == 0) { - mdns_dbg("No 'MyRecords' found that corresponds with this query.\n"); - } - - return antree; -} - -static int -pico_mdns_handle_data_as_answers_generic( uint8_t **ptr, - uint16_t count, - pico_dns_packet *packet, - uint8_t type ) -{ - struct pico_mdns_record mdns_answer = { - .record = NULL, .current_ttl = 0, - .flags = 0, .claim_id = 0 - }; - struct pico_dns_record answer; - char *orname = NULL; - uint16_t i = 0; - - /* Check params */ - if ((!ptr) || !packet || !(*ptr)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - for (i = 0; i < count; i++) { - /* Set rname of the record to the correct location */ - answer.rname = (char *)(*ptr); - - /* Set rsuffix of the record to the correct location */ - answer.rsuffix = (struct pico_dns_record_suffix *) - (answer.rname + - pico_dns_namelen_comp(answer.rname) + 1u); - - /* Set rdata of the record to the correct location */ - answer.rdata = (uint8_t *) answer.rsuffix + - sizeof(struct pico_dns_record_suffix); - - /* Make an mDNS record from the DNS answer */ - orname = pico_dns_record_decompress(&answer, packet); - mdns_answer.record = &answer; - mdns_answer.record->rname_length = (uint16_t)(pico_dns_strlen(answer.rname) + 1u); - - /* Handle a single aswer */ - switch (type) { - case 1: - pico_mdns_handle_single_authority(&mdns_answer); - break; - case 2: - pico_mdns_handle_single_additional(&mdns_answer); - break; - default: - pico_mdns_handle_single_answer(&mdns_answer); -#if PICO_MDNS_ALLOW_CACHING == 1 - pico_mdns_cache_add_record(&mdns_answer); -#endif - break; - } - - /* Free decompressed name and mDNS record */ - PICO_FREE(mdns_answer.record->rname); - answer.rname = orname; - - /* Move to next record */ - *ptr = (uint8_t *) answer.rdata + short_be(answer.rsuffix->rdlength); - } - return 0; -} - -/* **************************************************************************** - * Splits an mDNS record tree into two DNS record tree, one to send via - * unicast, one to send via multicast. - * - * @param answers mDNS record tree to split up - * @param unicast_tree DNS record tree with unicast answers. - * @param multicast_tree DNS record tee with multicast answers. - * @return 0 when the tree is properly split up. - * ****************************************************************************/ -static int -pico_mdns_sort_unicast_multicast( pico_mdns_rtree *answers, - pico_dns_rtree *unicast_tree, - pico_dns_rtree *multicast_tree ) -{ - struct pico_mdns_record *record = NULL; - struct pico_tree_node *node = NULL; - - /* Check params */ - if (!answers || !unicast_tree || !multicast_tree) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - pico_tree_foreach(node, answers) { - record = node->keyValue; - if ((record = node->keyValue)) { - if (IS_UNICAST_REQUESTED(record)) { - if (record->record) - pico_tree_insert(unicast_tree, record->record); - } else { - if (record->record) - pico_tree_insert(multicast_tree, record->record); - } - } - } - - return 0; -} - -static uint16_t -pico_mdns_nsec_highest_type( pico_mdns_rtree *rtree ) -{ - struct pico_tree_node *node = NULL, *next = NULL; - struct pico_mdns_record *record = NULL; - uint16_t highest_type = 0, type = 0; - - pico_tree_foreach_safe(node, rtree, next) { - if ((record = node->keyValue)) { - if (IS_SHARED_RECORD(record)) - pico_tree_delete(rtree, record); - - type = short_be(record->record->rsuffix->rtype); - highest_type = (type > highest_type) ? (type) : (highest_type); - } - } - - return highest_type; -} - -static void -pico_mdns_nsec_gen_bitmap( uint8_t *ptr, pico_mdns_rtree *rtree ) -{ - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL; - uint16_t type = 0; - - pico_tree_foreach(node, rtree) { - if ((record = node->keyValue)) { - type = short_be(record->record->rsuffix->rtype); - *(ptr + 1 + (type / 8)) = (uint8_t)(0x80 >> (type % 8)); - } - } -} - -/* **************************************************************************** - * Generates an NSEC record for a specific name. Looks in MyRecords for unique - * records with given name and generates the NSEC bitmap from them. - * - * @param name Name of the records you want to generate a bitmap for. - * @return Pointer to newly created NSEC record on success, NULL on failure. - * ****************************************************************************/ -static struct pico_mdns_record * -pico_mdns_gen_nsec_record( char *name ) -{ - PICO_MDNS_RTREE_DECLARE(rtree); - struct pico_mdns_record *record = NULL; - uint16_t highest_type = 0, rdlen = 0; - uint8_t bitmap_len = 0, *rdata = NULL, *ptr = NULL; - char *url = NULL; - - if (!name) { /* Check params */ - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - /* Determine the highest type of my unique records with this name */ - rtree = pico_mdns_rtree_find_name(&MyRecords, name, 0); - highest_type = pico_mdns_nsec_highest_type(&rtree); - - /* Determine the bimap_len */ - bitmap_len = (uint8_t)(highest_type / 8); - bitmap_len = (uint8_t)(bitmap_len + ((highest_type % 8) ? (1) : (0))); - - /* Provide rdata */ - rdlen = (uint16_t)(pico_dns_strlen(name) + 3u + bitmap_len); - if (!(rdata = PICO_ZALLOC((size_t)rdlen))) { - pico_err = PICO_ERR_ENOMEM; - pico_tree_destroy(&rtree, NULL); - return NULL; - } - - /* Set the next domain name */ - strcpy((char *)rdata, name); - /* Set the bitmap length */ - *(ptr = (uint8_t *)(rdata + pico_dns_strlen(name) + 2)) = bitmap_len; - /* Generate the bitmap */ - pico_mdns_nsec_gen_bitmap(ptr, &rtree); - pico_tree_destroy(&rtree, NULL); - - /* Generate the actual mDNS NSEC record */ - if (!(url = pico_dns_qname_to_url(name))) { - PICO_FREE(rdata); - return NULL; - } - - record = pico_mdns_record_create(url, (void *)rdata, rdlen, - PICO_DNS_TYPE_NSEC, - PICO_MDNS_SERVICE_TTL, - PICO_MDNS_RECORD_UNIQUE); - PICO_FREE(rdata); - PICO_FREE(url); - return record; -} - -/* **************************************************************************** - * Checks in additionals if there is an NSEC record already present with given - * name. If there's not, a new NSEC records will be generated and added to the - * additional tree. - * - * @param artree mDNS record-tree containing additional records. - * @param name Name to check for. - * @return 0 when NSEC is present in additional, whether it was already present - * or a new one is generated doesn't matter. - * ****************************************************************************/ -static int -pico_mdns_additionals_add_nsec( pico_mdns_rtree *artree, - char *name ) -{ - struct pico_mdns_record *record = NULL, *nsec = NULL; - struct pico_tree_node *node = NULL; - uint16_t type = 0; - - /* Check params */ - if (!artree || !name) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Check if there is a NSEC already for this name */ - pico_tree_foreach(node, artree) { - if (node != &LEAF && (record = node->keyValue)) { - type = short_be(record->record->rsuffix->rtype); - if (PICO_DNS_TYPE_NSEC == type) { - if (strcasecmp(record->record->rname, name) == 0) - return 0; - } - } - } - - /* If there is none present generate one for given name */ - if ((nsec = pico_mdns_gen_nsec_record(name))) - pico_tree_insert(artree, nsec); - return 0; -} - -/* **************************************************************************** - * Adds hostname records to the additional records - * - * @param artree mDNS record-tree containing additional records. - * @return 0 when hostname records are added successfully to additionals. Rets - * something else on failure. - * ****************************************************************************/ -static int -pico_mdns_additionals_add_host( pico_mdns_rtree *artree ) -{ - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL, *copy = NULL; - - pico_tree_foreach(node, &MyRecords) { - if ((record = node->keyValue) && - IS_HOSTNAME_RECORD(record) && - IS_RECORD_VERIFIED(record)) { - copy = pico_mdns_record_copy(record); - if (copy && pico_tree_insert(artree, copy)) - pico_mdns_record_delete((void **)©); - } - } - - return 0; -} - -static void -pico_rtree_add_copy( pico_mdns_rtree *tree, struct pico_mdns_record *record ) -{ - struct pico_mdns_record *copy = NULL; - - if (!tree || !record) { - pico_err = PICO_ERR_EINVAL; - return; - } - - if ((copy = pico_mdns_record_copy(record))) { - if (pico_tree_insert(tree, copy)) - pico_mdns_record_delete((void **)©); - } -} - -/* **************************************************************************** - * When a service is found additional records should be generated and added to - * the either the answer section or the additional sections. This happens here - * - * @param antree mDNS record tree with answers to send - * @param artree mDNS record tree with additionals to send - * @param srv_record Found SRV record in the answers - * @return 0 When additional records are properly generated - * ****************************************************************************/ -static int -pico_mdns_gather_service_meta( pico_mdns_rtree *antree, - pico_mdns_rtree *artree, - struct pico_mdns_record *srv_record ) -{ - struct pico_mdns_record *ptr_record = NULL, *meta_record = NULL; - char *sin = NULL, *service = NULL; - uint32_t ttl = 0; - - if (!antree || !artree || !srv_record) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Add hostname records */ - pico_mdns_additionals_add_host(artree); - - /* Generate proper service instance name and service */ - if (!(sin = pico_dns_qname_to_url(srv_record->record->rname))) - return -1; - - service = sin + pico_dns_first_label_length(sin) + 1u; - ttl = long_be(srv_record->record->rsuffix->rttl); - - /* Generate PTR records */ - ptr_record = pico_mdns_record_create(service, (void *)sin, - (uint16_t)strlen(sin), - PICO_DNS_TYPE_PTR, - ttl, PICO_MDNS_RECORD_SHARED); - /* Meta DNS-SD record */ - meta_record = pico_mdns_record_create("_services._dns-sd._udp.local", - (void *)service, - (uint16_t)strlen(service), - PICO_DNS_TYPE_PTR, - ttl, PICO_MDNS_RECORD_SHARED); - PICO_FREE(sin); - if (!meta_record || !ptr_record) { - mdns_dbg("Could not generate META or PTR records!\n"); - pico_mdns_record_delete((void **)&ptr_record); - pico_mdns_record_delete((void **)&meta_record); - return -1; - } - - ptr_record->flags |= (PICO_MDNS_RECORD_PROBED | PICO_MDNS_RECORD_CLAIMED); - meta_record->flags |= (PICO_MDNS_RECORD_PROBED | PICO_MDNS_RECORD_CLAIMED); - - /* Add copies to the answer tree */ - pico_rtree_add_copy(antree, meta_record); - pico_rtree_add_copy(antree, ptr_record); - - /* Insert the created service record in MyRecords, if it's already in, destroy them */ - if (meta_record && pico_tree_insert(&MyRecords, meta_record)) { - pico_mdns_record_delete((void **)&meta_record); - } - if (ptr_record && pico_tree_insert(&MyRecords, ptr_record)) { - pico_mdns_record_delete((void **)&ptr_record); - } - - return 0; -} - -/* **************************************************************************** - * Gathers additional records for a to send response. Checks for services and - * whether or not there should be NSEC records added to the additional section - * - * @param antree mDNS record tree with answers to send - * @param artree mDNS record tree with additionals to send - * @return Returns 0 when additionals are properly generated and added - * ****************************************************************************/ -static int -pico_mdns_gather_additionals( pico_mdns_rtree *antree, - pico_mdns_rtree *artree ) -{ - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL; - int ret = 0; - - /* Check params */ - if (!antree || !artree) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Look for SRV records in the answer tree */ - pico_tree_foreach(node, antree) { - if ((record = node->keyValue) && - short_be(record->record->rsuffix->rtype) == PICO_DNS_TYPE_SRV && - (ret = pico_mdns_gather_service_meta(antree, artree, record))) - return ret; - } - - /* Look for unique records in the answer tree to generate NSEC records */ - pico_tree_foreach(node, antree) { - if ((record = node->keyValue) && IS_UNIQUE_RECORD(record) && - (ret = pico_mdns_additionals_add_nsec(artree, - record->record->rname))) - return ret; - } - - /* Look for unique records in the additional tree to generate NSEC records*/ - pico_tree_foreach(node, artree) { - if ((record = node->keyValue) && IS_UNIQUE_RECORD(record) && - (ret = pico_mdns_additionals_add_nsec(artree, - record->record->rname))) - return ret; - } - - return 0; -} - -/* **************************************************************************** - * Sends mDNS records to either multicast peer via unicast to a single peer. - * - * @param antree Tree with mDNS records to send as answers - * @param peer IPv4-address of peer who this host has RCVD a packet. - * @return 0 when answers are properly handled, something else otherwise. - * ****************************************************************************/ -static int -pico_mdns_reply( pico_mdns_rtree *antree, struct pico_ip4 peer ) -{ - PICO_DNS_RTREE_DECLARE(antree_m); - PICO_DNS_RTREE_DECLARE(antree_u); - PICO_MDNS_RTREE_DECLARE(artree); - PICO_DNS_RTREE_DECLARE(artree_dummy); - PICO_DNS_RTREE_DECLARE(artree_dns); - - /* Try to gather additionals for the to send response */ - if (pico_mdns_gather_additionals(antree, &artree)) { - mdns_dbg("Could not gather additionals properly!\n"); - return -1; - } - - /* Sort the answers into multicast and unicast answers */ - pico_mdns_sort_unicast_multicast(antree, &antree_u, &antree_m); - - /* Convert the mDNS additional tree to a DNS additional tree to send with - * the the unicast AND the multicast response */ - pico_mdns_sort_unicast_multicast(&artree, &artree_dummy, &artree_dns); - - /* Send response via unicast */ - if (pico_mdns_unicast_reply(&antree_u, &artree_dns, peer)) { - mdns_dbg("Could not sent reply via unicast!\n"); - return -1; - } - - /* Send response via multicast */ - if (pico_mdns_multicast_reply(&antree_m, &artree_dns)) { - mdns_dbg("Could not sent reply via multicast!\n"); - return -1; - } - - pico_tree_destroy(&antree_m, NULL); - pico_tree_destroy(&antree_u, NULL); - pico_tree_destroy(&artree_dummy, NULL); - pico_tree_destroy(&artree_dns, NULL); - PICO_MDNS_RTREE_DESTROY(&artree); - - return 0; -} - -/* **************************************************************************** - * Parses DNS records from a plain chunk of data and looks for them in the - * answer tree. If they're found, they will be removed from the tree. - * - * @param rtree Tree to look in for known answers - * @param packet DNS packet in which to look for known answers - * @param ancount Amount of answers in the DNS packet - * @param data Answer section of the DNS packet as a flat chunk of memory. - * @return 0 K.A.S. could be properly applied, something else when not. - * ****************************************************************************/ -static int -pico_mdns_apply_k_a_s( pico_mdns_rtree *rtree, - pico_dns_packet *packet, - uint16_t ancount, - uint8_t **data ) -{ - struct pico_tree_node *node = NULL, *next = NULL; - struct pico_mdns_record *record = NULL, ka = { - 0 - }; - struct pico_dns_record answer = { - 0 - }; - uint16_t i = 0; - - /* Check params */ - if ((!data) || !rtree || !packet || !(*data)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - for (i = 0; i < ancount; i++) { - /* Set rname of the record to the correct location */ - answer.rname = (char *)(*data); - - /* Set rsuffix of the record to the correct location */ - answer.rsuffix = (struct pico_dns_record_suffix *) - (answer.rname + pico_dns_namelen_comp(answer.rname) + 1u); - - /* Set rdata of the record to the correct location */ - answer.rdata = (uint8_t *) answer.rsuffix + - sizeof(struct pico_dns_record_suffix); - - pico_dns_record_decompress(&answer, packet); - ka.record = &answer; - - /* If the answer is in the record vector */ - pico_tree_foreach_safe(node, rtree, next) { - if ((record = node->keyValue)) { - if (pico_mdns_record_cmp(record, &ka) == 0) - record = pico_tree_delete(rtree, record); - } - } - PICO_FREE(ka.record->rname); - ka.record = NULL; - - /* Move to next record */ - *data = (uint8_t *) answer.rdata + short_be(answer.rsuffix->rdlength); - } - return 0; -} - -/* **************************************************************************** - * Handles a single incoming query packet. Applies Known Answer Suppression - * after handling as well. - * - * @param packet Received packet - * @param peer IPv4 address of the peer who sent the received packet. - * @return Returns 0 when the query packet is properly handled. - * ****************************************************************************/ -static int -pico_mdns_handle_query_packet( pico_dns_packet *packet, struct pico_ip4 peer ) -{ - PICO_MDNS_RTREE_DECLARE(antree); - uint16_t qdcount = 0, ancount = 0; - uint8_t *data = NULL; - - /* Move to the data section of the packet */ - data = (uint8_t *)packet + sizeof(struct pico_dns_header); - - /* Generate a list of answers */ - qdcount = short_be(packet->qdcount); - antree = pico_mdns_handle_data_as_questions(&data, qdcount, packet); - if (pico_tree_count(&antree) == 0) { - mdns_dbg("No records found that correspond with this query!\n"); - return 0; - } - - /* Apply Known Answer Suppression */ - ancount = short_be(packet->ancount); - if (pico_mdns_apply_k_a_s(&antree, packet, ancount, &data)) { - mdns_dbg("Could not apply known answer suppression!\n"); - return -1; - } - - /* Try to reply with the left-over answers */ - pico_mdns_reply(&antree, peer); - PICO_MDNS_RTREE_DESTROY(&antree); - - return 0; -} - -/* **************************************************************************** - * Handles a single incoming probe packet. Checks for Simultaneous Probe - * Tiebreaking as well. - * - * @param packet Received probe packet. - * @param peer IPv4 address of the peer who sent the probe packet. - * @return Returns 0 when the probe packet is properly handled. - * ****************************************************************************/ -static int -pico_mdns_handle_probe_packet( pico_dns_packet *packet, struct pico_ip4 peer ) -{ - PICO_MDNS_RTREE_DECLARE(antree); - uint16_t qdcount = 0, nscount = 0; - uint8_t *data = NULL; - - /* Move to the data section of the packet */ - data = (uint8_t *)packet + sizeof(struct pico_dns_header); - - /* Generate a list of answers */ - qdcount = short_be(packet->qdcount); - antree = pico_mdns_handle_data_as_questions(&data, qdcount, packet); - - /* Check for Simultaneous Probe Tiebreaking */ - nscount = short_be(packet->nscount); - pico_mdns_handle_data_as_answers_generic(&data, nscount, packet, 1); - - /* Try to reply with the answers */ - if (pico_tree_count(&antree) != 0){ - int retval = pico_mdns_reply(&antree, peer); - PICO_MDNS_RTREE_DESTROY(&antree); - return retval; - } - - return 0; -} - -/* **************************************************************************** - * Handles a single incoming answer packet. - * - * @param packet Received answer packet. - * @return Returns 0 when the response packet is properly handled. - * ****************************************************************************/ -static int -pico_mdns_handle_response_packet( pico_dns_packet *packet ) -{ - uint8_t *data = NULL; - uint16_t ancount = 0; - - /* Move to the data section of the packet */ - data = (uint8_t *)packet + sizeof(struct pico_dns_header); - - /* Generate a list of answers */ - ancount = short_be(packet->ancount); - if (pico_mdns_handle_data_as_answers_generic(&data, ancount, packet, 0)) { - mdns_dbg("Could not handle data as answers\n"); - return -1; - } - - return 0; -} - -/* **************************************************************************** - * Parses an incoming packet and handles it according to the type of the - * packet. Packet type determination happens in this function. - * - * @param buf Memory buffer containing the received packet - * @param buflen Length in bytes of the memory buffer - * @param peer IPv4 address of the peer who sent the received packet. - * @return 0 when the packet is properly handled. Something else when it's not - * ****************************************************************************/ -static int -pico_mdns_recv( void *buf, int buflen, struct pico_ip4 peer ) -{ - pico_dns_packet *packet = (pico_dns_packet *) buf; - uint16_t qdcount = short_be(packet->qdcount); - uint16_t ancount = short_be(packet->ancount); - uint16_t authcount = short_be(packet->nscount); - uint16_t addcount = short_be(packet->arcount); - - mdns_dbg(">>>>>>> QDcount: %u, ANcount: %u, NScount: %u, ARcount: %u\n", - qdcount, ancount, authcount, addcount); - - IGNORE_PARAMETER(buflen); - IGNORE_PARAMETER(addcount); - - /* DNS PACKET TYPE DETERMINATION */ - if ((qdcount > 0)) { - if (authcount > 0) { - mdns_dbg(">>>>>>> RCVD a mDNS probe query:\n"); - /* Packet is probe query */ - if (pico_mdns_handle_probe_packet(packet, peer) < 0) { - mdns_dbg("Could not handle mDNS probe query!\n"); - return -1; - } - } else { - mdns_dbg(">>>>>>> RCVD a plain mDNS query:\n"); - /* Packet is a plain query */ - if (pico_mdns_handle_query_packet(packet, peer) < 0) { - mdns_dbg("Could not handle plain DNS query!\n"); - return -1; - } - } - } else { - if (ancount > 0) { - mdns_dbg(">>>>>>> RCVD a mDNS response:\n"); - /* Packet is a response */ - if (pico_mdns_handle_response_packet(packet) < 0) { - mdns_dbg("Could not handle DNS response!\n"); - return -1; - } - } else { - /* Something went wrong here... */ - mdns_dbg("RCVD Packet contains no questions or answers...\n"); - return -1; - } - } - - return 0; -} - -/* **************************************************************************** - * picoTCP callback for UDP IPv4 Socket events - * - * @param ev Determination of the occurred event - * @param s Socket on which the event occurred - * ****************************************************************************/ -static void -pico_mdns_event4( uint16_t ev, struct pico_socket *s ) -{ - char *recvbuf = NULL; - struct pico_ip4 peer = { - 0 - }; - int pico_read = 0; - uint16_t port = 0; - - /* process read event, data available */ - if (ev == PICO_SOCK_EV_RD) { - mdns_dbg("\n>>>>>>> READ EVENT! <<<<<<<\n"); - recvbuf = PICO_ZALLOC(PICO_MDNS_MAXBUF); - if (!recvbuf) { - pico_err = PICO_ERR_ENOMEM; - return; - } - - /* Receive while data is available in socket buffer */ - while((pico_read = pico_socket_recvfrom(s, recvbuf, PICO_MDNS_MAXBUF, - &peer, &port)) > 0) { - /* Handle the MDNS data received */ - pico_mdns_recv(recvbuf, pico_read, peer); - } - PICO_FREE(recvbuf); - mdns_dbg(">>>>>>>>>>>>>><<<<<<<<<<<<<\n\n"); - } else - mdns_dbg("Socket Error received. Bailing out.\n"); -} - -/* MARK: ADDRESS RESOLUTION */ - -/* **************************************************************************** - * Send a mDNS query packet on the wire. This is scheduled with a pico_timer- - * event. - * - * @param now Ignore - * @param arg Void-pointer to query-cookie - * ****************************************************************************/ -static void -pico_mdns_send_query_packet( pico_time now, void *arg ) -{ - struct pico_mdns_cookie *cookie = (struct pico_mdns_cookie *)arg; - pico_dns_qtree *questions = NULL; - pico_dns_packet *packet = NULL; - uint16_t len = 0; - - IGNORE_PARAMETER(now); - - /* Parse in the cookie */ - cookie = (struct pico_mdns_cookie *)arg; - if (!cookie || cookie->type != PICO_MDNS_PACKET_TYPE_QUERY) - return; - - /* Create DNS query packet */ - questions = &(cookie->qtree); - if (!(packet = pico_dns_query_create(questions, NULL, NULL, NULL, &len))) { - mdns_dbg("Could not create query packet!\n"); - return; - } - - packet->id = 0; - - if (cookie->status != PICO_MDNS_COOKIE_STATUS_CANCELLED) { - cookie->status = PICO_MDNS_COOKIE_STATUS_ACTIVE; - if(pico_mdns_send_packet(packet, len) != (int)len) { - mdns_dbg("Send error occurred!\n"); - return; - } - - mdns_dbg("DONE - Sent query.\n"); - } else { - mdns_dbg("DONE - Duplicate query suppressed.\n"); - pico_timer_cancel(cookie->send_timer); - /* Remove cookie from Cookies */ - cookie = pico_tree_delete(&Cookies, cookie); - pico_mdns_cookie_delete(&cookie); - } - PICO_FREE(packet); -} - -/* **************************************************************************** - * Generates a mDNS query packet and schedules a sending on the wire. - * - * @param url URL for the name of the question contained in the query - * @param type DNS type of the question contained in the query - * @param callback Callback to call when a response on this query is RCVD. - * @return 0 When the query is successfully generated and scheduled for sending - * ****************************************************************************/ -static int -pico_mdns_getrecord_generic( const char *url, uint16_t type, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg) -{ - struct pico_mdns_cookie *cookie = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(artree); - struct pico_dns_question *q = NULL; - uint16_t l = 0; - - /* Create a single question and add it to the tree */ - q = pico_mdns_question_create(url, &l, PICO_PROTO_IPV4, type, 0, 0); - if (!q) { - mdns_dbg("question_create returned NULL!\n"); - return -1; - } - pico_tree_insert(&qtree, q); - - /* Create a mDNS cookie to send */ - if (!(cookie = pico_mdns_cookie_create(qtree, antree, artree, 1, - PICO_MDNS_PACKET_TYPE_QUERY, - callback, arg))) { - PICO_DNS_QTREE_DESTROY(&qtree); - mdns_dbg("cookie_create returned NULL!\n"); - return -1; - } - - /* Add cookie to Cookies to be able to find it afterwards */ - pico_tree_insert(&Cookies, cookie); - /* Create new pico_timer-event to send packet */ - pico_timer_add((pico_rand() % 120) + 20, pico_mdns_send_query_packet, - (void *)cookie); - return 0; -} - -/* **************************************************************************** - * API-call to query a record with a certain URL and type. First checks the - * Cache for this record. If no cache-entry is found, a query will be sent on - * the wire for this record. - * - * @param url URL to query for. - * @param type DNS type top query for. - * @param callback Callback to call when records are found for the query. - * @return 0 when query is correctly parsed, something else on failure. - * ****************************************************************************/ -int -pico_mdns_getrecord( const char *url, uint16_t type, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ -#if PICO_MDNS_ALLOW_CACHING == 1 - PICO_MDNS_RTREE_DECLARE(cache_hits); - char *name = NULL; -#endif - - /* Check params */ - if (!url) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* First, try to find records in the cache */ -#if PICO_MDNS_ALLOW_CACHING == 1 - name = pico_dns_url_to_qname(url); - cache_hits = pico_mdns_rtree_find_name_type(&Cache, name, type, 0); - PICO_FREE(name); - if (pico_tree_count(&cache_hits) > 0) { - mdns_dbg("CACHE HIT! Passed cache records to callback.\n"); - callback(&cache_hits, NULL, arg); - } else { -#endif - mdns_dbg("CACHE MISS! Trying to resolve URL '%s'...\n", url); - return pico_mdns_getrecord_generic(url, type, callback, arg); -#if PICO_MDNS_ALLOW_CACHING == 1 -} -#endif - - return 0; -} - -/* MARK: PROBING & ANNOUNCING */ - -/* **************************************************************************** - * Function to create an announcement from an mDNS cookie and send it on the - * wire. - * - * @param now Ignore - * @param arg Void-pointer to mDNS announcement cookie - * ****************************************************************************/ -static void -pico_mdns_send_announcement_packet( pico_time now, void *arg ) -{ - struct pico_mdns_cookie *cookie = (struct pico_mdns_cookie *)arg; - - /* Check params */ - IGNORE_PARAMETER(now); - if (!cookie) - return; - - cookie->status = PICO_MDNS_COOKIE_STATUS_ACTIVE; - if (cookie->count > 0) { - /* Send the announcement on the wire */ - pico_mdns_reply(&(cookie->antree), inaddr_any); - mdns_dbg("DONE - Sent announcement!\n"); - - /* The host needs to send 2 announcements 1 second apart */ - if (--(cookie->count) == 0) { - cookie->status = PICO_MDNS_COOKIE_STATUS_INACTIVE; - - /* Update the states of the records */ - pico_mdns_my_records_claimed(cookie->antree, - cookie->callback, - cookie->arg); - - /* Try to delete the cookie */ - pico_tree_delete(&Cookies, cookie); - pico_mdns_cookie_delete(&cookie); - } - else /* Announcement should be sent with a delay of 1s in between. */ - pico_timer_add(1000, pico_mdns_send_announcement_packet, cookie); - } -} - -/* **************************************************************************** - * Announces all 'my records' which passed the probing-step or just shared - * records. - * - * @param callback Gets called when all records in the cookie are announced. - * @return 0 When the host successfully started announcing. - * ****************************************************************************/ -static int -pico_mdns_announce( void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ - struct pico_mdns_cookie *announcement_cookie = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(artree); - - /* Check params */ - if (!callback) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - IGNORE_PARAMETER(arg); - - /* Find out which resource records can be announced */ - antree = pico_mdns_my_records_find_probed(); - if (pico_tree_count(&antree) == 0) - return 0; - - /* Create a mDNS packet cookie */ - if (!(announcement_cookie = pico_mdns_cookie_create(qtree, antree, artree, - PICO_MDNS_ANNOUNCEMENT_COUNT, - PICO_MDNS_PACKET_TYPE_ANNOUNCEMENT, - callback, arg))) { - mdns_dbg("cookie_create returned NULL!\n"); - PICO_MDNS_RTREE_DESTROY(&antree); - return -1; - } - - /* Send a first unsolicited announcement */ - pico_mdns_send_announcement_packet(0, announcement_cookie); - mdns_dbg("DONE - Started announcing.\n"); - - return 0; -} - -/* **************************************************************************** - * Makes sure the cache flush bit of the to probe records is cleared, and - * generates a DNS record tree to insert in the Authority Section of the DNS - * packet - * - * @param records mDNS records to probe. - * @return DNS record tree to with actual DNS records to insert in Authority - * Section of probe packet. - * ****************************************************************************/ -static pico_dns_rtree -pico_mdns_gen_probe_auths( pico_mdns_rtree *records ) -{ - PICO_DNS_RTREE_DECLARE(nstree); - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL; - - pico_tree_foreach(node, records) { - if ((record = node->keyValue) && record->record) { - /* Clear the cache flush bit for authority records in probes */ - PICO_MDNS_CLR_MSB_BE(record->record->rsuffix->rclass); - /* Only the actual DNS records is required */ - pico_tree_insert(&nstree, record->record); - } - } - - return nstree; -} - -/* **************************************************************************** - * Function to create a probe form an mDNS cookie and send it on the wire. - * - * @param now Ignore - * @param arg Void-pointer to mDNS probe cookie - * ****************************************************************************/ -static void -pico_mdns_send_probe_packet( pico_time now, void *arg ) -{ - struct pico_mdns_cookie *cookie = (struct pico_mdns_cookie *)arg; - pico_dns_packet *packet = NULL; - PICO_DNS_RTREE_DECLARE(nstree); - uint16_t len = 0; - - /* Check params */ - IGNORE_PARAMETER(now); - if (!cookie || (cookie->type == PICO_MDNS_COOKIE_STATUS_INACTIVE)) { - pico_err = PICO_ERR_EINVAL; - return; - } - - /* Set the cookie to the active state */ - cookie->status = PICO_MDNS_COOKIE_STATUS_ACTIVE; - if (cookie->count-- > 0) { - /* Generate authority records */ - nstree = pico_mdns_gen_probe_auths(&(cookie->antree)); - - /* Create an mDNS answer */ - if (!(packet = pico_dns_query_create(&(cookie->qtree), NULL, - &nstree, NULL, &len))) { - PICO_DNS_RTREE_DESTROY(&nstree); - mdns_dbg("Could not create probe packet!\n"); - return; - } - pico_tree_destroy(&nstree, NULL); - - /* Send the mDNS answer unsolicited via multicast */ - if(pico_mdns_send_packet(packet, len) != (int)len) { - mdns_dbg("Send error occurred!\n"); - return; - } - PICO_FREE(packet); - - mdns_dbg("DONE - Sent probe!\n"); - - /* Probes should be sent with a delay in between of 250 ms */ - if (PICO_MDNS_COOKIE_STATUS_ACTIVE == cookie->status ) - cookie->send_timer = pico_timer_add(250, - pico_mdns_send_probe_packet, - (void *)cookie); - } else { - mdns_dbg("DONE - Probing.\n"); - - pico_mdns_my_records_probed(&(cookie->antree)); - - /* Start announcing */ - cookie->count = PICO_MDNS_ANNOUNCEMENT_COUNT; - cookie->type = PICO_MDNS_PACKET_TYPE_ANNOUNCEMENT; - pico_mdns_send_announcement_packet(0, (void*) cookie); - } - - - return; -} - -/* **************************************************************************** - * Adds a new probe question to the probe cookie questions, if a probe question - * for a new is already present in the question-tree, it will not be generated - * and inserted again - * - * @param qtree Probe question tree - * @param name Name for which the function has to create a probe question - * @return 0 when the probe question is already present or added successfully. - * ****************************************************************************/ -static int -pico_mdns_add_probe_question( pico_dns_qtree *qtree, - char *name ) -{ - struct pico_dns_question *new = NULL; - char *url = NULL; - uint16_t qlen = 0; - uint8_t flags = PICO_MDNS_QUESTION_FLAG_PROBE; - -#if PICO_MDNS_PROBE_UNICAST == 1 - flags |= PICO_MDNS_QUESTION_FLAG_UNICAST_RES; -#endif - - /* Convert name to URL and try to create a new probe question */ - if (!(url = pico_dns_qname_to_url(name))) - return -1; - - mdns_dbg("Probe question for URL: %s\n", url); - if (!(new = pico_mdns_question_create(url, &qlen, PICO_PROTO_IPV4, - PICO_DNS_TYPE_ANY, flags, 0))) { - PICO_FREE(url); - return -1; - } - - PICO_FREE(url); - - /* Try to find an existing question in the vector */ - if (pico_tree_insert(qtree, new)) - pico_dns_question_delete((void **)&new); - - return 0; -} - -/* **************************************************************************** - * Find any of my record that need to be probed and try to probe them. - * - * @param callback Callback to call when all records are properly registered - * @return When host successfully started probing. - * ****************************************************************************/ -static int pico_mdns_probe( void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ - struct pico_mdns_cookie *cookie = NULL; - struct pico_mdns_record *record = NULL; - struct pico_tree_node *node = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(artree); - - /* Check params */ - if (!callback) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Find my records that need to pass the probing step first */ - antree = pico_mdns_my_records_find_to_probe(); - - /* Crate probe questions for the to probe records */ - pico_tree_foreach(node, &antree) { - if ((record = node->keyValue)) { - pico_mdns_add_probe_question(&qtree, record->record->rname); - } - } - - /* Create a mDNS packet to send */ - cookie = pico_mdns_cookie_create(qtree, antree, artree, - PICO_MDNS_PROBE_COUNT, - PICO_MDNS_PACKET_TYPE_PROBE, - callback, arg); - if (!cookie) { - mdns_dbg("Cookie_create returned NULL @ probe()!\n"); - PICO_DNS_QTREE_DESTROY(&qtree); - PICO_MDNS_RTREE_DESTROY(&antree); - return -1; - } - - /* Add the probe cookie to the cookie tree */ - if (pico_tree_insert(&Cookies, cookie)) { - pico_mdns_cookie_delete(&cookie); - return -1; - } - - /* When the host is ready to send his probe query he SHOULD delay it's - transmission with a randomly chosen time between 0 and 250 ms. */ - cookie->send_timer = pico_timer_add(pico_rand() % 250, - pico_mdns_send_probe_packet, - (void *)cookie); - mdns_dbg("DONE - Started probing.\n"); - - return 0; -} - -/* MARK: API functions */ - -/* **************************************************************************** - * Claim or reclaim all the mDNS records contain in a tree in one single call - * - * @param rtree mDNS record tree with records to claim - * @param reclaim Whether or not the records in tree should be reclaimed. - * @param callback Callback to call when all records are properly registered - * @return 0 When claiming didn't horribly fail. - * ****************************************************************************/ -static int -pico_mdns_claim_generic( pico_mdns_rtree rtree, - uint8_t reclaim, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ - /* Check if arguments are passed correctly */ - if (!callback) { - mdns_dbg("NULL pointers passed to 'pico_mdns_claim()'!\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Check if module is initialised */ - if (!mdns_sock_ipv4) { - mdns_dbg("Socket not initialised, did you call 'pico_mdns_init()'?\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* 1.) Appending records to 'my records' */ - pico_mdns_my_records_add(&rtree, reclaim); - - /* 2a.) Try to probe any records */ - pico_mdns_probe(callback, arg); - - /* 2b.) Try to announce any records */ - pico_mdns_announce(callback, arg); - - return 0; -} - -/* **************************************************************************** - * Claim all different mDNS records in a tree in a single API-call. All records - * in tree are called in a single new claim-session. - * - * @param rtree mDNS record tree with records to claim - * @param callback Callback to call when all record are properly claimed. - * @return 0 When claiming didn't horribly fail. - * ****************************************************************************/ -int -pico_mdns_claim( pico_mdns_rtree rtree, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ - return pico_mdns_claim_generic(rtree, 0, callback, arg); -} - -/* **************************************************************************** - * Reclaim records when a conflict occurred, claim-session will stay the same - * as the session in which the conflict occurred. - * - * @param rtree mDNS record tree with records to claim - * @param callback Callback to call when all record are properly claimed. - * @return 0 When claiming didn't horribly fail. - * ****************************************************************************/ -static int -pico_mdns_reclaim( pico_mdns_rtree rtree, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ - return pico_mdns_claim_generic(rtree, 1, callback, arg); -} - -/* **************************************************************************** - * Sets the hostname for this machine. Claims automatically a unique A record - * with the IPv4-address of this host. The hostname won't be set directly when - * this functions returns, but only if the claiming of the unique record succ- - * eeded. Init-callback will be called when the hostname-record is successfully - * registered. - * - * @param url URL to set the hostname to. - * @param arg Argument to pass to the init-callback. - * @return 0 when the host started registering the hostname-record successfully, - * Returns something else when it didn't succeeded. - * ****************************************************************************/ -int -pico_mdns_set_hostname( const char *url, void *arg ) -{ - PICO_MDNS_RTREE_DECLARE(rtree); - struct pico_mdns_record *record = NULL; - - /* Check params */ - if (!url) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Check if module is initialised */ - if (!mdns_sock_ipv4) { - mdns_dbg("mDNS socket not initialised, did you call 'pico_mdns_init()'?\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Create an A record for hostname */ - record = pico_mdns_record_create(url, - &(mdns_sock_ipv4->local_addr.ip4.addr), - PICO_SIZE_IP4, PICO_DNS_TYPE_A, - PICO_MDNS_DEFAULT_TTL, - (PICO_MDNS_RECORD_UNIQUE | - PICO_MDNS_RECORD_HOSTNAME)); - if (!record) { - mdns_dbg("Could not create A record for hostname %s!\n", - strerror(pico_err)); - return -1; - } - - /* TODO: Create IPv6 record */ - /* TODO: Create a reverse resolution record */ - - /* Try to claim the record */ - if (pico_tree_insert(&rtree, record)) { - pico_mdns_record_delete((void **)&record); - return -1; - } - - if (pico_mdns_claim(rtree, init_callback, arg)) { - mdns_dbg("Could not claim record for hostname %s!\n", url); - PICO_MDNS_RTREE_DESTROY(&rtree); - return -1; - } - pico_tree_destroy(&rtree, NULL); - - return 0; -} - -/* **************************************************************************** - * Get the hostname for this machine. - * - * @return Returns the hostname for this machine when the module is initialised - * Returns NULL when the module is not initialised. - * ****************************************************************************/ -const char * -pico_mdns_get_hostname( void ) -{ - /* Check if module is initialised */ - if (!mdns_sock_ipv4) { - mdns_dbg("mDNS socket not initialised, did you call 'pico_mdns_init()'?\n"); - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - return (const char *)_hostname; -} - -/* **************************************************************************** - * Initialises the entire mDNS-module and sets the hostname for this machine. - * Sets up the global mDNS socket properly and calls callback when succeeded. - * Only when the module is properly initialised records can be registered on - * the module. - * - * @param hostname_url URL to set the hostname to. - * @param address IPv4-address of this host to bind to. - * @param callback Callback to call when the hostname is registered and - * also the global mDNS module callback. Gets called when - * Passive conflicts occur, so changes in records can be - * tracked in this callback. - * @param arg Argument to pass to the init-callback. - * @return 0 when the module is properly initialised and the host started regis- - * tering the hostname. Returns something else went the host failed - * initialising the module or registering the hostname. - * ****************************************************************************/ -int -pico_mdns_init( const char *hostname, - struct pico_ip4 address, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ) -{ - struct pico_ip_mreq mreq4; - uint16_t proto4 = PICO_PROTO_IPV4, port = 0, loop = 0, ttl = 255; - - /* Initialise port */ - port = short_be(mdns_port); - - /* Check callback parameter */ - if(!callback || !hostname) { - mdns_dbg("No callback function supplied!\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Open global IPv4 mDNS socket */ - mdns_sock_ipv4 = pico_socket_open(proto4, PICO_PROTO_UDP, &pico_mdns_event4); - if(!mdns_sock_ipv4) { - mdns_dbg("pico_socket_open returned NULL-ptr...\n"); - return -1; - } - - /* Convert the mDNS IPv4 destination address to struct */ - if(pico_string_to_ipv4(PICO_MDNS_DEST_ADDR4, &mreq4.mcast_group_addr.ip4.addr)) { - mdns_dbg("String to IPv4 error\n"); - return -1; - } - - /* Receive data on any network interface */ - mreq4.mcast_link_addr.ip4 = inaddr_any; - - /* Don't want the multicast data to be looped back to the host */ - if(pico_socket_setoption(mdns_sock_ipv4, PICO_IP_MULTICAST_LOOP, &loop)) { - mdns_dbg("socket_setoption PICO_IP_MULTICAST_LOOP failed\n"); - return -1; - } - - /* Tell the stack we're interested in this particular multicast group */ - if(pico_socket_setoption(mdns_sock_ipv4, PICO_IP_ADD_MEMBERSHIP, &mreq4)) { - mdns_dbg("socket_setoption PICO_IP_ADD_MEMBERSHIP failed\n"); - return -1; - } - - /* RFC: - * All multicast responses (including answers sent via unicast) SHOULD - * be send with IP TTL set to 255 for backward-compatibility reasons - */ - if(pico_socket_setoption(mdns_sock_ipv4, PICO_IP_MULTICAST_TTL, &ttl)) { - mdns_dbg("socket_setoption PICO_IP_MULTICAST_TTL failed\n"); - return -1; - } - - /* Bind to mDNS port */ - if (pico_socket_bind(mdns_sock_ipv4, (void *)&address, &port)) { - mdns_dbg("Bind error!\n"); - return -1; - } - - /* Set the global init callback variable */ - init_callback = callback; - pico_timer_add(PICO_MDNS_RR_TTL_TICK, pico_mdns_tick, NULL); - - /* Set the hostname eventually */ - return pico_mdns_set_hostname(hostname, arg); -} - -#endif /* PICO_SUPPORT_MDNS */ diff --git a/ext/picotcp/modules/pico_mdns.h b/ext/picotcp/modules/pico_mdns.h deleted file mode 100644 index d4e6a4e..0000000 --- a/ext/picotcp/modules/pico_mdns.h +++ /dev/null @@ -1,185 +0,0 @@ -/* **************************************************************************** - * PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved. - * See LICENSE and COPYING for usage. - * . - * Author: Toon Stegen, Jelle De Vleeschouwer - * ****************************************************************************/ -#ifndef INCLUDE_PICO_MDNS -#define INCLUDE_PICO_MDNS - -#include "pico_dns_common.h" -#include "pico_tree.h" -#include "pico_ipv4.h" - -/* ********************************* CONFIG ***********************************/ -#define PICO_MDNS_PROBE_UNICAST 1 /* Probe queries as QU-questions */ -#define PICO_MDNS_CONTINUOUS_REFRESH 0 /* Continuously update cache */ -#define PICO_MDNS_ALLOW_CACHING 1 /* Enable caching on this host */ -#define PICO_MDNS_DEFAULT_TTL 120 /* Default TTL of mDNS records */ -#define PICO_MDNS_SERVICE_TTL 120 /* Default TTL of SRV/TXT/PTR/NSEC */ -#define PICO_MDNS_PROBE_COUNT 4 /* Amount of probes to send */ -#define PICO_MDNS_ANNOUNCEMENT_COUNT 3 /* Amount of announcements to send */ -/* ****************************************************************************/ - -#define PICO_MDNS_DEST_ADDR4 "224.0.0.251" - -/* To make mDNS records unique or shared records */ -#define PICO_MDNS_RECORD_UNIQUE 0x00u -#define PICO_MDNS_RECORD_SHARED 0x01u - -/* Flag to check for when records are returned, to determine the hostname */ -#define PICO_MDNS_RECORD_HOSTNAME 0x02u -#define IS_HOSTNAME_RECORD(x) \ - (((x)->flags) & PICO_MDNS_RECORD_HOSTNAME) ? (1) : (0) - -/* --- MDNS resource record --- */ -struct pico_mdns_record -{ - struct pico_dns_record *record; /* DNS Resource Record */ - uint32_t current_ttl; /* Current TTL */ - uint8_t flags; /* Resource Record flags */ - uint8_t claim_id; /* Claim ID number */ -}; - -/* **************************************************************************** - * Compares 2 mDNS records by type, name AND rdata for a truly unique result - * - * @param ra mDNS record A - * @param rb mDNS record B - * @return 0 when records are equal, returns difference when they're not. - * ****************************************************************************/ -int -pico_mdns_record_cmp( void *a, void *b ); - -/* **************************************************************************** - * Deletes a single mDNS resource record. - * - * @param record Void-pointer to mDNS Resource Record. Can be used with pico_- - * tree-destroy. - * @return Returns 0 on success, something else on failure. - * ****************************************************************************/ -int -pico_mdns_record_delete( void **record ); - -/* **************************************************************************** - * Creates a single standalone mDNS resource record with given name, type and - * data to register on the network. - * - * @param url DNS rrecord name in URL format. Will be converted to DNS - * name notation format. - * @param _rdata Memory buffer with data to insert in the resource record. If - * data of record should contain a DNS name, the name in the - * databuffer needs to be in URL-format. - * @param datalen The exact length in bytes of the _rdata-buffer. If data of - * record should contain a DNS name, datalen needs to be - * pico_dns_strlen(_rdata). - * @param rtype DNS type of the resource record to be. - * @param rclass DNS class of the resource record to be. - * @param rttl DNS ttl of the resource record to be. - * @param flags You can specify if the mDNS record should be a shared record - * rather than a unique record. - * @return Pointer to newly created mDNS resource record. - * ****************************************************************************/ -struct pico_mdns_record * -pico_mdns_record_create( const char *url, - void *_rdata, - uint16_t datalen, - uint16_t rtype, - uint32_t rttl, - uint8_t flags ); - - - -/* **************************************************************************** - * Definition of DNS record tree - * ****************************************************************************/ -typedef struct pico_tree pico_mdns_rtree; -#define PICO_MDNS_RTREE_DECLARE(name) \ - pico_mdns_rtree (name) = {&LEAF, pico_mdns_record_cmp} -#define PICO_MDNS_RTREE_DESTROY(rtree) \ - pico_tree_destroy((rtree), pico_mdns_record_delete) -#define PICO_MDNS_RTREE_ADD(tree, record) \ - pico_tree_insert((tree), (record)) - -/* **************************************************************************** - * API-call to query a record with a certain URL and type. First checks the - * Cache for this record. If no cache-entry is found, a query will be sent on - * the wire for this record. - * - * @param url URL to query for. - * @param type DNS type top query for. - * @param callback Callback to call when records are found for the query. - * @return 0 when query is correctly parsed, something else on failure. - * ****************************************************************************/ -int -pico_mdns_getrecord( const char *url, uint16_t type, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ); - -/* **************************************************************************** - * Claim all different mDNS records in a tree in a single API-call. All records - * in tree are called in a single new claim-session. - * - * @param rtree mDNS record tree with records to claim - * @param callback Callback to call when all record are properly claimed. - * @return 0 When claiming didn't horribly fail. - * ****************************************************************************/ -int -pico_mdns_claim( pico_mdns_rtree record_tree, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ); - -/* **************************************************************************** - * Sets the hostname for this machine. Claims automatically a unique A record - * with the IPv4-address of this host. The hostname won't be set directly when - * this functions returns, but only if the claiming of the unique record succ- - * eeded. Init-callback will be called when the hostname-record is successfully - * registered. - * - * @param url URL to set the hostname to. - * @param arg Argument to pass to the init-callback. - * @return 0 when the host started registering the hostname-record successfully, - * Returns something else when it didn't succeeded. - * ****************************************************************************/ -int -pico_mdns_set_hostname( const char *url, void *arg ); - -/* **************************************************************************** - * Get the current hostname for this machine. - * - * @return Returns the hostname for this machine when the module is initialised - * Returns NULL when the module is not initialised. - * ****************************************************************************/ -const char * -pico_mdns_get_hostname( void ); - -/* **************************************************************************** - * Initialises the entire mDNS-module and sets the hostname for this machine. - * Sets up the global mDNS socket properly and calls callback when succeeded. - * Only when the module is properly initialised records can be registered on - * the module. - * - * @param hostname URL to set the hostname to. - * @param address IPv4-address of this host to bind to. - * @param callback Callback to call when the hostname is registered and - * also the global mDNS module callback. Gets called when - * Passive conflicts occur, so changes in records can be - * tracked in this callback. - * @param arg Argument to pass to the init-callback. - * @return 0 when the module is properly initialised and the host started regis- - * tering the hostname. Returns something else went the host failed - * initialising the module or registering the hostname. - * ****************************************************************************/ -int -pico_mdns_init( const char *hostname, - struct pico_ip4 address, - void (*callback)(pico_mdns_rtree *, - char *, - void *), - void *arg ); - -#endif /* _INCLUDE_PICO_MDNS */ diff --git a/ext/picotcp/modules/pico_mld.c b/ext/picotcp/modules/pico_mld.c deleted file mode 100644 index 67dd11f..0000000 --- a/ext/picotcp/modules/pico_mld.c +++ /dev/null @@ -1,1179 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See LICENSE and COPYING for usage. - - RFC 2710 3019 3590 3810 4604 6636 - - Authors: Roel Postelmans - *********************************************************************/ - -#include "pico_stack.h" -#include "pico_ipv6.h" -#include "pico_mld.h" -#include "pico_config.h" -#include "pico_eth.h" -#include "pico_addressing.h" -#include "pico_frame.h" -#include "pico_tree.h" -#include "pico_device.h" -#include "pico_socket.h" -#include "pico_icmp6.h" -#include "pico_dns_client.h" -#include "pico_mld.h" -#include "pico_constants.h" - -#if defined(PICO_SUPPORT_MLD) && defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_MCAST) - -#define mld_dbg(...) do {} while(0) -/* MLD groups */ -#define MLD_ALL_HOST_GROUP "FF01:0:0:0:0:0:0:1" -#define MLD_ALL_ROUTER_GROUP "FF01:0:0:0:0:0:0:2" -#define MLDV2_ALL_ROUTER_GROUP "FF02:0:0:0:0:0:0:16" -#define MLD_ROUTER_ALERT_LEN (8) - -uint8_t pico_mld_flag = 0; - -PACKED_STRUCT_DEF mld_message { - uint8_t type; - uint8_t code; - uint16_t crc; - uint16_t max_resp_delay; - uint16_t reserved; - struct pico_ip6 mcast_group; -}; -PACKED_STRUCT_DEF mldv2_group_record { - uint8_t type; - uint8_t aux; - uint16_t nbr_src; - struct pico_ip6 mcast_group; - struct pico_ip6 src[0]; -}; -PACKED_STRUCT_DEF mldv2_report { - uint8_t type; - uint8_t res; - uint16_t crc; - uint16_t res1; - uint16_t nbr_gr; - struct mldv2_group_record record[0]; -}; -PACKED_STRUCT_DEF mldv2_query { - uint8_t type; - uint8_t code; - uint16_t crc; - uint16_t max_resp_delay; - uint16_t res; - struct pico_ip6 mcast_group; - uint8_t rsq; - uint8_t qqic; - uint16_t nbr_src; - struct pico_ip6 source_addr[0]; -}; -typedef int (*mld_callback) (struct mld_parameters *); -static int pico_mld_process_event(struct mld_parameters *p); -static struct mld_parameters *pico_mld_find_parameter(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group); - -static uint8_t *pico_mld_fill_hopbyhop(struct pico_ipv6_hbhoption *hbh) { - uint8_t *p; - if(hbh == NULL) - return NULL; - hbh->type = PICO_PROTO_ICMP6; - hbh->len=0; - // ROUTER ALERT, RFC2711 - p = (uint8_t *)hbh + sizeof(struct pico_ipv6_hbhoption); - *(p++) = PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT; - *(p++) = PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT_DATALEN; - *(p++) = 0; - *(p++) = 0; - //PadN allignment with N=2 - *(p++) = 1; - *(p++) = 0; /* N-2 */ - return p; -} -static int pico_mld_check_hopbyhop(struct pico_ipv6_hbhoption *hbh) { - uint8_t options[8] = { PICO_PROTO_ICMP6, 0, PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT,\ - PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT_DATALEN,0,0,1,0 }; - int i; - uint8_t *p; - if(hbh == NULL) - return -1; - if(hbh->type != options[0] || hbh->len != options[1]) - return -1; - - p = (uint8_t *)hbh + sizeof(struct pico_ipv6_hbhoption); - for(i=0; itype < b->type) - return -1; - - if (a->type > b->type) - return 1; - - return 0; -} -static inline int mldt_group_compare(struct mld_timer *a, struct mld_timer *b) { - return pico_ipv6_compare(&a->mcast_group, &b->mcast_group); -} - -static inline int mldt_link_compare(struct mld_timer *a, struct mld_timer *b) { - return pico_ipv6_compare(&a->mcast_link, &b->mcast_link); -} -static int mld_timer_cmp(void *ka, void *kb) { - struct mld_timer *a = ka, *b = kb; - int cmp = mldt_type_compare(a, b); - if (cmp) - return cmp; - - cmp = mldt_group_compare(a, b); - if (cmp) - return cmp; - - return mldt_link_compare(a, b); -} -static void pico_mld_report_expired(struct mld_timer *t) { - struct mld_parameters *p = NULL; - - p = pico_mld_find_parameter(&t->mcast_link, &t->mcast_group); - if (!p) - return; - - p->event = MLD_EVENT_TIMER_EXPIRED; - pico_mld_process_event(p); -} -PICO_TREE_DECLARE(MLDTimers, mld_timer_cmp); -static void pico_mld_v1querier_expired(struct mld_timer *t) -{ - struct pico_ipv6_link *link = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL; - - link = pico_ipv6_link_by_dev(t->f->dev); - if (!link) - return; - - /* When changing compatibility mode, cancel all pending response - * and retransmission timers. - */ - pico_tree_foreach_safe(index, &MLDTimers, _tmp) - { - ((struct mld_timer *)index->keyValue)->stopped = MLD_TIMER_STOPPED; - pico_tree_delete(&MLDTimers, index->keyValue); - } - mld_dbg("MLD: switch to compatibility mode MLDv2\n"); - link->mcast_compatibility = PICO_MLDV2; - return; -} - - -static inline int mldparm_group_compare(struct mld_parameters *a, struct mld_parameters *b) { - return pico_ipv6_compare(&a->mcast_group, &b->mcast_group); -} -static inline int mldparm_link_compare(struct mld_parameters *a, struct mld_parameters *b) { - return pico_ipv6_compare(&a->mcast_link, &b->mcast_link); -} -static int mld_parameters_cmp(void *ka, void *kb) { - struct mld_parameters *a = ka, *b = kb; - int cmp = mldparm_group_compare(a, b); - if (cmp) - return cmp; - - return mldparm_link_compare(a, b); -} - -PICO_TREE_DECLARE(MLDParameters, mld_parameters_cmp); - -static int pico_mld_delete_parameter(struct mld_parameters *p) { - if (pico_tree_delete(&MLDParameters, p)) - PICO_FREE(p); - else - return -1; - return 0; -} -static void pico_mld_timer_expired(pico_time now, void *arg){ - struct mld_timer *t = NULL, *timer = NULL, test = { - 0 - }; -#ifdef PICO_DEBUG_MLD - char ipstr[PICO_IPV6_STRING] = { - 0 - }, grpstr[PICO_IPV6_STRING] = { - 0 - }; -#endif - - IGNORE_PARAMETER(now); - t = (struct mld_timer *)arg; - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; -#ifdef PICO_DEBUG_MLD - pico_ipv6_to_string(ipstr, t->mcast_link.addr); - pico_ipv6_to_string(grpstr, t->mcast_group.addr); - mld_dbg("MLD: timer expired for %s link %s type %u, delay %llu\n", grpstr, ipstr, t->type, (uint64_t) t->delay); -#endif - timer = pico_tree_findKey(&MLDTimers, &test); - if (!timer) { - return; - } - if (timer->stopped == MLD_TIMER_STOPPED) { - pico_tree_delete(&MLDTimers, timer); - PICO_FREE(t); - return; - } - if (timer->start + timer->delay < PICO_TIME_MS()) { - pico_tree_delete(&MLDTimers, timer); - if (timer->mld_callback) - timer->mld_callback(timer); - - PICO_FREE(timer); - } else { -#ifdef PICO_DEBUG_MLD - mld_dbg("MLD: restart timer for %s, delay %llu, new delay %llu\n", grpstr, t->delay, (timer->start + timer->delay) - PICO_TIME_MS()); -#endif - pico_timer_add((timer->start + timer->delay) - PICO_TIME_MS(), &pico_mld_timer_expired, timer); - } - return; -} - -static int pico_mld_timer_reset(struct mld_timer *t) { - struct mld_timer *timer = NULL, test = { - 0 - }; -#ifdef PICO_DEBUG_MLD - char grpstr[PICO_IPV6_STRING] = { - 0 - }; - pico_ipv6_to_string(grpstr, t->mcast_group.addr); - mld_dbg("MLD: reset timer for %s, delay %llu\n", grpstr, t->delay); -#endif - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&MLDTimers, &test); - if (!timer) - return -1; - - *timer = *t; - timer->start = PICO_TIME_MS(); - return 0; -} - -static int pico_mld_timer_start(struct mld_timer *t) { - struct mld_timer *timer = NULL, test = { - 0 - }; -#ifdef PICO_DEBUG_MLD - char ipstr[PICO_IPV6_STRING] = { - 0 - }, grpstr[PICO_IPV6_STRING] = { - 0 - }; - pico_ipv6_to_string(ipstr, t->mcast_link.addr); - pico_ipv6_to_string(grpstr, t->mcast_group.addr); - mld_dbg("MLD: start timer for %s link %s type %u, delay %llu\n", grpstr, ipstr, t->type, t->delay); -#endif - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&MLDTimers, &test); - if (timer) - return pico_mld_timer_reset(t); - - timer = PICO_ZALLOC(sizeof(struct mld_timer)); - if (!timer) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - *timer = *t; - timer->start = PICO_TIME_MS(); - pico_tree_insert(&MLDTimers, timer); - pico_timer_add(timer->delay, &pico_mld_timer_expired, timer); - return 0; -} - -static int pico_mld_timer_stop(struct mld_timer *t) { - struct mld_timer *timer = NULL, test = { - 0 - }; -#ifdef PICO_DEBUG_MLD - char grpstr[PICO_IPV6_STRING] = { - 0 - }; -#endif - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&MLDTimers, &test); - if (!timer) - return -1; -#ifdef PICO_DEBUG_MLD - pico_ipv6_to_string(grpstr, timer->mcast_group.addr); - mld_dbg("MLD: stop timer for %s, delay %llu\n", grpstr, timer->delay); -#endif - timer->stopped = MLD_TIMER_STOPPED; - return 0; -} - -static int pico_mld_timer_is_running(struct mld_timer *t) { - struct mld_timer *timer = NULL, test = { - 0 - }; - - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&MLDTimers, &test); - if (timer) - return 1; - - return 0; -} - -static struct mld_timer *pico_mld_find_timer(uint8_t type, struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group) { - struct mld_timer test = { - 0 - }; - - test.type = type; - test.mcast_link = *mcast_link; - test.mcast_group = *mcast_group; - return pico_tree_findKey(&MLDTimers, &test); -} - -static int mld_sources_cmp(void *ka, void *kb) { - struct pico_ip6 *a = ka, *b = kb; - return pico_ipv6_compare(a, b); -} - -PICO_TREE_DECLARE(MLDAllow, mld_sources_cmp); -PICO_TREE_DECLARE(MLDBlock, mld_sources_cmp); - -static struct mld_parameters *pico_mld_find_parameter(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group) { - struct mld_parameters test = { - 0 - }; - if (!mcast_link || !mcast_group) - return NULL; - test.mcast_link = *mcast_link; - test.mcast_group = *mcast_group; - return pico_tree_findKey(&MLDParameters, &test); -} -static int pico_mld_is_checksum_valid(struct pico_frame *f) { - if( pico_icmp6_checksum(f) == 0) - return 1; - mld_dbg("ICMP6 (MLD) : invalid checksum\n"); - return 0; -} -uint16_t pico_mld_checksum(struct pico_frame *f) { - struct pico_ipv6_pseudo_hdr pseudo; - struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; - struct mldv2_report *icmp6_hdr = (struct mldv2_report *)(f->transport_hdr + MLD_ROUTER_ALERT_LEN); - uint16_t len = (uint16_t) (f->transport_len - MLD_ROUTER_ALERT_LEN); - - pseudo.src = ipv6_hdr->src; - pseudo.dst = ipv6_hdr->dst; - pseudo.len = long_be(len); - pseudo.nxthdr = PICO_PROTO_ICMP6; - - pseudo.zero[0] = 0; - pseudo.zero[1] = 0; - pseudo.zero[2] = 0; - return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv6_pseudo_hdr), icmp6_hdr, len); -} -/* RFC 3810 $8 */ -static int pico_mld_compatibility_mode(struct pico_frame *f) { - struct pico_ipv6_link *link = NULL; - struct mld_timer t = { - 0 - }; - uint16_t datalen; - struct pico_tree_node *index = NULL, *_tmp = NULL; - link = pico_ipv6_link_by_dev(f->dev); - if (!link) - return -1; - - datalen = (uint16_t)(f->buffer_len - PICO_SIZE_IP6HDR - MLD_ROUTER_ALERT_LEN); - if (f->dev->eth) { - datalen = (uint16_t)(datalen - PICO_SIZE_ETHHDR); - } - if( datalen >= 28) { - /* MLDv2 */ - t.type = MLD_TIMER_V2_QUERIER; - if (pico_mld_timer_is_running(&t)) { /* MLDv1 querier present timer still running */ - mld_dbg("Timer is already running\n"); - return -1; - } else { - link->mcast_compatibility = PICO_MLDV2; - mld_dbg("MLD Compatibility: v2\n"); - return 0; - } - } else if( datalen == 24) { - pico_tree_foreach_safe(index, &MLDTimers, _tmp) - { - ((struct mld_timer *)index->keyValue)->stopped = MLD_TIMER_STOPPED; - pico_tree_delete(&MLDTimers, index->keyValue); - } - mld_dbg("MLD: switch to compatibility mode MLDv1\n"); - link->mcast_compatibility = PICO_MLDV1; - t.type = MLD_TIMER_V1_QUERIER; - t.delay =(pico_time) ((MLD_ROBUSTNESS * link->mcast_last_query_interval) + MLD_QUERY_RESPONSE_INTERVAL) * 1000; - t.f = f; - t.mld_callback = pico_mld_v1querier_expired; - pico_mld_timer_start(&t); - } else { - /* invalid query, silently ignored */ - return -1; - } - return 0; -} - -int pico_mld_state_change(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state) { - struct mld_parameters *p = NULL; - struct pico_ip6 ipv6; - - pico_string_to_ipv6(MLD_ALL_HOST_GROUP, &ipv6.addr[0]); - - if (!memcmp(&mcast_group->addr, &ipv6, sizeof(struct pico_ip6))) - return 0; - - p = pico_mld_find_parameter(mcast_link, mcast_group); - if (!p && state == PICO_MLD_STATE_CREATE) { - p = PICO_ZALLOC(sizeof(struct mld_parameters)); - if (!p) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if (!mcast_link || !mcast_group) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - p->state = MLD_STATE_NON_LISTENER; - p->mcast_link = *mcast_link; - p->mcast_group = *mcast_group; - pico_tree_insert(&MLDParameters, p); - } else if (!p) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (state) { - case PICO_MLD_STATE_CREATE: - p->event = MLD_EVENT_START_LISTENING; - break; - - case PICO_MLD_STATE_UPDATE: - p->event = MLD_EVENT_UPDATE_GROUP; - break; - - case PICO_MLD_STATE_DELETE: - p->event = MLD_EVENT_STOP_LISTENING; - break; - default: - return -1; - } - p->filter_mode = filter_mode; - p->MCASTFilter = _MCASTFilter; - return pico_mld_process_event(p); -} -/* finite state machine caller */ -static int pico_mld_process_event(struct mld_parameters *p); - -static struct mld_parameters *pico_mld_analyse_packet(struct pico_frame *f) { - struct pico_icmp6_hdr *hdr = (struct pico_icmp6_hdr *) (f->transport_hdr+MLD_ROUTER_ALERT_LEN); - struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *) f->net_hdr; - struct pico_ipv6_link *link = NULL; - struct mld_parameters *p = NULL; - struct pico_ip6 mcast_group = {{ - 0 - }}; - struct mld_message *mld_report = (struct mld_message *) hdr; - struct pico_ipv6_exthdr *hbh; - - link = pico_ipv6_link_by_dev(f->dev); - if(!link) - return NULL; - mcast_group = mld_report->mcast_group; - /* Package check */ - if(ipv6_hdr->hop != MLD_HOP_LIMIT) { - mld_dbg("MLD: Hop limit > 1, ignoring frame\n"); - return NULL; - } - hbh = (struct pico_ipv6_exthdr *) (f->transport_hdr); - if(pico_mld_check_hopbyhop((struct pico_ipv6_hbhoption *)hbh) < 0) { - mld_dbg("MLD: Router Alert option is not set\n"); - return NULL; - } - if(!pico_ipv6_is_linklocal(ipv6_hdr->src.addr) || pico_ipv6_is_unspecified(ipv6_hdr->src.addr) ) { - mld_dbg("MLD Source is invalid link-local address\n"); - return NULL; - } - /* end package check */ - p = pico_mld_find_parameter(&link->address, &mcast_group); - if(!p) { - mld_dbg("Alloc-ing MLD parameters\n"); - p = PICO_ZALLOC(sizeof(struct mld_parameters)); - if(!p) - return NULL; - p->state = MLD_STATE_NON_LISTENER; - p->mcast_link = link->address; - pico_tree_insert(&MLDParameters,p); - } - mld_dbg("Analyse package, type = %d\n", hdr->type); - switch(hdr->type) { - case PICO_MLD_QUERY: - p->max_resp_time = mld_report->max_resp_delay; - p->event = MLD_EVENT_QUERY_RECV; - break; - case PICO_MLD_REPORT: - p->event = MLD_EVENT_REPORT_RECV; - break; - case PICO_MLD_DONE: - p->event = MLD_EVENT_DONE_RECV; - break; - case PICO_MLD_REPORTV2: - p->event = MLD_EVENT_REPORT_RECV; - break; - default: - return NULL; - } - p->f = f; - return p; -} -int pico_mld_process_in(struct pico_frame *f) { - struct mld_parameters *p = NULL; - - if (!pico_mld_is_checksum_valid(f)) - goto out; - - if (pico_mld_compatibility_mode(f) < 0) - goto out; - - if((p = pico_mld_analyse_packet(f)) == NULL) - goto out; - - return pico_mld_process_event(p); -out: - mld_dbg("FRAME DISCARD\n"); - pico_frame_discard(f); - return 0; -} - - - -static int8_t pico_mld_send_done(struct mld_parameters *p, struct pico_frame *f) { - struct mld_message *report = NULL; - uint8_t report_type = PICO_MLD_DONE; - struct pico_ipv6_exthdr *hbh; - struct pico_ip6 dst = {{ - 0 - }}; -#ifdef PICO_DEBUG_MLD - char ipstr[PICO_IPV6_STRING] = { - 0 - }, grpstr[PICO_IPV6_STRING] ={ - 0 - }; -#endif - IGNORE_PARAMETER(f); - pico_string_to_ipv6(MLD_ALL_ROUTER_GROUP, &dst.addr[0]); - p->f = pico_proto_ipv6.alloc(&pico_proto_ipv6, sizeof(struct mld_message)+MLD_ROUTER_ALERT_LEN); - p->f->dev = pico_ipv6_link_find(&p->mcast_link); - /* p->f->len is correctly set by alloc */ - hbh = (struct pico_ipv6_exthdr *)(p->f->transport_hdr); - report = (struct mld_message *)(pico_mld_fill_hopbyhop((struct pico_ipv6_hbhoption*)hbh)); - if(!report) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - report->type = report_type; - report->max_resp_delay = 0; - report->mcast_group = p->mcast_group; - - report->crc = 0; - //Checksum done in ipv6 module, no need to do it twice - //report->crc = short_be(pico_icmp6_checksum(p->f)); -#ifdef PICO_DEBUG_MLD - pico_ipv6_to_string(ipstr, dst.addr); - pico_ipv6_to_string(grpstr, mcast_group.addr); - mld_dbg("MLD: send membership done on group %s to %s\n", grpstr, ipstr); -#endif - pico_ipv6_frame_push(p->f, NULL, &dst, 0,0); - return 0; -} -static int pico_mld_send_report(struct mld_parameters *p, struct pico_frame *f) { - struct pico_ip6 dst = {{ - 0 - }}; - struct pico_ip6 mcast_group = {{ - 0 - }}; -#ifdef PICO_DEBUG_MLD - char ipstr[PICO_IPV6_STRING] = { - 0 - }, grpstr[PICO_IPV6_STRING] ={ - 0 - }; -#endif - struct pico_ipv6_link *link = NULL; - link = pico_ipv6_link_get(&p->mcast_link); - if (!link) - return -1; - - mcast_group = p->mcast_group; - switch (link->mcast_compatibility) { - case PICO_MLDV1: - if (p->event == MLD_EVENT_STOP_LISTENING) - pico_string_to_ipv6(MLD_ALL_ROUTER_GROUP, &dst.addr[0]); - else - dst = mcast_group; - break; - case PICO_MLDV2: - pico_string_to_ipv6(MLDV2_ALL_ROUTER_GROUP, &dst.addr[0]); - break; - default: - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - } -#ifdef PICO_DEBUG_MLD - pico_ipv6_to_string(ipstr, dst.addr); - pico_ipv6_to_string(grpstr, mcast_group.addr); - mld_dbg("MLD: send membership report on group %s to %s\n", grpstr, ipstr); -#endif - pico_ipv6_frame_push(f, NULL, &dst, 0,0); - return 0; -} - -static int8_t pico_mld_generate_report(struct mld_parameters *p) { - struct pico_ipv6_link *link = NULL; - uint8_t i = 0; - link = pico_ipv6_link_get(&p->mcast_link); - if (!link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if( !pico_ipv6_is_multicast(p->mcast_group.addr) ) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - switch (link->mcast_compatibility) { - - case PICO_MLDV1: { - struct mld_message *report = NULL; - uint8_t report_type = PICO_MLD_REPORT; - struct pico_ipv6_exthdr *hbh; - p->f = pico_proto_ipv6.alloc(&pico_proto_ipv6, sizeof(struct mld_message)+MLD_ROUTER_ALERT_LEN ); - p->f->dev = pico_ipv6_link_find(&p->mcast_link); - /* p->f->len is correctly set by alloc */ - - hbh = (struct pico_ipv6_exthdr *)(p->f->transport_hdr); - report = (struct mld_message *)(pico_mld_fill_hopbyhop((struct pico_ipv6_hbhoption *)hbh)); - report->type = report_type; - report->max_resp_delay = MLD_DEFAULT_MAX_RESPONSE_TIME; - report->mcast_group = p->mcast_group; - - report->crc = 0; - //Checksum done in ipv6 module, no need to do it twice - //report->crc = short_be(pico_icmp6_checksum(p->f)); - break; - } - case PICO_MLDV2: { - struct mldv2_report *report = NULL; - struct mldv2_group_record *record = NULL; - struct pico_ipv6_mcast_group *g = NULL, test = { - 0 - }; - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_tree *MLDFilter = NULL; - struct pico_ip6 *source = NULL; - struct pico_ipv6_hbhoption *hbh; - uint8_t record_type = 0; - uint8_t sources = 0; - uint16_t len = 0; - test.mcast_addr = p->mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (!g) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - /* "non-existent" state of filter mode INCLUDE and empty source list */ - if (p->event == MLD_EVENT_DELETE_GROUP) { - p->filter_mode = PICO_IP_MULTICAST_INCLUDE; - p->MCASTFilter = NULL; - } - if (p->event == MLD_EVENT_QUERY_RECV) - goto mld2_report; - /* cleanup filters */ - pico_tree_foreach_safe(index, &MLDAllow, _tmp) - { - pico_tree_delete(&MLDAllow, index->keyValue); - } - pico_tree_foreach_safe(index, &MLDBlock, _tmp) - { - pico_tree_delete(&MLDBlock, index->keyValue); - } - switch (g->filter_mode) { - - case PICO_IP_MULTICAST_INCLUDE: - switch (p->filter_mode) { - case PICO_IP_MULTICAST_INCLUDE: - /* all ADD_SOURCE_MEMBERSHIP had an equivalent DROP_SOURCE_MEMBERSHIP */ - if (p->event == MLD_EVENT_DELETE_GROUP) { - /* TO_IN (B) */ - record_type = MLD_CHANGE_TO_INCLUDE_MODE; - MLDFilter = &MLDAllow; - if (p->MCASTFilter) { - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&MLDAllow, index->keyValue); - sources++; - } - } /* else { MLDAllow stays empty } */ - - break; - } - - /* ALLOW (B-A) */ - /* if event is CREATE A will be empty, thus only ALLOW (B-A) has sense */ - if (p->event == MLD_EVENT_CREATE_GROUP) /* first ADD_SOURCE_MEMBERSHIP */ - record_type = MLD_CHANGE_TO_INCLUDE_MODE; - else - record_type = MLD_ALLOW_NEW_SOURCES; - - MLDFilter = &MLDAllow; - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&MLDAllow, index->keyValue); - sources++; - } - pico_tree_foreach(index, &g->MCASTSources) /* A */ - { - source = pico_tree_findKey(&MLDAllow, index->keyValue); - if (source) { - pico_tree_delete(&MLDAllow, source); - sources--; - } - } - if (!pico_tree_empty(&MLDAllow)) /* record type is ALLOW */ - break; - - /* BLOCK (A-B) */ - record_type = MLD_BLOCK_OLD_SOURCES; - MLDFilter = &MLDBlock; - pico_tree_foreach(index, &g->MCASTSources) /* A */ - { - pico_tree_insert(&MLDBlock, index->keyValue); - sources++; - } - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - source = pico_tree_findKey(&MLDBlock, index->keyValue); - if (source) { - pico_tree_delete(&MLDBlock, source); - sources--; - } - } - if (!pico_tree_empty(&MLDBlock)) /* record type is BLOCK */ - break; - - /* ALLOW (B-A) and BLOCK (A-B) are empty: do not send report */ - p->f = NULL; - return 0; - case PICO_IP_MULTICAST_EXCLUDE: - /* TO_EX (B) */ - record_type = MLD_CHANGE_TO_EXCLUDE_MODE; - MLDFilter = &MLDBlock; - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&MLDBlock, index->keyValue); - sources++; - } - break; - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - break; - case PICO_IP_MULTICAST_EXCLUDE: - switch (p->filter_mode) { - case PICO_IP_MULTICAST_INCLUDE: - /* TO_IN (B) */ - record_type = MLD_CHANGE_TO_INCLUDE_MODE; - MLDFilter = &MLDAllow; - if (p->MCASTFilter) { - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&MLDAllow, index->keyValue); - sources++; - } - } /* else { MLDAllow stays empty } */ - - break; - case PICO_IP_MULTICAST_EXCLUDE: - /* BLOCK (B-A) */ - record_type = MLD_BLOCK_OLD_SOURCES; - MLDFilter = &MLDBlock; - pico_tree_foreach(index, p->MCASTFilter) - { - pico_tree_insert(&MLDBlock, index->keyValue); - sources++; - } - pico_tree_foreach(index, &g->MCASTSources) /* A */ - { - source = pico_tree_findKey(&MLDBlock, index->keyValue); /* B */ - if (source) { - pico_tree_delete(&MLDBlock, source); - sources--; - } - } - if (!pico_tree_empty(&MLDBlock)) /* record type is BLOCK */ - break; - /* ALLOW (A-B) */ - record_type = MLD_ALLOW_NEW_SOURCES; - MLDFilter = &MLDAllow; - pico_tree_foreach(index, &g->MCASTSources) - { - pico_tree_insert(&MLDAllow, index->keyValue); - sources++; - } - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - source = pico_tree_findKey(&MLDAllow, index->keyValue); /* A */ - if (source) { - pico_tree_delete(&MLDAllow, source); - sources--; - } - } - if (!pico_tree_empty(&MLDAllow)) /* record type is ALLOW */ - break; - /* BLOCK (B-A) and ALLOW (A-B) are empty: do not send report */ - p->f = NULL; - return 0; - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - break; - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } -mld2_report: - /* RFC3810 $5.1.10 */ - if(sources > MLD_MAX_SOURCES) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - len = (uint16_t)(sizeof(struct mldv2_report) + sizeof(struct mldv2_group_record) \ - + (sources * sizeof(struct pico_ip6))+MLD_ROUTER_ALERT_LEN); - - p->f = pico_proto_ipv6.alloc(&pico_proto_ipv6, len); - p->f->dev = pico_ipv6_link_find(&p->mcast_link); - /* p->f->len is correctly set by alloc */ - - hbh = (struct pico_ipv6_hbhoption *) p->f->transport_hdr; - report = (struct mldv2_report *)(pico_mld_fill_hopbyhop(hbh)); - report->type = PICO_MLD_REPORTV2; - report->res = 0; - report->crc = 0; - report->res1 = 0; - report->nbr_gr = short_be(1); - - record = &report->record[0]; - record->type = record_type; - record->aux = 0; - record->nbr_src = short_be(sources); - record->mcast_group = p->mcast_group; - if (MLDFilter && !pico_tree_empty(MLDFilter)) { - i = 0; - pico_tree_foreach(index, MLDFilter) - { - record->src[i] = (*(struct pico_ip6 *)index->keyValue); - i++; - } - } - if(i != sources) - return -1; - //Checksum done in ipv6 module, no need to do it twice - //report->crc= short_be(pico_mld_checksum(p->f)); - break; - } - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return 0; -} -/* stop timer, send done if flag set */ -static int mld_stsdifs(struct mld_parameters *p) { - struct mld_timer t = { - 0 - }; - struct pico_ipv6_link *link = NULL; - struct pico_frame *copy_frame = NULL; - link = pico_ipv6_link_get(&p->mcast_link); - if (!link) - return -1; - - mld_dbg("MLD: event = stop listening | action = stop timer, send done if flag set\n"); - - t.type = MLD_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - if (pico_mld_timer_stop(&t) < 0) - return -1; - switch(link->mcast_compatibility){ - case PICO_MLDV2: - if (pico_mld_generate_report(p) < 0) { - return -1; - } - copy_frame = pico_frame_copy(p->f); - if (!copy_frame) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - if (pico_mld_send_report(p, copy_frame) < 0) { - return -1; - } - break; - case PICO_MLDV1: - /* Send done if flag is set */ - if (pico_mld_flag && pico_mld_send_done(p, p->f) < 0) - return -1; - break; - } - - pico_mld_delete_parameter(p); - mld_dbg("MLD: new state = Non-Listener\n"); - return 0; -} -/* send report, set flag, start timer */ -static int mld_srsfst(struct mld_parameters *p) { - struct mld_timer t = { - 0 - }; - struct pico_frame *copy_frame = NULL; - mld_dbg("MLD: event = start listening | action = send report, set flag, start timer\n"); - - p->last_host = MLD_HOST_LAST; - if (pico_mld_generate_report(p) < 0) - return -1; - - if (!p->f) - return 0; - copy_frame = pico_frame_copy(p->f); - if (!copy_frame) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - if (pico_mld_send_report(p, copy_frame) < 0) - return -1; - - t.type = MLD_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - - t.delay = (pico_rand() % (MLD_UNSOLICITED_REPORT_INTERVAL * 10000)); - t.f = p->f; - t.mld_callback = pico_mld_report_expired; - pico_mld_timer_start(&t); - pico_mld_flag = 1; - p->state = MLD_STATE_DELAYING_LISTENER; - mld_dbg("MLD: new state = Delaying Listener\n"); - return 0; -} - -/* stop timer, clear flag */ -static int mld_stcl(struct mld_parameters *p) { - struct mld_timer t = { - 0 - }; - - mld_dbg("MLD: event = report received | action = stop timer, clear flag\n"); - - t.type = MLD_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - if (pico_mld_timer_stop(&t) < 0) - return -1; - pico_mld_flag = 0; - p->last_host = MLD_HOST_NOT_LAST; - p->state = MLD_STATE_IDLE_LISTENER; - mld_dbg("MLD: new state = Idle Listener\n"); - return 0; -} -/* send report, set flag */ -static int mld_srsf(struct mld_parameters *p) { - mld_dbg("MLD: event = timer expired | action = send report, set flag\n"); - - if (pico_mld_send_report(p, p->f) < 0) - return -1; - pico_mld_flag = 1; - p->state = MLD_STATE_IDLE_LISTENER; - mld_dbg("MLD: new state = Idle Listener\n"); - return 0; -} -/* reset timer if max response time < current timer */ -static int mld_rtimrtct(struct mld_parameters *p) { - struct mld_timer *t = NULL; - uint32_t current_timer = 0; - - mld_dbg("MLD: event = query received | action = reset timer if max response time < current timer\n"); - - t = pico_mld_find_timer(MLD_TIMER_GROUP_REPORT, &p->mcast_link, &p->mcast_group); - if (!t) - return -1; - - current_timer = (uint32_t)(t->start + t->delay - PICO_TIME_MS()); - if ((p->max_resp_time * 100u) < current_timer) { /* max_resp_time in units of 1/10 seconds */ - t->delay = pico_rand() % ((1u + p->max_resp_time) * 100u); - pico_mld_timer_reset(t); - } - p->state = MLD_STATE_DELAYING_LISTENER; - mld_dbg("MLD: new state = Delaying Listener\n"); - return 0; -} -/* merge report, send report, reset timer (MLDv2 only) */ -static int mld_mrsrrt(struct mld_parameters *p) { - struct mld_timer *t = NULL; - struct pico_frame *copy_frame = NULL; - struct pico_ipv6_link *link = NULL; - mld_dbg("MLD: event = update group | action = merge report, send report, reset timer (MLDv2 only)\n"); - - link = pico_ipv6_link_get(&p->mcast_link); - if (!link) - return -1; - - if (link->mcast_compatibility != PICO_MLDV2) { - mld_dbg("MLD: no MLDv3 compatible router on network\n"); - return -1; - } - - /* XXX: merge with pending report rfc 3376 $5.1 */ - - copy_frame = pico_frame_copy(p->f); - if (!copy_frame) - return -1; - - if (pico_mld_send_report(p, copy_frame) < 0) - return -1; - - t = pico_mld_find_timer(MLD_TIMER_GROUP_REPORT, &p->mcast_link, &p->mcast_group); - if (!t) - return -1; - - t->delay = (pico_rand() % (MLD_UNSOLICITED_REPORT_INTERVAL * 10000)); - pico_mld_timer_reset(t); - - p->state = MLD_STATE_DELAYING_LISTENER; - mld_dbg("MLD: new state = delaying member\n"); - return 0; -} - -/* send report, start timer (MLDv2 only) */ -static int mld_srst(struct mld_parameters *p){ - struct mld_timer t = { - 0 - }; - struct pico_frame *copy_frame = NULL; - struct pico_ipv6_link *link = NULL; - - mld_dbg("MLD: event = update group | action = send report, start timer (MLDv2 only)\n"); - - link = pico_ipv6_link_get(&p->mcast_link); - if (!link) - return -1; - - if (link->mcast_compatibility != PICO_MLDV2) { - mld_dbg("MLD: no MLDv2 compatible router on network\n"); - return -1; - } - - if (pico_mld_generate_report(p) < 0) - return -1; - - if (!p->f) - return 0; - - copy_frame = pico_frame_copy(p->f); - if (!copy_frame) - return -1; - - if (pico_mld_send_report(p, copy_frame) < 0) - return -1; - - t.type = MLD_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - t.delay = (pico_rand() % (MLD_UNSOLICITED_REPORT_INTERVAL * 10000)); - t.f = p->f; - t.mld_callback = pico_mld_report_expired; - pico_mld_timer_start(&t); - - p->state = MLD_STATE_DELAYING_LISTENER; - mld_dbg("MLD: new state = delaying member\n"); - return 0; -} -static int mld_discard(struct mld_parameters *p) { - mld_dbg("MLD: ignore and mld_discard frame\n"); - // the frame will be discared bij the ipv6 module!!! - IGNORE_PARAMETER(p); - return 0; -} - -/* finite state machine table */ -static const mld_callback mld_state_diagram[3][6] = -{ /* event | Stop Listening | Start Listening | Update Group |Query reveive |Report receive |Timer expired */ -/* none listener*/ { mld_discard , mld_srsfst, mld_srsfst, mld_discard, mld_discard, mld_discard}, -/* idle listener */ { mld_stsdifs , mld_mrsrrt, mld_mrsrrt, mld_rtimrtct, mld_stcl, mld_srsf }, -/* delaying listener */ { mld_rtimrtct, mld_srst, mld_srst, mld_srsf, mld_stsdifs, mld_discard } -}; - -static int pico_mld_process_event(struct mld_parameters *p) { - struct pico_tree_node *index= NULL; - struct mld_parameters *_p; -#ifdef PICO_DEBUG_MLD - char ipv6[PICO_IPV6_STRING]; - pico_ipv6_to_string(ipv6, p->mcast_group.addr); - mld_dbg("MLD: process event on group address %s\n", ipv6); -#endif - if (p->event == MLD_EVENT_QUERY_RECV && p->general_query) { /* general query */ - pico_tree_foreach(index, &MLDParameters) { - _p = index->keyValue; - _p->max_resp_time = p->max_resp_time; - _p->event = MLD_EVENT_QUERY_RECV; -#ifdef PICO_DEBUG_MLD - mld_dbg("MLD: for each mcast_group = %s | state = %u\n", ipv6, _p->state); -#endif - return mld_state_diagram[_p->state][_p->event](_p); - } - } else { - mld_dbg("MLD: state = %u (0: non-listener - 1: delaying listener - 2: idle listener) event = %u\n", p->state, p->event); - return mld_state_diagram[p->state][p->event](p); - } - return 0; -} -#else -uint16_t pico_mld_checksum(struct pico_frame *f) { - IGNORE_PARAMETER(f); - return 0; -} -int pico_mld_process_in(struct pico_frame *f) { - IGNORE_PARAMETER(f); - return -1; -} - -int pico_mld_state_change(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state) { - IGNORE_PARAMETER(mcast_link); - IGNORE_PARAMETER(mcast_group); - IGNORE_PARAMETER(filter_mode); - IGNORE_PARAMETER(_MCASTFilter); - IGNORE_PARAMETER(state); - return -1; -} -#endif diff --git a/ext/picotcp/modules/pico_mld.h b/ext/picotcp/modules/pico_mld.h deleted file mode 100644 index 219ef4a..0000000 --- a/ext/picotcp/modules/pico_mld.h +++ /dev/null @@ -1,119 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Roel Postelmans - *********************************************************************/ - -#ifndef INCLUDE_PICO_MLD -#define INCLUDE_PICO_MLD - -#define PICO_MLDV1 1 -#define PICO_MLDV2 2 - -#define PICO_MLD_QUERY 130 -#define PICO_MLD_REPORT 131 -#define PICO_MLD_DONE 132 -#define PICO_MLD_REPORTV2 143 - -/*RFC 3810 $6.2 */ -#define MLD_HOP_LIMIT 1 - -/* states */ -#define MLD_STATE_NON_LISTENER (0x0) -#define MLD_STATE_DELAYING_LISTENER (0x1) -#define MLD_STATE_IDLE_LISTENER (0x2) - -#define PICO_MLD_STATE_CREATE 1 -#define PICO_MLD_STATE_UPDATE 2 -#define PICO_MLD_STATE_DELETE 3 -/* group record types */ -#define MLD_MODE_IS_INCLUDE (1) -#define MLD_MODE_IS_EXCLUDE (2) -#define MLD_CHANGE_TO_INCLUDE_MODE (3) -#define MLD_CHANGE_TO_EXCLUDE_MODE (4) -#define MLD_ALLOW_NEW_SOURCES (5) -#define MLD_BLOCK_OLD_SOURCES (6) -/* events */ - -#define MLD_EVENT_START_LISTENING (0x1) -#define MLD_EVENT_STOP_LISTENING (0x0) -#define MLD_EVENT_QUERY_RECV (0x3) -#define MLD_EVENT_REPORT_RECV (0x4) -#define MLD_EVENT_TIMER_EXPIRED (0x5) -/*Not needed?*/ -#define MLD_EVENT_DONE_RECV (0x1) - -#define MLD_EVENT_DELETE_GROUP (0x0) -#define MLD_EVENT_CREATE_GROUP (0x1) -#define MLD_EVENT_UPDATE_GROUP (0x2) -#define MLD_EVENT_QUERY_RECV (0x3) -#define MLD_EVENT_REPORT_RECV (0x4) -#define MLD_EVENT_TIMER_EXPIRED (0x5) -/* (default) Variabels for times/counters */ -/* ALL IN SECONDS */ -#define MLD_ROBUSTNESS (2) -#define MLD_QUERY_INTERVAL (125) -#define MLD_QUERY_RESPONSE_INTERVAL (10) -#define MLD_DEFAULT_MAX_RESPONSE_TIME (100) -#define MLD_MULTICAST_LISTENER_INTERVAL (MLD_ROBUSTNESS * MLD_QUERY_INTERVAL) + MLD_QUERY_RESPONSE_INTERVAL -#define MLD_OTHER_QUERIER_PRESENT_INTERVAL (MLD_ROBUSTNESS * MLD_QUERY_INTERVAL) + (0.5 * MLD_QUERY_RESPONSE_INTERVAL) -#define MLD_STARTUP_QUERY_INTERVAL (0.25 * MLD_QUERY_INTERVAL) -#define MLD_STARTUP_QUERY_COUNT MLD_ROBUSTNESS -#define MLD_LAST_LISTENER_QUERY_INTERVAL 1 -#define MLD_LISTENER_QUERY_COUNT MLD_ROBUSTNESS -#define MLD_UNSOLICITED_REPORT_INTERVAL 10 - -/* custom timers types */ -#define MLD_TIMER_GROUP_REPORT (1) -#define MLD_TIMER_V1_QUERIER (2) -#define MLD_TIMER_V2_QUERIER (2) - - -/* Who has send the last report message */ -#define MLD_HOST_LAST (0x1) -#define MLD_HOST_NOT_LAST (0x0) - - -#define MLD_TIMER_STOPPED (1) -#define MLD_MAX_SOURCES (89) -extern struct pico_protocol pico_proto_mld; - -struct mld_multicast_address_record { - uint8_t type; - uint8_t aux_len; - uint16_t nbr_src; - struct pico_ip6 multicast; - struct pico_ip6 src[0]; -}; - -struct mld_parameters { - uint8_t event; - uint8_t state; - uint8_t general_query; - uint8_t filter_mode; - uint8_t last_host; - uint16_t max_resp_time; - struct pico_ip6 mcast_link; - struct pico_ip6 mcast_group; - struct pico_tree *MCASTFilter; - struct pico_frame *f; -}; - -struct mld_timer { - uint8_t type; - uint8_t stopped; - pico_time start; - pico_time delay; - struct pico_ip6 mcast_link; - struct pico_ip6 mcast_group; - struct pico_frame *f; - void (*mld_callback)(struct mld_timer *t); -}; - -uint16_t pico_mld_checksum(struct pico_frame *f); -int pico_mld_process_in(struct pico_frame *f); -int pico_mld_state_change(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state); -#endif /* _INCLUDE_PICO_MLD */ diff --git a/ext/picotcp/modules/pico_mm.c b/ext/picotcp/modules/pico_mm.c deleted file mode 100644 index 5a6517b..0000000 --- a/ext/picotcp/modules/pico_mm.c +++ /dev/null @@ -1,1605 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Gustav Janssens, Jonas Van Nieuwenberg, Sam Van Den Berge - *********************************************************************/ - -#include "pico_config.h" -#include "pico_mm.h" -#include "pico_tree.h" -#include "pico_config.h" -#include "pico_protocol.h" /* For pico_err */ - -#define DBG_MM(x, args ...) /* dbg("[%s:%s:%i] "x" \n",__FILE__,__func__,__LINE__ ,##args ) */ -#define DBG_MM_RED(x, args ...) /* dbg("\033[31m[%s:%s:%i] "x" \033[0m\n",__FILE__,__func__,__LINE__ ,##args ) */ -#define DBG_MM_GREEN(x, args ...) /* dbg("\033[32m[%s:%s:%i] "x" \033[0m\n",__FILE__,__func__,__LINE__ ,##args ) */ -#define DBG_MM_YELLOW(x, args ...) /* dbg("\033[33m[%s:%s:%i] "x" \033[0m\n",__FILE__,__func__,__LINE__ ,##args ) */ -#define DBG_MM_BLUE(x, args ...) /* dbg("\033[34m[%s:%s:%i] "x" \033[0m\n",__FILE__,__func__,__LINE__ ,##args ) */ - -/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has. - * These nodes should be placed in the manager page which is in a different memory region then the nodes - * which are used for the pico stack in general. - * Therefore the following 2 functions are created so that pico_tree can use them to to put these nodes - * into the correct memory regions. - */ -void*pico_mem_page0_zalloc(size_t len); -void pico_mem_page0_free(void*ptr); - - -/* this is a wrapper function for pico_tree_insert. The function pointers that are used by pico_tree - * to zalloc/free are modified so that pico_tree will insert the node in another memory region - */ -static void *manager_tree_insert(struct pico_tree*tree, void *key) -{ - return (void*) pico_tree_insert_implementation(tree, key, USE_PICO_PAGE0_ZALLOC); -} - -/* this is a wrapper function for pico_tree_insert. The function pointers that are used by pico_tree - * to zalloc/free are modified so that pico_tree will insert the node in another memory region - */ -static void *manager_tree_delete(struct pico_tree *tree, void *key) -{ - return (void *) pico_tree_delete_implementation(tree, key, USE_PICO_PAGE0_ZALLOC); -} - - -static const uint32_t slab_sizes[] = { - 1200, 1400, 1600 -}; /* Sizes must be from small to big */ -static uint32_t slab_size_statistics[] = { - 0, 0, 0 -}; -static uint32_t slab_size_global = PICO_MEM_DEFAULT_SLAB_SIZE; -/* - typedef struct pico_mem_manager pico_mem_manager; - typedef struct pico_mem_manager_extra pico_mem_manager_extra; - typedef struct pico_mem_page pico_mem_page; - typedef struct pico_mem_heap pico_mem_heap; - typedef struct pico_mem_slab pico_mem_slab; - typedef struct pico_mem_heap_block pico_mem_heap_block; - typedef struct pico_mem_slab_block pico_mem_slab_block; - typedef struct pico_mem_slab_node pico_mem_slab_node; - typedef struct pico_mem_block pico_mem_block; - typedef struct pico_tree pico_tree; - typedef struct pico_tree_node pico_tree_node; - typedef union block_internals block_internals; - */ -#define HEAP_BLOCK_NOT_FREE 0xCAFED001 -#define HEAP_BLOCK_FREE 0xCAFED00E - -#define SLAB_BLOCK_TYPE 0 -#define HEAP_BLOCK_TYPE 1 -/* - * page - * <----------------------------------------------------------------------> - * - * - * +------------<------------+----------<-----------+ - * | ^ ^ - * v | | - * +---------+------------+--+----+---------------+-+-----+---------------+ - * | | | | | | | - * | pico_ | | pico_ | | pico_ | | - * | mem_ | ...HEAP... | mem_ | slab | mem_ | slab | - * | page | | block | | block | | - * | | | | | | | - * +---------+------------+-------+-----+---------+-------+----------+----+ - * ^ | ^ | - * +-------+ | | | - * | | +-+ | - * +------|-----+ | | - * | | +-----|--------------------+ - * v | v | - * +---------+-----+-------+------+-+-----+-----+--+ - * | | | | | | | - * | pico_ | | pico_ | pico_ | | pico_ | - * | mem_ | ... | tree_ | mem_ | ... | mem_ | - * | manager | | node | slab_ | | slab_ | - * | | | | node | | node | - * +---------+-----+-+-----+-----+--+-----+-----+--+ - * | ^ | ^ | - * | | +---->---+ | - * +-->--+----<-----------<---+ - * - * <-----------------------------------------------> - * manager page - * - * - * +----------------+ - * | | - * | pico_tree_node +-------------------------------------+ - * | (size x) | | - * +--+----------+--+ | - * | | +---------v----------+ - * | | | | - * v v +----> pico_mem_slab_node +----+ - * | | | | | | - * +----<----+ +---->----+ | +--------------------+ | - * | | | | - * | | ^ v - * | | | | - * | | | +--------------------+ | - * +------v---------+ +---------v------+ +----+ <----+ - * | | | | | pico_mem_slab_node | - * | pico_tree_node | | pico_tree_node | +----> +----+ - * | (size x/2) | | (size 2x) | | +--------------------+ | - * +----------------+ +----------------+ | | - * | | - * | | - * ^ v - * ... ... - * - */ - -/* Housekeeping memory manager (start of page 0) */ -struct pico_mem_manager -{ - uint32_t size; /* Maximum size in bytes */ - uint32_t used_size; /* Used size in bytes */ - struct pico_tree tree; - struct pico_mem_page*first_page; - struct pico_mem_manager_extra*manager_extra; /* this is a pointer to a page with extra heap space used by the manager */ -}; -/* Housekeeping additionnal memory manager heap pages */ -struct pico_mem_manager_extra -{ - struct pico_mem_manager_extra*next; - uint32_t timestamp; - uint32_t blocks; -}; -/* Housekeeping of every page (start of all pages except the manager pages) */ -struct pico_mem_page -{ - uint32_t slab_size; - uint16_t slabs_max; - uint16_t slabs_free; - uint32_t heap_max_size; - uint32_t heap_max_free_space; - uint32_t timestamp; - struct pico_mem_page*next_page; -}; -/* Housekeeping struct for a heap block (kept per block of memory in heap) */ -struct pico_mem_heap_block -{ - uint32_t size; - /* uint8_t free; */ - uint32_t free; -}; -/* Housekeeping struct for a slab block (kept per block of memory in slabs) */ -struct pico_mem_slab_block -{ - struct pico_mem_page*page; - struct pico_mem_slab_node*slab_node; -}; -union block_internals -{ - struct pico_mem_heap_block heap_block; - struct pico_mem_slab_block slab_block; -}; -struct pico_mem_block -{ - union block_internals internals; /* Union has to be in first place!!! */ - uint8_t type; -}; -/* Used to store the slab objects in the RB-tree */ -struct pico_mem_slab_node -{ - struct pico_mem_block*slab; - struct pico_mem_slab_node*prev; - struct pico_mem_slab_node*next; -}; - -static struct pico_mem_manager*manager = NULL; - -/* - * This compare function will be called by pico_tree.c to compare 2 keyValues (type: struct pico_mem_slab_nodes) - * We want to compare slab_nodes by their size. We also want to be able to directly compare an integer, which explains - * the casts from void* to uint32_t*** - */ -static int compare_slab_keys(void*keyA, void*keyB) -{ - /* keyValues are pico_mem_slab_nodes */ - /* We want to compare the sizes */ - /* first element of pico_mem_slab_node: pico_mem_block* slab_block */ - /* first element of pico_mem_block: (slab_block in union): pico_mem_page* page */ - /* first element of pico_mem_page: uint32_t slab_size */ - uint32_t sizeKeyA = ***(uint32_t***) keyA; - uint32_t sizeKeyB = ***(uint32_t***) keyB; - DBG_MM_BLUE("Compare called: sizeA = %i, sizeB = %i", sizeKeyA, sizeKeyB); - if(sizeKeyA == sizeKeyB) - { - return 0; - } - else if(sizeKeyA < sizeKeyB) - { - return 1; - } - else - { - return -1; - } -} - -/* - * Pico_mem_init_page is called to initialize a block of memory pointed to by pico_mem_page* page. - * Slabs of size slabsize are created, and the page, heap and slab housekeeping is initialized. - */ -static void _pico_mem_init_page(struct pico_mem_page*page, size_t slabsize) -{ - uint8_t*byteptr = (uint8_t*) page; - struct pico_mem_block*slab_block; - struct pico_mem_block*heap_block; - struct pico_tree_node*tree_node; - struct pico_mem_slab_node*slab_node; - void*temp; - uint16_t i; - - DBG_MM_YELLOW("Initializing page %p with slabsize %u", page, slabsize); - - page->next_page = manager->first_page; - manager->first_page = page; - page->slab_size = (uint32_t)slabsize; - page->slabs_max = (uint16_t)((PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block)) / (slabsize + sizeof(struct pico_mem_block))); - page->heap_max_size = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - (page->slabs_max * (sizeof(struct pico_mem_block) + slabsize))); - if(page->heap_max_size < PICO_MIN_HEAP_SIZE) - { - DBG_MM_BLUE("Not enough heap size available with slabsize %u, allocating one slab to heap.", slabsize); - page->slabs_max--; - /* DBG_MM_BLUE("Heap size %u -> %lu",page->heap_max_size, page->heap_max_size + sizeof(pico_mem_slab_block) + slabsize); */ - DBG_MM_BLUE("Heap size %u -> %lu", page->heap_max_size, page->heap_max_size + sizeof(struct pico_mem_block) + slabsize); - page->heap_max_size += (uint32_t)(sizeof(struct pico_mem_block) + slabsize); - } - - page->slabs_free = page->slabs_max; - page->heap_max_free_space = page->heap_max_size; - page->timestamp = 0; - DBG_MM_BLUE("max slab objects = %i, object_size = %i", page->slabs_max, page->slab_size); - DBG_MM_BLUE("Heap size: %i", page->heap_max_size); - byteptr += sizeof(struct pico_mem_page); /* jump over page struct so byteptr points to start of heap */ - - /* Init HEAP at the beginning of the page */ - heap_block = (struct pico_mem_block*) byteptr; - heap_block->type = HEAP_BLOCK_TYPE; - heap_block->internals.heap_block.free = HEAP_BLOCK_FREE; - heap_block->internals.heap_block.size = page->heap_max_free_space; - - byteptr += sizeof(struct pico_mem_block) + heap_block->internals.heap_block.size; - for(i = 0; i < page->slabs_max; i++) - { - slab_block = (struct pico_mem_block*) byteptr; - DBG_MM_BLUE("Slab object %i at %p. Start of object data at %p", i, slab_block, (uint8_t*) slab_block + sizeof(struct pico_mem_slab_block)); - slab_block->type = SLAB_BLOCK_TYPE; - slab_block->internals.slab_block.page = page; - - DBG_MM_BLUE("Calling find_node with size %u", **((uint32_t**) slab_block)); - tree_node = pico_tree_findNode(&(manager->tree), &slab_block); - - DBG_MM("Creating slab_node.."); - slab_node = pico_mem_page0_zalloc(sizeof(struct pico_mem_slab_node)); - if(slab_node == NULL) - { - DBG_MM_RED("No more space in the manager heap for the housekeeping of slab %i, and no more space for extra manager pages!", i + 1); - DBG_MM_RED("Debug info:\nUsed size: %u/%u\nmanager_extra = %p", manager->used_size, manager->size, manager->manager_extra); - DBG_MM_RED("This page will be initialized with %u slabs instead of %u slabs", i, page->slabs_max); - page->slabs_max = i; - page->slabs_free = page->slabs_max; - return; - /* exit(1); */ - } - - slab_node->slab = slab_block; - slab_node->prev = NULL; - slab_node->next = NULL; - - slab_block->internals.slab_block.slab_node = slab_node; - - if(tree_node != NULL) - { - struct pico_mem_slab_node*first_node = (struct pico_mem_slab_node*) tree_node->keyValue; - tree_node->keyValue = slab_node; - slab_node->next = first_node; - first_node->prev = slab_node; - } - else - { - /* Insert new slab_node */ - DBG_MM_BLUE("Inserting new slab node in the tree of size %u", slabsize); - /* pico_err_t pico_err_backup = pico_err; */ - /* pico_err = 0; */ - - - /* temp = pico_tree_insert(&manager->tree, slab_node); */ - temp = manager_tree_insert(&manager->tree, slab_node); - - /* IF SLAB_NODE COULDN'T BE INSERTED */ - /* if(pico_err == PICO_ERR_ENOMEM) */ - /* if(temp == &LEAF) */ - if(temp != NULL) - { - DBG_MM_RED("No more space in the manager heap for the housekeeping of slab %i, and no more space for extra manager pages!", i + 1); - DBG_MM_RED("This page will be initialized without slabs."); - pico_mem_page0_free(slab_node); - page->slabs_max = (uint16_t) i; - page->slabs_free = page->slabs_max; - /* pico_err = pico_err_backup; */ - return; - } - } - - /* byteptr = (uint8_t*) (slab_block+1); */ - byteptr = (uint8_t*) slab_block; - byteptr += sizeof(struct pico_mem_block); - byteptr += page->slab_size; - } - DBG_MM_GREEN("Initialized page %p with slabsize %u", page, slabsize); -} - -/* - * Initializes the memory by creating a memory manager page and one page with default slab size - * A maximum space of memsize can be occupied by the memory manager at any time - */ -void pico_mem_init(uint32_t memsize) -{ - struct pico_mem_block*first_block; - struct pico_mem_page*page; - uint8_t*startofmanagerheap; - - DBG_MM_YELLOW("Initializing memory with memsize %u", memsize); - if(memsize < PICO_MEM_PAGE_SIZE * 2) - { - /* Not enough memory was provided to initialize a manager page and a data page, return without initializing memory */ - /* Set pico_err to an appropriate value */ - pico_err = PICO_ERR_ENOMEM; - DBG_MM_RED("The memsize provided is too small, memory not initialized!"); - - return; - } - - /* First pico_mem_page is already included in pico_mem_manager. Others are added. */ - /* manager = pico_azalloc(sizeof(pico_mem_manager) + sizeof(pico_mem_page*)*(pages - 1)); //Points to usermanager if one present */ - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - if( NULL != manager ) - { - manager->size = memsize; - manager->used_size = PICO_MEM_PAGE_SIZE; - manager->first_page = NULL; - manager->manager_extra = NULL; - - manager->tree.compare = compare_slab_keys; - manager->tree.root = &LEAF; - DBG_MM_BLUE("Manager page is at %p", manager); - - DBG_MM_BLUE("Start of tree: %p, sizeof(pico_tree): %lu", &manager->tree, sizeof(struct pico_tree)); - DBG_MM_BLUE("Root node of tree at %p", manager->tree.root); - - /* Init manager heap. Used to store the RB-tree nodes which store pointers to free slab objects */ - startofmanagerheap = (uint8_t*) manager + sizeof(struct pico_mem_manager); /* manager heap is after struct pico_mem_manager */ - DBG_MM_BLUE("Start of manager heap = %p", startofmanagerheap); - first_block = (struct pico_mem_block*) startofmanagerheap; - first_block->type = HEAP_BLOCK_TYPE; - first_block->internals.heap_block.free = HEAP_BLOCK_FREE; - first_block->internals.heap_block.size = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager) - sizeof(struct pico_mem_block); - - /* Initialize the first page only! */ - page = pico_zalloc(PICO_MEM_PAGE_SIZE); - if(page != NULL) - { - manager->used_size += PICO_MEM_PAGE_SIZE; - DBG_MM_BLUE("Page 1 at %p, manager used size = %u", page, manager->used_size); - _pico_mem_init_page(page, PICO_MEM_DEFAULT_SLAB_SIZE); - } - else - { - /* Not enough memory was provided to initialize a manager page and a data page, return without initializing memory */ - /* Set pico_err to an appropriate value */ - pico_err = PICO_ERR_ENOMEM; - /* Free the manager page */ - pico_free(manager); - manager = NULL; - DBG_MM_RED("Not enough space to allocate page 1, memory not initialized!"); - return; - } - - DBG_MM_GREEN("Memory initialized. Returning from pico_mem_init."); - } - else - { - /* Not enough memory was provided to initialize a manager page and a data page, return without initializing memory */ - /* Set pico_err to an appropriate value */ - pico_err = PICO_ERR_ENOMEM; - DBG_MM_RED("Not enough space to allocate manager page, memory not initialized!"); - return; - } -} - -/* - * Deinitializes the memory manager, returning all its memory to the system's control. - */ -void pico_mem_deinit() -{ - struct pico_mem_page*next_page; - struct pico_mem_manager_extra*next_manager_page; - - DBG_MM_YELLOW("Pico_mem_deinit called"); - if(manager == NULL) - { - DBG_MM_GREEN("No memory instance initialized, returning"); - } - else - { - while(manager->first_page != NULL) - { - next_page = manager->first_page->next_page; - pico_free(manager->first_page); - manager->first_page = next_page; - } - while(manager->manager_extra != NULL) - { - next_manager_page = manager->manager_extra->next; - pico_free(manager->manager_extra); - manager->manager_extra = next_manager_page; - } - DBG_MM_BLUE("Freeing manager page at %p", manager); - pico_free(manager); - manager = NULL; - slab_size_global = PICO_MEM_DEFAULT_SLAB_SIZE; - DBG_MM_GREEN("Memory manager reset"); - } -} - -/* - * This function is called internally by page0_zalloc if there isn't enough space left in the heap of the initial memory page - * This function allocates heap space in extra manager pages, creating new pages as necessary. - */ -static void*_pico_mem_manager_extra_alloc(struct pico_mem_manager_extra*heap_page, size_t len) -{ - struct pico_mem_manager_extra*extra_heap_page; - struct pico_mem_block*heap_block; - struct pico_mem_block*first_block; - struct pico_mem_block*new_block; - uint8_t*startOfData; - uint8_t*byteptr; - uint32_t sizeleft; - - DBG_MM_YELLOW("Searching for a block of len %u in extra manager page %p (%u blocks in use)", len, heap_page, heap_page->blocks); - /* Linearly search for a free heap block */ - - /* heap_block = (pico_mem_block*) (heap_page+1); */ - byteptr = (uint8_t*) heap_page + sizeof(struct pico_mem_manager_extra); - heap_block = (struct pico_mem_block*) byteptr; - - sizeleft = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager_extra); - - while(heap_block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE || heap_block->internals.heap_block.size < len) - { - sizeleft -= (uint32_t)sizeof(struct pico_mem_block); - sizeleft -= heap_block->internals.heap_block.size; - /* DBG_MM("Sizeleft=%i", sizeleft); */ - /* byteptr = (uint8_t*) (heap_block+1); */ - byteptr = (uint8_t*) heap_block + sizeof(struct pico_mem_block); - byteptr += heap_block->internals.heap_block.size; - heap_block = (struct pico_mem_block*) byteptr; - if(sizeleft <= sizeof(struct pico_mem_block)) - { - DBG_MM_RED("No more heap space left in the extra manager heap page!"); - if(heap_page->next == NULL) - { - /* TODO: Probably need another function for this */ - DBG_MM_RED("Trying to allocate a new page for extra heap space: space usage %uB/%uB", manager->used_size, manager->size); - if(manager->used_size + PICO_MEM_PAGE_SIZE > manager->size) - { - DBG_MM_RED("No more space left for this page!"); - /* exit(1); */ - return NULL; - } - - extra_heap_page = pico_zalloc(PICO_MEM_PAGE_SIZE); - if(extra_heap_page != NULL) - { - extra_heap_page->blocks = 0; - extra_heap_page->next = NULL; - extra_heap_page->timestamp = 0; - byteptr = (uint8_t*) extra_heap_page + sizeof(struct pico_mem_manager_extra); - first_block = (struct pico_mem_block*) byteptr; - first_block->type = HEAP_BLOCK_TYPE; - first_block->internals.heap_block.free = HEAP_BLOCK_FREE; - first_block->internals.heap_block.size = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager_extra) - sizeof(struct pico_mem_block); - extra_heap_page->next = heap_page; - manager->manager_extra = extra_heap_page; - manager->used_size += PICO_MEM_PAGE_SIZE; - DBG_MM_BLUE("Allocated an extra manager heap page at %p, manager space usage: %uB/%uB", extra_heap_page, manager->used_size, manager->size); - return _pico_mem_manager_extra_alloc(extra_heap_page, len); - } - else - { - /* This should be a dirty crash */ - DBG_MM_RED("Page not allocated even though the max size for the memory manager hasn't been reached yet!"); - /* exit(1); */ - return NULL; - } - } - else - { - DBG_MM_RED("This should never happen: debug information:"); - DBG_MM_RED("manager->manager_extra = %p", manager->manager_extra); - DBG_MM_RED("heap_page = %p", heap_page); - DBG_MM_RED("heap_page->next = %p", heap_page->next); - /* exit(1); */ - return NULL; - } - } - } - heap_page->blocks++; - heap_page->timestamp = 0; - DBG_MM_BLUE("Found free heap block in extra manager page %p at: %p (%u blocks in use)", heap_page, heap_block, heap_page->blocks); - heap_block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - - if(heap_block->internals.heap_block.size == sizeleft - sizeof(struct pico_mem_block)) - { - DBG_MM_BLUE("End of heap, splitting up into a new block"); - heap_block->internals.heap_block.size = (uint32_t)len; - sizeleft = (uint32_t)(sizeleft - (uint32_t)sizeof(struct pico_mem_block) - len); - if(sizeleft > sizeof(struct pico_mem_block)) - { - sizeleft -= (uint32_t)sizeof(struct pico_mem_block); - byteptr = (uint8_t*) heap_block + sizeof(struct pico_mem_block); - byteptr += len; - new_block = (struct pico_mem_block*) byteptr; - new_block->type = HEAP_BLOCK_TYPE; - new_block->internals.heap_block.free = HEAP_BLOCK_FREE; - new_block->internals.heap_block.size = sizeleft; - DBG_MM_BLUE("New block: %p, size = %u", new_block, new_block->internals.heap_block.size); - } - else - { - DBG_MM_RED("No more space in extra manager heap page left to initialize a new heap block!"); - DBG_MM_RED("A new page will be allocated when even more space is needed"); - } - } - - startOfData = (uint8_t*) heap_block + sizeof(struct pico_mem_block); - DBG_MM_GREEN("Start of data = %p", startOfData); - - return startOfData; -} - -/* - * Page0 zalloc is called by pico_tree.c so that nodes which contain pointers to the free slab objects are put in the - * manager page. Additional manager pages can be created if necessary. - */ -void*pico_mem_page0_zalloc(size_t len) -{ - struct pico_mem_manager_extra*heap_page; - struct pico_mem_block*heap_block; - struct pico_mem_block*first_block; - struct pico_mem_block*new_block; - uint8_t*startOfData; - uint8_t*byteptr; - uint32_t sizeleft; - - DBG_MM_YELLOW("pico_mem_page0_zalloc(%u) called", len); - - byteptr = (uint8_t*) manager + sizeof(struct pico_mem_manager); - heap_block = (struct pico_mem_block*) byteptr; - - /* If heap_block == NULL then a free block at the end of the list is found. */ - /* Else, if the block is free and the size > len, an available block is also found. */ - sizeleft = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager); - /* this would mean that heap_block is never NULL */ - /* while(heap_block != NULL && ( heap_block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE || heap_block->internals.heap_block.size < len)) */ - while(heap_block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE || heap_block->internals.heap_block.size < len) - { - sizeleft -= (uint32_t)sizeof(struct pico_mem_block); - sizeleft -= heap_block->internals.heap_block.size; - /* DBG_MM("Sizeleft=%i", sizeleft); */ - byteptr = (uint8_t*) heap_block + sizeof(struct pico_mem_block); /* byteptr points to start of heap block data */ - byteptr += heap_block->internals.heap_block.size; /* jump over that data to start of next heap_block */ - heap_block = (struct pico_mem_block*) byteptr; - if(sizeleft <= sizeof(struct pico_mem_block)) - { - DBG_MM_RED("No more heap space left in the manager page!"); - if(manager->manager_extra == NULL) - { - DBG_MM_RED("Trying to allocate a new page for extra heap space: space usage: %uB/%uB", manager->used_size, manager->size); - if(manager->used_size + PICO_MEM_PAGE_SIZE > manager->size) - { - DBG_MM_RED("No more space left for this page!"); - /* exit(1); */ - return NULL; - } - - heap_page = pico_zalloc(PICO_MEM_PAGE_SIZE); - if(heap_page != NULL) - { - /* Initialize the new heap page */ - heap_page->blocks = 0; - heap_page->next = NULL; - heap_page->timestamp = 0; - byteptr = (uint8_t*) heap_page + sizeof(struct pico_mem_manager_extra); - first_block = (struct pico_mem_block*) byteptr; - first_block->type = HEAP_BLOCK_TYPE; - first_block->internals.heap_block.free = HEAP_BLOCK_FREE; - first_block->internals.heap_block.size = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager_extra) - sizeof(struct pico_mem_block); - manager->manager_extra = heap_page; - manager->used_size += PICO_MEM_PAGE_SIZE; - DBG_MM_BLUE("Allocated an extra manager heap page at %p, manager space usage: %uB/%uB", heap_page, manager->used_size, manager->size); - return _pico_mem_manager_extra_alloc(heap_page, len); - } - else - { - /* This should be a dirty crash */ - DBG_MM_RED("Page not allocated even though the max size for the memory manager hasn't been reached yet!"); - /* exit(1); */ - return NULL; - } - } - else - { - return _pico_mem_manager_extra_alloc(manager->manager_extra, len); - } - } - } - DBG_MM_BLUE("Found free heap block in manager page at : %p", heap_block); - heap_block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - - if(heap_block->internals.heap_block.size == sizeleft - sizeof(struct pico_mem_block)) - { - sizeleft = (uint32_t)(sizeleft - (uint32_t)sizeof(struct pico_mem_block) - len); - if(sizeleft > sizeof(struct pico_mem_block)) - { - DBG_MM_BLUE("End of heap, splitting up into a new block"); - heap_block->internals.heap_block.size = (uint32_t)len; - sizeleft -= (uint32_t)sizeof(struct pico_mem_block); - byteptr = (uint8_t*) heap_block + sizeof(struct pico_mem_block); - byteptr += len; - new_block = (struct pico_mem_block*) byteptr; - new_block->internals.heap_block.free = HEAP_BLOCK_FREE; - new_block->internals.heap_block.size = sizeleft; - DBG_MM_BLUE("New block: %p, size = %u", new_block, new_block->internals.heap_block.size); - } - else - { - /* DBG_MM_RED("ERROR! No more space in manager heap left to initialise a new heap_block!"); */ - /* exit(1); */ - DBG_MM_RED("No more space in manager heap left to initialize a new heap block!"); - DBG_MM_RED("A new page will be allocated when more space is needed"); - } - } - - startOfData = (uint8_t*) heap_block + sizeof(struct pico_mem_block); - DBG_MM_GREEN("Start of data = %p", startOfData); - - return startOfData; -} - - -/* - * This method will free a given heap block and try to merge it with - * surrounding blocks if they are free. - */ -static void _pico_mem_free_and_merge_heap_block(struct pico_mem_page*page, struct pico_mem_block*mem_block) -{ - uint8_t*byteptr; - /* pico_mem_block* prev = NULL; */ - struct pico_mem_block*prev; - struct pico_mem_block*curr; - struct pico_mem_block*next; - - DBG_MM_YELLOW("Freeing heap block %p with size %u in page %p", mem_block, mem_block->internals.heap_block.size, page); - - mem_block->internals.heap_block.free = HEAP_BLOCK_FREE; - - byteptr = (uint8_t*) page + sizeof(struct pico_mem_page); - curr = (struct pico_mem_block*) byteptr; - byteptr = (uint8_t*) curr + sizeof(struct pico_mem_block); - byteptr += curr->internals.heap_block.size; - next = (struct pico_mem_block*) byteptr; - - while(curr->type == HEAP_BLOCK_TYPE && next->type == HEAP_BLOCK_TYPE) - { - DBG_MM("Checking heap block (%s) with size %u at %p", (curr->internals.heap_block.free == HEAP_BLOCK_FREE) ? "free" : "not free", curr->internals.heap_block.size, curr); - if(curr->internals.heap_block.free == HEAP_BLOCK_FREE && next->internals.heap_block.free == HEAP_BLOCK_FREE) - { - DBG_MM_BLUE("Merging blocks with sizes %u and %u", curr->internals.heap_block.size, next->internals.heap_block.size); - curr->internals.heap_block.size += (uint32_t)sizeof(struct pico_mem_block) + next->internals.heap_block.size; - } - - prev = curr; - byteptr = (uint8_t*) curr + sizeof(struct pico_mem_block); - byteptr += curr->internals.heap_block.size; - curr = (struct pico_mem_block*) byteptr; - byteptr = (uint8_t*) curr + sizeof(struct pico_mem_block); - byteptr += curr->internals.heap_block.size; - next = (struct pico_mem_block*) byteptr; - } - DBG_MM("Checking heap block (%s) with size %u at %p", (curr->internals.heap_block.free == HEAP_BLOCK_FREE) ? "free" : "not free", curr->internals.heap_block.size, curr); - if(curr->type == HEAP_BLOCK_TYPE && prev->internals.heap_block.free == HEAP_BLOCK_FREE && curr->internals.heap_block.free == HEAP_BLOCK_FREE) - { - DBG_MM_BLUE("Merging blocks with sizes %u and %u", prev->internals.heap_block.size, curr->internals.heap_block.size); - prev->internals.heap_block.size += (uint32_t)sizeof(struct pico_mem_block) + curr->internals.heap_block.size; - } - - DBG_MM_GREEN("Heap block freed and heap space defragmentized"); -} - -/* - * This method will return the max. available contiguous free space in the heap - * from a given page. - */ -static uint32_t _pico_mem_determine_max_free_space(struct pico_mem_page*page) -{ - uint32_t maxfreespace = 0; - uint8_t*byteptr; - struct pico_mem_block*mem_block; - - DBG_MM_YELLOW("Determining new maximum free space in page %p (old free space: %u)", page, page->heap_max_free_space); - - /* pico_mem_block* mem_block = (pico_mem_block*) (page+1); //reset mem_block to first block in the heap */ - byteptr = (uint8_t*) page + sizeof(struct pico_mem_page); - mem_block = (struct pico_mem_block*) byteptr; /* reset mem_block to first block in the heap */ - - /* Determine max free space by iterating trough the list */ - /* while(mem_block != NULL && mem_block->type == HEAP_BLOCK_TYPE) */ - while(mem_block->type == HEAP_BLOCK_TYPE) - { - /* DBG_MM("Memblock %p of size %i is free %i\n",block, block->size, block->free); */ - DBG_MM("Memblock %s (size %u) at %p", (mem_block->internals.heap_block.free == HEAP_BLOCK_FREE) ? "not in use" : "in use", mem_block->internals.heap_block.size, mem_block); - if(mem_block->internals.heap_block.free == HEAP_BLOCK_FREE && mem_block->internals.heap_block.size > maxfreespace) - { - maxfreespace = mem_block->internals.heap_block.size; - page->heap_max_free_space = maxfreespace; - } - - byteptr = (uint8_t*) mem_block + sizeof(struct pico_mem_block); - byteptr += mem_block->internals.heap_block.size; - mem_block = (struct pico_mem_block*) byteptr; - } - page->heap_max_free_space = maxfreespace; - DBG_MM_GREEN("New free space: %u", page->heap_max_free_space); - return maxfreespace; -} - -/* - * This method will make a slab object available again by putting it in the RB-tree. - * Slab objects of the same size are stored in a double linked list. One pico_tree_node represents - * all the slab objects of the same size by making the keyvalue of a pico_tree_node point to - * the first element of the linked list. - * An element in this linked list is a struct pico_mem_slab_node. All the elements are also - * stored in the heap of the manager page (page0), or in the heap of extra manager spaces if there isn't enough space. - */ -static void _pico_mem_free_slab_block(struct pico_mem_block*slab_block) -{ - struct pico_mem_slab_node*slab_node; - struct pico_mem_slab_node*first_slab_node; - struct pico_tree_node*tree_node; - void*temp; - - DBG_MM_YELLOW("Freeing slab object"); - - slab_node = pico_mem_page0_zalloc(sizeof(struct pico_mem_slab_node)); - - if(slab_node == NULL) - { - /* Update the page householding without making the slab available again! */ - DBG_MM_RED("No more space in the manager heap and no more space for extra pages!"); - DBG_MM_RED("This slab will be leaked, but the leak will be plugged at the next cleanup, if and when the page is empty"); - slab_block->internals.slab_block.page->slabs_free++; - return; - } - - slab_node->slab = slab_block; - slab_block->internals.slab_block.slab_node = slab_node; - tree_node = pico_tree_findNode(&manager->tree, slab_node); - if(tree_node != NULL) - { - first_slab_node = (struct pico_mem_slab_node*) tree_node->keyValue; - tree_node->keyValue = slab_node; - first_slab_node->prev = slab_node; - slab_node->prev = NULL; - slab_node->next = first_slab_node; - } - else{ - DBG_MM_BLUE("No node found for size %i so calling pico_tree_insert", slab_node->slab->internals.slab_block.page->slab_size); - slab_node->next = NULL; - slab_node->prev = NULL; - /* pico_err_t pico_err_backup = pico_err; */ - /* pico_err = 0; */ - - - /* temp = pico_tree_insert(&manager->tree, slab_node); */ - temp = manager_tree_insert(&manager->tree, slab_node); - - /* if(pico_err == PICO_ERR_ENOMEM) */ - if(temp == &LEAF) - { - DBG_MM_RED("No more space in the manager heap and no more space for extra pages!"); - DBG_MM_RED("This slab will be leaked, but the leak will be plugged at the next cleanup, if and when the page is empty"); - pico_mem_page0_free(slab_node); - /* pico_err = pico_err_backup; */ - slab_block->internals.slab_block.page->slabs_free++; - return; - } - } - - /* Update free slabs in page householding */ - slab_block->internals.slab_block.page->slabs_free++; - DBG_MM_GREEN("Freed slab object, there are now %i free slab objects in the corresponding page", slab_block->internals.slab_block.page->slabs_free); -} - -/* - * This method zero initializes a block of memory pointed to by startOfData, of size len - */ -static void _pico_mem_zero_initialize(void*startOfData, size_t len) -{ - if(startOfData != NULL) - { - DBG_MM_YELLOW("Zero initializing user memory at %p of %u bytes", startOfData, len); - memset(startOfData, 0, len); - DBG_MM_GREEN("Zero initialized."); - } - else - { - DBG_MM_RED("Got a NULL pointer to zero initialize!"); - } -} - -/* - * This method will try to find a free heap block of size len in a given page. - */ -static void*_pico_mem_find_heap_block(struct pico_mem_page*page, size_t len) -{ - struct pico_mem_block*mem_block; - struct pico_mem_block*inserted_block; - uint8_t*startOfData; - uint8_t*byteptr; - - DBG_MM_YELLOW("Searching for a heap block of length %u in page %p (largest free block size = %u)", len, page, page->heap_max_free_space); - if(page->heap_max_free_space < len ) - { - DBG_MM_RED("Size %u > max free space %u of the page. This should only happen when this page is newly created, and its heap space is not large enough for the heap length!", len, page->heap_max_free_space); - return NULL; - } - - byteptr = (uint8_t*) page + sizeof(struct pico_mem_page); - mem_block = (struct pico_mem_block*) byteptr; /* Jump over the page struct to the start of the heap */ - - /* If mem_block == NULL then a free block at the end of the list is found. */ - /* Else, if the block is free and the size > len, an available block is also found. */ - /* while(mem_block != NULL && mem_block->type == HEAP_BLOCK_TYPE && ( mem_block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE || mem_block->internals.heap_block.size < len)) */ - while(mem_block->type == HEAP_BLOCK_TYPE && (mem_block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE || mem_block->internals.heap_block.size < len)) - { - /* DBG_MM_RED("Skipping heap block in use at %p of size %i", mem_block, mem_block->size); */ - DBG_MM_BLUE("Skipping heap block %s (size %u) at %p", (mem_block->internals.heap_block.free == HEAP_BLOCK_FREE) ? "not in use" : "in use", mem_block->internals.heap_block.size, mem_block); - byteptr = (uint8_t*) mem_block + sizeof(struct pico_mem_block); - byteptr += mem_block->internals.heap_block.size; - mem_block = (struct pico_mem_block*) byteptr; - } - if(mem_block->type == SLAB_BLOCK_TYPE) - { - DBG_MM_RED("No free heap block of contiguous size %u could be found in page %p", len, page); - /* exit(1); */ - return NULL; - } - - DBG_MM_BLUE("Found free heap block of size %u at %p", mem_block->internals.heap_block.size, mem_block); - mem_block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - page->timestamp = 0; - - /* Check to split the block into two smaller blocks */ - if(mem_block->internals.heap_block.size >= (len + sizeof(struct pico_mem_block) + PICO_MEM_MINIMUM_OBJECT_SIZE)) - { - byteptr = (uint8_t*) mem_block + sizeof(struct pico_mem_block); - byteptr += len; - inserted_block = (struct pico_mem_block*) byteptr; - - /* Update newly inserted block */ - inserted_block->type = HEAP_BLOCK_TYPE; - inserted_block->internals.heap_block.free = HEAP_BLOCK_FREE; - inserted_block->internals.heap_block.size = (uint32_t)(mem_block->internals.heap_block.size - (uint32_t)sizeof(struct pico_mem_block) - len); - /* Update block that was split up */ - mem_block->internals.heap_block.size = (uint32_t)len; - DBG_MM_BLUE("Splitting up the block, creating a new block of size %u at %p", inserted_block->internals.heap_block.size, inserted_block); - } - - startOfData = (uint8_t*) mem_block + sizeof(struct pico_mem_block); - - page->heap_max_free_space = _pico_mem_determine_max_free_space(page); - - /* Zero-initialize */ - _pico_mem_zero_initialize(startOfData, len); - DBG_MM_GREEN("Returning %p", startOfData); - return startOfData; -} - -/* - * This method will be called from pico_mem_zalloc. If an appropriate slab object is found, - * it is deleted from the RB tree and a pointer to the start of data in the slab object - * is returned. - */ -static void*_pico_mem_find_slab(size_t len) -{ - size_t*lenptr = &len; - size_t**doublelenptr = &lenptr; - struct pico_tree_node*node; - uint8_t *returnVal = NULL; - - DBG_MM_YELLOW("Finding slab with size %u", len); - /* The compare function takes an int*** length */ - node = pico_tree_findNode(&manager->tree, &doublelenptr); - - if(node != NULL) { - /* DBG_MM_BLUE("Found node, size = %d ", ((pico_mem_slab_node*) node->keyValue)->slab->size); */ - struct pico_mem_slab_node*slab_node = node->keyValue; - slab_node->slab->internals.slab_block.page->slabs_free--; - slab_node->slab->internals.slab_block.page->timestamp = 0; - DBG_MM_BLUE("Found node, size = %u at page %p, %u free slabs left in page", slab_node->slab->internals.slab_block.page->slab_size, slab_node->slab->internals.slab_block.page, slab_node->slab->internals.slab_block.page->slabs_free); - if(slab_node->next == NULL) - { - DBG_MM_BLUE("This was the last available slab object. Deleting the tree node now."); - /* if this is the last slab object of this size in the tree, then also delete the tree_node! */ - - - /* pico_tree_delete(&manager->tree, &doublelenptr); */ - manager_tree_delete(&manager->tree, &doublelenptr); - - - } - else - { - /* Remove the pico_mem_slab_node by making the keyvalue of the pico_tree_node point to the next element. */ - slab_node->next->prev = NULL; - node->keyValue = slab_node->next; - } - - returnVal = ((uint8_t*) (slab_node->slab)) + sizeof(struct pico_mem_block); - DBG_MM_BLUE("Start of slab: %p -> start of data : %p", slab_node->slab, returnVal); - /* Update the slab block housekeeping */ - slab_node->slab->internals.slab_block.slab_node = NULL; - /* Zero-initialize */ - _pico_mem_zero_initialize(returnVal, len); - /* Free the struct that was used by the linked list in the RB-tree */ - pico_mem_page0_free(slab_node); - } - - DBG_MM_GREEN("Returning %p", returnVal); - return returnVal; -} - -/* - * This method is called by the picotcp stack to free memory. - */ -void pico_mem_free(void*ptr) -{ - struct pico_mem_block*generic_block; - struct pico_mem_page*page; - /*Uncomment i for debugging!*/ - /*uint16_t i = 0;*/ - - DBG_MM_YELLOW("Free called on %p", ptr); - - if(ptr == NULL) return; - - generic_block = (struct pico_mem_block*) ptr; - generic_block--; - - if(generic_block->type == SLAB_BLOCK_TYPE) - { - if(generic_block->internals.slab_block.slab_node) - { - DBG_MM_RED("ERROR: Double free on a slab block (recovered)!"); - return; - } - - DBG_MM_BLUE("Request to free a slab block"); - _pico_mem_free_slab_block(generic_block); - } - else if(generic_block->type == HEAP_BLOCK_TYPE) - { - if(generic_block->internals.heap_block.free == HEAP_BLOCK_FREE) - { - DBG_MM_RED("ERROR: Double free on a heap block (recovered)!"); - return; - } - - DBG_MM_BLUE("Request to free a heap block"); - - /* Update the page housekeeping */ - /* Update the housekeeping of the extra manager pages */ - page = manager->first_page; - while(page != NULL) - { - DBG_MM_BLUE("Checking page %i at %p", i++, page); - if(((uint8_t*) page < (uint8_t*) ptr) && ((uint8_t*) ptr < (uint8_t*) page + PICO_MEM_PAGE_SIZE)) - { - /* DBG_MM_RED("page < ptr < page + PICO_MEM_PAGE_SIZE"); */ - /* DBG_MM_RED("%p < %p < %p", (uint8_t*) page, (uint8_t*) ptr, (uint8_t*) page + PICO_MEM_PAGE_SIZE); */ - _pico_mem_free_and_merge_heap_block(page, generic_block); - _pico_mem_determine_max_free_space(page); - break; - } - - page = page->next_page; - } - } - else - { - DBG_MM_RED("ERROR: You tried to free a pointer from which the type ( heap block or slab object ) could not be determined!!"); - } -} - -/************************NEW***************************/ -static void _pico_mem_reset_slab_statistics(void) -{ - slab_size_statistics[0] = 0; - slab_size_statistics[1] = 0; - slab_size_statistics[2] = 0; -} - -static size_t _pico_mem_determine_slab_size(size_t len) -{ - DBG_MM_YELLOW("Determining slab size to use, request for %u bytes", len); - if (len > slab_sizes[1]) - { - slab_size_statistics[2]++; - if(slab_size_statistics[2] > 3) - { - _pico_mem_reset_slab_statistics(); - if(slab_size_global != slab_sizes[2]) - { - slab_size_global = slab_sizes[2]; - } - } - - if(slab_size_global != slab_sizes[2]) - { - DBG_MM_RED("Using slab size %u, but we have to use a slab size of %u for the request of %u bytes", slab_size_global, slab_sizes[2], len); - return slab_sizes[2]; - } - } - else if(len > slab_sizes[0]) - { - slab_size_statistics[1]++; - if (slab_size_statistics[1] > 3) - { - _pico_mem_reset_slab_statistics(); - if(slab_size_global != slab_sizes[1]) - { - slab_size_global = slab_sizes[1]; - } - } - - if(len > slab_size_global) - { - DBG_MM_RED("Using slab size %u, but we have to use a slab size of %u for the request of %u bytes", slab_size_global, slab_sizes[1], len); - return slab_sizes[1]; - } - } - else - { - slab_size_statistics[0]++; - if (slab_size_statistics[0] > 3) - { - _pico_mem_reset_slab_statistics(); - if(slab_size_global != slab_sizes[0]) - { - slab_size_global = slab_sizes[0]; - } - } - } - - DBG_MM_GREEN("Using slab size %u", slab_size_global); - return slab_size_global; -} -/************************NEW***************************/ - -/* - * This method will be called by the picotcp stack to allocate new memory. - * If the requested size is bigger than the threshold of a slab object, - * then the manager will try to find an appropriate slab object and return a pointer - * to the beginning of the data in that slab object. - * - * If no slab objects could be found, or the requested size is less then the threshold - * of a slab object, the manager will try to allocate a heap block and return a pointer - * to the beginning of the data of that heap block. - * - * If still no memory could be found, then the manager will check again if the - * requested size is smaller than the threshold of a slab object. - * If so, the manager will try to find a slab object again but now ignoring the threshold. - * By doing so, there will be a large amount of internal fragmentation, but at least the - * memory request could be fulfilled. - * - * In any other case, the manager will return NULL. - */ -void*pico_mem_zalloc(size_t len) -{ - struct pico_mem_page*page; - void*returnCandidate; - uint32_t pagenr; - void *ret; - - DBG_MM_YELLOW("===> pico_mem_zalloc(%i) called", len); - len += (len % 4 == 0) ? 0 : 4 - len % 4; - DBG_MM_YELLOW("Aligned size: %i", len); - - if(manager == NULL) - { - DBG_MM_RED("Invalid alloc, a memory manager hasn't been instantiated yet!"); - return NULL; - } - - if(len > PICO_MAX_SLAB_SIZE) - { - DBG_MM_RED("Invalid alloc, the size you requested is larger than the maximum slab size! (%uB>%uB)", len, PICO_MAX_SLAB_SIZE); - return NULL; - } - - /* /////// FIND SLAB OBJECTS ///////// */ - if(len >= PICO_MIN_SLAB_SIZE) - { - /* feed the size into a statistic engine that determines the slabsize to use */ - /* DBG_MM_RED("Placeholder: determine correct slab size to use!"); */ - len = _pico_mem_determine_slab_size(len); - ret = _pico_mem_find_slab(len); - if(ret != NULL) return ret; - - /* No slab object could be found. => Init new page? */ - - DBG_MM_BLUE("No free slab found, trying to create a new page (Used size = %u, max size = %u)", manager->used_size, manager->size); - if(manager->used_size + PICO_MEM_PAGE_SIZE <= manager->size) - { - struct pico_mem_page*newpage = pico_zalloc(PICO_MEM_PAGE_SIZE); - if(newpage != NULL) - { - manager->used_size += PICO_MEM_PAGE_SIZE; - DBG_MM_BLUE("Created new page at %p -> used size = %u", newpage, manager->used_size); - _pico_mem_init_page(newpage, len); - /* Return pointer to first slab in that page */ - return _pico_mem_find_slab(len); /* Find the new slab object! */ - } - else - { - DBG_MM_RED("Not enough space to allocate a new page, even though the max size hasn't been reached yet!"); - return NULL; - } - } - else - { - DBG_MM_RED("Not enough space to allocate a new page!"); - return NULL; - } - } - - /* /////// FIND HEAP BLOCKS ///////// */ - if(len < PICO_MEM_MINIMUM_OBJECT_SIZE) - len = PICO_MEM_MINIMUM_OBJECT_SIZE; - - DBG_MM_BLUE("Searching for heap space of length %u now.", len); - - pagenr = 1; - page = manager->first_page; - - /* The algorithm to find a heap block is based on first fit. */ - /* But when the internal fragmentation is too big, the block is split. */ - while(page != NULL) - { - /* DBG_MM_RED("Max free space in page %i = %i bytes", pagecounter+1, page->heap.max_free_space); */ - DBG_MM_BLUE("Max free space in page %u = %uB (page=%p)", pagenr, page->heap_max_free_space, page); - if(len <= page->heap_max_free_space) - { - return _pico_mem_find_heap_block(page, len); - } - - pagenr++; - page = page->next_page; - } - /* No free heap block could be found, try to alloc a new page */ - DBG_MM_BLUE("No free heap block found, trying to create a new page (Used size = %u, max size = %u)", manager->used_size, manager->size); - if(manager->used_size + PICO_MEM_PAGE_SIZE <= manager->size) - { - struct pico_mem_page*newpage = pico_zalloc(PICO_MEM_PAGE_SIZE); - if(newpage != NULL) - { - manager->used_size += PICO_MEM_PAGE_SIZE; - DBG_MM_BLUE("Created new page at %p -> used size = %u", newpage, manager->used_size); - /* TODO: Careful, if the current slabsize is determined in another way, this needs to change too */ - _pico_mem_init_page(newpage, slab_size_global); - returnCandidate = _pico_mem_find_heap_block(newpage, len); - if(returnCandidate != NULL) - return returnCandidate; - } - else - { - DBG_MM_RED("Not enough space to allocate a new page, even though the max size hasn't been reached yet!"); - return NULL; - } - } - - /* DBG_MM_RED("NO HEAP BLOCK FOUND!"); */ - - /* /////// TRY TO FIND NEW SLAB OBJECT, BUT INCREASE SIZE ///////// */ - DBG_MM_RED("TRYING TO FIND FREE SLAB OBJECT WITH DANGER OF LARGE INTERNAL FRAGMENTATION"); - /* TODO: Careful, if the current slabsize is determined in another way, this needs to change too */ - return _pico_mem_find_slab(slab_size_global); -} -/* - * This method frees heap space used in the manager page, or in one of the extra manager pages - */ -void pico_mem_page0_free(void*ptr) -{ - struct pico_mem_block*node = ptr; - struct pico_mem_manager_extra*heap_page; - /* Uncomment for debugging! */ - /* int i = 0; */ - - /* TODO: should be able to merge free neighbouring blocks (??) */ - DBG_MM_YELLOW("page0_free called"); - - node--; - node->internals.heap_block.free = HEAP_BLOCK_FREE; - /* Update the housekeeping of the extra manager pages */ - heap_page = manager->manager_extra; - while(heap_page != NULL) - { - DBG_MM_BLUE("Checking extra heap page %i at %p", i++, heap_page); - if(((uint8_t*) heap_page < (uint8_t*) ptr) && ((uint8_t*) ptr < (uint8_t*) heap_page + PICO_MEM_PAGE_SIZE)) - { - /* DBG_MM_RED("heap_page < ptr < heap_page + PICO_MEM_PAGE_SIZE"); */ - /* DBG_MM_RED("%p < %p < %p", (uint8_t*) heap_page, (uint8_t*) ptr, (uint8_t*) heap_page + PICO_MEM_PAGE_SIZE); */ - heap_page->blocks--; - DBG_MM_BLUE("Updating heap page housekeeping: %u->%u used blocks", heap_page->blocks + 1, heap_page->blocks); - break; - } - - heap_page = heap_page->next; - } - DBG_MM_GREEN("Heap block (located in %s) succesfully freed", (i != -1) ? "main manager page" : "extra manager page"); -} - -/* - * This cleanup function must be called externally at downtime moments. A system timestamp must be passed to the function. - * All pages and extra manager pages will be checked. If they are empty, the timestamp of the page will be updated. If the - * page has been empty for a time longer than PICO_MEM_PAGE_LIFETIME, the page is returned to the system's control, and all - * the housekeeping is updated. - */ -void pico_mem_cleanup(uint32_t timestamp) -{ - struct pico_mem_slab_node*slab_node; - struct pico_tree_node*tree_node; - struct pico_mem_block*slab_block; - struct pico_mem_page*next_page; - struct pico_mem_page*prev_page; - struct pico_mem_page*page; - struct pico_mem_manager_extra*heap_page; - struct pico_mem_manager_extra*next; - struct pico_mem_manager_extra*prev_heap_page; - uint8_t*byteptr; - int pagenr = 1; - int i; - - DBG_MM_YELLOW("Starting cleanup with timestamp %u", timestamp); - /* Iterate over all pages */ - page = manager->first_page; - prev_page = NULL; - while(page != NULL) - { - DBG_MM_BLUE("Checking page %i at %p", pagenr, page); - /* Check the timestamp of the page. If it doesn't have one (0), update it with the new timestamp if the page is completely empty. */ - if(page->timestamp == 0) - { - if((page->heap_max_size == page->heap_max_free_space) && (page->slabs_free == page->slabs_max)) - { - DBG_MM_BLUE("Page %i empty, updating timestamp", pagenr); - page->timestamp = timestamp; - } - } - /* If the timestamp is old enough, remove the page and all its slabs. This means we have to: */ - /* > Remove all slabs out of the RB tree */ - /* > Update the page list */ - /* > Return the page to the system's control */ - /* > Update manager housekeeping */ - else if(timestamp > page->timestamp) - { - if(timestamp - page->timestamp > PICO_MEM_PAGE_LIFETIME) - { - DBG_MM_BLUE("Page %i is empty and has exceeded the lifetime (%u > lifetime=%u)", pagenr, timestamp - page->timestamp, PICO_MEM_PAGE_LIFETIME); - /* Remove all the slabs out of the RB tree */ - byteptr = (uint8_t*) page + sizeof(struct pico_mem_page); /* byteptr points to the start of the heap (a pico_mem_block), after page housekeeping */ - byteptr += sizeof(struct pico_mem_block); /* jump over pico_mem_block, containing the housekeeping for the heap space */ - byteptr += page->heap_max_size; /* jump over heap space, byteptr now points to the start of the slabs */ - slab_block = (struct pico_mem_block*) byteptr; - slab_node = slab_block->internals.slab_block.slab_node; - /* The corresponding tree_node */ - tree_node = pico_tree_findNode(&manager->tree, slab_node); - for(i = 0; i < page->slabs_max; i++) - { - DBG_MM("Removing slab %i at %p", i, slab_block); - if(slab_node->prev == NULL && slab_node->next == NULL) - { - DBG_MM("This node is the last node in the tree_node, removing tree_node"); - /* slab_node is the last node in the tree leaf, delete it */ - - - /* pico_tree_delete(&manager->tree, slab_node); */ - manager_tree_delete(&manager->tree, slab_node); - - - } - else if(slab_node->prev == NULL) - { - DBG_MM("This node is the first node in the linked list, adjusting tree_node"); - tree_node->keyValue = slab_node->next; - slab_node->next->prev = NULL; - } - else if(slab_node->next == NULL) - { - DBG_MM("This node is the last node in the linked list"); - slab_node->prev->next = NULL; - } - else - { - DBG_MM("This node is neither the first, nor the last node in the list"); - slab_node->prev->next = slab_node->next; - slab_node->next->prev = slab_node->prev; - } - - pico_mem_page0_free(slab_node); - byteptr = (uint8_t*) slab_block + sizeof(struct pico_mem_block); /* byteptr points to the start of the slab data, after the housekeeping */ - byteptr += page->slab_size; /* jump over the slab data, byteptr now points to the start of the next slab block */ - slab_block = (struct pico_mem_block*) byteptr; - slab_node = slab_block->internals.slab_block.slab_node; - } - /* Update the page list */ - if(prev_page == NULL) /* prev_page == NULL when pagenr=1, or when previous pages were deleted */ - { - DBG_MM("Updating page list, manager->first_page = page->next_page"); - manager->first_page = page->next_page; - } - else - { - DBG_MM("Updating page list, prev_page->next_page = page->next_page"); - prev_page->next_page = page->next_page; - } - - /* Return the page to the system's control */ - next_page = page->next_page; - DBG_MM("Freeing page, manager used size = %u", manager->used_size); - pico_free(page); - /* Update the manager housekeeping */ - manager->used_size -= PICO_MEM_PAGE_SIZE; - DBG_MM("Freed page, manager used size = %u, down from %u", manager->used_size, manager->used_size + PICO_MEM_PAGE_SIZE); - /* ITERATION */ - page = next_page; - pagenr++; - continue; - } - else - { - DBG_MM_BLUE("Page %i is empty, but has not exceeded the lifetime (%u < lifetime=%u)", pagenr, timestamp - page->timestamp, PICO_MEM_PAGE_LIFETIME); - } - } - else /* timestamp < page->timestamp */ - { - DBG_MM_RED("Page %i is empty, but the system timestamp < page timestamp! (%u<%u)", pagenr, timestamp, page->timestamp); - DBG_MM_RED("Updating page %i timestamp!", pagenr); - page->timestamp = timestamp; - } - - pagenr++; - prev_page = page; - page = page->next_page; - } - /* Check all extra manager pages if they are empty */ - heap_page = manager->manager_extra; - prev_heap_page = NULL; - pagenr = 1; - while(heap_page != NULL) - { - DBG_MM_BLUE("Checking extra manager page %i at %p", pagenr, heap_page); - if(heap_page->timestamp == 0) - { - if( heap_page->blocks == 0 ) - { - DBG_MM_BLUE("Extra manager page %i empty, updating timestamp", pagenr); - heap_page->timestamp = timestamp; - } - } - else if(timestamp > heap_page->timestamp) - { - if(timestamp - heap_page->timestamp > PICO_MEM_PAGE_LIFETIME) - { - DBG_MM_BLUE("Extra manager page %i empty and has exceeded the lifetime (%u > lifetime=%u)", pagenr, timestamp - heap_page->timestamp, PICO_MEM_PAGE_LIFETIME); - /* Update the page list */ - if(prev_heap_page == NULL) - { - DBG_MM("Updating page list, manager->manager_extra = heap_page->next"); - manager->manager_extra = heap_page->next; - } - else - { - DBG_MM("Updating page list, prev_heap_page->next = heap_page->next"); - prev_heap_page->next = heap_page->next; - } - - /* Return the page to the system's control */ - next = heap_page->next; - DBG_MM("Freeing page, manager used size = %u", manager->used_size); - pico_free(heap_page); - /* Update the manager housekeeping */ - manager->used_size -= PICO_MEM_PAGE_SIZE; - DBG_MM("Freed page, manager used size = %u, down from %u", manager->used_size, manager->used_size + PICO_MEM_PAGE_SIZE); - /* ITERATION */ - heap_page = next; - pagenr++; - continue; - } - else - { - DBG_MM_BLUE("Page %i is empty, but has not exceeded the lifetime (%u < lifetime=%u)", pagenr, timestamp - heap_page->timestamp, PICO_MEM_PAGE_LIFETIME); - } - } - else - { - DBG_MM_RED("Page %i is empty, but the system timestamp < page timestamp! (%u<%u)", pagenr, timestamp, heap_page->timestamp); - DBG_MM_RED("Updating page %i timestamp!", pagenr); - heap_page->timestamp = timestamp; - } - - /* ITERATION */ - pagenr++; - prev_heap_page = heap_page; - heap_page = heap_page->next; - } -} - - - - - - -#ifdef PICO_SUPPORT_MM_PROFILING -/*********************************************************************************************************************** - *********************************************************************************************************************** - MEMORY PROFILING FUNCTIONS - *********************************************************************************************************************** - ***********************************************************************************************************************/ - -static struct pico_mem_manager*manager_profile; - -static void _pico_mem_print_tree(struct pico_tree_node*root) -{ - struct pico_mem_slab_node*iterator; - int j; - - if (root == &LEAF || root == NULL) - { - DBG_MM("No tree nodes at this time.\n"); - return; - } - - iterator = (struct pico_mem_slab_node*) root->keyValue; - DBG_MM("Tree node for size %u:\n", iterator->slab->internals.slab_block.page->slab_size); - j = 0; - while(iterator != NULL) - { - DBG_MM("\tSlab_node %i at %p:\n", j, iterator); - DBG_MM("\t\tPrev:%p\n", iterator->prev); - DBG_MM("\t\tNext:%p\n", iterator->next); - DBG_MM("\t\tSlab:%p\n", iterator->slab); - j++; - iterator = iterator->next; - } - if(root->leftChild != &LEAF && root->leftChild != NULL) - _pico_mem_print_tree(root->leftChild); - - if(root->rightChild != &LEAF && root->rightChild != NULL) - _pico_mem_print_tree(root->rightChild); -} - -void pico_mem_profile_scan_data() -{ - if(manager == NULL) - { - DBG_MM("No memory manager instantiated!\n"); - } - else - { - int manager_pages = 0; - int pages = 0; - int counter = 0; - struct pico_mem_manager_extra*heap_page; - struct pico_mem_page*page; - uint8_t*byteptr; - struct pico_mem_block*mem_block; - - DBG_MM("Memory manager: %uB/%uB in use\n", manager->used_size, manager->size); - _pico_mem_print_tree(manager->tree.root); - - /* Iterate over every extra manager page: */ - heap_page = manager->manager_extra; - while(heap_page != NULL) - { - manager_pages++; - DBG_MM("Extra manager page %i:\n\tBlocks in use: %u\n\tTimestamp: %u\n", manager_pages, heap_page->blocks, heap_page->timestamp); - heap_page = heap_page->next; - } - /* Iterate over every page: */ - pages = (manager->used_size / PICO_MEM_PAGE_SIZE) - manager_pages - 1; - page = manager->first_page; - while(page != NULL) - { - counter++; - DBG_MM("Page %i/%i:\n\tSlabsize: %u\n\tSlabs free: %u/%u\n\tTimestamp: %u\n", counter, pages, page->slab_size, page->slabs_free, page->slabs_max, page->timestamp); - byteptr = (uint8_t*) page + sizeof(struct pico_mem_page); - mem_block = (struct pico_mem_block*) byteptr; - DBG_MM("\tHeap:\n"); - while(mem_block->type == HEAP_BLOCK_TYPE) - { - DBG_MM("\t\tBlock: size %u, %s\n", mem_block->internals.heap_block.size, (mem_block->internals.heap_block.free == HEAP_BLOCK_FREE) ? "free" : "not free"); - byteptr = (uint8_t*) mem_block + sizeof(struct pico_mem_block); - byteptr += mem_block->internals.heap_block.size; - mem_block = (struct pico_mem_block*) byteptr; - } - page = page->next_page; - } - } -} - -void pico_mem_profile_collect_data(struct profiling_data*profiling_struct) -{ - struct pico_mem_block*mem_block; - uint8_t*byteptr; - - profiling_struct->free_heap_space = 0; - profiling_struct->free_slab_space = 0; - profiling_struct->used_heap_space = 0; - profiling_struct->used_slab_space = 0; - if(manager != NULL) - { - struct pico_mem_page*page = manager->first_page; - while(page != NULL) - { - profiling_struct->free_slab_space += page->slab_size * page->slabs_free; - profiling_struct->used_slab_space += page->slab_size * page->slabs_max; - - byteptr = (uint8_t*) page + sizeof(struct pico_mem_page); - mem_block = (struct pico_mem_block*) byteptr; - - while(mem_block->type == HEAP_BLOCK_TYPE) - { - if(mem_block->internals.heap_block.free == HEAP_BLOCK_FREE) - { - profiling_struct->free_heap_space += mem_block->internals.heap_block.size; - } - else - { - /* dbg("Block: size=%u\n", mem_block->internals.heap_block.size); */ - profiling_struct->used_heap_space += mem_block->internals.heap_block.size; - } - - byteptr += sizeof(struct pico_mem_block) + mem_block->internals.heap_block.size; - mem_block = (struct pico_mem_block*) byteptr; - } - page = page->next_page; - } - } -} - -uint32_t pico_mem_profile_used_size() -{ - if(manager != NULL) - { - return manager->used_size; - } - else - { - return 0; - } -} - -struct pico_mem_manager*pico_mem_profile_manager() -{ - return manager; -} -#endif /* PICO_SUPPORT_MM_PROFILING */ - diff --git a/ext/picotcp/modules/pico_mm.h b/ext/picotcp/modules/pico_mm.h deleted file mode 100644 index 29366d0..0000000 --- a/ext/picotcp/modules/pico_mm.h +++ /dev/null @@ -1,98 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Gustav Janssens, Jonas Van Nieuwenberg, Sam Van Den Berge - *********************************************************************/ - - -#ifndef _INCLUDE_PICO_MM -#define _INCLUDE_PICO_MM - -#include "pico_config.h" - -/* - * Memory init function, this will create a memory manager instance - * A memory_manager page will be created, along with one page of memory - * Memory can be asked for via the pico_mem_zalloc function - * More memory will be allocated to the memory manager according to its needs - * A maximum amount of memory of uint32_t memsize can be allocated - */ -void pico_mem_init(uint32_t memsize); -/* - * Memory deinit function, this will free all memory occupied by the current - * memory manager instance. - */ -void pico_mem_deinit(void); -/* - * Zero-initialized malloc function, will reserve a memory segment of length uint32_t len - * This memory will be quickly allocated in a slab of fixed size if possible - * or less optimally in the heap for a small variable size - * The fixed size of the slabs can be changed dynamically via a statistics engine - */ -void*pico_mem_zalloc(size_t len); -/* - * Free function, free a block of memory pointed to by ptr. - * Unused memory is only returned to the system's control by pico_mem_cleanup - */ -void pico_mem_free(void*ptr); -/* - * This cleanup function will be provided by the memory manager - * It can be called during processor downtime - * This function will return unused pages to the system's control - * Pages are unused if they no longer contain slabs or heap, and they have been idle for a longer time - */ -void pico_mem_cleanup(uint32_t timestamp); - - - -#ifdef PICO_SUPPORT_MM_PROFILING -/*********************************************************************************************************************** - *********************************************************************************************************************** - MEMORY PROFILING FUNCTIONS - *********************************************************************************************************************** - ***********************************************************************************************************************/ -/* General info struct */ -struct profiling_data -{ - uint32_t free_heap_space; - uint32_t free_slab_space; - uint32_t used_heap_space; - uint32_t used_slab_space; -}; - -/* - * This function fills up a struct with used and free slab and heap space in the memory manager - * The user is responsible for resource managment - */ -void pico_mem_profile_collect_data(struct profiling_data*profiling_page_struct); - -/* - * This function prints the general structure of the memory manager - * Printf in this function can be rerouted to send this data over a serial port, or to write it away to memory - */ -void pico_mem_profile_scan_data(void); - -/* - * This function returns the total size that the manager has received from the system - * This can give an indication of the total system resource commitment, but keep in mind that - * there can be many free blocks in this "used" size - * Together with pico_mem_profile_collect_data, this can give a good estimation of the total - * resource commitment - */ -uint32_t pico_mem_profile_used_size(void); - -/* - * This function returns a pointer to page 0, the main memory manager housekeeping (struct pico_mem_manager). - * This can be used to collect data about the memory in user defined functions. - * Use with care! - */ -void*pico_mem_profile_manager(void); - -/* - * paramter manager is a pointer to a struct pico_mem_manager - */ -void pico_mem_init_profiling(void*manager, uint32_t memsize); -#endif /* PICO_SUPPORT_MM_PROFILING */ - -#endif /* _INCLUDE_PICO_MM */ diff --git a/ext/picotcp/modules/pico_nat.c b/ext/picotcp/modules/pico_nat.c deleted file mode 100644 index 19f85e0..0000000 --- a/ext/picotcp/modules/pico_nat.c +++ /dev/null @@ -1,576 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Kristof Roelants, Brecht Van Cauwenberghe, - Simon Maes, Philippe Mariman - *********************************************************************/ - -#include "pico_stack.h" -#include "pico_frame.h" -#include "pico_tcp.h" -#include "pico_udp.h" -#include "pico_ipv4.h" -#include "pico_addressing.h" -#include "pico_nat.h" - -#ifdef PICO_SUPPORT_IPV4 -#ifdef PICO_SUPPORT_NAT - -#define nat_dbg(...) do {} while(0) -/* #define nat_dbg dbg */ -#define PICO_NAT_TIMEWAIT 240000 /* msec (4 mins) */ - -#define PICO_NAT_INBOUND 0 -#define PICO_NAT_OUTBOUND 1 - -struct pico_nat_tuple { - uint8_t proto; - uint16_t conn_active : 11; - uint16_t portforward : 1; - uint16_t rst : 1; - uint16_t syn : 1; - uint16_t fin_in : 1; - uint16_t fin_out : 1; - uint16_t src_port; - uint16_t dst_port; - uint16_t nat_port; - struct pico_ip4 src_addr; - struct pico_ip4 dst_addr; - struct pico_ip4 nat_addr; -}; - -static struct pico_ipv4_link *nat_link = NULL; - -static int nat_cmp_natport(struct pico_nat_tuple *a, struct pico_nat_tuple *b) -{ - - if (a->nat_port < b->nat_port) - return -1; - - if (a->nat_port > b->nat_port) - - return 1; - - return 0; - -} - -static int nat_cmp_srcport(struct pico_nat_tuple *a, struct pico_nat_tuple *b) -{ - - if (a->src_port < b->src_port) - return -1; - - if (a->src_port > b->src_port) - - return 1; - - return 0; - -} - -static int nat_cmp_proto(struct pico_nat_tuple *a, struct pico_nat_tuple *b) -{ - if (a->proto < b->proto) - return -1; - - if (a->proto > b->proto) - return 1; - - return 0; -} - -static int nat_cmp_address(struct pico_nat_tuple *a, struct pico_nat_tuple *b) -{ - return pico_ipv4_compare(&a->src_addr, &b->src_addr); -} - -static int nat_cmp_inbound(void *ka, void *kb) -{ - struct pico_nat_tuple *a = ka, *b = kb; - int cport = nat_cmp_natport(a, b); - if (cport) - return cport; - - return nat_cmp_proto(a, b); -} - - -static int nat_cmp_outbound(void *ka, void *kb) -{ - struct pico_nat_tuple *a = ka, *b = kb; - int caddr, cport; - - caddr = nat_cmp_address(a, b); - if (caddr) - return caddr; - - cport = nat_cmp_srcport(a, b); - - if (cport) - return cport; - - return nat_cmp_proto(a, b); -} - -PICO_TREE_DECLARE(NATOutbound, nat_cmp_outbound); -PICO_TREE_DECLARE(NATInbound, nat_cmp_inbound); - -void pico_ipv4_nat_print_table(void) -{ - struct pico_nat_tuple *t = NULL; - struct pico_tree_node *index = NULL; - (void)t; - - nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); - nat_dbg("+ NAT table +\n"); - nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n"); - nat_dbg("+ src_addr | src_port | dst_addr | dst_port | nat_addr | nat_port | proto | conn active | FIN1 | FIN2 | SYN | RST | FORW +\n"); - nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n"); - - pico_tree_foreach(index, &NATOutbound) - { - t = index->keyValue; - nat_dbg("+ %08X | %05u | %08X | %05u | %08X | %05u | %03u | %03u | %u | %u | %u | %u | %u +\n", - long_be(t->src_addr.addr), t->src_port, long_be(t->dst_addr.addr), t->dst_port, long_be(t->nat_addr.addr), t->nat_port, - t->proto, t->conn_active, t->fin_in, t->fin_out, t->syn, t->rst, t->portforward); - } - nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); -} - -/* - 2 options: - find on nat_port and proto - find on src_addr, src_port and proto - zero the unused parameters - */ -static struct pico_nat_tuple *pico_ipv4_nat_find_tuple(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto) -{ - struct pico_nat_tuple *found = NULL, test = { - 0 - }; - - test.nat_port = nat_port; - test.src_port = src_port; - test.proto = proto; - if (src_addr) - test.src_addr = *src_addr; - - if (nat_port) - found = pico_tree_findKey(&NATInbound, &test); - else - found = pico_tree_findKey(&NATOutbound, &test); - - if (found) - return found; - else - return NULL; -} - -int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto) -{ - struct pico_nat_tuple *t = NULL; - - t = pico_ipv4_nat_find_tuple(nat_port, src_addr, src_port, proto); - if (t) - return 1; - else - return 0; -} - -static struct pico_nat_tuple *pico_ipv4_nat_add(struct pico_ip4 dst_addr, uint16_t dst_port, struct pico_ip4 src_addr, uint16_t src_port, - struct pico_ip4 nat_addr, uint16_t nat_port, uint8_t proto) -{ - struct pico_nat_tuple *t = PICO_ZALLOC(sizeof(struct pico_nat_tuple)); - if (!t) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - t->dst_addr = dst_addr; - t->dst_port = dst_port; - t->src_addr = src_addr; - t->src_port = src_port; - t->nat_addr = nat_addr; - t->nat_port = nat_port; - t->proto = proto; - t->conn_active = 1; - t->portforward = 0; - t->rst = 0; - t->syn = 0; - t->fin_in = 0; - t->fin_out = 0; - - if (pico_tree_insert(&NATOutbound, t)) { - PICO_FREE(t); - return NULL; - } - - if (pico_tree_insert(&NATInbound, t)) { - pico_tree_delete(&NATOutbound, t); - PICO_FREE(t); - return NULL; - } - - return t; -} - -static int pico_ipv4_nat_del(uint16_t nat_port, uint8_t proto) -{ - struct pico_nat_tuple *t = NULL; - t = pico_ipv4_nat_find_tuple(nat_port, NULL, 0, proto); - if (t) { - pico_tree_delete(&NATOutbound, t); - pico_tree_delete(&NATInbound, t); - PICO_FREE(t); - } - - return 0; -} - -static struct pico_trans *pico_nat_generate_tuple_trans(struct pico_ipv4_hdr *net, struct pico_frame *f) -{ - struct pico_trans *trans = NULL; - switch (net->proto) { - case PICO_PROTO_TCP: - { - struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr; - trans = (struct pico_trans *)&tcp->trans; - break; - } - case PICO_PROTO_UDP: - { - struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr; - trans = (struct pico_trans *)&udp->trans; - break; - } - case PICO_PROTO_ICMP4: - /* XXX: implement */ - break; - } - return trans; -} - -static struct pico_nat_tuple *pico_ipv4_nat_generate_tuple(struct pico_frame *f) -{ - struct pico_trans *trans = NULL; - struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr; - uint16_t nport = 0; - uint8_t retry = 32; - - /* generate NAT port */ - do { - uint32_t rand = pico_rand(); - nport = (uint16_t) (rand & 0xFFFFU); - nport = (uint16_t)((nport % (65535 - 1024)) + 1024U); - nport = short_be(nport); - - if (pico_is_port_free(net->proto, nport, NULL, &pico_proto_ipv4)) - break; - } while (--retry); - - if (!retry) - return NULL; - - trans = pico_nat_generate_tuple_trans(net, f); - if(!trans) - return NULL; - - return pico_ipv4_nat_add(net->dst, trans->dport, net->src, trans->sport, nat_link->address, nport, net->proto); - /* XXX return pico_ipv4_nat_add(nat_link->address, port, net->src, trans->sport, net->proto); */ -} - -static inline void pico_ipv4_nat_set_tcp_flags(struct pico_nat_tuple *t, struct pico_frame *f, uint8_t direction) -{ - struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr; - if (tcp->flags & PICO_TCP_SYN) - t->syn = 1; - - if (tcp->flags & PICO_TCP_RST) - t->rst = 1; - - if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_INBOUND)) - t->fin_in = 1; - - if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_OUTBOUND)) - t->fin_out = 1; -} - -static int pico_ipv4_nat_sniff_session(struct pico_nat_tuple *t, struct pico_frame *f, uint8_t direction) -{ - struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr; - - switch (net->proto) { - case PICO_PROTO_TCP: - { - pico_ipv4_nat_set_tcp_flags(t, f, direction); - break; - } - - case PICO_PROTO_UDP: - t->conn_active = 1; - break; - - case PICO_PROTO_ICMP4: - /* XXX: implement */ - break; - - default: - return -1; - } - - return 0; -} - -static void pico_ipv4_nat_table_cleanup(pico_time now, void *_unused) -{ - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_nat_tuple *t = NULL; - IGNORE_PARAMETER(now); - IGNORE_PARAMETER(_unused); - nat_dbg("NAT: before table cleanup:\n"); - pico_ipv4_nat_print_table(); - - pico_tree_foreach_reverse_safe(index, &NATOutbound, _tmp) - { - t = index->keyValue; - switch (t->proto) - { - case PICO_PROTO_TCP: - if (t->portforward) - break; - else if (t->conn_active == 0 || t->conn_active > 360) /* conn active for > 24 hours */ - pico_ipv4_nat_del(t->nat_port, t->proto); - else if (t->rst || (t->fin_in && t->fin_out)) - t->conn_active = 0; - else - t->conn_active++; - - break; - - case PICO_PROTO_UDP: - if (t->portforward) - break; - else if (t->conn_active > 1) - pico_ipv4_nat_del(t->nat_port, t->proto); - else - t->conn_active++; - - break; - - case PICO_PROTO_ICMP4: - if (t->conn_active > 1) - pico_ipv4_nat_del(t->nat_port, t->proto); - else - t->conn_active++; - - default: - /* unknown protocol in NAT table, delete when it has existed NAT_TIMEWAIT */ - if (t->conn_active > 1) - pico_ipv4_nat_del(t->nat_port, t->proto); - else - t->conn_active++; - } - } - - nat_dbg("NAT: after table cleanup:\n"); - pico_ipv4_nat_print_table(); - pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL); -} - -int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag) -{ - struct pico_nat_tuple *t = NULL; - struct pico_ip4 any_addr = { - 0 - }; - uint16_t any_port = 0; - - switch (flag) - { - case PICO_NAT_PORT_FORWARD_ADD: - t = pico_ipv4_nat_add(any_addr, any_port, src_addr, src_port, nat_addr, nat_port, proto); - if (!t) { - pico_err = PICO_ERR_EAGAIN; - return -1; - } - - t->portforward = 1; - break; - - case PICO_NAT_PORT_FORWARD_DEL: - return pico_ipv4_nat_del(nat_port, proto); - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - - pico_ipv4_nat_print_table(); - return 0; -} - -int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr) -{ - struct pico_nat_tuple *tuple = NULL; - struct pico_trans *trans = NULL; - struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr; - - if (!pico_ipv4_nat_is_enabled(link_addr)) - return -1; - - switch (net->proto) { -#ifdef PICO_SUPPORT_TCP - case PICO_PROTO_TCP: - { - struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr; - trans = (struct pico_trans *)&tcp->trans; - tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto); - if (!tuple) - return -1; - - /* replace dst IP and dst PORT */ - net->dst = tuple->src_addr; - trans->dport = tuple->src_port; - /* recalculate CRC */ - tcp->crc = 0; - tcp->crc = short_be(pico_tcp_checksum_ipv4(f)); - break; - } -#endif -#ifdef PICO_SUPPORT_UDP - case PICO_PROTO_UDP: - { - struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr; - trans = (struct pico_trans *)&udp->trans; - tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto); - if (!tuple) - return -1; - - /* replace dst IP and dst PORT */ - net->dst = tuple->src_addr; - trans->dport = tuple->src_port; - /* recalculate CRC */ - udp->crc = 0; - udp->crc = short_be(pico_udp_checksum_ipv4(f)); - break; - } -#endif - case PICO_PROTO_ICMP4: - /* XXX reimplement */ - break; - - default: - nat_dbg("NAT ERROR: inbound NAT on erroneous protocol\n"); - return -1; - } - - pico_ipv4_nat_sniff_session(tuple, f, PICO_NAT_INBOUND); - net->crc = 0; - net->crc = short_be(pico_checksum(net, f->net_len)); - - nat_dbg("NAT: inbound translation {dst.addr, dport}: {%08X,%u} -> {%08X,%u}\n", - tuple->nat_addr.addr, short_be(tuple->nat_port), tuple->src_addr.addr, short_be(tuple->src_port)); - - return 0; -} - -int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr) -{ - struct pico_nat_tuple *tuple = NULL; - struct pico_trans *trans = NULL; - struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr; - - if (!pico_ipv4_nat_is_enabled(link_addr)) - return -1; - - switch (net->proto) { -#ifdef PICO_SUPPORT_TCP - case PICO_PROTO_TCP: - { - struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr; - trans = (struct pico_trans *)&tcp->trans; - tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto); - if (!tuple) - tuple = pico_ipv4_nat_generate_tuple(f); - - /* replace src IP and src PORT */ - net->src = tuple->nat_addr; - trans->sport = tuple->nat_port; - /* recalculate CRC */ - tcp->crc = 0; - tcp->crc = short_be(pico_tcp_checksum_ipv4(f)); - break; - } -#endif -#ifdef PICO_SUPPORT_UDP - case PICO_PROTO_UDP: - { - struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr; - trans = (struct pico_trans *)&udp->trans; - tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto); - if (!tuple) - tuple = pico_ipv4_nat_generate_tuple(f); - - /* replace src IP and src PORT */ - net->src = tuple->nat_addr; - trans->sport = tuple->nat_port; - /* recalculate CRC */ - udp->crc = 0; - udp->crc = short_be(pico_udp_checksum_ipv4(f)); - break; - } -#endif - case PICO_PROTO_ICMP4: - /* XXX reimplement */ - break; - - default: - nat_dbg("NAT ERROR: outbound NAT on erroneous protocol\n"); - return -1; - } - - pico_ipv4_nat_sniff_session(tuple, f, PICO_NAT_OUTBOUND); - net->crc = 0; - net->crc = short_be(pico_checksum(net, f->net_len)); - - nat_dbg("NAT: outbound translation {src.addr, sport}: {%08X,%u} -> {%08X,%u}\n", - tuple->src_addr.addr, short_be(tuple->src_port), tuple->nat_addr.addr, short_be(tuple->nat_port)); - - return 0; -} - -int pico_ipv4_nat_enable(struct pico_ipv4_link *link) -{ - if (link == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - nat_link = link; - pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL); - return 0; -} - -int pico_ipv4_nat_disable(void) -{ - nat_link = NULL; - return 0; -} - -int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr) -{ - if (!nat_link) - return 0; - - if (nat_link->address.addr != link_addr->addr) - return 0; - - return 1; -} - -#endif -#endif diff --git a/ext/picotcp/modules/pico_nat.h b/ext/picotcp/modules/pico_nat.h deleted file mode 100644 index 5237501..0000000 --- a/ext/picotcp/modules/pico_nat.h +++ /dev/null @@ -1,90 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Kristof Roelants, Simon Maes, Brecht Van Cauwenberghe - *********************************************************************/ - -#ifndef INCLUDE_PICO_NAT -#define INCLUDE_PICO_NAT -#include "pico_frame.h" - -#define PICO_NAT_PORT_FORWARD_DEL 0 -#define PICO_NAT_PORT_FORWARD_ADD 1 - -#ifdef PICO_SUPPORT_NAT -void pico_ipv4_nat_print_table(void); -int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto); -int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag); - -int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr); -int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr); -int pico_ipv4_nat_enable(struct pico_ipv4_link *link); -int pico_ipv4_nat_disable(void); -int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr); -#else - -#define pico_ipv4_nat_print_table() do {} while(0) -static inline int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr) -{ - (void)f; - (void)link_addr; - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static inline int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr) -{ - (void)f; - (void)link_addr; - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static inline int pico_ipv4_nat_enable(struct pico_ipv4_link *link) -{ - (void)link; - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static inline int pico_ipv4_nat_disable(void) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static inline int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr) -{ - (void)link_addr; - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static inline int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto) -{ - (void)nat_port; - (void)src_addr; - (void)src_port; - (void)proto; - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static inline int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag) -{ - (void)nat_addr; - (void)nat_port; - (void)src_addr; - (void)src_port; - (void)proto; - (void)flag; - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} -#endif - -#endif /* _INCLUDE_PICO_NAT */ - diff --git a/ext/picotcp/modules/pico_olsr.c b/ext/picotcp/modules/pico_olsr.c deleted file mode 100644 index e5300a9..0000000 --- a/ext/picotcp/modules/pico_olsr.c +++ /dev/null @@ -1,1143 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera - ********************************************************************/ - -#include "pico_stack.h" -#include "pico_config.h" -#include "pico_device.h" -#include "pico_ipv4.h" -#include "pico_arp.h" -#include "pico_socket.h" -#include "pico_olsr.h" -#ifdef PICO_SUPPORT_OLSR -#define DGRAM_MAX_SIZE (100 - 28) -#define MAX_OLSR_MEM (4 * DGRAM_MAX_SIZE) -#define olsr_dbg(...) do {} while(0) - -int OOM(void); - - -#define OLSR_HELLO_INTERVAL ((uint32_t)5000) -#define OLSR_TC_INTERVAL ((uint32_t)9000) -#define OLSR_MAXJITTER ((uint32_t)(OLSR_HELLO_INTERVAL >> 2)) -static const struct pico_ip4 HOST_NETMASK = { - 0xffffffff -}; -#ifndef MIN -# define MIN(a, b) (a < b ? a : b) -#endif - -#define fresher(a, b) ((a > b) || ((b - a) > 32768)) - - -static uint16_t msg_counter; /* Global message sequence number */ - -/* Objects */ -struct olsr_dev_entry -{ - struct olsr_dev_entry *next; - struct pico_device *dev; - uint16_t pkt_counter; -}; - - -/* OLSR Protocol */ -#define OLSRMSG_HELLO 0xc9 -#define OLSRMSG_MID 0x03 -#define OLSRMSG_TC 0xca - -#define OLSRLINK_SYMMETRIC 0x06 -#define OLSRLINK_UNKNOWN 0x08 -#define OLSRLINK_MPR 0x0a - - -#define OLSR_PORT (short_be((uint16_t)698)) - - -/* Headers */ - -PACKED_STRUCT_DEF olsr_link -{ - uint8_t link_code; - uint8_t reserved; - uint16_t link_msg_size; -}; - -PACKED_STRUCT_DEF olsr_neighbor -{ - uint32_t addr; - uint8_t lq; - uint8_t nlq; - uint16_t reserved; -}; - -PACKED_STRUCT_DEF olsr_hmsg_hello -{ - uint16_t reserved; - uint8_t htime; - uint8_t willingness; -}; - -PACKED_STRUCT_DEF olsr_hmsg_tc -{ - uint16_t ansn; - uint16_t reserved; -}; - - -PACKED_STRUCT_DEF olsrmsg -{ - uint8_t type; - uint8_t vtime; - uint16_t size; - struct pico_ip4 orig; - uint8_t ttl; - uint8_t hop; - uint16_t seq; -}; - -PACKED_STRUCT_DEF olsrhdr -{ - uint16_t len; - uint16_t seq; -}; - - - -/* Globals */ -static struct pico_socket *udpsock = NULL; -uint16_t my_ansn = 0; -static struct olsr_route_entry *Local_interfaces = NULL; -static struct olsr_dev_entry *Local_devices = NULL; - -static struct olsr_dev_entry *olsr_get_deventry(struct pico_device *dev) -{ - struct olsr_dev_entry *cur = Local_devices; - while(cur) { - if (cur->dev == dev) - return cur; - - cur = cur->next; - } - return NULL; -} - -struct olsr_route_entry *olsr_get_ethentry(struct pico_device *vif) -{ - struct olsr_route_entry *cur = Local_interfaces; - while(cur) { - if (cur->iface == vif) - return cur; - - cur = cur->next; - } - return NULL; -} - -static struct olsr_route_entry *get_next_hop(struct olsr_route_entry *dst) -{ - struct olsr_route_entry *hop = dst; - while(hop) { - /* olsr_dbg("Finding next hop to %08x m=%d\n", hop->destination.addr, hop->metric); */ - if(hop->metric <= 1) - return hop; - - hop = hop->gateway; - } - return NULL; -} - -static inline void olsr_route_add(struct olsr_route_entry *el) -{ - /* char dest[16],nxdest[16]; */ - struct olsr_route_entry *nexthop; - - if(!el) - return; - - my_ansn++; - - nexthop = get_next_hop(el); - if (el->gateway && nexthop && (nexthop->destination.addr != el->destination.addr)) { - /* 2-hops route or more */ - el->next = el->gateway->children; - el->gateway->children = el; - el->link_type = OLSRLINK_MPR; - olsr_dbg("[OLSR] ----------Adding route to %08x via %08x metric %d\n", el->destination.addr, nexthop->destination.addr, el->metric); - pico_ipv4_route_add(el->destination, HOST_NETMASK, nexthop->destination, (int) el->metric, NULL); - } else if (el->iface) { - /* neighbor */ - struct olsr_route_entry *ei = olsr_get_ethentry(el->iface); - struct pico_ip4 no_gw = { - 0U - }; - if (el->link_type == OLSRLINK_UNKNOWN) - el->link_type = OLSRLINK_SYMMETRIC; - - if (ei) { - el->next = ei->children; - ei->children = el; - } - - olsr_dbg("[OLSR] ----------Adding neighbor %08x iface %s\n", el->destination.addr, el->iface->name); - - pico_ipv4_route_add(el->destination, HOST_NETMASK, no_gw, 1, pico_ipv4_link_by_dev(el->iface)); - } -} - -static inline void olsr_route_del(struct olsr_route_entry *r) -{ - struct olsr_route_entry *cur, *prev = NULL, *lst; - /* olsr_dbg("[OLSR] DELETING route..................\n"); */ - my_ansn++; - if (r->gateway) { - lst = r->gateway->children; - } else if (r->iface) { - lst = olsr_get_ethentry(r->iface); - } else { - lst = Local_interfaces; - } - - cur = lst, prev = NULL; - while(cur) { - if (cur == r) { - /* found */ - if (r->gateway) { - pico_ipv4_route_del(r->destination, HOST_NETMASK, r->metric); - olsr_dbg("[OLSR] Deleting route to %08x \n", r->destination.addr); - if (!prev) - r->gateway->children = r->next; - else - prev->next = r->next; - } - - while (r->children) { - olsr_route_del(r->children); - /* Orphans must die. */ - /* PICO_FREE(r->children); */ - } - return; - } - - prev = cur; - cur = cur->next; - } -} - -static struct olsr_route_entry *get_route_by_address(struct olsr_route_entry *lst, uint32_t ip) -{ - struct olsr_route_entry *found; - if(lst) { - if (lst->destination.addr == ip) { - return lst; - } - - /* recursive function, could be dangerous for stack overflow if a lot of routes are available... */ - found = get_route_by_address(lst->children, ip); - if (found) - return found; - - found = get_route_by_address(lst->next, ip); - if (found) - return found; - } - - return NULL; -} - -#define OLSR_C_SHIFT (uint32_t)4 /* 1/16 */ -#define DEFAULT_VTIME 288UL - -static uint8_t seconds2olsr(uint32_t seconds) -{ - uint16_t a, b; - /* olsr_dbg("seconds=%u\n", (uint16_t)seconds); */ - - if (seconds > 32767) - seconds = 32767; - - /* find largest b such as seconds/C >= 2^b */ - for (b = 1; b <= 0x0fu; b++) { - if ((uint16_t)(seconds * 16u) < (1u << b)) { - b--; - break; - } - } - /* olsr_dbg("b=%u", b); */ - /* compute the expression 16*(T/(C*(2^b))-1), which may not be a - integer, and round it up. This results in the value for 'a' */ - /* a = (T / ( C * (1u << b) ) ) - 1u; */ - { - uint16_t den = ((uint16_t)(1u << b) >> 4u); - /* olsr_dbg(" den=%u ", den); */ - if (den == 0) - { - /* olsr_dbg("div by 0!\n"); */ - den = 1u; - } - - a = (uint16_t)(((uint16_t)seconds / den) - (uint16_t)1); - } - /* a = a & 0x0Fu; */ - - /* olsr_dbg(" a=%u\n", a); */ - - /* if 'a' is equal to 16: increment 'b' by one, and set 'a' to 0 */ - if (16u == a) { - b++; - a = 0u; - } - - return (uint8_t)((a << 4u) + b); -} - -static uint32_t olsr2seconds(uint8_t olsr) -{ - uint8_t a, b; - uint16_t seconds; - /* olsr_dbg("olsr format: %u -- ", olsr); */ - a = (olsr >> 4) & 0xFu; - b = olsr & 0x0f; - /* olsr_dbg("o2s: a=%u, b=%u\n", a,b); */ - if (b < 4) - seconds = (uint16_t)(((1u << b) + (uint16_t)(((uint16_t)(a << b) >> 4u) & 0xFu)) >> OLSR_C_SHIFT); - else - seconds = (uint16_t)(((1u << b) + (uint16_t)(((uint16_t)(a << (b - 4))) & 0xFu)) >> OLSR_C_SHIFT); - - /* olsr_dbg("o2s: seconds: %u\n", seconds); */ - return seconds; -} - -static void olsr_garbage_collector(struct olsr_route_entry *sublist) -{ - if(!sublist) - return; - - if (sublist->time_left <= 0) { - olsr_route_del(sublist); - PICO_FREE(sublist); - return; - } else { - /* sublist->time_left -= 2u; */ - sublist->time_left -= 8u; - } - - olsr_garbage_collector(sublist->children); - olsr_garbage_collector(sublist->next); -} - -struct olsr_fwd_pkt -{ - void *buf; - uint16_t len; - struct pico_device *pdev; -}; - -static uint32_t buffer_mem_used = 0U; - -static void olsr_process_out(pico_time now, void *arg) -{ - struct olsr_fwd_pkt *p = (struct olsr_fwd_pkt *)arg; - struct pico_ip4 bcast; - struct pico_ipv4_link *addr; - struct olsr_dev_entry *pdev = Local_devices; - struct olsrhdr *ohdr; - (void)now; - - /* Send the thing out */ - ohdr = (struct olsrhdr *)p->buf; - ohdr->len = short_be((uint16_t)p->len); - - if (p->pdev) { - struct olsr_dev_entry *odev = olsr_get_deventry(p->pdev); - if (!odev) { - goto out_free; - } - - addr = pico_ipv4_link_by_dev(p->pdev); - if (!addr) - goto out_free; - - ohdr->seq = short_be((uint16_t)(odev->pkt_counter)++); - if (addr->address.addr) - bcast.addr = (addr->netmask.addr & addr->address.addr) | (~addr->netmask.addr); - else - bcast.addr = 0xFFFFFFFFu; - - if ( 0 > pico_socket_sendto(udpsock, p->buf, p->len, &bcast, OLSR_PORT)) { - olsr_dbg("olsr send\n"); - } - } else { - while(pdev) { - ohdr->seq = short_be((uint16_t)(pdev->pkt_counter++)); - addr = pico_ipv4_link_by_dev(pdev->dev); - if (!addr) - continue; - - if (addr->address.addr) - bcast.addr = (addr->netmask.addr & addr->address.addr) | (~addr->netmask.addr); - else - bcast.addr = 0xFFFFFFFFu; - - if ( 0 > pico_socket_sendto(udpsock, p->buf, p->len, &bcast, OLSR_PORT)) { - olsr_dbg("olsr send\n"); - } - - pdev = pdev->next; - } - } - -out_free: - PICO_FREE(p->buf); /* XXX <-- broken? */ - buffer_mem_used -= DGRAM_MAX_SIZE; - PICO_FREE(p); -} - -static void olsr_scheduled_output(uint32_t when, void *buffer, uint16_t size, struct pico_device *pdev) -{ - struct olsr_fwd_pkt *p; - /* olsr_dbg("Scheduling olsr packet, type:%s, size: %x\n", when == OLSR_HELLO_INTERVAL?"HELLO":"TC", size); */ - if ((buffer_mem_used + DGRAM_MAX_SIZE) > MAX_OLSR_MEM) { - PICO_FREE(buffer); - return; - } - - p = PICO_ZALLOC(sizeof(struct olsr_fwd_pkt)); - if (!p) { - OOM(); - PICO_FREE(buffer); - return; - } - - p->buf = buffer; - p->len = size; - p->pdev = pdev; - buffer_mem_used += DGRAM_MAX_SIZE; - pico_timer_add(1 + when - ((pico_rand() % OLSR_MAXJITTER)), &olsr_process_out, p); -} - - -static void refresh_routes(void) -{ - struct olsr_route_entry *local; - struct olsr_dev_entry *icur = Local_devices; - - /* Refresh local entries */ - /* Step 1: set zero expire time for local addresses and neighbors*/ - local = Local_interfaces; - while(local) { - local = local->next; - } - /* Step 2: refresh timer for entries that are still valid. - * Add new entries. - */ - while(icur) { - struct pico_ipv4_link *lnk = NULL; - do { - lnk = pico_ipv4_link_by_dev_next(icur->dev, lnk); - if (!lnk) break; - - local = olsr_get_ethentry(icur->dev); - if (local) { - local->time_left = (OLSR_HELLO_INTERVAL << 2); - } else if (lnk) { - struct olsr_route_entry *e = PICO_ZALLOC(sizeof (struct olsr_route_entry)); - if (!e) { - olsr_dbg("olsr: adding local route entry\n"); - OOM(); - return; - } - - e->destination.addr = lnk->address.addr; /* Always pick the first address */ - e->time_left = (OLSR_HELLO_INTERVAL << 2); - e->iface = icur->dev; - e->metric = 0; - e->lq = 0xFF; - e->nlq = 0xFF; - e->next = Local_interfaces; - Local_interfaces = e; - } - } while (lnk); - - /* disabled if device type != eth */ - /* refresh_neighbors(icur->dev); */ - icur = icur->next; - } -} - -static uint32_t olsr_build_hello_neighbors(uint8_t *buf, uint32_t size, struct olsr_route_entry **bookmark) -{ - uint32_t ret = 0; - struct olsr_route_entry *local, *neighbor; - struct olsr_neighbor *dst = (struct olsr_neighbor *) buf; - uint32_t total_link_size = sizeof(struct olsr_neighbor) + sizeof(struct olsr_link); - local = Local_interfaces; - while (local) { - neighbor = local->children; - if (*bookmark) { - while ((neighbor) && *bookmark != neighbor) - neighbor = neighbor->next; - } - - while (neighbor) { - struct olsr_link *li = (struct olsr_link *) (buf + ret); - - if ((size - ret) < total_link_size) { - /* Incomplete list, new datagram needed. */ - *bookmark = neighbor; - return ret; - } - - li->link_code = neighbor->link_type; - li->reserved = 0; - li->link_msg_size = short_be((uint16_t)total_link_size); - ret += (uint32_t)sizeof(struct olsr_link); - dst = (struct olsr_neighbor *) (buf + ret); - dst->addr = neighbor->destination.addr; - dst->nlq = neighbor->nlq; - dst->lq = neighbor->lq; - dst->reserved = 0; - ret += (uint32_t)sizeof(struct olsr_neighbor); - neighbor = neighbor->next; - } - local = local->next; - } - *bookmark = NULL; /* All the list was visited, no more dgrams needed */ - return ret; -} - -static uint32_t olsr_build_tc_neighbors(uint8_t *buf, uint32_t size, struct olsr_route_entry **bookmark) -{ - uint32_t ret = 0; - struct olsr_route_entry *local, *neighbor; - struct olsr_neighbor *dst = (struct olsr_neighbor *) buf; - local = Local_interfaces; - while (local) { - neighbor = local->children; - if (*bookmark) { - while ((neighbor) && *bookmark != neighbor) - neighbor = neighbor->next; - } - - while (neighbor) { - if (size - ret < sizeof(struct olsr_neighbor)) { - /* Incomplete list, new datagram needed. */ - *bookmark = neighbor; - return ret; - } - - dst->addr = neighbor->destination.addr; - dst->nlq = neighbor->nlq; - dst->lq = neighbor->lq; - dst->reserved = 0; - ret += (uint32_t)sizeof(struct olsr_neighbor); - dst = (struct olsr_neighbor *) (buf + ret); - neighbor = neighbor->next; - } - local = local->next; - } - *bookmark = NULL; /* All the list was visited, no more dgrams needed */ - return ret; -} - -static uint32_t olsr_build_mid(uint8_t *buf, uint32_t size, struct pico_device *excluded) -{ - uint32_t ret = 0; - struct olsr_route_entry *local; - struct pico_ip4 *dst = (struct pico_ip4 *) buf; - local = Local_interfaces; - while (local) { - if (local->iface != excluded) { - dst->addr = local->destination.addr; - ret += (uint32_t)sizeof(uint32_t); - dst = (struct pico_ip4 *) (buf + ret); - if (ret >= size) - return (uint32_t)(ret - sizeof(uint32_t)); - } - - local = local->next; - } - return ret; -} - - -static void olsr_compose_tc_dgram(struct pico_device *pdev, struct pico_ipv4_link *ep) -{ - struct olsrmsg *msg_tc, *msg_mid; - uint32_t size = 0, r; - struct olsr_route_entry *last_neighbor = NULL; - uint8_t *dgram; - struct olsr_hmsg_tc *tc; - do { - dgram = PICO_ZALLOC(DGRAM_MAX_SIZE); - if (!dgram) { - OOM(); - return; - } - - size = (uint32_t)sizeof(struct olsrhdr); - ep = pico_ipv4_link_by_dev(pdev); - if (!ep) { - PICO_FREE(dgram); - return; - } - - - if (!last_neighbor) { - /* MID Message */ - - msg_mid = (struct olsrmsg *)(dgram + size); - size += (uint32_t)sizeof(struct olsrmsg); - msg_mid->type = OLSRMSG_MID; - msg_mid->vtime = seconds2olsr(60); - msg_mid->orig.addr = ep->address.addr; - msg_mid->ttl = 0xFF; - msg_mid->hop = 0; - msg_mid->seq = short_be(msg_counter++); - r = olsr_build_mid(dgram + size, DGRAM_MAX_SIZE - size, pdev); - if (r == 0) { - size -= (uint32_t)sizeof(struct olsrmsg); - } else { - if ((size + r) > DGRAM_MAX_SIZE) - return; - - size += r; - msg_mid->size = short_be((uint16_t)(sizeof(struct olsrmsg) + r)); - } - } - - if (size + sizeof(struct olsrmsg) > DGRAM_MAX_SIZE) - return; - - msg_tc = (struct olsrmsg *) (dgram + size); - size += (uint32_t)sizeof(struct olsrmsg); - msg_tc->type = OLSRMSG_TC; - msg_tc->vtime = seconds2olsr(DEFAULT_VTIME); - msg_tc->orig.addr = ep->address.addr; - msg_tc->ttl = 0xFF; - msg_tc->hop = 0; - msg_tc->seq = short_be(msg_counter++); - tc = (struct olsr_hmsg_tc *)(dgram + size); - size += (uint32_t)sizeof(struct olsr_hmsg_tc); - if (size > DGRAM_MAX_SIZE) - return; - - tc->ansn = short_be(my_ansn); - r = olsr_build_tc_neighbors(dgram + size, DGRAM_MAX_SIZE - size, &last_neighbor); - size += r; - msg_tc->size = short_be((uint16_t)(sizeof(struct olsrmsg) + sizeof(struct olsr_hmsg_tc) + r)); - olsr_scheduled_output(OLSR_TC_INTERVAL, dgram, (uint16_t)size, pdev ); - } while(last_neighbor); -} - -static void olsr_compose_hello_dgram(struct pico_device *pdev, struct pico_ipv4_link *ep) -{ - struct olsrmsg *msg_hello; - uint32_t size = 0, r; - struct olsr_route_entry *last_neighbor = NULL; - uint8_t *dgram; - struct olsr_hmsg_hello *hello; - /* HELLO Message */ - do { - dgram = PICO_ZALLOC(DGRAM_MAX_SIZE); - if (!dgram) { - OOM(); - return; - } - - size = (uint32_t)sizeof(struct olsrhdr); - msg_hello = (struct olsrmsg *) (dgram + size); - size += (uint32_t)sizeof(struct olsrmsg); - msg_hello->type = OLSRMSG_HELLO; - msg_hello->vtime = seconds2olsr(DEFAULT_VTIME); - msg_hello->orig.addr = ep->address.addr; - msg_hello->ttl = 1; - msg_hello->hop = 0; - msg_hello->seq = short_be(msg_counter++); - hello = (struct olsr_hmsg_hello *)(dgram + size); - size += (uint32_t)sizeof(struct olsr_hmsg_hello); - hello->reserved = 0; - hello->htime = seconds2olsr(OLSR_HELLO_INTERVAL); - hello->htime = 0x05; /* Todo: find and define values */ - hello->willingness = 0x07; - if (DGRAM_MAX_SIZE > size) { - r = olsr_build_hello_neighbors(dgram + size, DGRAM_MAX_SIZE - size, &last_neighbor); - if (r == 0) { - /* olsr_dbg("Building hello message\n"); */ - PICO_FREE(dgram); - return; - } - } - - size += r; - msg_hello->size = short_be((uint16_t)(sizeof(struct olsrmsg) + sizeof(struct olsr_hmsg_hello) + r)); - olsr_scheduled_output(OLSR_HELLO_INTERVAL, dgram, (uint16_t)size, pdev ); - } while(last_neighbor); -} - -static void olsr_make_dgram(struct pico_device *pdev, int full) -{ - struct pico_ipv4_link *ep; - ep = pico_ipv4_link_by_dev(pdev); - if (!ep) { - return; - } - - if (!full) { - olsr_compose_hello_dgram(pdev, ep); - } else { - olsr_compose_tc_dgram(pdev, ep); - } /*if full */ - -} - -/* Old code was relying on ethernet arp requests */ -#define arp_storm(...) do {} while(0) - -static void recv_mid(uint8_t *buffer, uint32_t len, struct olsr_route_entry *origin) -{ - uint32_t parsed = 0; - uint32_t *address; - struct olsr_route_entry *e; - - if (len % sizeof(uint32_t)) /*drop*/ - return; - - while (len > parsed) { - address = (uint32_t *)(buffer + parsed); - e = get_route_by_address(Local_interfaces, *address); - if (!e) { - e = PICO_ZALLOC(sizeof(struct olsr_route_entry)); - if (!e) { - olsr_dbg("olsr allocating route\n"); - OOM(); - return; - } - - e->time_left = (OLSR_HELLO_INTERVAL << 2); - e->destination.addr = *address; - e->gateway = origin; - /* e->iface = origin->iface; */ - e->iface = NULL; - e->metric = (uint16_t)(origin->metric + 1u); - e->lq = origin->lq; - e->nlq = origin->nlq; - olsr_route_add(e); - arp_storm(&e->destination); - } else if (e->metric > (origin->metric + 1)) { - olsr_route_del(e); - e->metric = (uint16_t)(origin->metric + 1u); - e->gateway = origin; - e->time_left = (OLSR_HELLO_INTERVAL << 2); - olsr_route_add(e); - } - - parsed += (uint32_t)sizeof(uint32_t); - } -} - -/* static void recv_hello(uint8_t *buffer, uint32_t len, struct olsr_route_entry *origin) */ -static void recv_hello(uint8_t *buffer, uint32_t len, struct olsr_route_entry *origin, uint16_t hops) -{ - struct olsr_link *li; - struct olsr_route_entry *e; - uint32_t parsed = 0; - struct olsr_neighbor *neigh; - - if (!origin) - return; - - /* Don't parse hello messages that were forwarded */ - if (hops > 0 || origin->metric > 1) - return; - - if (pico_ipv4_link_get(&origin->destination)) - return; - - - while (len > parsed) { - li = (struct olsr_link *) buffer; - neigh = (struct olsr_neighbor *)(buffer + parsed + sizeof(struct olsr_link)); - parsed += short_be(li->link_msg_size); - e = get_route_by_address(Local_interfaces, neigh->addr); - if (!e) { - e = PICO_ZALLOC(sizeof(struct olsr_route_entry)); - if (!e) { - olsr_dbg("olsr allocating route\n"); - OOM(); - return; - } - - e->time_left = (OLSR_HELLO_INTERVAL << 2); - e->destination.addr = neigh->addr; - e->gateway = origin; - e->iface = NULL; - e->metric = (uint16_t)(origin->metric + hops + 1); - e->link_type = OLSRLINK_UNKNOWN; - e->lq = MIN(origin->lq, neigh->lq); - e->nlq = MIN(origin->nlq, neigh->nlq); - olsr_route_add(e); - arp_storm(&e->destination); - } else if ((e->gateway != origin) && (origin->metric > 1) && (e->metric > (origin->metric + hops + 1))) { - olsr_route_del(e); - e->metric = (uint16_t)(origin->metric + hops + 1); - e->gateway = origin; - e->time_left = (OLSR_HELLO_INTERVAL << 2); - olsr_route_add(e); - } else { - e->time_left = (OLSR_HELLO_INTERVAL << 2); - } - } -} - -/* static uint32_t reconsider_topology(uint8_t *buf, uint32_t size, struct olsr_route_entry *e) */ -static uint32_t reconsider_topology(uint8_t *buf, uint32_t size, struct olsr_route_entry *e) -{ - struct olsr_hmsg_tc *tc = (struct olsr_hmsg_tc *) buf; - uint16_t new_ansn = short_be(tc->ansn); - uint32_t parsed = sizeof(struct olsr_hmsg_tc); - struct olsr_route_entry *rt; - struct olsr_neighbor *n; - uint32_t retval = 0; - - if (!e->advertised_tc) - retval = 1; - - if (e->advertised_tc && fresher(new_ansn, e->ansn)) - { - PICO_FREE(e->advertised_tc); /* <--- XXX check invalid free? */ - e->advertised_tc = NULL; - retval = 1; - } - - /* Ignore self packets */ - if (pico_ipv4_link_get(&e->destination)) - return 0; - - if (!e->advertised_tc) { - e->advertised_tc = PICO_ZALLOC(size); - if (!e->advertised_tc) { - OOM(); - olsr_dbg("Allocating forward packet\n"); - return 0; - } - - memcpy(e->advertised_tc, buf, size); - e->ansn = new_ansn; - while (parsed < size) { - n = (struct olsr_neighbor *) (buf + parsed); - parsed += (uint32_t)sizeof(struct olsr_neighbor); - rt = get_route_by_address(Local_interfaces, n->addr); - if (rt && (rt->gateway == e)) { - /* Refresh existing node */ - rt->time_left = e->time_left; - } else if (!rt || (rt->metric > (e->metric + 1)) || (rt->nlq < n->nlq)) { - if (!rt) { - rt = PICO_ZALLOC(sizeof (struct olsr_route_entry)); - if (!rt) { - OOM(); - return retval; - } - - rt->destination.addr = n->addr; - rt->link_type = OLSRLINK_UNKNOWN; - } else { - olsr_route_del(rt); - } - - rt->iface = e->iface; - rt->gateway = e; - rt->metric = (uint16_t)(e->metric + 1); - rt->lq = n->lq; /* 0xff */ - rt->nlq = n->nlq; /* 0xff */ - rt->time_left = e->time_left; /* 256 */ - olsr_route_add(rt); - } - } - /* olsr_dbg("Routes changed...\n"); */ - } - - return retval; -} - - -static void olsr_recv(uint8_t *buffer, uint32_t len) -{ - struct olsrmsg *msg; - struct olsrhdr *oh = (struct olsrhdr *) buffer; - struct olsr_route_entry *ancestor; - uint32_t parsed = 0; - uint16_t outsize = 0; - uint8_t *datagram; - - if (len != short_be(oh->len)) { - return; - } - - /* RFC 3626, section 3.4, if a packet is too small, it is silently discarded */ - if (len < 16) { - return; - } - - parsed += (uint32_t)sizeof(struct olsrhdr); - - datagram = PICO_ZALLOC(DGRAM_MAX_SIZE); - if (!datagram) { - OOM(); - return; - } - - outsize = (uint16_t) (outsize + (sizeof(struct olsrhdr))); - /* Section 1: parsing received messages. */ - while (len > parsed) { - struct olsr_route_entry *origin; - msg = (struct olsrmsg *) (buffer + parsed); - origin = get_route_by_address(Local_interfaces, msg->orig.addr); - - if(pico_ipv4_link_find(&msg->orig) != NULL) { - /* olsr_dbg("rebound\n"); */ - parsed += short_be(msg->size); - continue; - } - - /* OLSR's TTL expired. */ - if (msg->ttl < 1u) { - parsed += short_be(msg->size); - continue; - } - - if (!origin) { - if (msg->hop == 0) { - struct olsr_route_entry *e = PICO_ZALLOC(sizeof (struct olsr_route_entry)); - if (!e) { - parsed += short_be(msg->size); - OOM(); - break; - } - - e->destination.addr = msg->orig.addr; - e->link_type = OLSRLINK_SYMMETRIC; - e->time_left = (OLSR_HELLO_INTERVAL << 2); - e->iface = Local_devices->dev; - e->gateway = olsr_get_ethentry(e->iface); - e->metric = 1; - e->lq = 0xFF; - e->nlq = 0xFF; - olsr_route_add(e); - } - - parsed += short_be(msg->size); - continue; - } - - /* We know this is a Master host and a neighbor */ - origin->link_type = OLSRLINK_MPR; - origin->time_left = olsr2seconds(msg->vtime); - switch(msg->type) { - case OLSRMSG_HELLO: - ancestor = olsr_get_ethentry(origin->iface); - if ((origin->metric > 1) && ancestor) { - olsr_route_del(origin); - origin->gateway = ancestor; - origin->metric = 1; - olsr_route_add(origin); - } - - recv_hello(buffer + (uint32_t)parsed + (uint32_t)sizeof(struct olsrmsg) + (uint32_t)sizeof(struct olsr_hmsg_hello), - (uint32_t) ((short_be(msg->size) - (sizeof(struct olsrmsg))) - (uint32_t)sizeof(struct olsr_hmsg_hello)), - origin, msg->hop); - msg->ttl = 0; - break; - case OLSRMSG_MID: - if ((origin->seq != 0) && (!fresher(short_be(msg->seq), origin->seq))) { - msg->ttl = 0; - } else { - recv_mid(buffer + parsed + sizeof(struct olsrmsg), (uint32_t)(short_be(msg->size) - (sizeof(struct olsrmsg))), origin); - /* olsr_dbg("MID forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */ - origin->seq = short_be(msg->seq); - } - - break; - case OLSRMSG_TC: - if(!pico_ipv4_link_find(&origin->destination)) { - reconsider_topology(buffer + parsed + sizeof(struct olsrmsg), (uint32_t)(short_be(msg->size) - (sizeof(struct olsrmsg))), origin); - if ((origin->seq != 0) && (!fresher(short_be(msg->seq), origin->seq))) { - msg->ttl = 0; - } else { - /* olsr_dbg("TC forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */ - origin->seq = short_be(msg->seq); - } - } - - break; - default: - PICO_FREE(datagram); - return; - } - - if (msg->ttl > 1) { - msg->hop++; - msg->ttl--; - memcpy(datagram + outsize, msg, short_be(msg->size)); - outsize = (uint16_t)(outsize + short_be(msg->size)); - } - - parsed += short_be(msg->size); - } - /* Section 2: forwarding parsed messages that got past the filter. */ - if ((outsize > sizeof(struct olsrhdr))) { - /* Finalize FWD packet */ - olsr_scheduled_output(OLSR_MAXJITTER, datagram, outsize, NULL); - } else { - /* Nothing to forward. */ - PICO_FREE(datagram); - } -} - -static void wakeup(uint16_t ev, struct pico_socket *s) -{ - unsigned char *recvbuf; - int r = 0; - struct pico_ip4 ANY = { - 0 - }; - uint16_t port = OLSR_PORT; - recvbuf = PICO_ZALLOC(DGRAM_MAX_SIZE); - if (!recvbuf) { - OOM(); - return; - } - - if (ev & PICO_SOCK_EV_RD) { - r = pico_socket_recv(s, recvbuf, DGRAM_MAX_SIZE); - if (r > 0) - olsr_recv(recvbuf, (uint32_t)r); - } - - if (ev == PICO_SOCK_EV_ERR) { - pico_socket_close(udpsock); - udpsock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &wakeup); - if (udpsock) - pico_socket_bind(udpsock, &ANY, &port); - } - - PICO_FREE(recvbuf); -} - -static void olsr_hello_tick(pico_time when, void *unused) -{ - struct olsr_dev_entry *d; - (void)when; - (void)unused; - olsr_garbage_collector(Local_interfaces); - refresh_routes(); - d = Local_devices; - while(d) { - olsr_make_dgram(d->dev, 0); - d = d->next; - } - pico_timer_add(OLSR_HELLO_INTERVAL, &olsr_hello_tick, NULL); -} - -static void olsr_tc_tick(pico_time when, void *unused) -{ - struct olsr_dev_entry *d; - (void)when; - (void)unused; - d = Local_devices; - while(d) { - olsr_make_dgram(d->dev, 1); - d = d->next; - } - pico_timer_add(OLSR_TC_INTERVAL, &olsr_tc_tick, NULL); -} - - -/* Public interface */ - -void pico_olsr_init(void) -{ - struct pico_ip4 ANY = { - 0 - }; - uint16_t port = OLSR_PORT; - olsr_dbg("OLSR initialized.\n"); - if (!udpsock) { - udpsock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &wakeup); - if (udpsock) - pico_socket_bind(udpsock, &ANY, &port); - } - - pico_timer_add(pico_rand() % 100, &olsr_hello_tick, NULL); - pico_timer_add(pico_rand() % 900, &olsr_tc_tick, NULL); -} - - -int OOM(void) -{ - volatile int c = 3600; - c++; - c++; - c++; - return -1; -} - -int pico_olsr_add(struct pico_device *dev) -{ - struct pico_ipv4_link *lnk = NULL; - struct olsr_dev_entry *od; - - - if (!dev) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* olsr_dbg("OLSR: Adding device %s\n", dev->name); */ - od = PICO_ZALLOC(sizeof(struct olsr_dev_entry)); - if (!od) { - pico_err = PICO_ERR_ENOMEM; - /* OOM(); */ - return -1; - } - - od->dev = dev; - od->next = Local_devices; - Local_devices = od; - - do { - char ipaddr[20]; - lnk = pico_ipv4_link_by_dev_next(dev, lnk); - if (lnk) { - struct olsr_route_entry *e = PICO_ZALLOC(sizeof(struct olsr_route_entry)); - /* olsr_dbg("OLSR: Found IP address %08x\n", long_be(lnk->address.addr)); */ - pico_ipv4_to_string(ipaddr, (lnk->address.addr)); - /* olsr_dbg("OLSR: Found IP address %s\n", ipaddr); */ - if (!e) { - olsr_dbg("olsr allocating route\n"); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - e->destination.addr = lnk->address.addr; - e->link_type = OLSRLINK_SYMMETRIC; - e->time_left = (OLSR_HELLO_INTERVAL << 2); - e->gateway = NULL; - e->children = NULL; - e->iface = dev; - e->metric = 0; - e->lq = 0xFF; - e->nlq = 0xFF; - e->next = Local_interfaces; - Local_interfaces = e; - - } - } while(lnk); - - return 0; -} - -#endif diff --git a/ext/picotcp/modules/pico_olsr.h b/ext/picotcp/modules/pico_olsr.h deleted file mode 100644 index 11c3bf0..0000000 --- a/ext/picotcp/modules/pico_olsr.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera - *********************************************************************/ -#ifndef PICO_OLSR_H -#define PICO_OLSR_H - - -/* Objects */ -struct olsr_route_entry -{ - struct olsr_route_entry *next; - uint32_t time_left; - struct pico_ip4 destination; - struct olsr_route_entry *gateway; - struct pico_device *iface; - uint16_t metric; - uint8_t link_type; - struct olsr_route_entry *children; - uint16_t ansn; - uint16_t seq; - uint8_t lq, nlq; - uint8_t *advertised_tc; -}; - - -void pico_olsr_init(void); -int pico_olsr_add(struct pico_device *dev); -struct olsr_route_entry *olsr_get_ethentry(struct pico_device *vif); -#endif diff --git a/ext/picotcp/modules/pico_posix.c b/ext/picotcp/modules/pico_posix.c deleted file mode 100644 index 4820b12..0000000 --- a/ext/picotcp/modules/pico_posix.c +++ /dev/null @@ -1,99 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Andrei Carp, Maarten Vandersteegen - *********************************************************************/ - -#ifdef PICO_SUPPORT_THREADING - -#include -#include -#include "pico_config.h" - -/* POSIX mutex implementation */ -void *pico_mutex_init(void) -{ - pthread_mutex_t *m; - m = (pthread_mutex_t *)PICO_ZALLOC(sizeof(pthread_mutex_t)); - pthread_mutex_init(m, NULL); - return m; -} - -void pico_mutex_destroy(void *mux) -{ - PICO_FREE(mux); - mux = NULL; -} - -void pico_mutex_lock(void *mux) -{ - if (mux == NULL) return; - - pthread_mutex_t *m = (pthread_mutex_t *)mux; - pthread_mutex_lock(m); -} - -void pico_mutex_unlock(void *mux) -{ - if (mux == NULL) return; - - pthread_mutex_t *m = (pthread_mutex_t *)mux; - pthread_mutex_unlock(m); -} - -/* POSIX semaphore implementation */ -void *pico_sem_init(void) -{ - sem_t *s; - s = (sem_t *)PICO_ZALLOC(sizeof(sem_t)); - sem_init(s, 0, 0); - return s; -} - -void pico_sem_destroy(void *sem) -{ - PICO_FREE(sem); - sem = NULL; -} - -void pico_sem_post(void *sem) -{ - if (sem == NULL) return; - - sem_t *s = (sem_t *)sem; - sem_post(s); -} - -int pico_sem_wait(void *sem, int timeout) -{ - struct timespec t; - if (sem == NULL) return 0; - - sem_t *s = (sem_t *)sem; - - if (timeout < 0) { - sem_wait(s); - } else { - clock_gettime(CLOCK_REALTIME, &t); - t.tv_sec += timeout / 1000; - t.tv_nsec += (timeout % 1000) * 1000000; - if (sem_timedwait(s, &t) == -1) - return -1; - } - - return 0; -} - -/* POSIX thread implementation */ -void *pico_thread_create(void *(*routine)(void *), void *arg) -{ - pthread_t *thread; - thread = (pthread_t *)PICO_ZALLOC(sizeof(pthread_t)); - - if (pthread_create(thread, NULL, routine, arg) == -1) - return NULL; - - return thread; -} -#endif /* PICO_SUPPORT_THREADING */ diff --git a/ext/picotcp/modules/pico_slaacv4.c b/ext/picotcp/modules/pico_slaacv4.c deleted file mode 100644 index f9ac216..0000000 --- a/ext/picotcp/modules/pico_slaacv4.c +++ /dev/null @@ -1,266 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Bogdan Lupu - *********************************************************************/ -#include "pico_slaacv4.h" -#include "pico_arp.h" -#include "pico_constants.h" -#include "pico_stack.h" -#include "pico_hotplug_detection.h" - -#ifdef PICO_SUPPORT_SLAACV4 - -#define SLAACV4_NETWORK ((long_be(0xa9fe0000))) -#define SLAACV4_NETMASK ((long_be(0xFFFF0000))) -#define SLAACV4_MINRANGE (0x00000100) /* In host order */ -#define SLAACV4_MAXRANGE (0x0000FDFF) /* In host order */ - -#define SLAACV4_CREATE_IPV4(seed) ((long_be((seed % SLAACV4_MAXRANGE) + SLAACV4_MINRANGE) & ~SLAACV4_NETMASK) | SLAACV4_NETWORK) - -#define PROBE_WAIT 1 /* delay between two tries during claim */ -#define PROBE_NB 3 /* number of probe packets during claim */ -/* #define PROBE_MIN 1 */ -/* #define PROBE_MAX 2 */ -#define ANNOUNCE_WAIT 2 /* delay before start announcing */ -#define ANNOUNCE_NB 2 /* number of announcement packets */ -#define ANNOUNCE_INTERVAL 2 /* time between announcement packets */ -#define MAX_CONFLICTS 10 /* max conflicts before rate limiting */ -#define MAX_CONFLICTS_FAIL 20 /* max conflicts before declaring failure */ -#define RATE_LIMIT_INTERVAL 60 /* time between successive attempts */ -#define DEFEND_INTERVAL 10 /* minimum interval between defensive ARP */ - -enum slaacv4_state { - SLAACV4_RESET = 0, - SLAACV4_CLAIMING, - SLAACV4_CLAIMED, - SLAACV4_ANNOUNCING, - SLAACV4_ERROR -}; - -struct slaacv4_cookie { - enum slaacv4_state state; - uint8_t probe_try_nb; - uint8_t conflict_nb; - uint8_t announce_nb; - struct pico_ip4 ip; - struct pico_device *device; - uint32_t timer; - void (*cb)(struct pico_ip4 *ip, uint8_t code); -}; - -static void pico_slaacv4_hotplug_cb(struct pico_device *dev, int event); - -static struct slaacv4_cookie slaacv4_local; - -static uint32_t pico_slaacv4_getip(struct pico_device *dev, uint8_t rand) -{ - uint32_t seed = 0; - if (dev->eth != NULL) - { - seed = pico_hash((const uint8_t *)dev->eth->mac.addr, PICO_SIZE_ETH); - } - - if (rand) - { - seed += pico_rand(); - } - - return SLAACV4_CREATE_IPV4(seed); -} - -static void pico_slaacv4_init_cookie(struct pico_ip4 *ip, struct pico_device *dev, struct slaacv4_cookie *ck, void (*cb)(struct pico_ip4 *ip, uint8_t code)) -{ - ck->state = SLAACV4_RESET; - ck->probe_try_nb = 0; - ck->conflict_nb = 0; - ck->announce_nb = 0; - ck->cb = cb; - ck->device = dev; - ck->ip.addr = ip->addr; - ck->timer = 0; -} - -static void pico_slaacv4_cancel_timers(struct slaacv4_cookie *tmp) -{ - pico_timer_cancel(tmp->timer); - tmp->timer = 0; -} - -static void pico_slaacv4_send_announce_timer(pico_time now, void *arg) -{ - struct slaacv4_cookie *tmp = (struct slaacv4_cookie *)arg; - struct pico_ip4 netmask = { 0 }; - netmask.addr = long_be(0xFFFF0000); - - (void)now; - - if (tmp->announce_nb < ANNOUNCE_NB) - { - pico_arp_request(tmp->device, &tmp->ip, PICO_ARP_ANNOUNCE); - tmp->announce_nb++; - tmp->timer = pico_timer_add(ANNOUNCE_INTERVAL * 1000, pico_slaacv4_send_announce_timer, arg); - } - else - { - tmp->state = SLAACV4_CLAIMED; - pico_ipv4_link_add(tmp->device, tmp->ip, netmask); - if (tmp->cb != NULL) - tmp->cb(&tmp->ip, PICO_SLAACV4_SUCCESS); - } -} - -static void pico_slaacv4_send_probe_timer(pico_time now, void *arg) -{ - struct slaacv4_cookie *tmp = (struct slaacv4_cookie *)arg; - (void)now; - - if (tmp->probe_try_nb < PROBE_NB) - { - pico_arp_request(tmp->device, &tmp->ip, PICO_ARP_PROBE); - tmp->probe_try_nb++; - tmp->timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, tmp); - } - else - { - tmp->state = SLAACV4_ANNOUNCING; - tmp->timer = pico_timer_add(ANNOUNCE_WAIT * 1000, pico_slaacv4_send_announce_timer, arg); - } -} - -static void pico_slaacv4_receive_ipconflict(int reason) -{ - struct slaacv4_cookie *tmp = &slaacv4_local; - - tmp->conflict_nb++; - pico_slaacv4_cancel_timers(tmp); - - if(tmp->state == SLAACV4_CLAIMED) - { - if(reason == PICO_ARP_CONFLICT_REASON_CONFLICT) - { - pico_ipv4_link_del(tmp->device, tmp->ip); - } - } - - if (tmp->conflict_nb < MAX_CONFLICTS) - { - tmp->state = SLAACV4_CLAIMING; - tmp->probe_try_nb = 0; - tmp->announce_nb = 0; - tmp->ip.addr = pico_slaacv4_getip(tmp->device, (uint8_t)1); - pico_arp_register_ipconflict(&tmp->ip, &tmp->device->eth->mac, pico_slaacv4_receive_ipconflict); - pico_arp_request(tmp->device, &tmp->ip, PICO_ARP_PROBE); - tmp->probe_try_nb++; - tmp->timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, tmp); - } - else if (tmp->conflict_nb < MAX_CONFLICTS_FAIL) - { - tmp->state = SLAACV4_CLAIMING; - tmp->probe_try_nb = 0; - tmp->announce_nb = 0; - tmp->ip.addr = pico_slaacv4_getip(tmp->device, (uint8_t)1); - pico_arp_register_ipconflict(&tmp->ip, &tmp->device->eth->mac, pico_slaacv4_receive_ipconflict); - tmp->timer = pico_timer_add(RATE_LIMIT_INTERVAL * 1000, pico_slaacv4_send_probe_timer, tmp); - } - else - { - if (tmp->cb != NULL) - { - pico_hotplug_deregister(tmp->device, &pico_slaacv4_hotplug_cb); - tmp->cb(&tmp->ip, PICO_SLAACV4_ERROR); - } - - tmp->state = SLAACV4_ERROR; - } - -} - -static void pico_slaacv4_hotplug_cb(__attribute__((unused)) struct pico_device *dev, int event) -{ - struct slaacv4_cookie *tmp = &slaacv4_local; - - if (event == PICO_HOTPLUG_EVENT_UP ) - { - slaacv4_local.state = SLAACV4_CLAIMING; - tmp->probe_try_nb = 0; - tmp->announce_nb = 0; - - pico_arp_register_ipconflict(&tmp->ip, &tmp->device->eth->mac, pico_slaacv4_receive_ipconflict); - pico_arp_request(tmp->device, &tmp->ip, PICO_ARP_PROBE); - tmp->probe_try_nb++; - tmp->timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, tmp); - - } - else - { - if (tmp->state == SLAACV4_CLAIMED ) - pico_ipv4_link_del(tmp->device, tmp->ip); - pico_slaacv4_cancel_timers(tmp); - } -} - -int pico_slaacv4_claimip(struct pico_device *dev, void (*cb)(struct pico_ip4 *ip, uint8_t code)) -{ - struct pico_ip4 ip; - - if (!dev->eth) { - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - } - - if( dev->link_state != NULL ) - { - //hotplug detect will work - - ip.addr = pico_slaacv4_getip(dev, 0); - pico_slaacv4_init_cookie(&ip, dev, &slaacv4_local, cb); - - if (pico_hotplug_register(dev, &pico_slaacv4_hotplug_cb)) - { - return -1; - } - if (dev->link_state(dev) == 1) - { - pico_arp_register_ipconflict(&ip, &dev->eth->mac, pico_slaacv4_receive_ipconflict); - pico_arp_request(dev, &ip, PICO_ARP_PROBE); - slaacv4_local.state = SLAACV4_CLAIMING; - slaacv4_local.probe_try_nb++; - slaacv4_local.timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, &slaacv4_local); - } - } - else - { - ip.addr = pico_slaacv4_getip(dev, 0); - - pico_slaacv4_init_cookie(&ip, dev, &slaacv4_local, cb); - pico_arp_register_ipconflict(&ip, &dev->eth->mac, pico_slaacv4_receive_ipconflict); - pico_arp_request(dev, &ip, PICO_ARP_PROBE); - slaacv4_local.state = SLAACV4_CLAIMING; - slaacv4_local.probe_try_nb++; - slaacv4_local.timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, &slaacv4_local); - } - - return 0; -} - -void pico_slaacv4_unregisterip(void) -{ - struct slaacv4_cookie *tmp = &slaacv4_local; - struct pico_ip4 empty = { - .addr = 0x00000000 - }; - - if (tmp->state == SLAACV4_CLAIMED) - { - pico_ipv4_link_del(tmp->device, tmp->ip); - } - - pico_slaacv4_cancel_timers(tmp); - pico_slaacv4_init_cookie(&empty, NULL, tmp, NULL); - pico_arp_register_ipconflict(&tmp->ip, NULL, NULL); - pico_hotplug_deregister(tmp->device, &pico_slaacv4_hotplug_cb); -} - -#endif diff --git a/ext/picotcp/modules/pico_slaacv4.h b/ext/picotcp/modules/pico_slaacv4.h deleted file mode 100644 index d90ef65..0000000 --- a/ext/picotcp/modules/pico_slaacv4.h +++ /dev/null @@ -1,18 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Bogdan Lupu - *********************************************************************/ -#ifndef INCLUDE_PICO_SUPPORT_SLAACV4 -#define INCLUDE_PICO_SUPPORT_SLAACV4 -#include "pico_arp.h" - -#define PICO_SLAACV4_SUCCESS 0 -#define PICO_SLAACV4_ERROR 1 - -int pico_slaacv4_claimip(struct pico_device *dev, void (*cb)(struct pico_ip4 *ip, uint8_t code)); -void pico_slaacv4_unregisterip(void); - -#endif /* _INCLUDE_PICO_SUPPORT_SLAACV4 */ - diff --git a/ext/picotcp/modules/pico_sntp_client.c b/ext/picotcp/modules/pico_sntp_client.c deleted file mode 100644 index 10fa0af..0000000 --- a/ext/picotcp/modules/pico_sntp_client.c +++ /dev/null @@ -1,395 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Author: Toon Stegen - *********************************************************************/ -#include "pico_sntp_client.h" -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_addressing.h" -#include "pico_socket.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_dns_client.h" -#include "pico_tree.h" -#include "pico_stack.h" - -#ifdef PICO_SUPPORT_SNTP_CLIENT - -#define sntp_dbg(...) do {} while(0) -/* #define sntp_dbg dbg */ - -#define SNTP_VERSION 4 -#define PICO_SNTP_MAXBUF (1400) - -/* Sntp mode */ -#define SNTP_MODE_CLIENT 3 - -/* SNTP conversion parameters */ -#define SNTP_FRAC_TO_PICOSEC (4294967llu) -#define SNTP_THOUSAND (1000llu) -#define SNTP_UNIX_OFFSET (2208988800llu) /* nr of seconds from 1900 to 1970 */ -#define SNTP_BITMASK (0X00000000FFFFFFFF) /* mask to convert from 64 to 32 */ - -PACKED_STRUCT_DEF pico_sntp_ts -{ - uint32_t sec; /* Seconds */ - uint32_t frac; /* Fraction */ -}; - -PACKED_STRUCT_DEF pico_sntp_header -{ - uint8_t mode : 3; /* Mode */ - uint8_t vn : 3; /* Version number */ - uint8_t li : 2; /* Leap indicator */ - uint8_t stratum; /* Stratum */ - uint8_t poll; /* Poll, only significant in server messages */ - uint8_t prec; /* Precision, only significant in server messages */ - int32_t rt_del; /* Root delay, only significant in server messages */ - int32_t rt_dis; /* Root dispersion, only significant in server messages */ - int32_t ref_id; /* Reference clock ID, only significant in server messages */ - struct pico_sntp_ts ref_ts; /* Reference time stamp */ - struct pico_sntp_ts orig_ts; /* Originate time stamp */ - struct pico_sntp_ts recv_ts; /* Receive time stamp */ - struct pico_sntp_ts trs_ts; /* Transmit time stamp */ - -}; - -struct sntp_server_ns_cookie -{ - int rec; /* Indicates wheter an sntp packet has been received */ - uint16_t proto; /* IPV4 or IPV6 prototype */ - pico_time stamp; /* Timestamp of the moment the sntp packet is sent */ - char *hostname; /* Hostname of the (s)ntp server*/ - struct pico_socket *sock; /* Socket which contains the cookie */ - void (*cb_synced)(pico_err_t status); /* Callback function for telling the user - wheter/when the time is synchronised */ - uint32_t timer; /* Timer that will signal timeout */ -}; - -/* global variables */ -static uint16_t sntp_port = 123u; -static struct pico_timeval server_time = { - 0 -}; -static pico_time tick_stamp = 0ull; -static union pico_address sntp_inaddr_any = { - .ip6.addr = { 0 } -}; - -/*************************************************************************/ - -/* Converts a sntp time stamp to a pico_timeval struct */ -static int timestamp_convert(const struct pico_sntp_ts *ts, struct pico_timeval *tv, pico_time delay) -{ - if(long_be(ts->sec) < SNTP_UNIX_OFFSET) { - pico_err = PICO_ERR_EINVAL; - tv->tv_sec = 0; - tv->tv_msec = 0; - sntp_dbg("Error: input too low\n"); - return -1; - } - - sntp_dbg("Delay: %llu\n", delay); - tv->tv_msec = (pico_time) (((uint32_t)(long_be(ts->frac))) / SNTP_FRAC_TO_PICOSEC + delay); - tv->tv_sec = (pico_time) (long_be(ts->sec) - SNTP_UNIX_OFFSET + (uint32_t)tv->tv_msec / SNTP_THOUSAND); - tv->tv_msec = (uint32_t) (tv->tv_msec & SNTP_BITMASK) % SNTP_THOUSAND; - sntp_dbg("Converted time stamp: %llusec, %llumsec\n", tv->tv_sec, tv->tv_msec); - return 0; -} - -/* Cleanup function that is called when the time is synced or an error occured */ -static void pico_sntp_cleanup(struct sntp_server_ns_cookie *ck, pico_err_t status) -{ - sntp_dbg("Cleanup called\n"); - if(!ck) - return; - - ck->cb_synced(status); - if(ck->sock) - ck->sock->priv = NULL; - - sntp_dbg("FREE!\n"); - PICO_FREE(ck->hostname); - PICO_FREE(ck); - -} - -/* Extracts the current time from a server sntp packet*/ -static int pico_sntp_parse(char *buf, struct sntp_server_ns_cookie *ck) -{ - int ret = 0; - struct pico_sntp_header *hp = (struct pico_sntp_header*) buf; - - if(!ck) { - sntp_dbg("pico_sntp_parse: invalid cookie\n"); - return -1; - } - - sntp_dbg("Received mode: %u, version: %u, stratum: %u\n", hp->mode, hp->vn, hp->stratum); - - tick_stamp = pico_tick; - /* tick_stamp - ck->stamp is the delay between sending and receiving the ntp packet */ - ret = timestamp_convert(&(hp->trs_ts), &server_time, (tick_stamp - ck->stamp) / 2); - if(ret != 0) { - sntp_dbg("Conversion error!\n"); - pico_sntp_cleanup(ck, PICO_ERR_EINVAL); - return ret; - } - - sntp_dbg("Server time: %llu seconds and %llu milisecs since 1970\n", server_time.tv_sec, server_time.tv_msec); - - /* Call back the user saying the time is synced */ - pico_sntp_cleanup(ck, PICO_ERR_NOERR); - return ret; -} - -/* callback for UDP socket events */ -static void pico_sntp_client_wakeup(uint16_t ev, struct pico_socket *s) -{ - struct sntp_server_ns_cookie *ck = (struct sntp_server_ns_cookie *)s->priv; - char *recvbuf; - int read = 0; - uint32_t peer; - uint16_t port; - - if(!ck) { - sntp_dbg("pico_sntp_client_wakeup: invalid cookie\n"); - return; - } - - /* process read event, data available */ - if (ev == PICO_SOCK_EV_RD) { - ck->rec = 1; - /* receive while data available in socket buffer */ - recvbuf = PICO_ZALLOC(PICO_SNTP_MAXBUF); - if (!recvbuf) - return; - - do { - read = pico_socket_recvfrom(s, recvbuf, PICO_SNTP_MAXBUF, &peer, &port); - } while(read > 0); - pico_sntp_parse(recvbuf, s->priv); - pico_timer_cancel(ck->timer); - PICO_FREE(recvbuf); - } - /* socket is closed */ - else if(ev == PICO_SOCK_EV_CLOSE) { - sntp_dbg("Socket is closed. Bailing out.\n"); - pico_sntp_cleanup(ck, PICO_ERR_ENOTCONN); - return; - } - /* process error event, socket error occured */ - else if(ev == PICO_SOCK_EV_ERR) { - sntp_dbg("Socket Error received. Bailing out.\n"); - pico_sntp_cleanup(ck, PICO_ERR_ENOTCONN); - return; - } - - sntp_dbg("Received data from %08X:%u\n", peer, port); -} - -/* Function that is called after the receive timer expires */ -static void sntp_receive_timeout(pico_time now, void *arg) -{ - struct sntp_server_ns_cookie *ck = (struct sntp_server_ns_cookie *)arg; - (void) now; - - if(!ck) { - sntp_dbg("sntp_timeout: invalid cookie\n"); - return; - } - - if(!ck->rec) { - pico_sntp_cleanup(ck, PICO_ERR_ETIMEDOUT); - } -} - -/* Sends an sntp packet on sock to dst*/ -static void pico_sntp_send(struct pico_socket *sock, union pico_address *dst) -{ - struct pico_sntp_header header = { - 0 - }; - struct sntp_server_ns_cookie *ck = (struct sntp_server_ns_cookie *)sock->priv; - - if(!ck) { - sntp_dbg("pico_sntp_sent: invalid cookie\n"); - return; - } - - ck->timer = pico_timer_add(5000, sntp_receive_timeout, ck); - header.vn = SNTP_VERSION; - header.mode = SNTP_MODE_CLIENT; - /* header.trs_ts.frac = long_be(0ul); */ - ck->stamp = pico_tick; - pico_socket_sendto(sock, &header, sizeof(header), dst, short_be(sntp_port)); -} - -/* used for getting a response from DNS servers */ -static void dnsCallback(char *ip, void *arg) -{ - struct sntp_server_ns_cookie *ck = (struct sntp_server_ns_cookie *)arg; - union pico_address address; - struct pico_socket *sock; - int retval = -1; - uint16_t any_port = 0; - - if(!ck) { - sntp_dbg("dnsCallback: Invalid argument\n"); - return; - } - - if (0) { - - } -#ifdef PICO_SUPPORT_IPV6 - else if(ck->proto == PICO_PROTO_IPV6) { - if (ip) { - /* add the ip address to the client, and start a tcp connection socket */ - sntp_dbg("using IPv6 address: %s\n", ip); - retval = pico_string_to_ipv6(ip, address.ip6.addr); - } else { - sntp_dbg("Invalid query response for AAAA\n"); - retval = -1; - pico_sntp_cleanup(ck, PICO_ERR_ENETDOWN); - } - } - -#endif -#ifdef PICO_SUPPORT_IPV4 - else if(ck->proto == PICO_PROTO_IPV4) { - if(ip) { - sntp_dbg("using IPv4 address: %s\n", ip); - retval = pico_string_to_ipv4(ip, (uint32_t *)&address.ip4.addr); - } else { - sntp_dbg("Invalid query response for A\n"); - retval = -1; - pico_sntp_cleanup(ck, PICO_ERR_ENETDOWN); - } - } -#endif - - if (retval >= 0) { - sock = pico_socket_open(ck->proto, PICO_PROTO_UDP, &pico_sntp_client_wakeup); - if (!sock) - return; - - sock->priv = ck; - ck->sock = sock; - if ((pico_socket_bind(sock, &sntp_inaddr_any, &any_port) == 0)) { - pico_sntp_send(sock, &address); - } - } -} - -/* user function to sync the time from a given sntp source */ -int pico_sntp_sync(const char *sntp_server, void (*cb_synced)(pico_err_t status)) -{ - struct sntp_server_ns_cookie *ck; -#ifdef PICO_SUPPORT_IPV6 - struct sntp_server_ns_cookie *ck6; -#endif - int retval = -1, retval6 = -1; - if (sntp_server == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* IPv4 query */ - ck = PICO_ZALLOC(sizeof(struct sntp_server_ns_cookie)); - if (!ck) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - ck->proto = PICO_PROTO_IPV4; - ck->stamp = 0ull; - ck->rec = 0; - ck->sock = NULL; - ck->hostname = PICO_ZALLOC(strlen(sntp_server) + 1); - if (!ck->hostname) { - PICO_FREE(ck); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - strcpy(ck->hostname, sntp_server); - - if(cb_synced == NULL) { - PICO_FREE(ck->hostname); - PICO_FREE(ck); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - ck->cb_synced = cb_synced; - -#ifdef PICO_SUPPORT_IPV6 - /* IPv6 query */ - ck6 = PICO_ZALLOC(sizeof(struct sntp_server_ns_cookie)); - if (!ck6) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - ck6->proto = PICO_PROTO_IPV6; - ck6->hostname = PICO_ZALLOC(strlen(sntp_server) + 1); - if (!ck6->hostname) { - PICO_FREE(ck6); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - strcpy(ck6->hostname, sntp_server); - ck6->proto = PICO_PROTO_IPV6; - ck6->stamp = 0ull; - ck6->rec = 0; - ck6->sock = NULL; - ck6->cb_synced = cb_synced; - sntp_dbg("Resolving AAAA %s\n", ck6->hostname); - retval6 = pico_dns_client_getaddr6(sntp_server, &dnsCallback, ck6); - if (retval6 != 0) { - PICO_FREE(ck6->hostname); - PICO_FREE(ck6); - return -1; - } - -#endif - sntp_dbg("Resolving A %s\n", ck->hostname); - retval = pico_dns_client_getaddr(sntp_server, &dnsCallback, ck); - if (retval != 0) { - PICO_FREE(ck->hostname); - PICO_FREE(ck); - return -1; - } - - return 0; -} - -/* user function to get the current time */ -int pico_sntp_gettimeofday(struct pico_timeval *tv) -{ - pico_time diff, temp; - uint32_t diffH, diffL; - int ret = 0; - if (tick_stamp == 0) { - /* TODO: set pico_err */ - ret = -1; - sntp_dbg("Error: Unsynchronised\n"); - return ret; - } - - diff = pico_tick - tick_stamp; - diffL = ((uint32_t) (diff & SNTP_BITMASK)) / 1000; - diffH = ((uint32_t) (diff >> 32)) / 1000; - - temp = server_time.tv_msec + (uint32_t)(diff & SNTP_BITMASK) % SNTP_THOUSAND; - tv->tv_sec = server_time.tv_sec + ((uint64_t)diffH << 32) + diffL + (uint32_t)temp / SNTP_THOUSAND; - tv->tv_msec = (uint32_t)(temp & SNTP_BITMASK) % SNTP_THOUSAND; - sntp_dbg("Time of day: %llu seconds and %llu milisecs since 1970\n", tv->tv_sec, tv->tv_msec); - return ret; -} - -#endif /* PICO_SUPPORT_SNTP_CLIENT */ diff --git a/ext/picotcp/modules/pico_sntp_client.h b/ext/picotcp/modules/pico_sntp_client.h deleted file mode 100644 index 79b02b8..0000000 --- a/ext/picotcp/modules/pico_sntp_client.h +++ /dev/null @@ -1,22 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Author: Toon Stegen - *********************************************************************/ -#ifndef INCLUDE_PICO_SNTP_CLIENT -#define INCLUDE_PICO_SNTP_CLIENT - -#include "pico_config.h" -#include "pico_protocol.h" - -struct pico_timeval -{ - pico_time tv_sec; - pico_time tv_msec; -}; - -int pico_sntp_sync(const char *sntp_server, void (*cb_synced)(pico_err_t status)); -int pico_sntp_gettimeofday(struct pico_timeval *tv); - -#endif /* _INCLUDE_PICO_SNTP_CLIENT */ diff --git a/ext/picotcp/modules/pico_socket_tcp.c b/ext/picotcp/modules/pico_socket_tcp.c deleted file mode 100644 index ee977b8..0000000 --- a/ext/picotcp/modules/pico_socket_tcp.c +++ /dev/null @@ -1,267 +0,0 @@ -#include "pico_config.h" -#include "pico_socket.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_tcp.h" -#include "pico_socket_tcp.h" - - -static int sockopt_validate_args(struct pico_socket *s, void *value) -{ - if (!value) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (s->proto->proto_number != PICO_PROTO_TCP) { - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - } - - return 0; -} - -int pico_getsockopt_tcp(struct pico_socket *s, int option, void *value) -{ - if (sockopt_validate_args(s, value) < 0) - return -1; - -#ifdef PICO_SUPPORT_TCP - if (option == PICO_TCP_NODELAY) { - /* state of the NODELAY option */ - *(int *)value = PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_TCPNODELAY); - return 0; - } - else if (option == PICO_SOCKET_OPT_RCVBUF) { - return pico_tcp_get_bufsize_in(s, (uint32_t *)value); - } - - else if (option == PICO_SOCKET_OPT_SNDBUF) { - return pico_tcp_get_bufsize_out(s, (uint32_t *)value); - } - -#endif - return -1; -} - -static void tcp_set_nagle_option(struct pico_socket *s, void *value) -{ - int *val = (int*)value; - if (*val > 0) { - dbg("setsockopt: Nagle algorithm disabled.\n"); - PICO_SOCKET_SETOPT_EN(s, PICO_SOCKET_OPT_TCPNODELAY); - } else { - dbg("setsockopt: Nagle algorithm enabled.\n"); - PICO_SOCKET_SETOPT_DIS(s, PICO_SOCKET_OPT_TCPNODELAY); - } -} - -int pico_setsockopt_tcp(struct pico_socket *s, int option, void *value) -{ - if (sockopt_validate_args(s, value) < 0) - return -1; - -#ifdef PICO_SUPPORT_TCP - if (option == PICO_TCP_NODELAY) { - tcp_set_nagle_option(s, value); - return 0; - } - else if (option == PICO_SOCKET_OPT_RCVBUF) { - uint32_t *val = (uint32_t*)value; - pico_tcp_set_bufsize_in(s, *val); - return 0; - } - else if (option == PICO_SOCKET_OPT_SNDBUF) { - uint32_t *val = (uint32_t*)value; - pico_tcp_set_bufsize_out(s, *val); - return 0; - } - else if (option == PICO_SOCKET_OPT_KEEPCNT) { - uint32_t *val = (uint32_t*)value; - pico_tcp_set_keepalive_probes(s, *val); - return 0; - } - else if (option == PICO_SOCKET_OPT_KEEPIDLE) { - uint32_t *val = (uint32_t*)value; - pico_tcp_set_keepalive_time(s, *val); - return 0; - } - else if (option == PICO_SOCKET_OPT_KEEPINTVL) { - uint32_t *val = (uint32_t*)value; - pico_tcp_set_keepalive_intvl(s, *val); - return 0; - } - else if (option == PICO_SOCKET_OPT_LINGER) { - uint32_t *val = (uint32_t*)value; - pico_tcp_set_linger(s, *val); - return 0; - } - -#endif - pico_err = PICO_ERR_EINVAL; - return -1; -} - -void pico_socket_tcp_cleanup(struct pico_socket *sock) -{ -#ifdef PICO_SUPPORT_TCP - /* for tcp sockets go further and clean the sockets inside queue */ - if(is_sock_tcp(sock)) - pico_tcp_cleanup_queues(sock); - -#endif -} - - -void pico_socket_tcp_delete(struct pico_socket *s) -{ -#ifdef PICO_SUPPORT_TCP - if(s->parent) - s->parent->number_of_pending_conn--; - -#endif -} - -static struct pico_socket *socket_tcp_deliver_ipv4(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket *found = NULL; - #ifdef PICO_SUPPORT_IPV4 - struct pico_ip4 s_local, s_remote, p_src, p_dst; - struct pico_ipv4_hdr *ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr); - struct pico_trans *tr = (struct pico_trans *) f->transport_hdr; - s_local.addr = s->local_addr.ip4.addr; - s_remote.addr = s->remote_addr.ip4.addr; - p_src.addr = ip4hdr->src.addr; - p_dst.addr = ip4hdr->dst.addr; - if ((s->remote_port == tr->sport) && /* remote port check */ - (s_remote.addr == p_src.addr) && /* remote addr check */ - ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */ - found = s; - return found; - } else if ((s->remote_port == 0) && /* not connected... listening */ - ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */ - /* listen socket */ - found = s; - } - - #endif - return found; -} - -static struct pico_socket *socket_tcp_deliver_ipv6(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket *found = NULL; - #ifdef PICO_SUPPORT_IPV6 - struct pico_trans *tr = (struct pico_trans *) f->transport_hdr; - struct pico_ip6 s_local = {{0}}, s_remote = {{0}}, p_src = {{0}}, p_dst = {{0}}; - struct pico_ipv6_hdr *ip6hdr = (struct pico_ipv6_hdr *)(f->net_hdr); - s_local = s->local_addr.ip6; - s_remote = s->remote_addr.ip6; - p_src = ip6hdr->src; - p_dst = ip6hdr->dst; - if ((s->remote_port == tr->sport) && - (!memcmp(s_remote.addr, p_src.addr, PICO_SIZE_IP6)) && - ((!memcmp(s_local.addr, PICO_IP6_ANY, PICO_SIZE_IP6)) || (!memcmp(s_local.addr, p_dst.addr, PICO_SIZE_IP6)))) { - found = s; - return found; - } else if ((s->remote_port == 0) && /* not connected... listening */ - ((!memcmp(s_local.addr, PICO_IP6_ANY, PICO_SIZE_IP6)) || (!memcmp(s_local.addr, p_dst.addr, PICO_SIZE_IP6)))) { - /* listen socket */ - found = s; - } - - #else - (void) s; - (void) f; - #endif - return found; -} - -static int socket_tcp_do_deliver(struct pico_socket *s, struct pico_frame *f) -{ - if (s != NULL) { - pico_tcp_input(s, f); - if ((s->ev_pending) && s->wakeup) { - s->wakeup(s->ev_pending, s); - if(!s->parent) - s->ev_pending = 0; - } - - return 0; - } - - dbg("TCP SOCKET> Not s.\n"); - return -1; -} - -int pico_socket_tcp_deliver(struct pico_sockport *sp, struct pico_frame *f) -{ - struct pico_socket *found = NULL; - struct pico_tree_node *index = NULL; - struct pico_tree_node *_tmp; - struct pico_socket *s = NULL; - - - pico_tree_foreach_safe(index, &sp->socks, _tmp){ - s = index->keyValue; - /* 4-tuple identification of socket (port-IP) */ - if (IS_IPV4(f)) { - found = socket_tcp_deliver_ipv4(s, f); - } - - if (IS_IPV6(f)) { - found = socket_tcp_deliver_ipv6(s, f); - } - - if (found) - break; - } /* FOREACH */ - - return socket_tcp_do_deliver(found, f); -} - -struct pico_socket *pico_socket_tcp_open(uint16_t family) -{ - struct pico_socket *s = NULL; - (void) family; -#ifdef PICO_SUPPORT_TCP - s = pico_tcp_open(family); - if (!s) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - s->proto = &pico_proto_tcp; - /*check if Nagle enabled */ - /* - if (!IS_NAGLE_ENABLED(s)) - dbg("ERROR Nagle should be enabled here\n\n"); - */ -#endif - return s; -} - -int pico_socket_tcp_read(struct pico_socket *s, void *buf, uint32_t len) -{ -#ifdef PICO_SUPPORT_TCP - /* check if in shutdown state and if no more data in tcpq_in */ - if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) { - pico_err = PICO_ERR_ESHUTDOWN; - return -1; - } else { - return (int)(pico_tcp_read(s, buf, (uint32_t)len)); - } - -#else - return 0; -#endif -} - -void transport_flags_update(struct pico_frame *f, struct pico_socket *s) -{ -#ifdef PICO_SUPPORT_TCP - if(is_sock_tcp(s)) - pico_tcp_flags_update(f, s); - -#endif -} diff --git a/ext/picotcp/modules/pico_socket_tcp.h b/ext/picotcp/modules/pico_socket_tcp.h deleted file mode 100644 index 6479103..0000000 --- a/ext/picotcp/modules/pico_socket_tcp.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef PICO_SOCKET_TCP_H -#define PICO_SOCKET_TCP_H -#include "pico_socket.h" - -#ifdef PICO_SUPPORT_TCP - -/* Functions/macros: conditional! */ - -# define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY))))) -int pico_setsockopt_tcp(struct pico_socket *s, int option, void *value); -int pico_getsockopt_tcp(struct pico_socket *s, int option, void *value); -int pico_socket_tcp_deliver(struct pico_sockport *sp, struct pico_frame *f); -void pico_socket_tcp_delete(struct pico_socket *s); -void pico_socket_tcp_cleanup(struct pico_socket *sock); -struct pico_socket *pico_socket_tcp_open(uint16_t family); -int pico_socket_tcp_read(struct pico_socket *s, void *buf, uint32_t len); -void transport_flags_update(struct pico_frame *, struct pico_socket *); - -#else -# define pico_getsockopt_tcp(...) (-1) -# define pico_setsockopt_tcp(...) (-1) -# define pico_socket_tcp_deliver(...) (-1) -# define IS_NAGLE_ENABLED(s) (0) -# define pico_socket_tcp_delete(...) do {} while(0) -# define pico_socket_tcp_cleanup(...) do {} while(0) -# define pico_socket_tcp_open(f) (NULL) -# define pico_socket_tcp_read(...) (-1) -# define transport_flags_update(...) do {} while(0) - -#endif - - -#endif diff --git a/ext/picotcp/modules/pico_socket_udp.c b/ext/picotcp/modules/pico_socket_udp.c deleted file mode 100644 index bf3d9f8..0000000 --- a/ext/picotcp/modules/pico_socket_udp.c +++ /dev/null @@ -1,256 +0,0 @@ -#include "pico_config.h" -#include "pico_socket.h" -#include "pico_udp.h" -#include "pico_socket_multicast.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_socket_udp.h" - -#define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame)) - - -struct pico_socket *pico_socket_udp_open(void) -{ - struct pico_socket *s = NULL; -#ifdef PICO_SUPPORT_UDP - s = pico_udp_open(); - if (!s) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - s->proto = &pico_proto_udp; - s->q_in.overhead = UDP_FRAME_OVERHEAD; - s->q_out.overhead = UDP_FRAME_OVERHEAD; -#endif - return s; -} - - -#ifdef PICO_SUPPORT_IPV4 -static inline int pico_socket_udp_deliver_ipv4_mcast_initial_checks(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_ip4 p_dst; - struct pico_ipv4_hdr *ip4hdr; - - ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr); - p_dst.addr = ip4hdr->dst.addr; - if (pico_ipv4_is_multicast(p_dst.addr) && (pico_socket_mcast_filter(s, (union pico_address *)&ip4hdr->dst, (union pico_address *)&ip4hdr->src) < 0)) - return -1; - - - if ((pico_ipv4_link_get(&ip4hdr->src)) && (PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP) == 0u)) { - /* Datagram from ourselves, Loop disabled, discarding. */ - return -1; - } - - return 0; -} - - -static int pico_socket_udp_deliver_ipv4_mcast(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_ip4 s_local; - struct pico_frame *cpy; - struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4); - - s_local.addr = s->local_addr.ip4.addr; - - if (pico_socket_udp_deliver_ipv4_mcast_initial_checks(s, f) < 0) - return 0; - - if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */ - (dev == f->dev)) { /* the source of the bcast packet is a neighbor... */ - cpy = pico_frame_copy(f); - if (!cpy) - return -1; - - if (pico_enqueue(&s->q_in, cpy) > 0) { - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_RD, s); - } - else - pico_frame_discard(cpy); - } - - return 0; -} - -static int pico_socket_udp_deliver_ipv4_unicast(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_frame *cpy; - /* Either local socket is ANY, or matches dst */ - cpy = pico_frame_copy(f); - if (!cpy) - return -1; - - if (pico_enqueue(&s->q_in, cpy) > 0) { - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_RD, s); - } else { - pico_frame_discard(cpy); - } - - return 0; -} - - -static int pico_socket_udp_deliver_ipv4(struct pico_socket *s, struct pico_frame *f) -{ - int ret = 0; - struct pico_ip4 s_local, p_dst; - struct pico_ipv4_hdr *ip4hdr; - ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr); - s_local.addr = s->local_addr.ip4.addr; - p_dst.addr = ip4hdr->dst.addr; - if ((pico_ipv4_is_broadcast(p_dst.addr)) || pico_ipv4_is_multicast(p_dst.addr)) { - ret = pico_socket_udp_deliver_ipv4_mcast(s, f); - } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr)) { - ret = pico_socket_udp_deliver_ipv4_unicast(s, f); - } - - pico_frame_discard(f); - return ret; -} -#endif - -#ifdef PICO_SUPPORT_IPV6 -static inline int pico_socket_udp_deliver_ipv6_mcast(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_ipv6_hdr *ip6hdr; - struct pico_frame *cpy; - struct pico_device *dev = pico_ipv6_link_find(&s->local_addr.ip6); - - ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr); - - if ((pico_ipv6_link_get(&ip6hdr->src)) && (PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP) == 0u)) { - /* Datagram from ourselves, Loop disabled, discarding. */ - return 0; - } - - - if (pico_ipv6_is_unspecified(s->local_addr.ip6.addr) || /* If our local ip is ANY, or.. */ - (dev == f->dev)) { /* the source of the bcast packet is a neighbor... */ - cpy = pico_frame_copy(f); - if (!cpy) - { - return -1; - } - - if (pico_enqueue(&s->q_in, cpy) > 0) { - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_RD, s); - } - else - pico_frame_discard(cpy); - } - - return 0; -} - -static int pico_socket_udp_deliver_ipv6(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_ip6 s_local, p_dst; - struct pico_ipv6_hdr *ip6hdr; - struct pico_frame *cpy; - ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr); - s_local = s->local_addr.ip6; - p_dst = ip6hdr->dst; - if ((pico_ipv6_is_multicast(p_dst.addr))) { - int retval = pico_socket_udp_deliver_ipv6_mcast(s, f); - pico_frame_discard(f); - return retval; - } - else if (pico_ipv6_is_unspecified(s->local_addr.ip6.addr) || (pico_ipv6_compare(&s_local, &p_dst) == 0)) - { /* Either local socket is ANY, or matches dst */ - cpy = pico_frame_copy(f); - if (!cpy) - { - pico_frame_discard(f); - return -1; - } - - if (pico_enqueue(&s->q_in, cpy) > 0) { - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_RD, s); - } - } - - pico_frame_discard(f); - return 0; -} -#endif - - -int pico_socket_udp_deliver(struct pico_sockport *sp, struct pico_frame *f) -{ - struct pico_tree_node *index = NULL; - struct pico_tree_node *_tmp; - struct pico_socket *s = NULL; - pico_err = PICO_ERR_EPROTONOSUPPORT; - #ifdef PICO_SUPPORT_UDP - pico_err = PICO_ERR_NOERR; - pico_tree_foreach_safe(index, &sp->socks, _tmp){ - s = index->keyValue; - if (IS_IPV4(f)) { /* IPV4 */ -#ifdef PICO_SUPPORT_IPV4 - return pico_socket_udp_deliver_ipv4(s, f); -#endif - } else if (IS_IPV6(f)) { -#ifdef PICO_SUPPORT_IPV6 - return pico_socket_udp_deliver_ipv6(s, f); -#endif - } else { - /* something wrong in the packet header*/ - } - } /* FOREACH */ - pico_frame_discard(f); - if (s) - return 0; - - pico_err = PICO_ERR_ENXIO; - #endif - return -1; -} - -int pico_setsockopt_udp(struct pico_socket *s, int option, void *value) -{ - switch(option) { - case PICO_SOCKET_OPT_RCVBUF: - s->q_in.max_size = (*(uint32_t*)value); - return 0; - case PICO_SOCKET_OPT_SNDBUF: - s->q_out.max_size = (*(uint32_t*)value); - return 0; - } - - /* switch's default */ -#ifdef PICO_SUPPORT_MCAST - return pico_setsockopt_mcast(s, option, value); -#else - pico_err = PICO_ERR_EINVAL; - return -1; -#endif -} - -int pico_getsockopt_udp(struct pico_socket *s, int option, void *value) -{ - uint32_t *val = (uint32_t *)value; - switch(option) { - case PICO_SOCKET_OPT_RCVBUF: - *val = s->q_in.max_size; - return 0; - case PICO_SOCKET_OPT_SNDBUF: - *val = s->q_out.max_size; - return 0; - } - - /* switch's default */ -#ifdef PICO_SUPPORT_MCAST - return pico_getsockopt_mcast(s, option, value); -#else - pico_err = PICO_ERR_EINVAL; - return -1; -#endif -} - diff --git a/ext/picotcp/modules/pico_socket_udp.h b/ext/picotcp/modules/pico_socket_udp.h deleted file mode 100644 index 6b3a4c9..0000000 --- a/ext/picotcp/modules/pico_socket_udp.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef PICO_SOCKET_UDP_H -#define PICO_SOCKET_UDP_H - -struct pico_socket *pico_socket_udp_open(void); -int pico_socket_udp_deliver(struct pico_sockport *sp, struct pico_frame *f); - - -#ifdef PICO_SUPPORT_UDP -int pico_setsockopt_udp(struct pico_socket *s, int option, void *value); -int pico_getsockopt_udp(struct pico_socket *s, int option, void *value); -# define pico_socket_udp_recv(s, buf, len, addr, port) pico_udp_recv(s, buf, len, addr, port, NULL) -#else -# define pico_socket_udp_recv(...) (0) -# define pico_getsockopt_udp(...) (-1) -# define pico_setsockopt_udp(...) (-1) -#endif - - -#endif diff --git a/ext/picotcp/modules/pico_strings.c b/ext/picotcp/modules/pico_strings.c deleted file mode 100644 index 974126f..0000000 --- a/ext/picotcp/modules/pico_strings.c +++ /dev/null @@ -1,101 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2015 Altran ISY BeNeLux. Some rights reserved. - See LICENSE and COPYING for usage. - - - - Author: Michele Di Pede - *********************************************************************/ - -#include -#include -#include "pico_strings.h" - -char *get_string_terminator_position(char *const block, size_t len) -{ - size_t length = pico_strnlen(block, len); - - return (len != length) ? (block + length) : 0; -} - -int pico_strncasecmp(const char *const str1, const char *const str2, size_t n) -{ - int ch1; - int ch2; - size_t i; - - for (i = 0; i < n; ++i) { - ch1 = toupper(*(str1 + i)); - ch2 = toupper(*(str2 + i)); - if (ch1 < ch2) - return -1; - - if (ch1 > ch2) - return 1; - - if ((!ch1) && (!ch2)) - return 0; - } - return 1; -} - -size_t pico_strnlen(const char *str, size_t n) -{ - size_t len = 0; - - if (!str) - return 0; - - for (; len < n && *(str + len); ++len) - ; /* TICS require this empty statement here */ - - return len; -} - -static inline int num2string_validate(int32_t num, char *buf, int len) -{ - if (num < 0) - return -1; - - if (!buf) - return -2; - - if (len < 2) - return -3; - - return 0; -} - -static inline int revert_and_shift(char *buf, int len, int pos) -{ - int i; - - len -= pos; - for (i = 0; i < len; ++i) - buf[i] = buf[i + pos]; - return len; -} - -int num2string(int32_t num, char *buf, int len) -{ - ldiv_t res; - int pos = 0; - - if (num2string_validate(num, buf, len)) - return -1; - - pos = len; - buf[--pos] = '\0'; - - res.quot = (long)num; - - do { - if (!pos) - return -3; - - res = ldiv(res.quot, 10); - buf[--pos] = (char)((res.rem + '0') & 0xFF); - } while (res.quot); - - return revert_and_shift(buf, len, pos); -} diff --git a/ext/picotcp/modules/pico_strings.h b/ext/picotcp/modules/pico_strings.h deleted file mode 100644 index 9a6209d..0000000 --- a/ext/picotcp/modules/pico_strings.h +++ /dev/null @@ -1,21 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2015 Altran ISY BeNeLux. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Author: Michele Di Pede - *********************************************************************/ - -#ifndef PICO_STRINGS_H -#define PICO_STRINGS_H -#include -#include - -char *get_string_terminator_position(char *const block, size_t len); -int pico_strncasecmp(const char *const str1, const char *const str2, size_t n); -size_t pico_strnlen(const char *str, size_t n); - -int num2string(int32_t num, char *buf, int len); - -#endif diff --git a/ext/picotcp/modules/pico_tcp.c b/ext/picotcp/modules/pico_tcp.c deleted file mode 100644 index 67e3c73..0000000 --- a/ext/picotcp/modules/pico_tcp.c +++ /dev/null @@ -1,3236 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Daniele Lacamera, Philippe Mariman - *********************************************************************/ - -#include "pico_tcp.h" -#include "pico_config.h" -#include "pico_eth.h" -#include "pico_socket.h" -#include "pico_stack.h" -#include "pico_socket.h" -#include "pico_queue.h" -#include "pico_tree.h" - -#define TCP_IS_STATE(s, st) ((s->state & PICO_SOCKET_STATE_TCP) == st) -#define TCP_SOCK(s) ((struct pico_socket_tcp *)s) -#define SEQN(f) ((f) ? (long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->seq)) : 0) -#define ACKN(f) ((f) ? (long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->ack)) : 0) - -#define TCP_TIME (pico_time)(PICO_TIME_MS()) - -#define PICO_TCP_RTO_MIN (70) -#define PICO_TCP_RTO_MAX (120000) -#define PICO_TCP_IW 2 -#define PICO_TCP_SYN_TO 2000u -#define PICO_TCP_ZOMBIE_TO 30000 - -#define PICO_TCP_MAX_RETRANS 10 -#define PICO_TCP_MAX_CONNECT_RETRIES 3 - -#define PICO_TCP_LOOKAHEAD 0x00 -#define PICO_TCP_FIRST_DUPACK 0x01 -#define PICO_TCP_SECOND_DUPACK 0x02 -#define PICO_TCP_RECOVER 0x03 -#define PICO_TCP_BLACKOUT 0x04 -#define PICO_TCP_UNREACHABLE 0x05 -#define PICO_TCP_WINDOW_FULL 0x06 - -#define ONE_GIGABYTE ((uint32_t)(1024UL * 1024UL * 1024UL)) - -/* check if the Nagle algorithm is enabled on the socket */ -#define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1u << PICO_SOCKET_OPT_TCPNODELAY))))) -/* check if tcp connection is "idle" according to Nagle (RFC 896) */ -#define IS_TCP_IDLE(t) ((t->in_flight == 0) && (t->tcpq_out.size == 0)) -/* check if the hold queue contains data (again Nagle) */ -#define IS_TCP_HOLDQ_EMPTY(t) (t->tcpq_hold.size == 0) - -#define IS_INPUT_QUEUE(q) (q->pool.compare == input_segment_compare) -#define TCP_INPUT_OVERHEAD (sizeof(struct tcp_input_segment) + sizeof(struct pico_tree_node)) - - -#ifdef PICO_SUPPORT_TCP -#define tcp_dbg_nagle(...) do {} while(0) -#define tcp_dbg_options(...) do {} while(0) - - -#define tcp_dbg(...) do {} while(0) -/* #define tcp_dbg dbg */ - -#ifdef PICO_SUPPORT_MUTEX -static void *Mutex = NULL; -#endif - - - -/* Input segment, used to keep only needed data, not the full frame */ -struct tcp_input_segment -{ - uint32_t seq; - /* Pointer to payload */ - unsigned char *payload; - uint16_t payload_len; -}; - -/* Function to compare input segments */ -static int input_segment_compare(void *ka, void *kb) -{ - struct tcp_input_segment *a = ka, *b = kb; - return pico_seq_compare(a->seq, b->seq); -} - -static struct tcp_input_segment *segment_from_frame(struct pico_frame *f) -{ - struct tcp_input_segment *seg = PICO_ZALLOC(sizeof(struct tcp_input_segment)); - if ((!seg) || (!f->payload_len)) - return NULL; - - seg->payload = PICO_ZALLOC(f->payload_len); - if(!seg->payload) - { - PICO_FREE(seg); - return NULL; - } - - seg->seq = SEQN(f); - seg->payload_len = f->payload_len; - memcpy(seg->payload, f->payload, seg->payload_len); - return seg; -} - -static int segment_compare(void *ka, void *kb) -{ - struct pico_frame *a = ka, *b = kb; - return pico_seq_compare(SEQN(a), SEQN(b)); -} - -struct pico_tcp_queue -{ - struct pico_tree pool; - uint32_t max_size; - uint32_t size; - uint32_t frames; -}; - -static void tcp_discard_all_segments(struct pico_tcp_queue *tq); -static void *peek_segment(struct pico_tcp_queue *tq, uint32_t seq) -{ - if(!IS_INPUT_QUEUE(tq)) - { - struct pico_tcp_hdr H; - struct pico_frame f = { - 0 - }; - f.transport_hdr = (uint8_t *) (&H); - H.seq = long_be(seq); - - return pico_tree_findKey(&tq->pool, &f); - } - else - { - struct tcp_input_segment dummy = { 0 }; - dummy.seq = seq; - - return pico_tree_findKey(&tq->pool, &dummy); - } - -} - -static void *first_segment(struct pico_tcp_queue *tq) -{ - return pico_tree_first(&tq->pool); -} - -static void *next_segment(struct pico_tcp_queue *tq, void *cur) -{ - if (!cur) - return NULL; - - if(IS_INPUT_QUEUE(tq)) - { - return peek_segment(tq, ((struct tcp_input_segment *)cur)->seq + ((struct tcp_input_segment *)cur)->payload_len); - } - else - { - return peek_segment(tq, SEQN((struct pico_frame *)cur) + ((struct pico_frame *)cur)->payload_len); - } -} - -static uint16_t enqueue_segment_len(struct pico_tcp_queue *tq, void *f) -{ - if (IS_INPUT_QUEUE(tq)) { - return ((struct tcp_input_segment *)f)->payload_len; - } else { - return (uint16_t)(((struct pico_frame *)f)->buffer_len); - } -} - - -static int32_t do_enqueue_segment(struct pico_tcp_queue *tq, void *f, uint16_t payload_len) -{ - int32_t ret = -1; - PICOTCP_MUTEX_LOCK(Mutex); - if ((tq->size + payload_len) > tq->max_size) - { - ret = 0; - goto out; - } - - if (pico_tree_insert(&tq->pool, f) != 0) - { - ret = 0; - goto out; - } - - tq->size += (uint16_t)payload_len; - if (payload_len > 0) - tq->frames++; - - ret = (int32_t)payload_len; - -out: - PICOTCP_MUTEX_UNLOCK(Mutex); - return ret; -} - -static int32_t pico_enqueue_segment(struct pico_tcp_queue *tq, void *f) -{ - uint16_t payload_len; - - if (!f) - return -1; - - payload_len = enqueue_segment_len(tq, f); - - - if (payload_len == 0) { - tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n"); - return -1; - } - - return do_enqueue_segment(tq, f, payload_len); -} - -static void pico_discard_segment(struct pico_tcp_queue *tq, void *f) -{ - void *f1; - uint16_t payload_len = (uint16_t)((IS_INPUT_QUEUE(tq)) ? - (((struct tcp_input_segment *)f)->payload_len) : - (((struct pico_frame *)f)->buffer_len)); - PICOTCP_MUTEX_LOCK(Mutex); - f1 = pico_tree_delete(&tq->pool, f); - if (f1) { - tq->size -= (uint16_t)payload_len; - if (payload_len > 0) - tq->frames--; - } - - if(f1 && IS_INPUT_QUEUE(tq)) - { - struct tcp_input_segment *inp = f1; - PICO_FREE(inp->payload); - PICO_FREE(inp); - } - else - pico_frame_discard(f); - - PICOTCP_MUTEX_UNLOCK(Mutex); -} - -/* Structure for TCP socket */ -struct tcp_sack_block { - uint32_t left; - uint32_t right; - struct tcp_sack_block *next; -}; - -struct pico_socket_tcp { - struct pico_socket sock; - - /* Tree/queues */ - struct pico_tcp_queue tcpq_in; /* updated the input queue to hold input segments not the full frame. */ - struct pico_tcp_queue tcpq_out; - struct pico_tcp_queue tcpq_hold; /* buffer to hold delayed frames according to Nagle */ - - /* tcp_output */ - uint32_t snd_nxt; - uint32_t snd_last; - uint32_t snd_old_ack; - uint32_t snd_retry; - uint32_t snd_last_out; - - /* congestion control */ - uint32_t avg_rtt; - uint32_t rttvar; - uint32_t rto; - uint32_t in_flight; - uint32_t retrans_tmr; - pico_time retrans_tmr_due; - uint16_t cwnd_counter; - uint16_t cwnd; - uint16_t ssthresh; - uint16_t recv_wnd; - uint16_t recv_wnd_scale; - - /* tcp_input */ - uint32_t rcv_nxt; - uint32_t rcv_ackd; - uint32_t rcv_processed; - uint16_t wnd; - uint16_t wnd_scale; - uint16_t remote_closed; - - /* options */ - uint32_t ts_nxt; - uint16_t mss; - uint8_t sack_ok; - uint8_t ts_ok; - uint8_t mss_ok; - uint8_t scale_ok; - struct tcp_sack_block *sacks; - uint8_t jumbo; - uint32_t linger_timeout; - - /* Transmission */ - uint8_t x_mode; - uint8_t dupacks; - uint8_t backoff; - uint8_t localZeroWindow; - - /* Keepalive */ - uint32_t keepalive_tmr; - pico_time ack_timestamp; - uint32_t ka_time; - uint32_t ka_intvl; - uint32_t ka_probes; - uint32_t ka_retries_count; - - /* FIN timer */ - uint32_t fin_tmr; -}; - -/* Queues */ -static struct pico_queue tcp_in = { - 0 -}; -static struct pico_queue tcp_out = { - 0 -}; - -/* If Nagle enabled, this function can make 1 new segment from smaller segments in hold queue */ -static struct pico_frame *pico_hold_segment_make(struct pico_socket_tcp *t); - -/* checks if tcpq_in is empty */ -int pico_tcp_queue_in_is_empty(struct pico_socket *s) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - - if (t->tcpq_in.frames == 0) - return 1; - else - return 0; -} - -/* Useful for getting rid of the beginning of the buffer (read() op) */ -static int release_until(struct pico_tcp_queue *q, uint32_t seq) -{ - void *head = first_segment(q); - int ret = 0; - int32_t seq_result = 0; - - if (!head) - return ret; - - do { - void *cur = head; - - if (IS_INPUT_QUEUE(q)) - seq_result = pico_seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq); - else - seq_result = pico_seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq); - - if (seq_result <= 0) - { - head = next_segment(q, cur); - //tcp_dbg("Releasing %08x, len: %d\n", SEQN((struct pico_frame *)head), ((struct pico_frame *)head)->payload_len); - pico_discard_segment(q, cur); - ret++; - } else { - break; - } - } while (head); - - return ret; -} - -static int release_all_until(struct pico_tcp_queue *q, uint32_t seq, pico_time *timestamp) -{ - void *f = NULL; - struct pico_tree_node *idx, *temp; - int seq_result; - int ret = 0; - *timestamp = 0; - - pico_tree_foreach_safe(idx, &q->pool, temp) - { - f = idx->keyValue; - - if (IS_INPUT_QUEUE(q)) - seq_result = pico_seq_compare(((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq); - else - seq_result = pico_seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq); - - if (seq_result <= 0) { - tcp_dbg("Releasing %p\n", f); - if ((seq_result == 0) && !IS_INPUT_QUEUE(q)) - *timestamp = ((struct pico_frame *)f)->timestamp; - - pico_discard_segment(q, f); - ret++; - } else { - return ret; - } - } - return ret; -} - - -/* API calls */ - -uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - struct pico_socket *s = f->sock; - struct pico_ipv4_pseudo_hdr pseudo; - - if (s) { - /* Case of outgoing frame */ - /* dbg("TCP CRC: on outgoing frame\n"); */ - pseudo.src.addr = s->local_addr.ip4.addr; - pseudo.dst.addr = s->remote_addr.ip4.addr; - } else { - /* Case of incoming frame */ - /* dbg("TCP CRC: on incoming frame\n"); */ - pseudo.src.addr = hdr->src.addr; - pseudo.dst.addr = hdr->dst.addr; - } - - pseudo.zeros = 0; - pseudo.proto = PICO_PROTO_TCP; - pseudo.len = (uint16_t)short_be(f->transport_len); - - return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), tcp_hdr, f->transport_len); -} - -#ifdef PICO_SUPPORT_IPV6 -uint16_t pico_tcp_checksum_ipv6(struct pico_frame *f) -{ - struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; - struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *)f->transport_hdr; - struct pico_ipv6_pseudo_hdr pseudo; - struct pico_socket *s = f->sock; - - /* XXX If the IPv6 packet contains a Routing header, the Destination - * Address used in the pseudo-header is that of the final destination */ - if (s) { - /* Case of outgoing frame */ - pseudo.src = s->local_addr.ip6; - pseudo.dst = s->remote_addr.ip6; - } else { - /* Case of incoming frame */ - pseudo.src = ipv6_hdr->src; - pseudo.dst = ipv6_hdr->dst; - } - - pseudo.zero[0] = 0; - pseudo.zero[1] = 0; - pseudo.zero[2] = 0; - pseudo.len = long_be(f->transport_len); - pseudo.nxthdr = PICO_PROTO_TCP; - - return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv6_pseudo_hdr), tcp_hdr, f->transport_len); -} -#endif - -#ifdef PICO_SUPPORT_IPV4 -static inline int checksum_is_ipv4(struct pico_frame *f) -{ - return (IS_IPV4(f) || (f->sock && (f->sock->net == &pico_proto_ipv4))); -} -#endif - -#ifdef PICO_SUPPORT_IPV6 -static inline int checksum_is_ipv6(struct pico_frame *f) -{ - return ((IS_IPV6(f)) || (f->sock && (f->sock->net == &pico_proto_ipv6))); -} -#endif - -uint16_t pico_tcp_checksum(struct pico_frame *f) -{ - (void)f; - - #ifdef PICO_SUPPORT_IPV4 - if (checksum_is_ipv4(f)) - return pico_tcp_checksum_ipv4(f); - - #endif - - #ifdef PICO_SUPPORT_IPV6 - if (checksum_is_ipv6(f)) - return pico_tcp_checksum_ipv6(f); - - #endif - return 0xffff; -} - -static void tcp_send_fin(struct pico_socket_tcp *t); -static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr; - struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock; - IGNORE_PARAMETER(self); - hdr = (struct pico_tcp_hdr *)f->transport_hdr; - f->sock->timestamp = TCP_TIME; - if (f->payload_len > 0) { - tcp_dbg("Process out: sending %p (%d bytes)\n", f, f->payload_len); - } else { - tcp_dbg("Sending empty packet\n"); - } - - if (f->payload_len > 0) { - if (pico_seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) { - t->snd_nxt = SEQN(f) + f->payload_len; - tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); - } - } else if (hdr->flags == PICO_TCP_ACK) { /* pure ack */ - /* hdr->seq = long_be(t->snd_nxt); / * XXX disabled this to not to mess with seq nrs of ACKs anymore * / */ - } else { - tcp_dbg("%s: non-pure ACK with len=0, fl:%04x\n", __FUNCTION__, hdr->flags); - } - - pico_network_send(f); - return 0; -} - -int pico_tcp_push(struct pico_protocol *self, struct pico_frame *data); - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_tcp = { - .name = "tcp", - .proto_number = PICO_PROTO_TCP, - .layer = PICO_LAYER_TRANSPORT, - .process_in = pico_transport_process_in, - .process_out = pico_tcp_process_out, - .push = pico_tcp_push, - .q_in = &tcp_in, - .q_out = &tcp_out, -}; - -static uint32_t pico_paws(void) -{ - static uint32_t _paws = 0; - _paws = pico_rand(); - return long_be(_paws); -} - -static inline void tcp_add_sack_option(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint32_t *ii) -{ - if (flags & PICO_TCP_ACK) { - struct tcp_sack_block *sb; - uint32_t len_off; - - if (ts->sack_ok && ts->sacks) { - f->start[(*ii)++] = PICO_TCP_OPTION_SACK; - len_off = *ii; - f->start[(*ii)++] = PICO_TCPOPTLEN_SACK; - while(ts->sacks) { - sb = ts->sacks; - ts->sacks = sb->next; - memcpy(f->start + *ii, sb, 2 * sizeof(uint32_t)); - *ii += (2 * (uint32_t)sizeof(uint32_t)); - f->start[len_off] = (uint8_t)(f->start[len_off] + (2 * sizeof(uint32_t))); - PICO_FREE(sb); - } - } - } -} - -static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint16_t optsiz) -{ - uint32_t tsval = long_be((uint32_t)TCP_TIME); - uint32_t tsecr = long_be(ts->ts_nxt); - uint32_t i = 0; - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - - memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */ - - if (flags & PICO_TCP_SYN) { - f->start[i++] = PICO_TCP_OPTION_MSS; - f->start[i++] = PICO_TCPOPTLEN_MSS; - f->start[i++] = (uint8_t)((ts->mss >> 8) & 0xFF); - f->start[i++] = (uint8_t)(ts->mss & 0xFF); - f->start[i++] = PICO_TCP_OPTION_SACK_OK; - f->start[i++] = PICO_TCPOPTLEN_SACK_OK; - } - - f->start[i++] = PICO_TCP_OPTION_WS; - f->start[i++] = PICO_TCPOPTLEN_WS; - f->start[i++] = (uint8_t)(ts->wnd_scale); - - if ((flags & PICO_TCP_SYN) || ts->ts_ok) { - f->start[i++] = PICO_TCP_OPTION_TIMESTAMP; - f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP; - memcpy(f->start + i, &tsval, 4); - i += 4; - memcpy(f->start + i, &tsecr, 4); - i += 4; - } - - tcp_add_sack_option(ts, f, flags, &i); - - if (i < optsiz) - f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END; -} - -static uint16_t tcp_options_size_frame(struct pico_frame *f) -{ - uint16_t size = 0; - - /* Always update window scale. */ - size = (uint16_t)(size + PICO_TCPOPTLEN_WS); - if (f->transport_flags_saved) - size = (uint16_t)(size + PICO_TCPOPTLEN_TIMESTAMP); - - size = (uint16_t)(size + PICO_TCPOPTLEN_END); - size = (uint16_t)(((uint16_t)(size + 3u) >> 2u) << 2u); - return size; -} - -static void tcp_add_options_frame(struct pico_socket_tcp *ts, struct pico_frame *f) -{ - uint32_t tsval = long_be((uint32_t)TCP_TIME); - uint32_t tsecr = long_be(ts->ts_nxt); - uint32_t i = 0; - uint16_t optsiz = tcp_options_size_frame(f); - - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - - memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */ - - - f->start[i++] = PICO_TCP_OPTION_WS; - f->start[i++] = PICO_TCPOPTLEN_WS; - f->start[i++] = (uint8_t)(ts->wnd_scale); - - if (f->transport_flags_saved) { - f->start[i++] = PICO_TCP_OPTION_TIMESTAMP; - f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP; - memcpy(f->start + i, &tsval, 4); - i += 4; - memcpy(f->start + i, &tsecr, 4); - i += 4; - } - - if (i < optsiz) - f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END; -} - -static void tcp_send_ack(struct pico_socket_tcp *t); -#define tcp_send_windowUpdate(t) (tcp_send_ack(t)) - -static inline void tcp_set_space_check_winupdate(struct pico_socket_tcp *t, int32_t space, uint32_t shift) -{ - if (((uint32_t)space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (int32_t)((uint32_t)space >> 2u))) { - t->wnd = (uint16_t)space; - t->wnd_scale = (uint16_t)shift; - - if(t->wnd == 0) /* mark the entering to zero window state */ - t->localZeroWindow = 1u; - else if(t->localZeroWindow) - { - t->localZeroWindow = 0u; - tcp_send_windowUpdate(t); - } - } -} - -static void tcp_set_space(struct pico_socket_tcp *t) -{ - int32_t space; - uint32_t shift = 0; - - if (t->tcpq_in.max_size == 0) { - space = ONE_GIGABYTE; - } else { - space = (int32_t)(t->tcpq_in.max_size - t->tcpq_in.size); - } - - if (space < 0) - space = 0; - - while(space > 0xFFFF) { - space = (int32_t)(((uint32_t)space >> 1u)); - shift++; - } - tcp_set_space_check_winupdate(t, space, shift); -} - -/* Return 32-bit aligned option size */ -static uint16_t tcp_options_size(struct pico_socket_tcp *t, uint16_t flags) -{ - uint16_t size = 0; - struct tcp_sack_block *sb = t->sacks; - - if (flags & PICO_TCP_SYN) { /* Full options */ - size = PICO_TCPOPTLEN_MSS + PICO_TCP_OPTION_SACK_OK + PICO_TCPOPTLEN_WS + PICO_TCPOPTLEN_TIMESTAMP; - } else { - - /* Always update window scale. */ - size = (uint16_t)(size + PICO_TCPOPTLEN_WS); - - if (t->ts_ok) - size = (uint16_t)(size + PICO_TCPOPTLEN_TIMESTAMP); - - size = (uint16_t)(size + PICO_TCPOPTLEN_END); - } - - if ((flags & PICO_TCP_ACK) && (t->sack_ok && sb)) { - size = (uint16_t)(size + 2); - while(sb) { - size = (uint16_t)(size + (2 * sizeof(uint32_t))); - sb = sb->next; - } - } - - size = (uint16_t)(((size + 3u) >> 2u) << 2u); - return size; -} - -uint16_t pico_tcp_overhead(struct pico_socket *s) -{ - if (!s) - return 0; - - return (uint16_t)(PICO_SIZE_TCPHDR + tcp_options_size((struct pico_socket_tcp *)s, (uint16_t)0)); /* hdr + Options size for data pkt */ - -} - -static inline int tcp_sack_marker(struct pico_frame *f, uint32_t start, uint32_t end, uint16_t *count) -{ - int cmp; - cmp = pico_seq_compare(SEQN(f), start); - if (cmp > 0) - return 0; - - if (cmp == 0) { - cmp = pico_seq_compare(SEQN(f) + f->payload_len, end); - if (cmp > 0) { - tcp_dbg("Invalid SACK: ignoring.\n"); - } - - tcp_dbg("Marking (by SACK) segment %08x BLK:[%08x::%08x]\n", SEQN(f), start, end); - f->flags |= PICO_FRAME_FLAG_SACKED; - (*count)++; - } - - return cmp; -} - -static void tcp_process_sack(struct pico_socket_tcp *t, uint32_t start, uint32_t end) -{ - struct pico_frame *f; - struct pico_tree_node *index, *temp; - uint16_t count = 0; - - pico_tree_foreach_safe(index, &t->tcpq_out.pool, temp){ - f = index->keyValue; - if (tcp_sack_marker(f, start, end, &count) == 0) - goto done; - } - -done: - if (t->x_mode > PICO_TCP_LOOKAHEAD) { - if (t->in_flight > (count)) - t->in_flight -= (count); - else - t->in_flight = 0; - } -} - -inline static void tcp_add_header(struct pico_socket_tcp *t, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; - f->timestamp = TCP_TIME; - tcp_add_options(t, f, 0, (uint16_t)(f->transport_len - f->payload_len - (uint16_t)PICO_SIZE_TCPHDR)); - hdr->rwnd = short_be(t->wnd); - hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK; - hdr->ack = long_be(t->rcv_nxt); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum(f)); -} - -static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len) -{ - uint32_t start, end; - int i = 0; - if (len % 8) { - tcp_dbg("SACK: Invalid len.\n"); - return; - } - - while (i < len) { - start = long_from(opt + i); - i += 4; - end = long_from(opt + i); - i += 4; - tcp_process_sack(t, long_be(start), long_be(end)); - } -} - -static int tcpopt_len_check(uint32_t *idx, uint8_t len, uint8_t expected) -{ - if (len != expected) { - *idx = *idx + len - 2; - return -1; - } - - return 0; -} - -static inline void tcp_parse_option_ws(struct pico_socket_tcp *t, uint8_t len, uint8_t *opt, uint32_t *idx) -{ - if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_WS) < 0) - return; - - t->recv_wnd_scale = opt[(*idx)++]; - tcp_dbg_options("TCP Window scale: received %d\n", t->recv_wnd_scale); - -} - -static inline void tcp_parse_option_sack_ok(struct pico_socket_tcp *t, struct pico_frame *f, uint8_t len, uint32_t *idx) -{ - if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_SACK_OK) < 0) - return; - - if(((struct pico_tcp_hdr *)(f->transport_hdr))->flags & PICO_TCP_SYN ) - t->sack_ok = 1; -} - -static inline void tcp_parse_option_mss(struct pico_socket_tcp *t, uint8_t len, uint8_t *opt, uint32_t *idx) -{ - uint16_t mss; - if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_MSS) < 0) - return; - - t->mss_ok = 1; - mss = short_from(opt + *idx); - *idx += (uint32_t)sizeof(uint16_t); - if (t->mss > short_be(mss)) - t->mss = short_be(mss); -} - -static inline void tcp_parse_option_timestamp(struct pico_socket_tcp *t, struct pico_frame *f, uint8_t len, uint8_t *opt, uint32_t *idx) -{ - uint32_t tsval, tsecr; - if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_TIMESTAMP) < 0) - return; - - t->ts_ok = 1; - tsval = long_from(opt + *idx); - *idx += (uint32_t)sizeof(uint32_t); - tsecr = long_from(opt + *idx); - f->timestamp = long_be(tsecr); - *idx += (uint32_t)sizeof(uint32_t); - t->ts_nxt = long_be(tsval); -} - -static void tcp_parse_options(struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock; - uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR; - uint32_t i = 0; - f->timestamp = 0; - while (i < (f->transport_len - PICO_SIZE_TCPHDR)) { - uint8_t type = opt[i++]; - uint8_t len; - if(i < (f->transport_len - PICO_SIZE_TCPHDR) && (type > 1)) - len = opt[i++]; - else - len = 1; - - if (f->payload && ((opt + i) > f->payload)) - break; - - tcp_dbg_options("Received option '%d', len = %d \n", type, len); - switch (type) { - case PICO_TCP_OPTION_NOOP: - case PICO_TCP_OPTION_END: - break; - case PICO_TCP_OPTION_WS: - tcp_parse_option_ws(t, len, opt, &i); - break; - case PICO_TCP_OPTION_SACK_OK: - tcp_parse_option_sack_ok(t, f, len, &i); - break; - case PICO_TCP_OPTION_MSS: - tcp_parse_option_mss(t, len, opt, &i); - break; - case PICO_TCP_OPTION_TIMESTAMP: - tcp_parse_option_timestamp(t, f, len, opt, &i); - break; - - case PICO_TCP_OPTION_SACK: - tcp_rcv_sack(t, opt + i, len - 2); - i = i + len - 2; - break; - default: - tcp_dbg_options("TCP: received unsupported option %u\n", type); - i = i + len - 2; - } - } -} - -static inline void tcp_send_add_tcpflags(struct pico_socket_tcp *ts, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; - if (ts->rcv_nxt != 0) { - if ((ts->rcv_ackd == 0) || (pico_seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) { - hdr->flags |= PICO_TCP_ACK; - hdr->ack = long_be(ts->rcv_nxt); - ts->rcv_ackd = ts->rcv_nxt; - } - } - - if (hdr->flags & PICO_TCP_SYN) { - ts->snd_nxt++; - } - - if (f->payload_len > 0) { - hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK; - hdr->ack = long_be(ts->rcv_nxt); - ts->rcv_ackd = ts->rcv_nxt; - } -} - -static inline int tcp_send_try_enqueue(struct pico_socket_tcp *ts, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; - struct pico_frame *cpy; - (void)hdr; - - /* TCP: ENQUEUE to PROTO ( Transmit ) */ - cpy = pico_frame_copy(f); - if (!cpy) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if ((pico_enqueue(&tcp_out, cpy) > 0)) { - if (f->payload_len > 0) { - ts->in_flight++; - ts->snd_nxt += f->payload_len; /* update next pointer here to prevent sending same segment twice when called twice in same tick */ - } - - tcp_dbg("DBG> [tcp output] state: %02x --> local port:%u remote port: %u seq: %08x ack: %08x flags: %02x = t_len: %u, hdr: %u payload: %d\n", - TCPSTATE(&ts->sock) >> 8, short_be(hdr->trans.sport), short_be(hdr->trans.dport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len ); - } else { - pico_frame_discard(cpy); - } - - return 0; - -} - -static int tcp_send(struct pico_socket_tcp *ts, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->trans.sport = ts->sock.local_port; - hdr->trans.dport = ts->sock.remote_port; - if (!hdr->seq) - hdr->seq = long_be(ts->snd_nxt); - - tcp_send_add_tcpflags(ts, f); - - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - hdr->rwnd = short_be(ts->wnd); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum(f)); - - return tcp_send_try_enqueue(ts, f); - -} - -/* #define PICO_TCP_SUPPORT_SOCKET_STATS */ - -#ifdef PICO_TCP_SUPPORT_SOCKET_STATS -static void sock_stats(uint32_t when, void *arg) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; - tcp_dbg("STATISTIC> [%lu] socket state: %02x --> local port:%d remote port: %d queue size: %d snd_una: %08x snd_nxt: %08x cwnd: %d\n", - when, t->sock.state, short_be(t->sock.local_port), short_be(t->sock.remote_port), t->tcpq_out.size, SEQN((struct pico_frame *)first_segment(&t->tcpq_out)), t->snd_nxt, t->cwnd); - pico_timer_add(2000, sock_stats, t); -} -#endif - -static void tcp_send_probe(struct pico_socket_tcp *t); - -static void pico_tcp_keepalive(pico_time now, void *arg) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; - if (((t->sock.state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) && (t->ka_time > 0)) { - if (t->ka_time < (now - t->ack_timestamp)) { - if (t->ka_retries_count == 0) { - /* First probe */ - tcp_send_probe(t); - t->ka_retries_count++; - } - if (t->ka_retries_count > t->ka_probes) { - if (t->sock.wakeup) - { - pico_err = PICO_ERR_ECONNRESET; - t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock); - } - } - if (((t->ka_retries_count * t->ka_intvl) + t->ka_time) < (now - t->ack_timestamp)) { - /* Next probe */ - tcp_send_probe(t); - t->ka_retries_count++; - } - } else { - t->ka_retries_count = 0; - } - } - t->keepalive_tmr = pico_timer_add(1000, pico_tcp_keepalive, t); -} - -static inline void rto_set(struct pico_socket_tcp *t, uint32_t rto) -{ - if (rto < PICO_TCP_RTO_MIN) - rto = PICO_TCP_RTO_MIN; - - if (rto > PICO_TCP_RTO_MAX) - rto = PICO_TCP_RTO_MAX; - - t->rto = rto; -} - - -struct pico_socket *pico_tcp_open(uint16_t family) -{ - struct pico_socket_tcp *t = PICO_ZALLOC(sizeof(struct pico_socket_tcp)); - if (!t) - return NULL; - - t->sock.timestamp = TCP_TIME; - pico_socket_set_family(&t->sock, family); - t->mss = (uint16_t)(pico_socket_get_mss(&t->sock) - PICO_SIZE_TCPHDR); - t->tcpq_in.pool.root = t->tcpq_hold.pool.root = t->tcpq_out.pool.root = &LEAF; - t->tcpq_hold.pool.compare = t->tcpq_out.pool.compare = segment_compare; - t->tcpq_in.pool.compare = input_segment_compare; - t->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ; - t->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ; - t->tcpq_hold.max_size = 2u * t->mss; - rto_set(t, PICO_TCP_RTO_MIN); - - /* Uncomment next line and disable Nagle by default */ - t->sock.opt_flags |= (1 << PICO_SOCKET_OPT_TCPNODELAY); - - /* Uncomment next line and Nagle is enabled by default */ - /* t->sock.opt_flags &= (uint16_t) ~(1 << PICO_SOCKET_OPT_TCPNODELAY); */ - - /* Set default linger for the socket */ - t->linger_timeout = PICO_SOCKET_LINGER_TIMEOUT; - - -#ifdef PICO_TCP_SUPPORT_SOCKET_STATS - pico_timer_add(2000, sock_stats, t); -#endif - - t->keepalive_tmr = pico_timer_add(1000, pico_tcp_keepalive, t); - tcp_set_space(t); - - return &t->sock; -} - -static uint32_t tcp_read_finish(struct pico_socket *s, uint32_t tot_rd_len) -{ - struct pico_socket_tcp *t = TCP_SOCK(s); - tcp_set_space(t); - if (t->tcpq_in.size == 0) { - s->ev_pending &= (uint16_t)(~PICO_SOCK_EV_RD); - } - - if (t->remote_closed) { - s->ev_pending |= (uint16_t)(PICO_SOCK_EV_CLOSE); - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; - /* set SHUT_REMOTE */ - s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; - if (s->wakeup) { - s->wakeup(PICO_SOCK_EV_CLOSE, s); - } - } - - return tot_rd_len; -} - -static inline uint32_t tcp_read_in_frame_len(struct tcp_input_segment *f, int32_t in_frame_off, uint32_t tot_rd_len, uint32_t read_op_len) -{ - uint32_t in_frame_len = 0; - if (in_frame_off > 0) - { - if ((uint32_t)in_frame_off > f->payload_len) { - tcp_dbg("FATAL TCP ERR: in_frame_off > f->payload_len\n"); - } - - in_frame_len = f->payload_len - (uint32_t)in_frame_off; - } else { /* in_frame_off == 0 */ - in_frame_len = f->payload_len; - } - - if ((in_frame_len + tot_rd_len) > (uint32_t)read_op_len) { - in_frame_len = read_op_len - tot_rd_len; - } - - return in_frame_len; - -} - -static inline void tcp_read_check_segment_done(struct pico_socket_tcp *t, struct tcp_input_segment *f, uint32_t in_frame_len) -{ - if ((in_frame_len == 0u) || (in_frame_len == (uint32_t)f->payload_len)) { - pico_discard_segment(&t->tcpq_in, f); - } -} - -uint32_t pico_tcp_read(struct pico_socket *s, void *buf, uint32_t len) -{ - struct pico_socket_tcp *t = TCP_SOCK(s); - struct tcp_input_segment *f; - int32_t in_frame_off; - uint32_t in_frame_len; - uint32_t tot_rd_len = 0; - - while (tot_rd_len < len) { - /* To be sure we don't have garbage at the beginning */ - release_until(&t->tcpq_in, t->rcv_processed); - f = first_segment(&t->tcpq_in); - if (!f) - return tcp_read_finish(s, tot_rd_len); - - in_frame_off = pico_seq_compare(t->rcv_processed, f->seq); - /* Check for hole at the beginning of data, awaiting retransmissions. */ - if (in_frame_off < 0) { - tcp_dbg("TCP> read hole beginning of data, %08x - %08x. rcv_nxt is %08x\n", t->rcv_processed, f->seq, t->rcv_nxt); - return tcp_read_finish(s, tot_rd_len); - } - - in_frame_len = tcp_read_in_frame_len(f, in_frame_off, tot_rd_len, len); - - - memcpy((uint8_t *)buf + tot_rd_len, f->payload + in_frame_off, in_frame_len); - tot_rd_len += in_frame_len; - t->rcv_processed += in_frame_len; - - tcp_read_check_segment_done(t, f, in_frame_len); - - } - return tcp_read_finish(s, tot_rd_len); -} - -int pico_tcp_initconn(struct pico_socket *s); -static void initconn_retry(pico_time when, void *arg) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; - IGNORE_PARAMETER(when); - if (TCPSTATE(&t->sock) != PICO_SOCKET_STATE_TCP_ESTABLISHED) - { - if (t->backoff > PICO_TCP_MAX_CONNECT_RETRIES) { - tcp_dbg("TCP> Connection timeout. \n"); - if (t->sock.wakeup) - { - pico_err = PICO_ERR_ECONNREFUSED; - t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock); - } - pico_socket_del(&t->sock); - return; - } - - tcp_dbg("TCP> SYN retry %d...\n", t->backoff); - t->backoff++; - pico_tcp_initconn(&t->sock); - } else { - tcp_dbg("TCP> Connection is already established: no retry needed. good.\n"); - } -} - -int pico_tcp_initconn(struct pico_socket *s) -{ - struct pico_socket_tcp *ts = TCP_SOCK(s); - struct pico_frame *syn; - struct pico_tcp_hdr *hdr; - uint16_t mtu, opt_len = tcp_options_size(ts, PICO_TCP_SYN); - - syn = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); - if (!syn) - return -1; - - hdr = (struct pico_tcp_hdr *) syn->transport_hdr; - - if (!ts->snd_nxt) - ts->snd_nxt = long_be(pico_paws()); - - ts->snd_last = ts->snd_nxt; - ts->cwnd = PICO_TCP_IW; - mtu = (uint16_t)pico_socket_get_mss(s); - ts->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR); - ts->ssthresh = (uint16_t)((uint16_t)(PICO_DEFAULT_SOCKETQ / ts->mss) - (((uint16_t)(PICO_DEFAULT_SOCKETQ / ts->mss)) >> 3u)); - syn->sock = s; - hdr->seq = long_be(ts->snd_nxt); - hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo); - hdr->flags = PICO_TCP_SYN; - tcp_set_space(ts); - hdr->rwnd = short_be(ts->wnd); - tcp_add_options(ts, syn, PICO_TCP_SYN, opt_len); - hdr->trans.sport = ts->sock.local_port; - hdr->trans.dport = ts->sock.remote_port; - - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum(syn)); - - /* TCP: ENQUEUE to PROTO ( SYN ) */ - tcp_dbg("Sending SYN... (ports: %d - %d) size: %d\n", short_be(ts->sock.local_port), short_be(ts->sock.remote_port), syn->buffer_len); - pico_enqueue(&tcp_out, syn); - ts->retrans_tmr = pico_timer_add(PICO_TCP_SYN_TO << ts->backoff, initconn_retry, ts); - return 0; -} - -static int tcp_send_synack(struct pico_socket *s) -{ - struct pico_socket_tcp *ts = TCP_SOCK(s); - struct pico_frame *synack; - struct pico_tcp_hdr *hdr; - uint16_t opt_len = tcp_options_size(ts, PICO_TCP_SYN | PICO_TCP_ACK); - - synack = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); - if (!synack) - return -1; - - hdr = (struct pico_tcp_hdr *) synack->transport_hdr; - - synack->sock = s; - hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo); - hdr->flags = PICO_TCP_SYN | PICO_TCP_ACK; - hdr->rwnd = short_be(ts->wnd); - hdr->seq = long_be(ts->snd_nxt); - ts->rcv_processed = long_be(hdr->seq); - ts->snd_last = ts->snd_nxt; - tcp_set_space(ts); - tcp_add_options(ts, synack, hdr->flags, opt_len); - synack->payload_len = 0; - synack->timestamp = TCP_TIME; - tcp_send(ts, synack); - pico_frame_discard(synack); - return 0; -} - -static void tcp_send_empty(struct pico_socket_tcp *t, uint16_t flags, int is_keepalive) -{ - struct pico_frame *f; - struct pico_tcp_hdr *hdr; - uint16_t opt_len = tcp_options_size(t, flags); - f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); - if (!f) { - return; - } - - f->sock = &t->sock; - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); - hdr->flags = (uint8_t)flags; - hdr->rwnd = short_be(t->wnd); - tcp_set_space(t); - tcp_add_options(t, f, flags, opt_len); - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - hdr->seq = long_be(t->snd_nxt); - if ((flags & PICO_TCP_ACK) != 0) { - hdr->ack = long_be(t->rcv_nxt); - } - - if (is_keepalive) - hdr->seq = long_be(t->snd_nxt - 1); - - t->rcv_ackd = t->rcv_nxt; - - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - hdr->rwnd = short_be(t->wnd); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum(f)); - - /* TCP: ENQUEUE to PROTO */ - pico_enqueue(&tcp_out, f); -} - -static void tcp_send_ack(struct pico_socket_tcp *t) -{ - tcp_send_empty(t, PICO_TCP_ACK, 0); -} - -static void tcp_send_probe(struct pico_socket_tcp *t) -{ - /* tcp_dbg("Sending probe\n"); */ - tcp_send_empty(t, PICO_TCP_PSHACK, 1); -} - -static int tcp_do_send_rst(struct pico_socket *s, uint32_t seq) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST); - struct pico_frame *f; - struct pico_tcp_hdr *hdr; - f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); - if (!f) { - return -1; - } - f->sock = &t->sock; - tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> START\n"); - - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); - hdr->flags = PICO_TCP_RST; - hdr->rwnd = short_be(t->wnd); - tcp_set_space(t); - tcp_add_options(t, f, PICO_TCP_RST, opt_len); - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - hdr->seq = seq; - hdr->ack = long_be(t->rcv_nxt); - t->rcv_ackd = t->rcv_nxt; - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - hdr->rwnd = short_be(t->wnd); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum(f)); - - /* TCP: ENQUEUE to PROTO */ - pico_enqueue(&tcp_out, f); - tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> DONE\n"); - return 0; -} - -static int tcp_send_rst(struct pico_socket *s, struct pico_frame *fr) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - struct pico_tcp_hdr *hdr_rcv; - int ret; - - if (fr && ((s->state & PICO_SOCKET_STATE_TCP) > PICO_SOCKET_STATE_TCP_SYN_RECV)) { - /* in synchronized state: send RST with seq = ack from previous segment */ - hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr; - ret = tcp_do_send_rst(s, hdr_rcv->ack); - } else { - /* non-synchronized state */ - /* go to CLOSED here to prevent timer callback to go on after timeout */ - (t->sock).state &= 0x00FFU; - (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; - ret = tcp_do_send_rst(s, long_be(t->snd_nxt)); - - /* Set generic socket state to CLOSED, too */ - (t->sock).state &= 0xFF00U; - (t->sock).state |= PICO_SOCKET_STATE_CLOSED; - - /* call EV_FIN wakeup before deleting */ - if ((t->sock).wakeup) - (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); - - /* delete socket */ - pico_socket_del(&t->sock); - } - return ret; -} - -static inline void tcp_fill_rst_payload(struct pico_frame *fr, struct pico_frame *f) -{ - /* fill in IP data from original frame */ - if (IS_IPV4(fr)) { - memcpy(f->net_hdr, fr->net_hdr, sizeof(struct pico_ipv4_hdr)); - ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->src.addr; - ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->dst.addr; - tcp_dbg("Making IPv4 reset frame...\n"); - - } else { - memcpy(f->net_hdr, fr->net_hdr, sizeof(struct pico_ipv6_hdr)); - ((struct pico_ipv6_hdr *)(f->net_hdr))->dst = ((struct pico_ipv6_hdr *)(fr->net_hdr))->src; - ((struct pico_ipv6_hdr *)(f->net_hdr))->src = ((struct pico_ipv6_hdr *)(fr->net_hdr))->dst; - } - - /* fill in TCP data from original frame */ - ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.dport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.sport; - ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.sport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.dport; - -} - - -static inline void tcp_fill_rst_header(struct pico_frame *fr, struct pico_tcp_hdr *hdr1, struct pico_frame *f, struct pico_tcp_hdr *hdr) -{ - if(!(hdr1->flags & PICO_TCP_ACK)) - hdr->flags |= PICO_TCP_ACK; - - hdr->rwnd = 0; - if (((struct pico_tcp_hdr *)(fr->transport_hdr))->flags & PICO_TCP_ACK) { - hdr->seq = ((struct pico_tcp_hdr *)(fr->transport_hdr))->ack; - } else { - hdr->seq = 0U; - } - - hdr->ack = 0; - if(!(hdr1->flags & PICO_TCP_ACK)) - hdr->ack = long_be(long_be(((struct pico_tcp_hdr *)(fr->transport_hdr))->seq) + fr->payload_len); - - hdr->crc = short_be(pico_tcp_checksum(f)); -} - -int pico_tcp_reply_rst(struct pico_frame *fr) -{ - struct pico_tcp_hdr *hdr, *hdr1; - struct pico_frame *f; - uint16_t size = PICO_SIZE_TCPHDR; - - - hdr1 = (struct pico_tcp_hdr *) (fr->transport_hdr); - if ((hdr1->flags & PICO_TCP_RST) != 0) - return -1; - - tcp_dbg("TCP> sending RST ... \n"); - - f = fr->sock->net->alloc(fr->sock->net, size); - if (!f) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - tcp_fill_rst_payload(fr, f); - - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->len = (uint8_t)(size << 2); - hdr->flags = PICO_TCP_RST; - - tcp_fill_rst_header(fr, hdr1, f, hdr); - - if (0) { -#ifdef PICO_SUPPORT_IPV4 - } else if (IS_IPV4(f)) { - tcp_dbg("Pushing IPv4 reset frame...\n"); - pico_ipv4_frame_push(f, &(((struct pico_ipv4_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP); -#endif -#ifdef PICO_SUPPORT_IPV6 - } else { - pico_ipv6_frame_push(f, NULL, &(((struct pico_ipv6_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP, 0); -#endif - } - - - return 0; -} - -static int tcp_nosync_rst(struct pico_socket *s, struct pico_frame *fr) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - struct pico_frame *f; - struct pico_tcp_hdr *hdr, *hdr_rcv; - uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK); - hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr; - - tcp_dbg("TCP SEND RST (NON-SYNC) >>>>>>>>>>>>>>>>>> state %x\n", (s->state & PICO_SOCKET_STATE_TCP)); - if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_LISTEN)) { - if ((fr->flags & PICO_TCP_RST) != 0) - return 0; - - return pico_tcp_reply_rst(fr); - } - - /***************************************************************************/ - /* sending RST */ - f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); - - if (!f) { - return -1; - } - - - f->sock = &t->sock; - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); - hdr->flags = PICO_TCP_RST | PICO_TCP_ACK; - hdr->rwnd = short_be(t->wnd); - tcp_set_space(t); - tcp_add_options(t, f, PICO_TCP_RST | PICO_TCP_ACK, opt_len); - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - - /* non-synchronized state */ - if (hdr_rcv->flags & PICO_TCP_ACK) { - hdr->seq = hdr_rcv->ack; - } else { - hdr->seq = 0U; - } - - hdr->ack = long_be(SEQN(fr) + fr->payload_len); - - t->rcv_ackd = t->rcv_nxt; - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - hdr->rwnd = short_be(t->wnd); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum(f)); - - /* TCP: ENQUEUE to PROTO */ - pico_enqueue(&tcp_out, f); - - /***************************************************************************/ - - tcp_dbg("TCP SEND_RST (NON_SYNC) >>>>>>>>>>>>>>> DONE, ...\n"); - - return 0; -} - -static void tcp_deltcb(pico_time when, void *arg); - -static void tcp_linger(struct pico_socket_tcp *t) -{ - pico_timer_cancel(t->fin_tmr); - t->fin_tmr = pico_timer_add(t->linger_timeout, tcp_deltcb, t); -} - -static void tcp_send_fin(struct pico_socket_tcp *t) -{ - struct pico_frame *f; - struct pico_tcp_hdr *hdr; - uint16_t opt_len = tcp_options_size(t, PICO_TCP_FIN); - f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); - if (!f) { - return; - } - - f->sock = &t->sock; - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); - hdr->flags = PICO_TCP_FIN | PICO_TCP_ACK; - hdr->ack = long_be(t->rcv_nxt); - t->rcv_ackd = t->rcv_nxt; - hdr->rwnd = short_be(t->wnd); - tcp_set_space(t); - tcp_add_options(t, f, PICO_TCP_FIN, opt_len); - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - hdr->seq = long_be(t->snd_nxt); - - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - hdr->rwnd = short_be(t->wnd); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum(f)); - /* tcp_dbg("SENDING FIN...\n"); */ - if (t->linger_timeout > 0) { - pico_enqueue(&tcp_out, f); - t->snd_nxt++; - } else { - pico_frame_discard(f); - } - tcp_linger(t); -} - -static void tcp_sack_prepare(struct pico_socket_tcp *t) -{ - struct tcp_input_segment *pkt; - uint32_t left = 0, right = 0; - struct tcp_sack_block *sb; - int n = 0; - if (t->sacks) /* previous sacks are pending */ - return; - - pkt = first_segment(&t->tcpq_in); - while(n < 3) { - if (!pkt) { - if(left) { - sb = PICO_ZALLOC(sizeof(struct tcp_sack_block)); - if (!sb) - break; - - sb->left = long_be(left); - sb->right = long_be(right); - n++; - sb->next = t->sacks; - t->sacks = sb; - left = 0; - right = 0; - } - - break; - } - - if (pkt->seq < t->rcv_nxt) { - pkt = next_segment(&t->tcpq_in, pkt); - continue; - } - - if (!left) { - left = pkt->seq; - right = pkt->seq + pkt->payload_len; - pkt = next_segment(&t->tcpq_in, pkt); - continue; - } - - if(pkt->seq == right) { - right += pkt->payload_len; - pkt = next_segment(&t->tcpq_in, pkt); - continue; - } else { - sb = PICO_ZALLOC(sizeof(struct tcp_sack_block)); - if (!sb) - break; - - sb->left = long_be(left); - sb->right = long_be(right); - n++; - sb->next = t->sacks; - t->sacks = sb; - left = 0; - right = 0; - pkt = next_segment(&t->tcpq_in, pkt); - } - } -} - -static inline int tcp_data_in_expected(struct pico_socket_tcp *t, struct pico_frame *f) -{ - struct tcp_input_segment *nxt; - if (pico_seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */ - /* Create new segment and enqueue it */ - struct tcp_input_segment *input = segment_from_frame(f); - if (!input) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if(pico_enqueue_segment(&t->tcpq_in, input) <= 0) - { - /* failed to enqueue, destroy segment */ - PICO_FREE(input->payload); - PICO_FREE(input); - return -1; - } else { - t->rcv_nxt = SEQN(f) + f->payload_len; - nxt = peek_segment(&t->tcpq_in, t->rcv_nxt); - while(nxt) { - tcp_dbg("scrolling rcv_nxt...%08x\n", t->rcv_nxt); - t->rcv_nxt += nxt->payload_len; - nxt = peek_segment(&t->tcpq_in, t->rcv_nxt); - } - t->sock.ev_pending |= PICO_SOCK_EV_RD; - } - } else { - tcp_dbg("TCP> lo segment. Uninteresting retransmission. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); - } - - return 0; -} - -static inline int tcp_data_in_high_segment(struct pico_socket_tcp *t, struct pico_frame *f) -{ - tcp_dbg("TCP> hi segment. Possible packet loss. I'll dupack this. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); - if (t->sack_ok) { - struct tcp_input_segment *input = segment_from_frame(f); - if (!input) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if(pico_enqueue_segment(&t->tcpq_in, input) <= 0) { - /* failed to enqueue, destroy segment */ - PICO_FREE(input->payload); - PICO_FREE(input); - return -1; - } - - tcp_sack_prepare(t); - } - - return 0; -} - -static inline void tcp_data_in_send_ack(struct pico_socket_tcp *t, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; - /* In either case, ack til recv_nxt, unless received data raises a RST flag. */ - if (((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_CLOSE_WAIT) && - ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_SENT) && - ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_RECV) && - ((hdr->flags & PICO_TCP_RST) == 0)) - tcp_send_ack(t); -} - -static int tcp_data_in(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; - uint16_t payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0u) >> 2u)); - int ret = 0; - (void)hdr; - - if (((hdr->len & 0xf0u) >> 2u) <= f->transport_len) { - tcp_parse_options(f); - f->payload = f->transport_hdr + ((hdr->len & 0xf0u) >> 2u); - f->payload_len = payload_len; - tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); - - if (pico_seq_compare(SEQN(f), t->rcv_nxt) <= 0) { - ret = tcp_data_in_expected(t, f); - } else { - ret = tcp_data_in_high_segment(t, f); - } - - tcp_data_in_send_ack(t, f); - return ret; - } else { - tcp_dbg("TCP: invalid data in pkt len, exp: %d, got %d\n", (hdr->len & 0xf0) >> 2, f->transport_len); - return -1; - } -} - -static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f, pico_time *timestamp) -{ - int ret = release_all_until(&t->tcpq_out, ACKN(f), timestamp); - if (ret > 0) { - t->sock.ev_pending |= PICO_SOCK_EV_WR; - } - - return ret; -} - -static uint16_t time_diff(pico_time a, pico_time b) -{ - if (a >= b) - return (uint16_t)(a - b); - else - return (uint16_t)(b - a); -} - -static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt) -{ - - uint32_t avg = t->avg_rtt; - uint32_t rvar = t->rttvar; - if (!avg) { - /* This follows RFC2988 - * (2.2) When the first RTT measurement R is made, the host MUST set - * - * SRTT <- R - * RTTVAR <- R/2 - * RTO <- SRTT + max (G, K*RTTVAR) - */ - t->avg_rtt = rtt; - t->rttvar = rtt >> 1; - rto_set(t, t->avg_rtt + (t->rttvar << 2)); - } else { - int32_t var = (int32_t)t->avg_rtt - (int32_t)rtt; - if (var < 0) - var = 0 - var; - - /* RFC2988, section (2.3). Alpha and beta are the ones suggested. */ - - /* First, evaluate a new value for the rttvar */ - t->rttvar <<= 2; - t->rttvar -= rvar; - t->rttvar += (uint32_t)var; - t->rttvar >>= 2; - - /* Then, calculate the new avg_rtt */ - t->avg_rtt <<= 3; - t->avg_rtt -= avg; - t->avg_rtt += rtt; - t->avg_rtt >>= 3; - - /* Finally, assign a new value for the RTO, as specified in the RFC, with K=4 */ - rto_set(t, t->avg_rtt + (t->rttvar << 2)); - } - - tcp_dbg(" -----=============== RTT CUR: %u AVG: %u RTTVAR: %u RTO: %u ======================----\n", rtt, t->avg_rtt, t->rttvar, t->rto); -} - -static void tcp_congestion_control(struct pico_socket_tcp *t) -{ - if (t->x_mode > PICO_TCP_LOOKAHEAD) - return; - - tcp_dbg("Doing congestion control\n"); - if (t->cwnd < t->ssthresh) { - t->cwnd++; - } else { - t->cwnd_counter++; - if (t->cwnd_counter >= t->cwnd) { - t->cwnd++; - t->cwnd_counter = 0; - } - } - - tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", TCP_TIME, t->cwnd, t->ssthresh, t->in_flight); -} - -static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts); - - -/* Retransmission time out (RTO). */ - -static void tcp_first_timeout(struct pico_socket_tcp *t) -{ - t->x_mode = PICO_TCP_BLACKOUT; - t->cwnd = PICO_TCP_IW; - t->in_flight = 0; -} - -static int tcp_rto_xmit(struct pico_socket_tcp *t, struct pico_frame *f) -{ - struct pico_frame *cpy; - /* TCP: ENQUEUE to PROTO ( retransmit )*/ - cpy = pico_frame_copy(f); - if (!cpy) { - add_retransmission_timer(t, (t->rto << t->backoff) + TCP_TIME); - return -1; - } - - if (pico_enqueue(&tcp_out, cpy) > 0) { - t->snd_last_out = SEQN(cpy); - add_retransmission_timer(t, (t->rto << (++t->backoff)) + TCP_TIME); - tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", TCP_TIME, t->cwnd, t->ssthresh, t->in_flight); - tcp_dbg("Sending RTO!\n"); - return 1; - } else { - tcp_dbg("RTO fail, retry!\n"); - add_retransmission_timer(t, (t->rto << t->backoff) + TCP_TIME); - pico_frame_discard(cpy); - return 0; - } -} - -static void tcp_next_zerowindow_probe(struct pico_socket_tcp *t) -{ - tcp_dbg("Sending probe!\n"); - tcp_send_probe(t); - add_retransmission_timer(t, (t->rto << ++t->backoff) + TCP_TIME); -} - -static int tcp_is_allowed_to_send(struct pico_socket_tcp *t) -{ - return t->sock.net && - ( - ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED) || - ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) - ) && - ((t->backoff < PICO_TCP_MAX_RETRANS)); -} - -static inline int tcp_retrans_timeout_check_queue(struct pico_socket_tcp *t) -{ - struct pico_frame *f = NULL; - f = first_segment(&t->tcpq_out); - while (f) { - tcp_dbg("Checking frame in queue \n"); - if (t->x_mode == PICO_TCP_WINDOW_FULL) { - tcp_dbg("TCP BLACKOUT> TIMED OUT (output) frame %08x, len= %d rto=%d Win full: %d frame flags: %04x\n", SEQN(f), f->payload_len, t->rto, t->x_mode == PICO_TCP_WINDOW_FULL, f->flags); - tcp_next_zerowindow_probe(t); - return -1; - } - - if (t->x_mode != PICO_TCP_BLACKOUT) - tcp_first_timeout(t); - - tcp_add_header(t, f); - if (tcp_rto_xmit(t, f) > 0) /* A segment has been rexmit'd */ - return -1; - - f = next_segment(&t->tcpq_out, f); - } - if (t->tcpq_out.size < t->tcpq_out.max_size) - t->sock.ev_pending |= PICO_SOCK_EV_WR; - - return 0; - - - -} - -static void tcp_retrans_timeout(pico_time val, void *sock) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) sock; - - t->retrans_tmr = 0; - - if (t->retrans_tmr_due == 0ull) { - return; - } - - if (t->retrans_tmr_due > val) { - /* Timer was postponed... */ - add_retransmission_timer(t, t->retrans_tmr_due); - return; - } - - tcp_dbg("TIMEOUT! backoff = %d, rto: %d\n", t->backoff, t->rto); - t->retrans_tmr_due = 0ull; - - if (tcp_is_allowed_to_send(t)) { - if (tcp_retrans_timeout_check_queue(t) < 0) - return; - } - else if(t->backoff >= PICO_TCP_MAX_RETRANS && (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED ) - { - tcp_dbg("Connection timeout!\n"); - /* the retransmission timer, failed to get an ack for a frame, gives up on the connection */ - tcp_discard_all_segments(&t->tcpq_out); - if(t->sock.wakeup) - t->sock.wakeup(PICO_SOCK_EV_FIN, &t->sock); - - /* delete socket */ - pico_socket_del(&t->sock); - return; - } else { - tcp_dbg("Retransmission not allowed, rescheduling\n"); - } -} - -static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts) -{ - struct pico_tree_node *index; - pico_time now = TCP_TIME; - pico_time val = 0; - - - if (next_ts == 0) { - struct pico_frame *f; - - pico_tree_foreach(index, &t->tcpq_out.pool){ - f = index->keyValue; - if ((next_ts == 0) || ((f->timestamp < next_ts) && (f->timestamp > 0))) { - next_ts = f->timestamp; - val = next_ts + (t->rto << t->backoff); - } - } - } else { - val = next_ts; - } - - if ((val > 0) || (val > now)) { - t->retrans_tmr_due = val; - } else { - t->retrans_tmr_due = now + 1; - } - - if (!t->retrans_tmr) { - t->retrans_tmr = pico_timer_add(t->retrans_tmr_due - now, tcp_retrans_timeout, t); - tcp_dbg("Next timeout in %u msec\n", (uint32_t) (t->retrans_tmr_due - now)); - } -} - -static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f) -{ - struct pico_frame *cpy; - if (f) { - tcp_dbg("TCP> RETRANS (by dupack) frame %08x, len= %d\n", SEQN(f), f->payload_len); - tcp_add_header(t, f); - /* TCP: ENQUEUE to PROTO ( retransmit )*/ - cpy = pico_frame_copy(f); - if (!cpy) { - return -1; - } - - if (pico_enqueue(&tcp_out, cpy) > 0) { - t->in_flight++; - t->snd_last_out = SEQN(cpy); - } else { - pico_frame_discard(cpy); - } - - add_retransmission_timer(t, TCP_TIME + t->rto); - return(f->payload_len); - } - - return 0; -} - -#ifdef TCP_ACK_DBG -static void tcp_ack_dbg(struct pico_socket *s, struct pico_frame *f) -{ - uint32_t una, nxt, ack, cur; - struct pico_frame *una_f = NULL, *cur_f; - struct pico_tree_node *idx; - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - char info[64]; - char tmp[64]; - ack = ACKN(f); - nxt = t->snd_nxt; - tcp_dbg("===================================\n"); - tcp_dbg("Queue out (%d/%d). ACKED=%08x\n", t->tcpq_out.size, t->tcpq_out.max_size, ack); - - pico_tree_foreach(idx, &t->tcpq_out.pool) { - info[0] = 0; - cur_f = idx->keyValue; - cur = SEQN(cur_f); - if (!una_f) { - una_f = cur_f; - una = SEQN(una_f); - } - - if (cur == nxt) { - strncpy(tmp, info, strlen(info)); - snprintf(info, 64, "%s SND_NXT", tmp); - } - - if (cur == ack) { - strncpy(tmp, info, strlen(info)); - snprintf(info, 64, "%s ACK", tmp); - } - - if (cur == una) { - strncpy(tmp, info, strlen(info)); - snprintf(info, 64, "%s SND_UNA", tmp); - } - - if (cur == t->snd_last) { - strncpy(tmp, info, strlen(info)); - snprintf(info, 64, "%s SND_LAST", tmp); - } - - tcp_dbg("%08x %d%s\n", cur, cur_f->payload_len, info); - - } - tcp_dbg("SND_NXT is %08x, snd_LAST is %08x\n", nxt, t->snd_last); - tcp_dbg("===================================\n"); - tcp_dbg("\n\n"); -} -#endif - -static int tcp_ack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_frame *f_new; /* use with Nagle to push to out queue */ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; - uint32_t rtt = 0; - uint16_t acked = 0; - pico_time acked_timestamp = 0; - - struct pico_frame *una = NULL; - if ((hdr->flags & PICO_TCP_ACK) == 0) - return -1; - -#ifdef TCP_ACK_DBG - tcp_ack_dbg(s, f); -#endif - - tcp_parse_options(f); - t->recv_wnd = short_be(hdr->rwnd); - - acked = (uint16_t)tcp_ack_advance_una(t, f, &acked_timestamp); - una = first_segment(&t->tcpq_out); - t->ack_timestamp = TCP_TIME; - - if ((t->x_mode == PICO_TCP_BLACKOUT) || - ((t->x_mode == PICO_TCP_WINDOW_FULL) && ((t->recv_wnd << t->recv_wnd_scale) > t->mss))) { - int prev_mode = t->x_mode; - tcp_dbg("Re-entering look-ahead...\n\n\n"); - t->x_mode = PICO_TCP_LOOKAHEAD; - t->backoff = 0; - - if((prev_mode == PICO_TCP_BLACKOUT) && (acked > 0) && una) - { - t->snd_nxt = SEQN(una); - /* restart the retrans timer */ - if (t->retrans_tmr) { - t->retrans_tmr_due = 0ull; - } - } - } - - /* One should be acked. */ - if ((acked == 0) && (f->payload_len == 0) && (t->in_flight > 0)) - t->in_flight--; - - if (!una || acked > 0) { - t->x_mode = PICO_TCP_LOOKAHEAD; - tcp_dbg("Mode: Look-ahead. In flight: %d/%d buf: %d\n", t->in_flight, t->cwnd, t->tcpq_out.frames); - t->backoff = 0; - - /* Do rtt/rttvar/rto calculations */ - /* First, try with timestamps, using the value from options */ - if(f && (f->timestamp != 0)) { - rtt = time_diff(TCP_TIME, f->timestamp); - if (rtt) - tcp_rtt(t, rtt); - } else if(acked_timestamp) { - /* If no timestamps are there, use conservative estimation on the una */ - rtt = time_diff(TCP_TIME, acked_timestamp); - if (rtt) - tcp_rtt(t, rtt); - } - - tcp_dbg("TCP ACK> FRESH ACK %08x (acked %d) Queue size: %u/%u frames: %u cwnd: %u in_flight: %u snd_una: %u\n", ACKN(f), acked, t->tcpq_out.size, t->tcpq_out.max_size, t->tcpq_out.frames, t->cwnd, t->in_flight, SEQN(una)); - if (acked > t->in_flight) { - tcp_dbg("WARNING: in flight < 0\n"); - t->in_flight = 0; - } else - t->in_flight -= (acked); - - } else if ((t->snd_old_ack == ACKN(f)) && /* We've just seen this ack, and... */ - ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) && - (f->payload_len == 0)) && /* This is a pure ack, and... */ - (ACKN(f) != t->snd_nxt)) /* There is something in flight awaiting to be acked... */ - { - /* Process incoming duplicate ack. */ - if (t->x_mode < PICO_TCP_RECOVER) { - t->x_mode++; - tcp_dbg("Mode: DUPACK %d, due to PURE ACK %0x, len = %d\n", t->x_mode, SEQN(f), f->payload_len); - /* tcp_dbg("ACK: %x - QUEUE: %x\n", ACKN(f), SEQN(first_segment(&t->tcpq_out))); */ - if (t->x_mode == PICO_TCP_RECOVER) { /* Switching mode */ - if (t->in_flight > PICO_TCP_IW) - t->cwnd = (uint16_t)t->in_flight; - else - t->cwnd = PICO_TCP_IW; - - t->snd_retry = SEQN((struct pico_frame *)first_segment(&t->tcpq_out)); - if (t->ssthresh > t->cwnd) - t->ssthresh >>= 2; - else - t->ssthresh = (t->cwnd >> 1); - - if (t->ssthresh < 2) - t->ssthresh = 2; - } - } else if (t->x_mode == PICO_TCP_RECOVER) { - /* tcp_dbg("TCP RECOVER> DUPACK! snd_una: %08x, snd_nxt: %08x, acked now: %08x\n", SEQN(first_segment(&t->tcpq_out)), t->snd_nxt, ACKN(f)); */ - if (t->in_flight <= t->cwnd) { - struct pico_frame *nxt = peek_segment(&t->tcpq_out, t->snd_retry); - if (!nxt) - nxt = first_segment(&t->tcpq_out); - - while (nxt && (nxt->flags & PICO_FRAME_FLAG_SACKED) && (nxt != first_segment(&t->tcpq_out))) { - tcp_dbg("Skipping %08x because it is sacked.\n", SEQN(nxt)); - nxt = next_segment(&t->tcpq_out, nxt); - } - if (nxt && (pico_seq_compare(SEQN(nxt), t->snd_nxt)) > 0) - nxt = NULL; - - if (nxt && (pico_seq_compare(SEQN(nxt), SEQN((struct pico_frame *)first_segment(&t->tcpq_out))) > (int)(t->recv_wnd << t->recv_wnd_scale))) - nxt = NULL; - - if(!nxt) - nxt = first_segment(&t->tcpq_out); - - if (nxt) { - tcp_retrans(t, peek_segment(&t->tcpq_out, t->snd_retry)); - t->snd_retry = SEQN(nxt); - } - } - - if (++t->cwnd_counter > 1) { - t->cwnd--; - if (t->cwnd < 2) - t->cwnd = 2; - - t->cwnd_counter = 0; - } - } else { - tcp_dbg("DUPACK in mode %d \n", t->x_mode); - - } - } /* End case duplicate ack detection */ - - /* Linux very special zero-window probe detection (see bug #107) */ - if ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) && /* This is a pure ack, and... */ - (ACKN(f) == t->snd_nxt) && /* it's acking our snd_nxt, and... */ - (pico_seq_compare(SEQN(f), t->rcv_nxt) < 0)) /* Has an old seq number */ - { - tcp_send_ack(t); - } - - - /* Do congestion control */ - tcp_congestion_control(t); - if ((acked > 0) && t->sock.wakeup) { - if (t->tcpq_out.size < t->tcpq_out.max_size) - t->sock.wakeup(PICO_SOCK_EV_WR, &(t->sock)); - - /* t->sock.ev_pending |= PICO_SOCK_EV_WR; */ - } - - /* if Nagle enabled, check if no unack'ed data and fill out queue (till window) */ - if (IS_NAGLE_ENABLED((&(t->sock)))) { - while (!IS_TCP_HOLDQ_EMPTY(t) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= t->mss)) { - tcp_dbg_nagle("TCP_ACK - NAGLE add new segment\n"); - f_new = pico_hold_segment_make(t); - if (f_new == NULL) - break; /* XXX corrupt !!! (or no memory) */ - - if (pico_enqueue_segment(&t->tcpq_out, f_new) <= 0) - /* handle error */ - tcp_dbg_nagle("TCP_ACK - NAGLE FAILED to enqueue in out\n"); - } - } - - /* If some space was created, put a few segments out. */ - tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", TCP_TIME, t->cwnd, t->ssthresh, t->in_flight); - if (t->x_mode == PICO_TCP_LOOKAHEAD) { - if ((t->cwnd >= t->in_flight) && (t->snd_nxt > t->snd_last_out)) { - pico_tcp_output(&t->sock, (int)t->cwnd - (int)t->in_flight); - } - } - - add_retransmission_timer(t, 0); - t->snd_old_ack = ACKN(f); - return 0; -} - -static int tcp_finwaitack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - tcp_dbg("RECEIVED ACK IN FIN_WAIT1\n"); - - /* acking part */ - tcp_ack(s, f); - - - tcp_dbg("FIN_WAIT1: ack is %08x - snd_nxt is %08x\n", ACKN(f), t->snd_nxt); - if (ACKN(f) == (t->snd_nxt - 1u)) { - /* update TCP state */ - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT2; - tcp_dbg("TCP> IN STATE FIN_WAIT2\n"); - } - return 0; -} - -static void tcp_deltcb(pico_time when, void *arg) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; - IGNORE_PARAMETER(when); - - /* send RST if not yet in TIME_WAIT */ - if ( (((t->sock).state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_TIME_WAIT) - && (((t->sock).state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_CLOSING) ) { - tcp_dbg("Called deltcb in state = %04x (sending reset!)\n", (t->sock).state); - tcp_do_send_rst(&t->sock, long_be(t->snd_nxt)); - } else { - tcp_dbg("Called deltcb in state = %04x\n", (t->sock).state); - } - - /* update state */ - (t->sock).state &= 0x00FFU; - (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; - (t->sock).state &= 0xFF00U; - (t->sock).state |= PICO_SOCKET_STATE_CLOSED; - /* call EV_FIN wakeup before deleting */ - if (t->sock.wakeup) { - (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); - } - - /* delete socket */ - pico_socket_del(&t->sock); -} - -static int tcp_finwaitfin(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); - tcp_dbg("TCP> received fin in FIN_WAIT2\n"); - /* received FIN, increase ACK nr */ - t->rcv_nxt = long_be(hdr->seq) + 1; - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; - /* set SHUT_REMOTE */ - s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_CLOSE, s); - - if (f->payload_len > 0) /* needed?? */ - tcp_data_in(s, f); - - /* send ACK */ - tcp_send_ack(t); - /* linger */ - tcp_linger(t); - return 0; -} - -static int tcp_closing_ack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - tcp_dbg("TCP> received ack in CLOSING\n"); - /* acking part */ - tcp_ack(s, f); - - /* update TCP state DLA TODO: Only if FIN is acked! */ - tcp_dbg("CLOSING: ack is %08x - snd_nxt is %08x\n", ACKN(f), t->snd_nxt); - if (ACKN(f) == t->snd_nxt) { - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; - /* set timer */ - tcp_linger(t); - } - return 0; -} - -static int tcp_lastackwait(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - tcp_dbg("LAST_ACK: ack is %08x - snd_nxt is %08x\n", ACKN(f), t->snd_nxt); - if (ACKN(f) == t->snd_nxt) { - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_CLOSED; - s->state &= 0xFF00U; - s->state |= PICO_SOCKET_STATE_CLOSED; - /* call socket wakeup with EV_FIN */ - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_FIN, s); - - /* delete socket */ - pico_socket_del(s); - } - return 0; -} - -static int tcp_syn(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *new = NULL; - struct pico_tcp_hdr *hdr = NULL; - uint16_t mtu; - if(s->number_of_pending_conn >= s->max_backlog) - return -1; - - new = (struct pico_socket_tcp *)pico_socket_clone(s); - hdr = (struct pico_tcp_hdr *)f->transport_hdr; - if (!new) - return -1; - -#ifdef PICO_TCP_SUPPORT_SOCKET_STATS - pico_timer_add(2000, sock_stats, s); -#endif - - new->sock.remote_port = ((struct pico_trans *)f->transport_hdr)->sport; -#ifdef PICO_SUPPORT_IPV4 - if (IS_IPV4(f)) { - new->sock.remote_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr; - new->sock.local_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr; - } - -#endif -#ifdef PICO_SUPPORT_IPV6 - if (IS_IPV6(f)) { - new->sock.remote_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->src; - new->sock.local_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->dst; - } - -#endif - f->sock = &new->sock; - tcp_parse_options(f); - mtu = (uint16_t)pico_socket_get_mss(&new->sock); - new->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR); - new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ; - new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ; - new->tcpq_hold.max_size = 2u * mtu; - new->rcv_nxt = long_be(hdr->seq) + 1; - new->snd_nxt = long_be(pico_paws()); - new->snd_last = new->snd_nxt; - new->cwnd = PICO_TCP_IW; - new->ssthresh = (uint16_t)((uint16_t)(PICO_DEFAULT_SOCKETQ / new->mss) - (((uint16_t)(PICO_DEFAULT_SOCKETQ / new->mss)) >> 3u)); - new->recv_wnd = short_be(hdr->rwnd); - new->jumbo = hdr->len & 0x07; - new->linger_timeout = PICO_SOCKET_LINGER_TIMEOUT; - s->number_of_pending_conn++; - new->sock.parent = s; - new->sock.wakeup = s->wakeup; - rto_set(new, PICO_TCP_RTO_MIN); - /* Initialize timestamp values */ - new->sock.state = PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_RECV; - pico_socket_add(&new->sock); - tcp_send_synack(&new->sock); - tcp_dbg("SYNACK sent, socket added. snd_nxt is %08x\n", new->snd_nxt); - return 0; -} - -static int tcp_synrecv_syn(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr = NULL; - struct pico_socket_tcp *t = TCP_SOCK(s); - hdr = (struct pico_tcp_hdr *)f->transport_hdr; - if (t->rcv_nxt == long_be(hdr->seq) + 1u) { - /* take back our own SEQ number to its original value, - * so the synack retransmitted is identical to the original. - */ - t->snd_nxt--; - tcp_send_synack(s); - } else { - tcp_send_rst(s, f); - return -1; - } - - return 0; -} - -static void tcp_set_init_point(struct pico_socket *s) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - t->rcv_processed = t->rcv_nxt; -} - - -uint16_t pico_tcp_get_socket_mss(struct pico_socket *s) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - if (t->mss > 0) - return (uint16_t)(t->mss + PICO_SIZE_TCPHDR); - else - return (uint16_t)pico_socket_get_mss(s); -} - -static int tcp_synack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; - - if (ACKN(f) == (1u + t->snd_nxt)) { - /* Get rid of initconn retry */ - pico_timer_cancel(t->retrans_tmr); - t->retrans_tmr = 0; - - t->rcv_nxt = long_be(hdr->seq); - t->rcv_processed = t->rcv_nxt + 1; - tcp_ack(s, f); - - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED; - tcp_dbg("TCP> Established. State: %x\n", s->state); - - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_CONN, s); - - s->ev_pending |= PICO_SOCK_EV_WR; - - t->rcv_nxt++; - t->snd_nxt++; - tcp_send_ack(t); /* return ACK */ - - return 0; - - } else if ((hdr->flags & PICO_TCP_RST) == 0) { - tcp_dbg("TCP> Not established, RST sent.\n"); - tcp_nosync_rst(s, f); - return 0; - } else { - /* The segment has the reset flag on: Ignore! */ - return 0; - } -} - -static int tcp_first_ack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; - tcp_dbg("ACK in SYN_RECV: expecting %08x got %08x\n", t->snd_nxt, ACKN(f)); - if (t->snd_nxt == ACKN(f)) { - tcp_set_init_point(s); - tcp_ack(s, f); - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED; - tcp_dbg("TCP: Established. State now: %04x\n", s->state); - if( !s->parent && s->wakeup) { /* If the socket has no parent, -> sending socket that has a sim_open */ - tcp_dbg("FIRST ACK - No parent found -> sending socket\n"); - s->wakeup(PICO_SOCK_EV_CONN, s); - } - - if (s->parent && s->parent->wakeup) { - tcp_dbg("FIRST ACK - Parent found -> listening socket\n"); - s->wakeup = s->parent->wakeup; - s->parent->wakeup(PICO_SOCK_EV_CONN, s->parent); - } - - s->ev_pending |= PICO_SOCK_EV_WR; - tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); - return 0; - } else if ((hdr->flags & PICO_TCP_RST) == 0) { - tcp_nosync_rst(s, f); - return 0; - } else { - /* The segment has the reset flag on: Ignore! */ - return 0; - } -} - -static void tcp_attempt_closewait(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); - if (pico_seq_compare(SEQN(f), t->rcv_nxt) == 0) { - /* received FIN, increase ACK nr */ - t->rcv_nxt = long_be(hdr->seq) + 1; - if (pico_seq_compare(SEQN(f), t->rcv_processed) == 0) { - if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) { - tcp_dbg("Changing state to CLOSE_WAIT\n"); - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; - } - - /* set SHUT_REMOTE */ - s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; - tcp_dbg("TCP> Close-wait\n"); - if (s->wakeup) { - s->wakeup(PICO_SOCK_EV_CLOSE, s); - } - } else { - t->remote_closed = 1; - } - } - - -} - -static int tcp_closewait(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); - - if (f->payload_len > 0) - tcp_data_in(s, f); - - if (hdr->flags & PICO_TCP_ACK) - tcp_ack(s, f); - - tcp_dbg("called close_wait (%p), in state %08x, f->flags: 0x%02x, hdr->flags: 0x%02x\n", tcp_closewait, s->state, f->flags, hdr->flags); - tcp_attempt_closewait(s, f); - - /* Ensure that the notification given to the socket - * did not put us in LAST_ACK state before sending the ACK: i.e. if - * pico_socket_close() has been called in the socket callback, we don't need to send - * an ACK here. - * - */ - if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) || - ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) - { - tcp_dbg("In closewait: Sending ack! (state is %08x)\n", s->state); - tcp_send_ack(t); - } - - return 0; -} - -static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - IGNORE_PARAMETER(f); - tcp_dbg("TCP> Received FIN in FIN_WAIT1\n"); - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_CLOSING; - t->rcv_processed = t->rcv_nxt + 1; - t->rcv_nxt++; - /* send ACK */ - tcp_send_ack(t); - return 0; -} - -static int tcp_finack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - IGNORE_PARAMETER(f); - - tcp_dbg("TCP> ENTERED finack\n"); - t->rcv_nxt++; - /* send ACK */ - tcp_send_ack(t); - - /* call socket wakeup with EV_FIN */ - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_FIN, s); - - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; - /* set SHUT_REMOTE */ - s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; - - tcp_linger(t); - - return 0; -} - -static void tcp_force_closed(struct pico_socket *s) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - /* update state */ - (t->sock).state &= 0x00FFU; - (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; - (t->sock).state &= 0xFF00U; - (t->sock).state |= PICO_SOCKET_STATE_CLOSED; - /* call EV_ERR wakeup before deleting */ - if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) { - if ((t->sock).wakeup) - (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); - } else { - pico_err = PICO_ERR_ECONNRESET; - if ((t->sock).wakeup) - (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock)); - - /* delete socket */ - pico_socket_del(&t->sock); - } -} - -static void tcp_wakeup_pending(struct pico_socket *s, uint16_t ev) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - if ((t->sock).wakeup) - (t->sock).wakeup(ev, &(t->sock)); -} - -static int tcp_rst(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); - - tcp_dbg("TCP >>>>>>>>>>>>>> received RST <<<<<<<<<<<<<<<<<<<<\n"); - if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_SENT) { - /* the RST is acceptable if the ACK field acknowledges the SYN */ - if ((t->snd_nxt + 1u) == ACKN(f)) { /* valid, got to closed state */ - tcp_force_closed(s); - } else { /* not valid, ignore */ - tcp_dbg("TCP RST> IGNORE\n"); - return 0; - } - } else { /* all other states */ - /* all reset (RST) segments are validated by checking their SEQ-fields, - a reset is valid if its sequence number is in the window */ - uint32_t this_seq = long_be(hdr->seq); - if ((this_seq >= t->rcv_ackd) && (this_seq <= ((uint32_t)(short_be(hdr->rwnd) << (t->wnd_scale)) + t->rcv_ackd))) { - tcp_force_closed(s); - } else { /* not valid, ignore */ - tcp_dbg("TCP RST> IGNORE\n"); - return 0; - } - } - - return 0; -} -static int tcp_halfopencon(struct pico_socket *s, struct pico_frame *fr) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - IGNORE_PARAMETER(fr); - tcp_send_ack(t); - return 0; -} - -static int tcp_closeconn(struct pico_socket *s, struct pico_frame *fr) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (fr->transport_hdr); - - if (pico_seq_compare(SEQN(fr), t->rcv_nxt) == 0) { - /* received FIN, increase ACK nr */ - t->rcv_nxt = long_be(hdr->seq) + 1; - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; - /* set SHUT_LOCAL */ - s->state |= PICO_SOCKET_STATE_SHUT_LOCAL; - pico_socket_close(s); - return 1; - } - - return 0; -} - -struct tcp_action_entry { - uint16_t tcpstate; - int (*syn)(struct pico_socket *s, struct pico_frame *f); - int (*synack)(struct pico_socket *s, struct pico_frame *f); - int (*ack)(struct pico_socket *s, struct pico_frame *f); - int (*data)(struct pico_socket *s, struct pico_frame *f); - int (*fin)(struct pico_socket *s, struct pico_frame *f); - int (*finack)(struct pico_socket *s, struct pico_frame *f); - int (*rst)(struct pico_socket *s, struct pico_frame *f); -}; - -static const struct tcp_action_entry tcp_fsm[] = { - /* State syn synack ack data fin finack rst*/ - { PICO_SOCKET_STATE_TCP_UNDEF, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, - { PICO_SOCKET_STATE_TCP_CLOSED, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, - { PICO_SOCKET_STATE_TCP_LISTEN, &tcp_syn, NULL, NULL, NULL, NULL, NULL, NULL }, - { PICO_SOCKET_STATE_TCP_SYN_SENT, NULL, &tcp_synack, NULL, NULL, NULL, NULL, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_SYN_RECV, &tcp_synrecv_syn, NULL, &tcp_first_ack, &tcp_data_in, NULL, &tcp_closeconn, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_ESTABLISHED, &tcp_halfopencon, &tcp_ack, &tcp_ack, &tcp_data_in, &tcp_closewait, &tcp_closewait, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_CLOSE_WAIT, NULL, &tcp_ack, &tcp_ack, &tcp_send_rst, &tcp_closewait, &tcp_closewait, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_LAST_ACK, NULL, &tcp_ack, &tcp_lastackwait, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_FIN_WAIT1, NULL, &tcp_ack, &tcp_finwaitack, &tcp_data_in, &tcp_rcvfin, &tcp_finack, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_FIN_WAIT2, NULL, &tcp_ack, &tcp_ack, &tcp_data_in, &tcp_finwaitfin, &tcp_finack, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_CLOSING, NULL, &tcp_ack, &tcp_closing_ack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_TIME_WAIT, NULL, NULL, NULL, &tcp_send_rst, NULL, NULL, NULL} -}; - -#define MAX_VALID_FLAGS 10 /* Maximum number of valid flag combinations */ -static uint8_t invalid_flags(struct pico_socket *s, uint8_t flags) -{ - uint8_t i; - static const uint8_t valid_flags[PICO_SOCKET_STATE_TCP_ARRAYSIZ][MAX_VALID_FLAGS] = { - { /* PICO_SOCKET_STATE_TCP_UNDEF */ 0, }, - { /* PICO_SOCKET_STATE_TCP_CLOSED */ 0, }, - { /* PICO_SOCKET_STATE_TCP_LISTEN */ PICO_TCP_SYN }, - { /* PICO_SOCKET_STATE_TCP_SYN_SENT */ PICO_TCP_SYNACK, PICO_TCP_RST, PICO_TCP_RSTACK}, - { /* PICO_SOCKET_STATE_TCP_SYN_RECV */ PICO_TCP_SYN, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, - { /* PICO_SOCKET_STATE_TCP_ESTABLISHED*/ PICO_TCP_SYN, PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST, PICO_TCP_RSTACK}, - { /* PICO_SOCKET_STATE_TCP_CLOSE_WAIT */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, - { /* PICO_SOCKET_STATE_TCP_LAST_ACK */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, - { /* PICO_SOCKET_STATE_TCP_FIN_WAIT1 */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, - { /* PICO_SOCKET_STATE_TCP_FIN_WAIT2 */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, - { /* PICO_SOCKET_STATE_TCP_CLOSING */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, - { /* PICO_SOCKET_STATE_TCP_TIME_WAIT */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, - }; - if(!flags) - return 1; - - for(i = 0; i < MAX_VALID_FLAGS; i++) { - if(valid_flags[s->state >> 8u][i] == flags) - return 0; - } - return 1; -} - -static void tcp_action_call(int (*call)(struct pico_socket *s, struct pico_frame *f), struct pico_socket *s, struct pico_frame *f ) -{ - if (call) - call(s, f); -} - -static int tcp_action_by_flags(const struct tcp_action_entry *action, struct pico_socket *s, struct pico_frame *f, uint8_t flags) -{ - int ret = 0; - - if ((flags == PICO_TCP_ACK) || (flags == (PICO_TCP_ACK | PICO_TCP_PSH))) { - tcp_action_call(action->ack, s, f); - } - - if ((f->payload_len > 0 || (flags & PICO_TCP_PSH)) && - !(s->state & PICO_SOCKET_STATE_CLOSED) && !TCP_IS_STATE(s, PICO_SOCKET_STATE_TCP_LISTEN)) - { - ret = f->payload_len; - tcp_action_call(action->data, s, f); - } - - if (flags == PICO_TCP_FIN) { - tcp_action_call(action->fin, s, f); - } - - if ((flags == (PICO_TCP_FIN | PICO_TCP_ACK)) || (flags == (PICO_TCP_FIN | PICO_TCP_ACK | PICO_TCP_PSH))) { - tcp_action_call(action->finack, s, f); - } - - if (flags & PICO_TCP_RST) { - tcp_action_call(action->rst, s, f); - } - - return ret; -} - -int pico_tcp_input(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); - int ret = 0; - uint8_t flags = hdr->flags; - const struct tcp_action_entry *action = &tcp_fsm[s->state >> 8]; - - f->payload = (f->transport_hdr + ((hdr->len & 0xf0u) >> 2u)); - f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0u) >> 2u)); - - tcp_dbg("[sam] TCP> [tcp input] t_len: %u\n", f->transport_len); - tcp_dbg("[sam] TCP> flags = 0x%02x\n", hdr->flags); - tcp_dbg("[sam] TCP> s->state >> 8 = %u\n", s->state >> 8); - tcp_dbg("[sam] TCP> [tcp input] socket: %p state: %d <-- local port:%u remote port: %u seq: 0x%08x ack: 0x%08x flags: 0x%02x t_len: %u, hdr: %u payload: %d\n", s, s->state >> 8, short_be(hdr->trans.dport), short_be(hdr->trans.sport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len ); - - /* This copy of the frame has the current socket as owner */ - f->sock = s; - s->timestamp = TCP_TIME; - /* Those are not supported at this time. */ - /* flags &= (uint8_t) ~(PICO_TCP_CWR | PICO_TCP_URG | PICO_TCP_ECN); */ - if(invalid_flags(s, flags)) { - pico_tcp_reply_rst(f); - } - else if (flags == PICO_TCP_SYN) { - tcp_action_call(action->syn, s, f); - } else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) { - tcp_action_call(action->synack, s, f); - } else { - ret = tcp_action_by_flags(action, s, f, flags); - } - - if (s->ev_pending) - tcp_wakeup_pending(s, s->ev_pending); - -/* discard: */ - pico_frame_discard(f); - return ret; -} - - -inline static int checkLocalClosing(struct pico_socket *s); -inline static int checkRemoteClosing(struct pico_socket *s); - -static struct pico_frame *tcp_split_segment(struct pico_socket_tcp *t, struct pico_frame *f, uint16_t size) -{ - struct pico_frame *f1, *f2; - uint16_t size1, size2, size_f; - uint16_t overhead; - struct pico_tcp_hdr *hdr1, *hdr2, *hdr = (struct pico_tcp_hdr *)f->transport_hdr; - overhead = pico_tcp_overhead(&t->sock); - size_f = f->payload_len; - - - if (size >= size_f) - return f; /* no need to split! */ - - size1 = size; - size2 = (uint16_t)(size_f - size); - - f1 = pico_socket_frame_alloc(&t->sock, (uint16_t) (size1 + overhead)); - f2 = pico_socket_frame_alloc(&t->sock, (uint16_t) (size2 + overhead)); - - if (!f1 || !f2) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - /* Advance payload pointer to the beginning of segment data */ - f1->payload += overhead; - f1->payload_len = (uint16_t)(f1->payload_len - overhead); - f2->payload += overhead; - f2->payload_len = (uint16_t)(f2->payload_len - overhead); - - hdr1 = (struct pico_tcp_hdr *)f1->transport_hdr; - hdr2 = (struct pico_tcp_hdr *)f2->transport_hdr; - - /* Copy payload */ - memcpy(f1->payload, f->payload, size1); - memcpy(f2->payload, f->payload + size1, size2); - - /* Copy tcp hdr */ - memcpy(hdr1, hdr, sizeof(struct pico_tcp_hdr)); - memcpy(hdr2, hdr, sizeof(struct pico_tcp_hdr)); - - /* Adjust f2's sequence number */ - hdr2->seq = long_be(SEQN(f) + size1); - - /* Add TCP options */ - pico_tcp_flags_update(f1, &t->sock); - pico_tcp_flags_update(f2, &t->sock); - tcp_add_options_frame(t, f1); - tcp_add_options_frame(t, f2); - - /* Get rid of the full frame */ - pico_discard_segment(&t->tcpq_out, f); - - /* Enqueue f2 for later send... */ - pico_enqueue_segment(&t->tcpq_out, f2); - - /* Return the partial frame */ - return f1; -} - - -int pico_tcp_output(struct pico_socket *s, int loop_score) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_frame *f, *una; - int sent = 0; - int data_sent = 0; - int32_t seq_diff = 0; - - una = first_segment(&t->tcpq_out); - f = peek_segment(&t->tcpq_out, t->snd_nxt); - - while((f) && (t->cwnd >= t->in_flight)) { - f->timestamp = TCP_TIME; - add_retransmission_timer(t, t->rto + TCP_TIME); - tcp_add_options_frame(t, f); - seq_diff = pico_seq_compare(SEQN(f), SEQN(una)); - if (seq_diff < 0) { - tcp_dbg(">>> FATAL: seq diff is negative!\n"); - break; - } - - /* Check if advertised window is full */ - if ((uint32_t)seq_diff >= (uint32_t)(t->recv_wnd << t->recv_wnd_scale)) { - if (t->x_mode != PICO_TCP_WINDOW_FULL) { - tcp_dbg("TCP> RIGHT SIZING (rwnd: %d, frame len: %d\n", t->recv_wnd << t->recv_wnd_scale, f->payload_len); - tcp_dbg("In window full...\n"); - t->snd_nxt = SEQN(una); - t->snd_retry = SEQN(una); - t->x_mode = PICO_TCP_WINDOW_FULL; - } - - break; - } - - /* Check if the advertised window is too small to receive the current frame */ - if ((uint32_t)(seq_diff + f->payload_len) > (uint32_t)(t->recv_wnd << t->recv_wnd_scale)) { - f = tcp_split_segment(t, f, (uint16_t)(t->recv_wnd << t->recv_wnd_scale)); - if (!f) - break; - - /* Limit sending window to packets in flight (right sizing) */ - t->cwnd = (uint16_t)t->in_flight; - if (t->cwnd < 1) - t->cwnd = 1; - } - - tcp_dbg("TCP> DEQUEUED (for output) frame %08x, acks %08x len= %d, remaining frames %d\n", SEQN(f), ACKN(f), f->payload_len, t->tcpq_out.frames); - tcp_send(t, f); - sent++; - loop_score--; - t->snd_last_out = SEQN(f); - if (loop_score < 1) - break; - - if (f->payload_len > 0) { - data_sent++; - f = next_segment(&t->tcpq_out, f); - } else { - f = NULL; - } - } - if ((sent > 0 && data_sent > 0)) { - rto_set(t, t->rto); - } else { - /* Nothing to transmit. */ - } - - if ((t->tcpq_out.frames == 0) && (s->state & PICO_SOCKET_STATE_SHUT_LOCAL)) { /* if no more packets in queue, XXX replaced !f by tcpq check */ - if(!checkLocalClosing(&t->sock)) /* check if local closing started and send fin */ - { - checkRemoteClosing(&t->sock); /* check if remote closing started and send fin */ - } - } - - return loop_score; -} - -/* function to make new segment from hold queue with specific size (mss) */ -static struct pico_frame *pico_hold_segment_make(struct pico_socket_tcp *t) -{ - struct pico_frame *f_temp, *f_new; - struct pico_socket *s = (struct pico_socket *) &t->sock; - struct pico_tcp_hdr *hdr; - uint16_t total_len = 0, total_payload_len = 0; - uint16_t off = 0, test = 0; - - off = pico_tcp_overhead(s); - - /* init with first frame in hold queue */ - f_temp = first_segment(&t->tcpq_hold); - total_len = f_temp->payload_len; - f_temp = next_segment(&t->tcpq_hold, f_temp); - - /* check till total_len <= MSS */ - while ((f_temp != NULL) && ((total_len + f_temp->payload_len) <= t->mss)) { - total_len = (uint16_t)(total_len + f_temp->payload_len); - f_temp = next_segment(&t->tcpq_hold, f_temp); - if (f_temp == NULL) - break; - } - /* alloc new frame with payload size = off + total_len */ - f_new = pico_socket_frame_alloc(s, (uint16_t)(off + total_len)); - if (!f_new) { - pico_err = PICO_ERR_ENOMEM; - return f_new; - } - - pico_tcp_flags_update(f_new, &t->sock); - hdr = (struct pico_tcp_hdr *) f_new->transport_hdr; - /* init new frame */ - f_new->payload += off; - f_new->payload_len = (uint16_t)(f_new->payload_len - off); - f_new->sock = s; - - f_temp = first_segment(&t->tcpq_hold); - hdr->seq = ((struct pico_tcp_hdr *)(f_temp->transport_hdr))->seq; /* get sequence number of first frame */ - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - - /* check till total_payload_len <= MSS */ - while ((f_temp != NULL) && ((total_payload_len + f_temp->payload_len) <= t->mss)) { - /* cpy data and discard frame */ - test++; - memcpy(f_new->payload + total_payload_len, f_temp->payload, f_temp->payload_len); - total_payload_len = (uint16_t)(total_payload_len + f_temp->payload_len); - pico_discard_segment(&t->tcpq_hold, f_temp); - f_temp = first_segment(&t->tcpq_hold); - } - hdr->len = (uint8_t)((f_new->payload - f_new->transport_hdr) << 2u | (int8_t)t->jumbo); - - tcp_dbg_nagle("NAGLE make - joined %d segments, len %d bytes\n", test, total_payload_len); - tcp_add_options_frame(t, f_new); - - return f_new; -} - - - -static int pico_tcp_push_nagle_enqueue(struct pico_socket_tcp *t, struct pico_frame *f) -{ - if (pico_enqueue_segment(&t->tcpq_out, f) > 0) { - tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t); - t->snd_last += f->payload_len; - return f->payload_len; - } else { - tcp_dbg("Enqueue failed.\n"); - return 0; - } -} - -static int pico_tcp_push_nagle_hold(struct pico_socket_tcp *t, struct pico_frame *f) -{ - struct pico_frame *f_new; - uint32_t total_len = 0; - total_len = f->payload_len + t->tcpq_hold.size; - if ((total_len >= t->mss) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= t->mss)) { - /* IF enough data in hold (>mss) AND space in out queue (>mss) */ - /* add current frame in hold and make new segment */ - if (pico_enqueue_segment(&t->tcpq_hold, f) > 0 ) { - tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold, make new (enqueued frames out %d)\n", t->tcpq_out.frames); - t->snd_last += f->payload_len; /* XXX WATCH OUT */ - f_new = pico_hold_segment_make(t); - } else { - tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 1\n"); - return 0; - } - - /* and put new frame in out queue */ - if ((f_new != NULL) && (pico_enqueue_segment(&t->tcpq_out, f_new) > 0)) { - return f_new->payload_len; - } else { - tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue out failed, f_new = %p\n", f_new); - return -1; /* XXX something seriously wrong */ - } - } else { - /* ELSE put frame in hold queue */ - if (pico_enqueue_segment(&t->tcpq_hold, f) > 0) { - tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold (enqueued frames out %d)\n", t->tcpq_out.frames); - t->snd_last += f->payload_len; /* XXX WATCH OUT */ - return f->payload_len; - } else { - pico_err = PICO_ERR_EAGAIN; - tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 2\n"); - } - } - - return 0; -} - - -static int pico_tcp_push_nagle_on(struct pico_socket_tcp *t, struct pico_frame *f) -{ - /* Nagle's algorithm enabled, check if ready to send, or put frame in hold queue */ - if (IS_TCP_IDLE(t) && IS_TCP_HOLDQ_EMPTY(t)) - return pico_tcp_push_nagle_enqueue(t, f); - - return pico_tcp_push_nagle_hold(t, f); -} - - - -/* original behavior kept when Nagle disabled; - Nagle algorithm added here, keeping hold frame queue instead of eg linked list of data */ -int pico_tcp_push(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; - struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock; - IGNORE_PARAMETER(self); - pico_err = PICO_ERR_NOERR; - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - hdr->seq = long_be(t->snd_last + 1); - hdr->len = (uint8_t)((f->payload - f->transport_hdr) << 2u | (int8_t)t->jumbo); - - if ((uint32_t)f->payload_len > (uint32_t)(t->tcpq_out.max_size - t->tcpq_out.size)) - t->sock.ev_pending &= (uint16_t)(~PICO_SOCK_EV_WR); - - /***************************************************************************/ - - if (!IS_NAGLE_ENABLED((&(t->sock)))) { - /* TCP_NODELAY enabled, original behavior */ - if (pico_enqueue_segment(&t->tcpq_out, f) > 0) { - tcp_dbg_nagle("TCP_PUSH - NO NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t); - t->snd_last += f->payload_len; - return f->payload_len; - } else { - tcp_dbg("Enqueue failed.\n"); - return 0; - } - } else { - return pico_tcp_push_nagle_on(t, f); - } - -} - -inline static void tcp_discard_all_segments(struct pico_tcp_queue *tq) -{ - struct pico_tree_node *index = NULL, *index_safe = NULL; - PICOTCP_MUTEX_LOCK(Mutex); - pico_tree_foreach_safe(index, &tq->pool, index_safe) - { - void *f = index->keyValue; - if(!f) - break; - - pico_tree_delete(&tq->pool, f); - if(IS_INPUT_QUEUE(tq)) - { - struct tcp_input_segment *inp = (struct tcp_input_segment *)f; - PICO_FREE(inp->payload); - PICO_FREE(inp); - } - else - pico_frame_discard(f); - } - tq->frames = 0; - tq->size = 0; - PICOTCP_MUTEX_UNLOCK(Mutex); -} - -void pico_tcp_cleanup_queues(struct pico_socket *sck) -{ - struct pico_socket_tcp *tcp = (struct pico_socket_tcp *)sck; - pico_timer_cancel(tcp->retrans_tmr); - pico_timer_cancel(tcp->keepalive_tmr); - pico_timer_cancel(tcp->fin_tmr); - - tcp->retrans_tmr = 0; - tcp->keepalive_tmr = 0; - tcp->fin_tmr = 0; - - tcp_discard_all_segments(&tcp->tcpq_in); - tcp_discard_all_segments(&tcp->tcpq_out); - tcp_discard_all_segments(&tcp->tcpq_hold); -} - -static int checkLocalClosing(struct pico_socket *s) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) { - tcp_dbg("TCP> buffer empty, shutdown established ...\n"); - /* send fin if queue empty and in state shut local (write) */ - tcp_send_fin(t); - /* change tcp state to FIN_WAIT1 */ - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1; - return 1; - } - - return 0; -} - -static int checkRemoteClosing(struct pico_socket *s) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) { - /* send fin if queue empty and in state shut local (write) */ - tcp_send_fin(t); - /* change tcp state to LAST_ACK */ - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK; - tcp_dbg("TCP> STATE: LAST_ACK.\n"); - return 1; - } - - return 0; -} - -void pico_tcp_notify_closing(struct pico_socket *sck) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)sck; - if(t->tcpq_out.frames == 0) - { - if(!checkLocalClosing(sck)) - checkRemoteClosing(sck); - } -} - - -int pico_tcp_check_listen_close(struct pico_socket *s) -{ - if (TCP_IS_STATE(s, PICO_SOCKET_STATE_TCP_LISTEN)) { - pico_socket_del(s); - return 0; - } - - return -1; -} - -void pico_tcp_flags_update(struct pico_frame *f, struct pico_socket *s) -{ - f->transport_flags_saved = ((struct pico_socket_tcp *)s)->ts_ok; -} - -int pico_tcp_set_bufsize_in(struct pico_socket *s, uint32_t value) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - t->tcpq_in.max_size = value; - return 0; -} - -int pico_tcp_set_bufsize_out(struct pico_socket *s, uint32_t value) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - t->tcpq_out.max_size = value; - return 0; -} - -int pico_tcp_get_bufsize_in(struct pico_socket *s, uint32_t *value) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - *value = t->tcpq_in.max_size; - return 0; -} - -int pico_tcp_get_bufsize_out(struct pico_socket *s, uint32_t *value) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - *value = t->tcpq_out.max_size; - return 0; -} - -int pico_tcp_set_keepalive_probes(struct pico_socket *s, uint32_t value) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - t->ka_probes = value; - return 0; -} - -int pico_tcp_set_keepalive_intvl(struct pico_socket *s, uint32_t value) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - t->ka_intvl = value; - return 0; -} - -int pico_tcp_set_keepalive_time(struct pico_socket *s, uint32_t value) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - t->ka_time = value; - return 0; -} - -int pico_tcp_set_linger(struct pico_socket *s, uint32_t value) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - t->linger_timeout = value; - return 0; -} - -#endif /* PICO_SUPPORT_TCP */ diff --git a/ext/picotcp/modules/pico_tcp.h b/ext/picotcp/modules/pico_tcp.h deleted file mode 100644 index ece38bb..0000000 --- a/ext/picotcp/modules/pico_tcp.h +++ /dev/null @@ -1,106 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - *********************************************************************/ -#ifndef INCLUDE_PICO_TCP -#define INCLUDE_PICO_TCP -#include "pico_addressing.h" -#include "pico_protocol.h" -#include "pico_socket.h" - -extern struct pico_protocol pico_proto_tcp; - -PACKED_STRUCT_DEF pico_tcp_hdr { - struct pico_trans trans; - uint32_t seq; - uint32_t ack; - uint8_t len; - uint8_t flags; - uint16_t rwnd; - uint16_t crc; - uint16_t urgent; -}; - -PACKED_STRUCT_DEF tcp_pseudo_hdr_ipv4 -{ - struct pico_ip4 src; - struct pico_ip4 dst; - uint16_t tcp_len; - uint8_t res; - uint8_t proto; -}; - -#define PICO_TCPHDR_SIZE 20 -#define PICO_SIZE_TCPOPT_SYN 20 -#define PICO_SIZE_TCPHDR (uint32_t)(sizeof(struct pico_tcp_hdr)) - -/* TCP options */ -#define PICO_TCP_OPTION_END 0x00 -#define PICO_TCPOPTLEN_END 1u -#define PICO_TCP_OPTION_NOOP 0x01 -#define PICO_TCPOPTLEN_NOOP 1 -#define PICO_TCP_OPTION_MSS 0x02 -#define PICO_TCPOPTLEN_MSS 4 -#define PICO_TCP_OPTION_WS 0x03 -#define PICO_TCPOPTLEN_WS 3u -#define PICO_TCP_OPTION_SACK_OK 0x04 -#define PICO_TCPOPTLEN_SACK_OK 2 -#define PICO_TCP_OPTION_SACK 0x05 -#define PICO_TCPOPTLEN_SACK 2 /* Plus the block */ -#define PICO_TCP_OPTION_TIMESTAMP 0x08 -#define PICO_TCPOPTLEN_TIMESTAMP 10u - -/* TCP flags */ -#define PICO_TCP_FIN 0x01u -#define PICO_TCP_SYN 0x02u -#define PICO_TCP_RST 0x04u -#define PICO_TCP_PSH 0x08u -#define PICO_TCP_ACK 0x10u -#define PICO_TCP_URG 0x20u -#define PICO_TCP_ECN 0x40u -#define PICO_TCP_CWR 0x80u - -#define PICO_TCP_SYNACK (PICO_TCP_SYN | PICO_TCP_ACK) -#define PICO_TCP_PSHACK (PICO_TCP_PSH | PICO_TCP_ACK) -#define PICO_TCP_FINACK (PICO_TCP_FIN | PICO_TCP_ACK) -#define PICO_TCP_FINPSHACK (PICO_TCP_FIN | PICO_TCP_PSH | PICO_TCP_ACK) -#define PICO_TCP_RSTACK (PICO_TCP_RST | PICO_TCP_ACK) - - -PACKED_STRUCT_DEF pico_tcp_option -{ - uint8_t kind; - uint8_t len; -}; - -struct pico_socket *pico_tcp_open(uint16_t family); -uint32_t pico_tcp_read(struct pico_socket *s, void *buf, uint32_t len); -int pico_tcp_initconn(struct pico_socket *s); -int pico_tcp_input(struct pico_socket *s, struct pico_frame *f); -uint16_t pico_tcp_checksum(struct pico_frame *f); -uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f); -#ifdef PICO_SUPPORT_IPV6 -uint16_t pico_tcp_checksum_ipv6(struct pico_frame *f); -#endif -uint16_t pico_tcp_overhead(struct pico_socket *s); -int pico_tcp_output(struct pico_socket *s, int loop_score); -int pico_tcp_queue_in_is_empty(struct pico_socket *s); -int pico_tcp_reply_rst(struct pico_frame *f); -void pico_tcp_cleanup_queues(struct pico_socket *sck); -void pico_tcp_notify_closing(struct pico_socket *sck); -void pico_tcp_flags_update(struct pico_frame *f, struct pico_socket *s); -int pico_tcp_set_bufsize_in(struct pico_socket *s, uint32_t value); -int pico_tcp_set_bufsize_out(struct pico_socket *s, uint32_t value); -int pico_tcp_get_bufsize_in(struct pico_socket *s, uint32_t *value); -int pico_tcp_get_bufsize_out(struct pico_socket *s, uint32_t *value); -int pico_tcp_set_keepalive_probes(struct pico_socket *s, uint32_t value); -int pico_tcp_set_keepalive_intvl(struct pico_socket *s, uint32_t value); -int pico_tcp_set_keepalive_time(struct pico_socket *s, uint32_t value); -int pico_tcp_set_linger(struct pico_socket *s, uint32_t value); -uint16_t pico_tcp_get_socket_mss(struct pico_socket *s); -int pico_tcp_check_listen_close(struct pico_socket *s); - -#endif diff --git a/ext/picotcp/modules/pico_tftp.c b/ext/picotcp/modules/pico_tftp.c deleted file mode 100644 index 83c5c6f..0000000 --- a/ext/picotcp/modules/pico_tftp.c +++ /dev/null @@ -1,1300 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Author: Daniele Lacamera - *********************************************************************/ - -#include -#include -#include -#include -#include - -/* a zero value means adaptative timeout! (2, 4, 8) */ -#define PICO_TFTP_TIMEOUT 2000U - -#define TFTP_MAX_RETRY 3 - -#define TFTP_STATE_READ_REQUESTED 0 -#define TFTP_STATE_RX 1 -#define TFTP_STATE_LAST_ACK_SENT 2 -#define TFTP_STATE_WRITE_REQUESTED 3 -#define TFTP_STATE_TX 4 -#define TFTP_STATE_WAIT_OPT_CONFIRM 5 -#define TFTP_STATE_WAIT_LAST_ACK 6 -#define TFTP_STATE_CLOSING 7 - -#define AUTOMA_STATES (TFTP_STATE_CLOSING + 1) - -/* MAX_OPTIONS_SIZE: "timeout" 255 "tsize" filesize => 8 + 4 + 6 + 11 */ -#define MAX_OPTIONS_SIZE 29 - -/* RRQ and WRQ packets (opcodes 1 and 2 respectively) */ -PACKED_STRUCT_DEF pico_tftp_hdr -{ - uint16_t opcode; -}; - -/* DATA or ACK (opcodes 3 and 4 respectively)*/ -PACKED_STRUCT_DEF pico_tftp_data_hdr -{ - uint16_t opcode; - uint16_t block; -}; - -/* ERROR (opcode 5) */ -PACKED_STRUCT_DEF pico_tftp_err_hdr -{ - uint16_t opcode; - uint16_t error_code; -}; - -#define PICO_TFTP_TOTAL_BLOCK_SIZE (PICO_TFTP_PAYLOAD_SIZE + (int32_t)sizeof(struct pico_tftp_data_hdr)) -#define tftp_payload(p) (((uint8_t *)(p)) + sizeof(struct pico_tftp_data_hdr)) - -/* STATUS FLAGS */ -#define SESSION_STATUS_CLOSED 1 -#define SESSION_STATUS_APP_PENDING 2 -#define SESSION_STATUS_IN_CALLBACK 4 -#define SESSION_STATUS_APP_ACK 64 - -struct pico_tftp_session { - int state; - int status; - int options; - int retry; - uint16_t packet_counter; - /* Current connection */ - struct pico_socket *socket; - union pico_address remote_address; - uint16_t remote_port; - uint16_t localport; - pico_time wallclock_timeout; - pico_time bigger_wallclock; - struct pico_tftp_session *next; - uint32_t timer; - unsigned int active_timers; - void *argument; - int (*callback)(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg); - int32_t file_size; - int32_t len; - uint8_t option_timeout; - uint8_t tftp_block[PICO_TFTP_TOTAL_BLOCK_SIZE]; - int32_t block_len; -}; - -struct server_t { - void (*listen_callback)(union pico_address *addr, uint16_t port, uint16_t opcode, char *filename, int32_t len); - struct pico_socket *listen_socket; - uint8_t tftp_block[PICO_TFTP_TOTAL_BLOCK_SIZE]; -}; - -struct automa_events { - void (*ack)(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port); - void (*data)(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port); - void (*error)(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port); - void (*oack)(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port); - void (*timeout)(struct pico_tftp_session *session, pico_time t); -}; - -static struct server_t server; - -static struct pico_tftp_session *tftp_sessions = NULL; - -static inline void session_status_set(struct pico_tftp_session *session, int status) -{ - session->status |= status; -} - -static inline void session_status_clear(struct pico_tftp_session *session, int status) -{ - session->status &= ~status; -} - -static char *extract_arg_pointer(char *arg, char *end_arg, char **value) -{ - char *pos; - - pos = get_string_terminator_position(arg, (size_t)(end_arg - arg)); - if (!pos) - return NULL; - - if (end_arg == ++pos) - return NULL; - - arg = get_string_terminator_position(pos, (size_t)(end_arg - pos)); - - if (!arg) - return NULL; - - *value = pos; - return arg + 1; -} - -static int extract_value(char *str, uint32_t *value, uint32_t max) -{ - char *endptr; - unsigned long num; - - num = strtoul(str, &endptr, 10); - - if (endptr == str || *endptr || num > max) - return -1; - - *value = (uint32_t)num; - return 0; -} - -static int parse_optional_arguments(char *option_string, int32_t len, int *options, uint8_t *timeout, int32_t *filesize) -{ - char *pos; - char *end_args = option_string + len; - char *current_option; - int ret; - uint32_t value; - - *options = 0; - - while (option_string < end_args) { - current_option = option_string; - option_string = extract_arg_pointer(option_string, end_args, &pos); - if (!option_string) - return 0; - - if (!pico_strncasecmp("timeout", current_option, (size_t)(pos - current_option))) { - ret = extract_value(pos, &value, PICO_TFTP_MAX_TIMEOUT); - if (ret) - return -1; - - *timeout = (uint8_t)value; - *options |= PICO_TFTP_OPTION_TIME; - } else { - if (!pico_strncasecmp("tsize", current_option, (size_t)(pos - current_option))) { - ret = extract_value(pos, (uint32_t *)filesize, PICO_TFTP_MAX_FILESIZE); - if (ret) - return -1; - - if (*filesize < 0) - return -1; - - *options |= PICO_TFTP_OPTION_FILE; - } - } - } - return 0; -} - -static inline struct pico_tftp_session *pico_tftp_session_create(struct pico_socket *sock, union pico_address *remote_addr) -{ - struct pico_tftp_session *session; - - session = (struct pico_tftp_session *) PICO_ZALLOC(sizeof (struct pico_tftp_session)); - - if (!session) - pico_err = PICO_ERR_ENOMEM; - else { - session->state = 0; - session->status = 0; - session->options = 0; - session->packet_counter = 0u; - session->socket = sock; - session->wallclock_timeout = 0; - session->bigger_wallclock = 0; - session->active_timers = 0; - session->next = NULL; - session->localport = 0; - session->callback = NULL; - session->argument = NULL; - memcpy(&session->remote_address, remote_addr, sizeof(union pico_address)); - session->remote_port = 0; - session->len = 0; - } - - return session; -} - -static struct pico_tftp_session *find_session_by_socket(struct pico_socket *tftp_socket) -{ - struct pico_tftp_session *pos = tftp_sessions; - - for (; pos; pos = pos->next) - if (pos->socket == tftp_socket) - return pos; - - return NULL; -} - -/* **************** for future use... - static struct pico_tftp_session * find_session_by_localport(uint16_t localport) - { - struct pico_tftp_session *idx = tftp_sessions; - - for (; idx; idx = idx->next) - if (idx->localport == localport) - return idx; - - return NULL; - } *********************/ - -static void add_session(struct pico_tftp_session *idx) -{ - struct pico_tftp_session *prev = NULL; - struct pico_tftp_session *pos; - - for (pos = tftp_sessions; pos; prev = pos, pos = pos->next) - if (pos->localport > idx->localport) - break; - - if (prev) { - idx->next = prev->next; - prev->next = idx; - } else { - idx->next = tftp_sessions; - tftp_sessions = idx; - } -} - -/* Returns 0 if OK and -1 in case of errors */ -static int del_session(struct pico_tftp_session *idx) -{ - struct pico_tftp_session *prev = NULL; - struct pico_tftp_session *pos; - - for (pos = tftp_sessions; pos; pos = pos->next) { - if (pos == idx) { - if (pos == tftp_sessions) - tftp_sessions = tftp_sessions->next; - else - prev->next = pos->next; - - PICO_FREE(idx); - return 0; - } - - prev = pos; - } - return -1; -} - -static inline int do_callback(struct pico_tftp_session *session, uint16_t err, uint8_t *data, int32_t len) -{ - int ret; - - session_status_set(session, SESSION_STATUS_IN_CALLBACK); - ret = session->callback(session, err, data, len, session->argument); - session_status_clear(session, SESSION_STATUS_IN_CALLBACK); - - return ret; -} - -static void timer_callback(pico_time now, void *arg); - -static void tftp_schedule_timeout(struct pico_tftp_session *session, pico_time interval) -{ - pico_time new_timeout = PICO_TIME_MS() + interval; - - if (session->active_timers) { - if (session->bigger_wallclock > new_timeout) { - session->timer = pico_timer_add(interval + 1, timer_callback, session); - session->active_timers++; - } - } else { - session->timer = pico_timer_add(interval + 1, timer_callback, session); - session->active_timers++; - session->bigger_wallclock = new_timeout; - } - - session->wallclock_timeout = new_timeout; -} - -static void tftp_finish(struct pico_tftp_session *session) -{ - if (session->state != TFTP_STATE_CLOSING) { - pico_socket_close(session->socket); - session->state = TFTP_STATE_CLOSING; - if (session->active_timers) { - pico_timer_cancel(session->timer); - --session->active_timers; - } - - session->wallclock_timeout = 0; - tftp_schedule_timeout(session, 5); - } -} - -static void tftp_send(struct pico_tftp_session *session, int len) -{ - if (len) - session->len = len; - else - len = session->len; - - pico_socket_sendto(session->socket, session->tftp_block, session->len, &session->remote_address, session->remote_port); -} - -static void tftp_send_ack(struct pico_tftp_session *session) -{ - struct pico_tftp_data_hdr *dh; - - dh = PICO_ZALLOC(sizeof(struct pico_tftp_data_hdr)); - if (!dh) - return; - - dh->opcode = short_be(PICO_TFTP_ACK); - dh->block = short_be(session->packet_counter); - - if (session->socket) { - pico_socket_sendto(session->socket, dh, (int) sizeof(struct pico_tftp_err_hdr), - &session->remote_address, session->remote_port); - tftp_schedule_timeout(session, PICO_TFTP_TIMEOUT); - } - - PICO_FREE(dh); -} - -static size_t prepare_options_string(struct pico_tftp_session *session, char *str_options, int32_t filesize) -{ - size_t len = 0; - int res; - - if (session->options & PICO_TFTP_OPTION_TIME) { - strcpy(str_options, "timeout"); - len += 8; - res = num2string(session->option_timeout, &str_options[len], 4); - if (res < 0) - return 0; - - len += (size_t)res; - } - - if (session->options & PICO_TFTP_OPTION_FILE) { - strcpy(&str_options[len], "tsize"); - len += 6; - res = num2string(filesize, &str_options[len], 11); - if (res < 0) - return 0; - - len += (size_t)res; - } - - return len; -} - -static void tftp_send_oack(struct pico_tftp_session *session) -{ - struct pico_tftp_hdr *hdr; - size_t options_size; - size_t options_pos = sizeof(struct pico_tftp_hdr); - uint8_t *buf; - char str_options[MAX_OPTIONS_SIZE] = { 0 }; - - options_size = prepare_options_string(session, str_options, session->file_size); - - buf = PICO_ZALLOC(options_pos + options_size); - if (!buf) { - strcpy((char *)session->tftp_block, "Out of memory"); - do_callback(session, PICO_TFTP_EV_ERR_LOCAL, session->tftp_block, 0); - tftp_finish(session); - return; - } - - hdr = (struct pico_tftp_hdr *)buf; - hdr->opcode = short_be(PICO_TFTP_OACK); - memcpy(buf + options_pos, str_options, options_size); - (void)pico_socket_sendto(session->socket, buf, (int)(options_pos + options_size), &session->remote_address, session->remote_port); - PICO_FREE(buf); -} - -static void tftp_send_req(struct pico_tftp_session *session, union pico_address *a, uint16_t port, const char *filename, uint16_t opcode) -{ -#define OCTET_STRSIZ 7U - static const char octet[OCTET_STRSIZ] = { - 0, 'o', 'c', 't', 'e', 't', 0 - }; - struct pico_tftp_hdr *hdr; - size_t len; - size_t options_size; - size_t options_pos; - uint8_t *buf; - char str_options[MAX_OPTIONS_SIZE] = { 0 }; - - if (!filename) { - return; - } - - len = strlen(filename); - - options_size = prepare_options_string(session, str_options, (opcode == PICO_TFTP_WRQ) ? (session->file_size) : (0)); - - options_pos = sizeof(struct pico_tftp_hdr) + OCTET_STRSIZ + len; - buf = PICO_ZALLOC(options_pos + options_size); - if (!buf) { - strcpy((char *)session->tftp_block, "Out of memory"); - do_callback(session, PICO_TFTP_EV_ERR_LOCAL, session->tftp_block, 0); - tftp_finish(session); - return; - } - - hdr = (struct pico_tftp_hdr *)buf; - hdr->opcode = short_be(opcode); - memcpy(buf + sizeof(struct pico_tftp_hdr), filename, len); - memcpy(buf + sizeof(struct pico_tftp_hdr) + len, octet, OCTET_STRSIZ); - memcpy(buf + options_pos, str_options, options_size); - (void)pico_socket_sendto(session->socket, buf, (int)(options_pos + options_size), a, port); - PICO_FREE(buf); -} - -static void tftp_send_rx_req(struct pico_tftp_session *session, union pico_address *a, uint16_t port, const char *filename) -{ - tftp_send_req(session, a, port, filename, PICO_TFTP_RRQ); - session->state = TFTP_STATE_READ_REQUESTED; - tftp_schedule_timeout(session, PICO_TFTP_TIMEOUT); -} - -static void tftp_send_tx_req(struct pico_tftp_session *session, union pico_address *a, uint16_t port, const char *filename) -{ - tftp_send_req(session, a, port, filename, PICO_TFTP_WRQ); - session->state = TFTP_STATE_WRITE_REQUESTED; - tftp_schedule_timeout(session, PICO_TFTP_TIMEOUT); -} - -static int send_error(uint8_t *buf, struct pico_socket *sock, union pico_address *a, uint16_t port, uint16_t errcode, const char *errmsg) -{ - struct pico_tftp_err_hdr *eh; - int32_t len; - int32_t maxlen = PICO_TFTP_TOTAL_BLOCK_SIZE - sizeof(struct pico_tftp_err_hdr); - - if (!errmsg) - len = 0; - else - len = (int32_t)strlen(errmsg); - - eh = (struct pico_tftp_err_hdr *) buf; - eh->opcode = short_be(PICO_TFTP_ERROR); - eh->error_code = short_be(errcode); - if (len + 1 > maxlen) - len = maxlen; - - if (len) - memcpy(tftp_payload(eh), errmsg, (size_t)len); - - tftp_payload(eh)[len++] = (char)0; - - return pico_socket_sendto(sock, eh, (int)(len + (int32_t)sizeof(struct pico_tftp_err_hdr)), a, port); -} - -static void tftp_send_error(struct pico_tftp_session *session, union pico_address *a, uint16_t port, uint16_t errcode, const char *errmsg) -{ - struct pico_tftp_err_hdr *eh; - int32_t len; - int32_t maxlen = PICO_TFTP_TOTAL_BLOCK_SIZE - sizeof(struct pico_tftp_err_hdr); - - if (!errmsg) - len = 0; - else - len = (int32_t)strlen(errmsg); - - if (!a) { - a = &session->remote_address; - port = session->remote_port; - } - - eh = (struct pico_tftp_err_hdr *) (session ? (session->tftp_block) : (server.tftp_block)); - eh->opcode = short_be(PICO_TFTP_ERROR); - eh->error_code = short_be(errcode); - if (len + 1 > maxlen) - len = maxlen; - - if (len) - memcpy(tftp_payload(eh), errmsg, (size_t)len); - - tftp_payload(eh)[len++] = (char)0; - if (session) { - (void)pico_socket_sendto(session->socket, eh, (int) (len + (int32_t)sizeof(struct pico_tftp_err_hdr)), a, port); - tftp_finish(session); - } else - (void)pico_socket_sendto(server.listen_socket, eh, (int) (len + (int32_t)sizeof(struct pico_tftp_err_hdr)), a, port); -} - -static void tftp_send_data(struct pico_tftp_session *session, const uint8_t *data, int32_t len) -{ - struct pico_tftp_data_hdr *dh; - - dh = (struct pico_tftp_data_hdr *) session->tftp_block; - dh->opcode = short_be(PICO_TFTP_DATA); - dh->block = short_be(session->packet_counter++); - - if (len < PICO_TFTP_PAYLOAD_SIZE) - session->state = TFTP_STATE_WAIT_LAST_ACK; - else - session->state = TFTP_STATE_TX; - - memcpy(session->tftp_block + sizeof(struct pico_tftp_data_hdr), data, (size_t)len); - pico_socket_sendto(session->socket, session->tftp_block, (int)(len + (int32_t)sizeof(struct pico_tftp_data_hdr)), - &session->remote_address, session->remote_port); - tftp_schedule_timeout(session, PICO_TFTP_TIMEOUT); -} - -static inline void tftp_eval_finish(struct pico_tftp_session *session, int32_t len) -{ - if (len < PICO_TFTP_PAYLOAD_SIZE) { - pico_socket_close(session->socket); - session->state = TFTP_STATE_CLOSING; - } -} - -static inline int tftp_data_prepare(struct pico_tftp_session *session, union pico_address *a, uint16_t port) -{ - if (!session->socket) - return -1; - - if (pico_address_compare(a, &session->remote_address, session->socket->net->proto_number) != 0) { - tftp_send_error(session, a, port, TFTP_ERR_EXCEEDED, "TFTP busy, try again later."); - return -1; - } - - return 0; -} - -static void tftp_req(uint8_t *block, int32_t len, union pico_address *a, uint16_t port) -{ - struct pico_tftp_hdr *hdr = (struct pico_tftp_hdr *)block; - char *filename; - char *pos; - char *mode; - int ret; - - switch (short_be(hdr->opcode)) { - case PICO_TFTP_RRQ: - case PICO_TFTP_WRQ: - filename = (char *)(block + sizeof(struct pico_tftp_hdr)); - len -= (int32_t)sizeof(struct pico_tftp_hdr); - - pos = extract_arg_pointer(filename, filename + len, &mode); - if (!pos) { - send_error(block, server.listen_socket, a, port, TFTP_ERR_EILL, "Invalid argument in request"); - return; - } - - ret = strcmp("octet", mode); - if (ret) { - send_error(block, server.listen_socket, a, port, TFTP_ERR_EILL, "Unsupported mode"); - return; - } - - /*ret = parse_optional_arguments((char *)(block + sizeof(struct pico_tftp_hdr)), len - sizeof(struct pico_tftp_hdr), &new_options, &new_timeout, &new_filesize); - if (ret) { - tftp_send_error(NULL, a, port, TFTP_ERR_EILL, "Bad request"); - return; - } */ - - if (server.listen_callback) { - server.listen_callback(a, port, short_be(hdr->opcode), filename, len); - } - - break; - default: - send_error(block, server.listen_socket, a, port, TFTP_ERR_EILL, "Illegal opcode"); - } -} - -static int event_ack_base(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - struct pico_tftp_data_hdr *dh; - uint16_t block_n; - const char *wrong_address = "Wrong address"; - const char *wrong_block = "Wrong packet number"; - - (void)len; - if (pico_address_compare(a, &session->remote_address, session->socket->net->proto_number) != 0) { - strcpy((char *)session->tftp_block, wrong_address); - do_callback(session, PICO_TFTP_EV_ERR_PEER, session->tftp_block, len); - tftp_send_error(session, a, port, TFTP_ERR_EXCEEDED, wrong_address); - return -1; - } - - dh = (struct pico_tftp_data_hdr *)session->tftp_block; - block_n = short_be(dh->block); - if (block_n != (session->packet_counter - 1U)) { - strcpy((char *)session->tftp_block, wrong_block); - do_callback(session, PICO_TFTP_EV_ERR_PEER, session->tftp_block, len); - tftp_send_error(session, a, port, TFTP_ERR_EILL, wrong_block); - return -1; - } - - return 0; -} - -static inline int event_ack0_check(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - struct pico_tftp_data_hdr *dh; - uint16_t block_n; - - (void)len; - if (pico_address_compare(a, &session->remote_address, session->socket->net->proto_number) != 0) { - tftp_send_error(session, a, port, TFTP_ERR_EXCEEDED, "TFTP busy, try again later."); - return -1; - } - - dh = (struct pico_tftp_data_hdr *)session->tftp_block; - block_n = short_be(dh->block); - if (block_n != 0) { - tftp_send_error(session, a, port, TFTP_ERR_EILL, "TFTP connection broken!"); - return -1; - } - - return 0; -} - -static void event_ack0_wr(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - if (!event_ack0_check(session, len, a, port)) { - session->remote_port = port; - do_callback(session, PICO_TFTP_EV_OK, session->tftp_block, 0); - } -} - -static void event_ack0_woc(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - if (!event_ack0_check(session, len, a, port)) - do_callback(session, PICO_TFTP_EV_OPT, session->tftp_block, 0); -} - -static void event_ack(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - if (!event_ack_base(session, len, a, port)) - do_callback(session, PICO_TFTP_EV_OK, session->tftp_block, 0); -} - -static void event_ack_last(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - if (!event_ack_base(session, len, a, port)) - tftp_finish(session); -} - -static void event_data(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - struct pico_tftp_data_hdr *dh; - int32_t payload_len = len - (int32_t)sizeof(struct pico_tftp_data_hdr); - - if (tftp_data_prepare(session, a, port)) - return; - - dh = (struct pico_tftp_data_hdr *)session->tftp_block; - if (short_be(dh->block) > (session->packet_counter + 1U)) { - strcpy((char *)session->tftp_block, "Wrong/unexpected sequence number"); - do_callback(session, PICO_TFTP_EV_ERR_LOCAL, session->tftp_block, 0); - tftp_send_error(session, a, port, TFTP_ERR_EILL, "TFTP connection broken!"); - return; - } - - if (short_be(dh->block) == (session->packet_counter + 1U)) { - session->packet_counter++; - if (do_callback(session, PICO_TFTP_EV_OK, tftp_payload(session->tftp_block), payload_len) >= 0) { - if (!(session->status & SESSION_STATUS_APP_ACK)) - tftp_send_ack(session); - } - - if (!(session->status & SESSION_STATUS_APP_ACK)) - tftp_eval_finish(session, len); - } -} - -static void event_data_rdr(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - if (tftp_data_prepare(session, a, port)) - return; - - session->remote_port = port; - session->state = TFTP_STATE_RX; - event_data(session, len, a, port); -} - -static void event_data_rpl(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - struct pico_tftp_data_hdr *dh; - - (void)len; - if (tftp_data_prepare(session, a, port)) - return; - - dh = (struct pico_tftp_data_hdr *)session->tftp_block; - - if (short_be(dh->block) == session->packet_counter) - tftp_send_ack(session); -} - -static void event_err(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - (void)a; - (void)port; - do_callback(session, PICO_TFTP_EV_ERR_PEER, session->tftp_block, len); - tftp_finish(session); -} - -static inline void event_oack(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - char *option_string = (char *)session->tftp_block + sizeof(struct pico_tftp_hdr); - int ret; - int proposed_options = session->options; - - (void)a; - - session->remote_port = port; - - ret = parse_optional_arguments(option_string, len - (int32_t)sizeof(struct pico_tftp_hdr), &session->options, &session->option_timeout, &session->file_size); - if (ret || (session->options & ~proposed_options)) { - do_callback(session, PICO_TFTP_EV_ERR_PEER, session->tftp_block, len); - tftp_send_error(session, a, port, TFTP_ERR_EOPT, "Invalid option"); - return; - } - - do_callback(session, PICO_TFTP_EV_OPT, session->tftp_block, len); -} - -static void event_oack_rr(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - event_oack(session, len, a, port); - tftp_send_ack(session); - session->state = TFTP_STATE_RX; -} - -static void event_oack_wr(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - event_oack(session, len, a, port); - session->state = TFTP_STATE_TX; -} - -static void event_timeout(struct pico_tftp_session *session, pico_time t) -{ - pico_time new_timeout; - int factor; - - (void)t; - if (++session->retry == TFTP_MAX_RETRY) { - strcpy((char *)session->tftp_block, "Network timeout"); - do_callback(session, PICO_TFTP_EV_ERR_PEER, session->tftp_block, 0); - tftp_finish(session); - return; - } - - tftp_send(session, 0); - if (session->options & PICO_TFTP_OPTION_TIME) - new_timeout = session->option_timeout * 1000U; - else { - new_timeout = PICO_TFTP_TIMEOUT; - for (factor = session->retry; factor; --factor) - new_timeout *= 2; - } - - tftp_schedule_timeout(session, new_timeout); -} - -static void event_timeout_closing(struct pico_tftp_session *session, pico_time t) -{ - (void)t; - if (session->active_timers == 0) - del_session(session); -} - -static void event_timeout_final(struct pico_tftp_session *session, pico_time t) -{ - (void)t; - - tftp_finish(session); -} - -static void unexpected(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - (void)len; - tftp_send_error(session, a, port, TFTP_ERR_EILL, "Unexpected message"); -} - -static void null(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) -{ - (void)session; - (void)len; - (void)a; - (void)port; -} - -static struct automa_events fsm[AUTOMA_STATES] = { - /* STATE * ACK DATA ERROR OACK TIMEOUT */ - /* ***************************************************************************************************************** */ - { /* TFTP_STATE_READ_REQUESTED */ unexpected, event_data_rdr, event_err, event_oack_rr, event_timeout}, - { /* TFTP_STATE_RX */ unexpected, event_data, event_err, unexpected, event_timeout}, - { /* TFTP_STATE_LAST_ACK_SENT */ unexpected, event_data_rpl, null, unexpected, event_timeout_final}, - { /* TFTP_STATE_WRITE_REQUESTED */ event_ack0_wr, unexpected, event_err, event_oack_wr, event_timeout}, - { /* TFTP_STATE_TX */ event_ack, unexpected, event_err, unexpected, event_timeout}, - { /* TFTP_STATE_WAIT_OPT_CONFIRM */ event_ack0_woc, unexpected, event_err, unexpected, event_timeout}, - { /* TFTP_STATE_WAIT_LAST_ACK */ event_ack_last, unexpected, event_err, unexpected, event_timeout}, - { /* TFTP_STATE_CLOSING */ null, null, null, null, event_timeout_closing} -}; - -static void tftp_message_received(struct pico_tftp_session *session, uint8_t *block, int32_t len, union pico_address *a, uint16_t port) -{ - struct pico_tftp_hdr *th = (struct pico_tftp_hdr *) block; - - if (!session->callback) - return; - - session->wallclock_timeout = 0; - - switch (short_be(th->opcode)) { - case PICO_TFTP_RRQ: - case PICO_TFTP_WRQ: - unexpected(session, len, a, port); - break; - case PICO_TFTP_DATA: - fsm[session->state].data(session, len, a, port); - break; - case PICO_TFTP_ACK: - fsm[session->state].ack(session, len, a, port); - break; - case PICO_TFTP_ERROR: - fsm[session->state].error(session, len, a, port); - break; - case PICO_TFTP_OACK: - fsm[session->state].oack(session, len, a, port); - break; - default: - tftp_send_error(session, NULL, 0, TFTP_ERR_EILL, "Illegal opcode"); - } -} - -static void tftp_cb(uint16_t ev, struct pico_socket *s) -{ - int r; - struct pico_tftp_session *session; - union pico_address ep; - uint16_t port = 0; - - session = find_session_by_socket(s); - if (session) { - if (ev == PICO_SOCK_EV_ERR) { - strcpy((char *)session->tftp_block, "Socket Error"); - do_callback(session, PICO_TFTP_EV_ERR_LOCAL, session->tftp_block, (int32_t)strlen((char *)session->tftp_block)); - tftp_finish(session); - return; - } - - r = pico_socket_recvfrom(s, session->tftp_block, PICO_TFTP_TOTAL_BLOCK_SIZE, &ep, &port); - if (r < (int)sizeof(struct pico_tftp_hdr)) - return; - - tftp_message_received(session, session->tftp_block, r, &ep, port); - } else { - if (!server.listen_socket || s != server.listen_socket) { - return; - } - - r = pico_socket_recvfrom(s, server.tftp_block, PICO_TFTP_TOTAL_BLOCK_SIZE, &ep, &port); - if (r < (int)sizeof(struct pico_tftp_hdr)) - return; - - tftp_req(server.tftp_block, r, &ep, port); - } -} - -static int application_rx_cb(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg) -{ - int *flag = (int *)arg; - - (void)block; - - switch (event) { - case PICO_TFTP_EV_ERR_PEER: - case PICO_TFTP_EV_ERR_LOCAL: - *flag = 0 - event; - break; - case PICO_TFTP_EV_OK: - session->len = len; - *flag = 1; - break; - case PICO_TFTP_EV_OPT: - break; - } - return 0; -} - -static int application_tx_cb(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg) -{ - (void)session; - (void)block; - (void)len; - - *(int*)arg = ((event == PICO_TFTP_EV_OK) || (event == PICO_TFTP_EV_OPT)) ? (1) : (0 - event); - return 0; -} - -static void timer_callback(pico_time now, void *arg) -{ - struct pico_tftp_session *session = (struct pico_tftp_session *)arg; - - --session->active_timers; - if (session->wallclock_timeout == 0) { - /* Timer is cancelled. */ - return; - } - - if (now >= session->wallclock_timeout) { - session->wallclock_timeout = 0ULL; - fsm[session->state].timeout(session, now); - } else { - tftp_schedule_timeout(session, session->wallclock_timeout - now); - } -} - -static struct pico_socket *tftp_socket_open(uint16_t family, uint16_t localport) -{ - struct pico_socket *sock; - union pico_address local_address; - - sock = pico_socket_open(family, PICO_PROTO_UDP, tftp_cb); - if (!sock) - return NULL; - - localport = short_be(localport); - - memset(&local_address, 0, sizeof(union pico_address)); - if (pico_socket_bind(sock, &local_address, &localport) < 0) { - pico_socket_close(sock); - return NULL; - } - - return sock; -} - -static inline int tftp_start_check(struct pico_tftp_session *session, uint16_t port, const char *filename, - int (*user_cb)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg)) -{ - if (!session) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if ((!server.listen_socket) && (port != short_be(PICO_TFTP_PORT))) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (!filename) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (!user_cb) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return 0; -} - -/* *** EXPORTED FUNCTIONS *** */ - -struct pico_tftp_session *pico_tftp_session_setup(union pico_address *a, uint16_t family) -{ - struct pico_socket *sock; - - sock = tftp_socket_open(family, 0); - if (!sock) - return NULL; - - return pico_tftp_session_create(sock, a); -} - -int pico_tftp_get_option(struct pico_tftp_session *session, uint8_t type, int32_t *value) -{ - if (!session) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (type) { - case PICO_TFTP_OPTION_FILE: - if (session->options & PICO_TFTP_OPTION_FILE) - *value = session->file_size; - else { - pico_err = PICO_ERR_ENOENT; - return -1; - } - - break; - case PICO_TFTP_OPTION_TIME: - if (session->options & PICO_TFTP_OPTION_TIME) - *value = session->option_timeout; - else { - pico_err = PICO_ERR_ENOENT; - return -1; - } - - break; - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return 0; -} - -int pico_tftp_set_option(struct pico_tftp_session *session, uint8_t type, int32_t value) -{ - if (!session) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (type) { - case PICO_TFTP_OPTION_FILE: - if (value < 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - session->file_size = value; - session->options |= PICO_TFTP_OPTION_FILE; - break; - case PICO_TFTP_OPTION_TIME: - if (value > PICO_TFTP_MAX_TIMEOUT) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - session->option_timeout = (uint8_t)(value & 0xFF); - if (value) { - session->options |= PICO_TFTP_OPTION_TIME; - } else { - session->options &= ~PICO_TFTP_OPTION_TIME; - } - - break; - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return 0; -} - -/* Active RX request from PicoTCP */ -int pico_tftp_start_rx(struct pico_tftp_session *session, uint16_t port, const char *filename, - int (*user_cb)(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg), void *arg) -{ - if (tftp_start_check(session, port, filename, user_cb)) - return -1; - - session->callback = user_cb; - session->packet_counter = 0u; - session->argument = arg; - - add_session(session); - - if (port != short_be(PICO_TFTP_PORT)) { - session->remote_port = port; - session->state = TFTP_STATE_RX; - if (session->options & (PICO_TFTP_OPTION_FILE | PICO_TFTP_OPTION_TIME)) - tftp_send_oack(session); - else - tftp_send_ack(session); - } else { - tftp_send_rx_req(session, &session->remote_address, port, filename); - } - - return 0; -} - -int pico_tftp_start_tx(struct pico_tftp_session *session, uint16_t port, const char *filename, - int (*user_cb)(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg), void *arg) -{ - if (tftp_start_check(session, port, filename, user_cb)) - return -1; - - session->callback = user_cb; - session->packet_counter = 1u; - session->argument = arg; - - add_session(session); - - if (port != short_be(PICO_TFTP_PORT)) { - session->remote_port = port; - if (session->options) { - tftp_send_oack(session); - session->state = TFTP_STATE_WAIT_OPT_CONFIRM; - } else { - do_callback(session, PICO_TFTP_EV_OK, NULL, 0); - } - } else - tftp_send_tx_req(session, &session->remote_address, port, filename); - - return 0; -} - -int pico_tftp_reject_request(union pico_address*addr, uint16_t port, uint16_t error_code, const char*error_message) -{ - return send_error(server.tftp_block, server.listen_socket, addr, port, error_code, error_message); -} - -int32_t pico_tftp_send(struct pico_tftp_session *session, const uint8_t *data, int32_t len) -{ - int32_t size; - - - if (len < 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - size = len; - - if (size > PICO_TFTP_PAYLOAD_SIZE) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - tftp_send_data(session, data, size); - - return len; -} - -int pico_tftp_listen(uint16_t family, void (*cb)(union pico_address *addr, uint16_t port, uint16_t opcode, char *filename, int32_t len)) -{ - struct pico_socket *sock; - - if (server.listen_socket) { - pico_err = PICO_ERR_EEXIST; - return -1; - } - - sock = tftp_socket_open(family, PICO_TFTP_PORT); - if (!sock) - return -1; - - server.listen_socket = sock; - server.listen_callback = cb; - - return 0; -} - -int pico_tftp_parse_request_args(char *args, int32_t len, int *options, uint8_t *timeout, int32_t *filesize) -{ - char *pos; - char *end_args = args + len; - - args = extract_arg_pointer(args, end_args, &pos); - - return parse_optional_arguments(args, (int32_t)(end_args - args), options, timeout, filesize); -} - -int pico_tftp_abort(struct pico_tftp_session *session, uint16_t error, const char *reason) -{ - if (!session) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (!find_session_by_socket(session->socket)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - tftp_send_error(session, NULL, 0, error, reason); - - return 0; -} - -int pico_tftp_close_server(void) -{ - if (!server.listen_socket) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - pico_socket_close(server.listen_socket); - server.listen_socket = NULL; - return 0; -} - -int pico_tftp_get_file_size(struct pico_tftp_session *session, int32_t *file_size) -{ - return pico_tftp_get_option(session, PICO_TFTP_OPTION_FILE, file_size); -} - -struct pico_tftp_session *pico_tftp_app_setup(union pico_address *a, uint16_t port, uint16_t family, int *synchro) -{ - struct pico_tftp_session *session; - - if (!synchro) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - session = pico_tftp_session_setup(a, family); - if (!session) - return NULL; - - session->remote_port = port; - session->status |= SESSION_STATUS_APP_ACK; - session->argument = synchro; - - *synchro = 0; - - return session; -} - -int pico_tftp_app_start_rx(struct pico_tftp_session *session, const char *filename) -{ - return pico_tftp_start_rx(session, session->remote_port, filename, application_rx_cb, session->argument); -} - -int pico_tftp_app_start_tx(struct pico_tftp_session *session, const char *filename) -{ - return pico_tftp_start_tx(session, session->remote_port, filename, application_tx_cb, session->argument); -} - -int32_t pico_tftp_get(struct pico_tftp_session *session, uint8_t *data, int32_t len) -{ - int synchro; - - if (!session || len < session->len ) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - synchro = *(int*)session->argument; - *(int*)session->argument = 0; - if ((session->state != TFTP_STATE_RX) && (session->state != TFTP_STATE_READ_REQUESTED)) - return -1; - - if (synchro < 0) - return synchro; - - memcpy(data, tftp_payload(session->tftp_block), (size_t)session->len); - len = session->len; - - tftp_send_ack(session); - tftp_eval_finish(session, len); - return len; -} - -int32_t pico_tftp_put(struct pico_tftp_session *session, uint8_t *data, int32_t len) -{ - int synchro; - - if ((!session) || (!data) || (len < 0)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - synchro = *(int*)session->argument; - *(int*)session->argument = 0; - if (synchro < 0) - return synchro; - - if (len > PICO_TFTP_PAYLOAD_SIZE) - len = PICO_TFTP_PAYLOAD_SIZE; - - pico_tftp_send(session, data, len); - return len; -} diff --git a/ext/picotcp/modules/pico_tftp.h b/ext/picotcp/modules/pico_tftp.h deleted file mode 100644 index bcbb648..0000000 --- a/ext/picotcp/modules/pico_tftp.h +++ /dev/null @@ -1,83 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - *********************************************************************/ -#ifndef PICO_TFTP_H -#define PICO_TFTP_H - -#include -#include - -#define PICO_TFTP_PORT (69) -#define PICO_TFTP_PAYLOAD_SIZE (512) - -#define PICO_TFTP_NONE 0 -#define PICO_TFTP_RRQ 1 -#define PICO_TFTP_WRQ 2 -#define PICO_TFTP_DATA 3 -#define PICO_TFTP_ACK 4 -#define PICO_TFTP_ERROR 5 -#define PICO_TFTP_OACK 6 - -/* Callback user events */ -#define PICO_TFTP_EV_OK 0 -#define PICO_TFTP_EV_OPT 1 -#define PICO_TFTP_EV_ERR_PEER 2 -#define PICO_TFTP_EV_ERR_LOCAL 3 - -/* TFTP ERROR CODES */ -#define TFTP_ERR_UNDEF 0 -#define TFTP_ERR_ENOENT 1 -#define TFTP_ERR_EACC 2 -#define TFTP_ERR_EXCEEDED 3 -#define TFTP_ERR_EILL 4 -#define TFTP_ERR_ETID 5 -#define TFTP_ERR_EEXIST 6 -#define TFTP_ERR_EUSR 7 -#define TFTP_ERR_EOPT 8 - -/* Session options */ -#define PICO_TFTP_OPTION_FILE 1 - -/* timeout: 0 -> adaptative, 1-255 -> fixed */ -#define PICO_TFTP_OPTION_TIME 2 - - -#define PICO_TFTP_MAX_TIMEOUT 255 -#define PICO_TFTP_MAX_FILESIZE (65535 * 512 - 1) - -struct pico_tftp_session; - -struct pico_tftp_session *pico_tftp_session_setup(union pico_address *a, uint16_t family); -int pico_tftp_set_option(struct pico_tftp_session *session, uint8_t type, int32_t value); -int pico_tftp_get_option(struct pico_tftp_session *session, uint8_t type, int32_t *value); - -int pico_tftp_start_rx(struct pico_tftp_session *session, uint16_t port, const char *filename, - int (*user_cb)(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg), void *arg); -int pico_tftp_start_tx(struct pico_tftp_session *session, uint16_t port, const char *filename, - int (*user_cb)(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg), void *arg); - -int pico_tftp_reject_request(union pico_address *addr, uint16_t port, uint16_t error_code, const char *error_message); -int32_t pico_tftp_send(struct pico_tftp_session *session, const uint8_t *data, int32_t len); - -int pico_tftp_listen(uint16_t family, void (*cb)(union pico_address *addr, uint16_t port, uint16_t opcode, char *filename, int32_t len)); - -int pico_tftp_parse_request_args(char *args, int32_t len, int *options, uint8_t *timeout, int32_t *filesize); - -int pico_tftp_abort(struct pico_tftp_session *session, uint16_t error, const char *reason); -int pico_tftp_close_server(void); - -int pico_tftp_get_file_size(struct pico_tftp_session *session, int32_t *file_size); - -/* SPECIFIC APPLICATION DRIVEN FUNCTIONS */ -struct pico_tftp_session *pico_tftp_app_setup(union pico_address *a, uint16_t port, uint16_t family, int *synchro); - -int pico_tftp_app_start_rx(struct pico_tftp_session *session, const char *filename); -int pico_tftp_app_start_tx(struct pico_tftp_session *session, const char *filename); - -int32_t pico_tftp_get(struct pico_tftp_session *session, uint8_t *data, int32_t len); -int32_t pico_tftp_put(struct pico_tftp_session *session, uint8_t *data, int32_t len); - -#endif diff --git a/ext/picotcp/modules/pico_udp.c b/ext/picotcp/modules/pico_udp.c deleted file mode 100644 index 9545781..0000000 --- a/ext/picotcp/modules/pico_udp.c +++ /dev/null @@ -1,217 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include "pico_udp.h" -#include "pico_config.h" -#include "pico_eth.h" -#include "pico_socket.h" -#include "pico_stack.h" - -#define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame)) -#define udp_dbg(...) do {} while(0) - -/* Queues */ -static struct pico_queue udp_in = { - 0 -}; -static struct pico_queue udp_out = { - 0 -}; - - -/* Functions */ - -uint16_t pico_udp_checksum_ipv4(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - struct pico_socket *s = f->sock; - struct pico_ipv4_pseudo_hdr pseudo; - - if (s) { - /* Case of outgoing frame */ - udp_dbg("UDP CRC: on outgoing frame\n"); - pseudo.src.addr = s->local_addr.ip4.addr; - pseudo.dst.addr = s->remote_addr.ip4.addr; - } else { - /* Case of incomming frame */ - udp_dbg("UDP CRC: on incomming frame\n"); - pseudo.src.addr = hdr->src.addr; - pseudo.dst.addr = hdr->dst.addr; - } - - pseudo.zeros = 0; - pseudo.proto = PICO_PROTO_UDP; - pseudo.len = short_be(f->transport_len); - - return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), udp_hdr, f->transport_len); -} - -#ifdef PICO_SUPPORT_IPV6 -uint16_t pico_udp_checksum_ipv6(struct pico_frame *f) -{ - struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; - struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *)f->transport_hdr; - struct pico_ipv6_pseudo_hdr pseudo = { - .src = {{0}}, .dst = {{0}}, .len = 0, .zero = {0}, .nxthdr = 0 - }; - struct pico_socket *s = f->sock; - struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *)f->info; - - /* XXX If the IPv6 packet contains a Routing header, the Destination - * Address used in the pseudo-header is that of the final destination */ - if (s) { - /* Case of outgoing frame */ - pseudo.src = s->local_addr.ip6; - if (remote_endpoint) - pseudo.dst = remote_endpoint->remote_addr.ip6; - else - pseudo.dst = s->remote_addr.ip6; - } else { - /* Case of incomming frame */ - pseudo.src = ipv6_hdr->src; - pseudo.dst = ipv6_hdr->dst; - } - - pseudo.len = long_be(f->transport_len); - pseudo.nxthdr = PICO_PROTO_UDP; - - return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv6_pseudo_hdr), udp_hdr, f->transport_len); -} -#endif - - - -static int pico_udp_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - IGNORE_PARAMETER(self); - return (int)pico_network_send(f); -} - -static int pico_udp_push(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_udp_hdr *hdr = (struct pico_udp_hdr *) f->transport_hdr; - struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *) f->info; - - /* this (fragmented) frame should contain a transport header */ - if (f->transport_hdr != f->payload) { - hdr->trans.sport = f->sock->local_port; - if (remote_endpoint) { - hdr->trans.dport = remote_endpoint->remote_port; - } else { - hdr->trans.dport = f->sock->remote_port; - } - - hdr->len = short_be(f->transport_len); - - /* do not perform CRC validation. If you want to, a system needs to be - implemented to calculate the CRC over the total payload of a - fragmented payload - */ - hdr->crc = 0; - } - - if (pico_enqueue(self->q_out, f) > 0) { - return f->payload_len; - } else { - return 0; - } -} - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_udp = { - .name = "udp", - .proto_number = PICO_PROTO_UDP, - .layer = PICO_LAYER_TRANSPORT, - .process_in = pico_transport_process_in, - .process_out = pico_udp_process_out, - .push = pico_udp_push, - .q_in = &udp_in, - .q_out = &udp_out, -}; - - - -struct pico_socket *pico_udp_open(void) -{ - struct pico_socket_udp *u = PICO_ZALLOC(sizeof(struct pico_socket_udp)); - if (!u) - return NULL; - - u->mode = PICO_UDP_MODE_UNICAST; - -#ifdef PICO_SUPPORT_MCAST - u->mc_ttl = PICO_IP_DEFAULT_MULTICAST_TTL; - /* enable multicast loopback by default */ - u->sock.opt_flags |= (1 << PICO_SOCKET_OPT_MULTICAST_LOOP); -#endif - - return &u->sock; -} - -static void pico_udp_get_msginfo(struct pico_frame *f, struct pico_msginfo *msginfo) -{ - if (!msginfo || !f->net_hdr) - return; - - msginfo->dev = f->dev; - - if (IS_IPV4(f)) { /* IPV4 */ -#ifdef PICO_SUPPORT_IPV4 - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)(f->net_hdr); - msginfo->ttl = hdr->ttl; - msginfo->tos = hdr->tos; -#endif - } else { -#ifdef PICO_SUPPORT_IPV6 - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)(f->net_hdr); - msginfo->ttl = hdr->hop; - msginfo->tos = (hdr->vtf >> 20) & 0xFF; /* IPv6 traffic class */ -#endif - } -} - -uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port, struct pico_msginfo *msginfo) -{ - struct pico_frame *f = pico_queue_peek(&s->q_in); - if (f) { - if(!f->payload_len) { - f->payload = f->transport_hdr + sizeof(struct pico_udp_hdr); - f->payload_len = (uint16_t)(f->transport_len - sizeof(struct pico_udp_hdr)); - } - - udp_dbg("expected: %d, got: %d\n", len, f->payload_len); - if (src) - pico_store_network_origin(src, f); - - if (port) { - struct pico_trans *hdr = (struct pico_trans *)f->transport_hdr; - *port = hdr->sport; - } - - if (msginfo) { - pico_udp_get_msginfo(f, msginfo); - } - - if (f->payload_len > len) { - memcpy(buf, f->payload, len); - f->payload += len; - f->payload_len = (uint16_t)(f->payload_len - len); - return len; - } else { - uint16_t ret = f->payload_len; - memcpy(buf, f->payload, f->payload_len); - f = pico_dequeue(&s->q_in); - pico_frame_discard(f); - return ret; - } - } else return 0; -} - diff --git a/ext/picotcp/modules/pico_udp.h b/ext/picotcp/modules/pico_udp.h deleted file mode 100644 index 80b97a9..0000000 --- a/ext/picotcp/modules/pico_udp.h +++ /dev/null @@ -1,45 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - *********************************************************************/ -#ifndef INCLUDE_PICO_UDP -#define INCLUDE_PICO_UDP -#include "pico_addressing.h" -#include "pico_protocol.h" -#include "pico_socket.h" -#define PICO_UDP_MODE_UNICAST 0x01 -#define PICO_UDP_MODE_MULTICAST 0x02 -#define PICO_UDP_MODE_BROADCAST 0xFF - -struct pico_socket_udp -{ - struct pico_socket sock; - int mode; - uint8_t mc_ttl; /* Multicasting TTL */ -}; - - -extern struct pico_protocol pico_proto_udp; - -PACKED_STRUCT_DEF pico_udp_hdr { - struct pico_trans trans; - uint16_t len; - uint16_t crc; -}; -#define PICO_UDPHDR_SIZE 8 - -struct pico_socket *pico_udp_open(void); -uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port, struct pico_msginfo *msginfo); -uint16_t pico_udp_checksum_ipv4(struct pico_frame *f); - -#ifdef PICO_SUPPORT_IPV6 -uint16_t pico_udp_checksum_ipv6(struct pico_frame *f); -#endif - - -int pico_udp_setsockopt(struct pico_socket *s, int option, void *value); - -#endif diff --git a/ext/picotcp/rules/crc.mk b/ext/picotcp/rules/crc.mk deleted file mode 100644 index 8ec9344..0000000 --- a/ext/picotcp/rules/crc.mk +++ /dev/null @@ -1 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_CRC diff --git a/ext/picotcp/rules/cyassl.mk b/ext/picotcp/rules/cyassl.mk deleted file mode 100644 index 5903b8e..0000000 --- a/ext/picotcp/rules/cyassl.mk +++ /dev/null @@ -1,3 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_CYASSL -LDFLAGS+=-lcyassl - diff --git a/ext/picotcp/rules/devloop.mk b/ext/picotcp/rules/devloop.mk deleted file mode 100644 index 066a281..0000000 --- a/ext/picotcp/rules/devloop.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_DEVLOOP -MOD_OBJ+=$(LIBBASE)modules/pico_dev_loop.o diff --git a/ext/picotcp/rules/dhcp_client.mk b/ext/picotcp/rules/dhcp_client.mk deleted file mode 100644 index 94a1507..0000000 --- a/ext/picotcp/rules/dhcp_client.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_DHCPC -MOD_OBJ+=$(LIBBASE)modules/pico_dhcp_client.o $(LIBBASE)modules/pico_dhcp_common.o diff --git a/ext/picotcp/rules/dhcp_server.mk b/ext/picotcp/rules/dhcp_server.mk deleted file mode 100644 index c6d2b59..0000000 --- a/ext/picotcp/rules/dhcp_server.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_DHCPD -MOD_OBJ+=$(LIBBASE)modules/pico_dhcp_server.o $(LIBBASE)modules/pico_dhcp_common.o diff --git a/ext/picotcp/rules/dns_client.mk b/ext/picotcp/rules/dns_client.mk deleted file mode 100644 index f5e14c7..0000000 --- a/ext/picotcp/rules/dns_client.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_DNS_CLIENT -MOD_OBJ+=$(LIBBASE)modules/pico_dns_client.o $(LIBBASE)modules/pico_dns_common.o diff --git a/ext/picotcp/rules/dns_sd.mk b/ext/picotcp/rules/dns_sd.mk deleted file mode 100644 index 62d05cc..0000000 --- a/ext/picotcp/rules/dns_sd.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_DNS_SD -MOD_OBJ+=$(LIBBASE)modules/pico_dns_sd.o $(LIBBASE)modules/pico_mdns.o $(LIBBASE)modules/pico_dns_common.o \ No newline at end of file diff --git a/ext/picotcp/rules/eth.mk b/ext/picotcp/rules/eth.mk deleted file mode 100644 index f955bd8..0000000 --- a/ext/picotcp/rules/eth.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_ETH -MOD_OBJ+=$(LIBBASE)modules/pico_arp.o diff --git a/ext/picotcp/rules/icmp4.mk b/ext/picotcp/rules/icmp4.mk deleted file mode 100644 index 826e0e0..0000000 --- a/ext/picotcp/rules/icmp4.mk +++ /dev/null @@ -1,5 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_ICMP4 -MOD_OBJ+=$(LIBBASE)modules/pico_icmp4.o -ifneq ($(PING),0) - OPTIONS+=-DPICO_SUPPORT_PING -endif diff --git a/ext/picotcp/rules/igmp.mk b/ext/picotcp/rules/igmp.mk deleted file mode 100644 index 804079b..0000000 --- a/ext/picotcp/rules/igmp.mk +++ /dev/null @@ -1,3 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_IGMP -MOD_OBJ+=$(LIBBASE)modules/pico_igmp.o - diff --git a/ext/picotcp/rules/ipfilter.mk b/ext/picotcp/rules/ipfilter.mk deleted file mode 100644 index 3044eb6..0000000 --- a/ext/picotcp/rules/ipfilter.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_IPFILTER -MOD_OBJ+=$(LIBBASE)modules/pico_ipfilter.o diff --git a/ext/picotcp/rules/ipv4.mk b/ext/picotcp/rules/ipv4.mk deleted file mode 100644 index 34d2108..0000000 --- a/ext/picotcp/rules/ipv4.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_IPV4 -MOD_OBJ+=$(LIBBASE)modules/pico_ipv4.o diff --git a/ext/picotcp/rules/ipv4frag.mk b/ext/picotcp/rules/ipv4frag.mk deleted file mode 100644 index a79ccb3..0000000 --- a/ext/picotcp/rules/ipv4frag.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_IPV4FRAG -MOD_OBJ+=$(LIBBASE)modules/pico_fragments.o diff --git a/ext/picotcp/rules/ipv6.mk b/ext/picotcp/rules/ipv6.mk deleted file mode 100644 index f313cbf..0000000 --- a/ext/picotcp/rules/ipv6.mk +++ /dev/null @@ -1,3 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_IPV6 -DPICO_SUPPORT_ICMP6 -MOD_OBJ+=$(LIBBASE)modules/pico_ipv6.o $(LIBBASE)modules/pico_ipv6_nd.o $(LIBBASE)modules/pico_icmp6.o -include rules/ipv6frag.mk diff --git a/ext/picotcp/rules/ipv6frag.mk b/ext/picotcp/rules/ipv6frag.mk deleted file mode 100644 index da6435b..0000000 --- a/ext/picotcp/rules/ipv6frag.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_IPV6FRAG -MOD_OBJ+=$(LIBBASE)modules/pico_fragments.o diff --git a/ext/picotcp/rules/mcast.mk b/ext/picotcp/rules/mcast.mk deleted file mode 100644 index 037305b..0000000 --- a/ext/picotcp/rules/mcast.mk +++ /dev/null @@ -1 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_MCAST diff --git a/ext/picotcp/rules/mdns.mk b/ext/picotcp/rules/mdns.mk deleted file mode 100644 index b28aeeb..0000000 --- a/ext/picotcp/rules/mdns.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_MDNS -MOD_OBJ+=$(LIBBASE)modules/pico_mdns.o $(LIBBASE)modules/pico_dns_common.o diff --git a/ext/picotcp/rules/memory_manager.mk b/ext/picotcp/rules/memory_manager.mk deleted file mode 100644 index 7b0d923..0000000 --- a/ext/picotcp/rules/memory_manager.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_MM -MOD_OBJ+=$(LIBBASE)modules/pico_mm.o diff --git a/ext/picotcp/rules/mld.mk b/ext/picotcp/rules/mld.mk deleted file mode 100644 index 3302e7e..0000000 --- a/ext/picotcp/rules/mld.mk +++ /dev/null @@ -1,3 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_MLD -MOD_OBJ+=$(LIBBASE)modules/pico_mld.o - diff --git a/ext/picotcp/rules/nat.mk b/ext/picotcp/rules/nat.mk deleted file mode 100644 index 2bd67b5..0000000 --- a/ext/picotcp/rules/nat.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_NAT -MOD_OBJ+=$(LIBBASE)modules/pico_nat.o diff --git a/ext/picotcp/rules/olsr.mk b/ext/picotcp/rules/olsr.mk deleted file mode 100644 index 3cf4443..0000000 --- a/ext/picotcp/rules/olsr.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_OLSR -MOD_OBJ+=$(LIBBASE)modules/pico_olsr.o diff --git a/ext/picotcp/rules/pcap.mk b/ext/picotcp/rules/pcap.mk deleted file mode 100644 index 9c67277..0000000 --- a/ext/picotcp/rules/pcap.mk +++ /dev/null @@ -1 +0,0 @@ -MOD_OBJ+=$(LIBBASE)modules/pico_dev_pcap.o diff --git a/ext/picotcp/rules/polarssl.mk b/ext/picotcp/rules/polarssl.mk deleted file mode 100644 index e5df9d9..0000000 --- a/ext/picotcp/rules/polarssl.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS += -DPICO_SUPPORT_POLARSSL -LDFLAGS += -lpolarssl diff --git a/ext/picotcp/rules/ppp.mk b/ext/picotcp/rules/ppp.mk deleted file mode 100644 index f47c083..0000000 --- a/ext/picotcp/rules/ppp.mk +++ /dev/null @@ -1,3 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_PPP -MOD_OBJ+=$(LIBBASE)modules/pico_dev_ppp.o - diff --git a/ext/picotcp/rules/slaacv4.mk b/ext/picotcp/rules/slaacv4.mk deleted file mode 100644 index 2073a2a..0000000 --- a/ext/picotcp/rules/slaacv4.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_SLAACV4 -MOD_OBJ+=$(LIBBASE)modules/pico_slaacv4.o $(LIBBASE)modules/pico_hotplug_detection.o diff --git a/ext/picotcp/rules/sntp_client.mk b/ext/picotcp/rules/sntp_client.mk deleted file mode 100644 index 423583b..0000000 --- a/ext/picotcp/rules/sntp_client.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_SNTP_CLIENT -MOD_OBJ+=$(LIBBASE)modules/pico_sntp_client.o diff --git a/ext/picotcp/rules/tap.mk b/ext/picotcp/rules/tap.mk deleted file mode 100644 index 2f3e149..0000000 --- a/ext/picotcp/rules/tap.mk +++ /dev/null @@ -1 +0,0 @@ -MOD_OBJ+=$(LIBBASE)modules/pico_dev_tap.o diff --git a/ext/picotcp/rules/tcp.mk b/ext/picotcp/rules/tcp.mk deleted file mode 100644 index ae53034..0000000 --- a/ext/picotcp/rules/tcp.mk +++ /dev/null @@ -1,3 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_TCP -MOD_OBJ+=$(LIBBASE)modules/pico_tcp.o -MOD_OBJ+=$(LIBBASE)modules/pico_socket_tcp.o diff --git a/ext/picotcp/rules/tun.mk b/ext/picotcp/rules/tun.mk deleted file mode 100644 index a5b93fe..0000000 --- a/ext/picotcp/rules/tun.mk +++ /dev/null @@ -1 +0,0 @@ -MOD_OBJ+=$(LIBBASE)modules/pico_dev_tun.o diff --git a/ext/picotcp/rules/udp.mk b/ext/picotcp/rules/udp.mk deleted file mode 100644 index ec9157c..0000000 --- a/ext/picotcp/rules/udp.mk +++ /dev/null @@ -1,3 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_UDP -MOD_OBJ+=$(LIBBASE)modules/pico_udp.o -MOD_OBJ+=$(LIBBASE)modules/pico_socket_udp.o diff --git a/ext/picotcp/rules/wolfssl.mk b/ext/picotcp/rules/wolfssl.mk deleted file mode 100644 index f66d114..0000000 --- a/ext/picotcp/rules/wolfssl.mk +++ /dev/null @@ -1,3 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_CYASSL -DPICO_SUPPORT_WOLFSSL -LDFLAGS+=-lwolfssl - diff --git a/ext/picotcp/stack/pico_device.c b/ext/picotcp/stack/pico_device.c deleted file mode 100644 index c137180..0000000 --- a/ext/picotcp/stack/pico_device.c +++ /dev/null @@ -1,408 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - -#include "pico_config.h" -#include "pico_device.h" -#include "pico_stack.h" -#include "pico_protocol.h" -#include "pico_tree.h" -#include "pico_ipv6.h" -#include "pico_ipv4.h" -#include "pico_icmp6.h" -#include "pico_eth.h" -#define PICO_DEVICE_DEFAULT_MTU (1500) - -struct pico_devices_rr_info { - struct pico_tree_node *node_in, *node_out; -}; - -static struct pico_devices_rr_info Devices_rr_info = { - NULL, NULL -}; - -static int pico_dev_cmp(void *ka, void *kb) -{ - struct pico_device *a = ka, *b = kb; - if (a->hash < b->hash) - return -1; - - if (a->hash > b->hash) - return 1; - - return 0; -} - -PICO_TREE_DECLARE(Device_tree, pico_dev_cmp); - -#ifdef PICO_SUPPORT_IPV6 -static void device_init_ipv6_final(struct pico_device *dev, struct pico_ip6 *linklocal) -{ - dev->hostvars.basetime = PICO_ND_REACHABLE_TIME; - /* RFC 4861 $6.3.2 value between 0.5 and 1.5 times basetime */ - dev->hostvars.reachabletime = ((5 + (pico_rand() % 10)) * PICO_ND_REACHABLE_TIME) / 10; - dev->hostvars.retranstime = PICO_ND_RETRANS_TIMER; - pico_icmp6_router_solicitation(dev, linklocal); - dev->hostvars.hoplimit = PICO_IPV6_DEFAULT_HOP; -} - -struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix) -{ - struct pico_ip6 newaddr; - struct pico_ip6 netmask64 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - struct pico_ipv6_link *link; - memcpy(newaddr.addr, prefix->addr, PICO_SIZE_IP6); - /* modified EUI-64 + invert universal/local bit */ - newaddr.addr[8] = (dev->eth->mac.addr[0] ^ 0x02); - newaddr.addr[9] = dev->eth->mac.addr[1]; - newaddr.addr[10] = dev->eth->mac.addr[2]; - newaddr.addr[11] = 0xff; - newaddr.addr[12] = 0xfe; - newaddr.addr[13] = dev->eth->mac.addr[3]; - newaddr.addr[14] = dev->eth->mac.addr[4]; - newaddr.addr[15] = dev->eth->mac.addr[5]; - link = pico_ipv6_link_add(dev, newaddr, netmask64); - if (link) { - device_init_ipv6_final(dev, &newaddr); - } - - return link; -} -#endif - -static int device_init_mac(struct pico_device *dev, uint8_t *mac) -{ - #ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}}; - #endif - dev->eth = PICO_ZALLOC(sizeof(struct pico_ethdev)); - if (dev->eth) { - memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH); - #ifdef PICO_SUPPORT_IPV6 - if (pico_ipv6_link_add_local(dev, &linklocal) == NULL) { - PICO_FREE(dev->q_in); - PICO_FREE(dev->q_out); - PICO_FREE(dev->eth); - return -1; - } - - #endif - } else { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - return 0; -} - -int pico_device_ipv6_random_ll(struct pico_device *dev) -{ - #ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}}; - struct pico_ip6 netmask6 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - uint32_t len = (uint32_t)strlen(dev->name); - if (strcmp(dev->name, "loop")) { - do { - /* privacy extension + unset universal/local and individual/group bit */ - len = pico_rand(); - linklocal.addr[8] = (uint8_t)((len & 0xffu) & (uint8_t)(~0x03)); - linklocal.addr[9] = (uint8_t)(len >> 8); - linklocal.addr[10] = (uint8_t)(len >> 16); - linklocal.addr[11] = (uint8_t)(len >> 24); - len = pico_rand(); - linklocal.addr[12] = (uint8_t)len; - linklocal.addr[13] = (uint8_t)(len >> 8); - linklocal.addr[14] = (uint8_t)(len >> 16); - linklocal.addr[15] = (uint8_t)(len >> 24); - pico_rand_feed(dev->hash); - } while (pico_ipv6_link_get(&linklocal)); - - if (pico_ipv6_link_add(dev, linklocal, netmask6) == NULL) { - return -1; - } - } - - #endif - return 0; -} - -static int device_init_nomac(struct pico_device *dev) -{ - if (pico_device_ipv6_random_ll(dev) < 0) { - PICO_FREE(dev->q_in); - PICO_FREE(dev->q_out); - return -1; - } - - dev->eth = NULL; - return 0; -} - -int pico_device_init(struct pico_device *dev, const char *name, uint8_t *mac) -{ - uint32_t len = (uint32_t)strlen(name); - int ret = 0; - if(len > MAX_DEVICE_NAME) - len = MAX_DEVICE_NAME; - - memcpy(dev->name, name, len); - dev->hash = pico_hash(dev->name, len); - - Devices_rr_info.node_in = NULL; - Devices_rr_info.node_out = NULL; - dev->q_in = PICO_ZALLOC(sizeof(struct pico_queue)); - if (!dev->q_in) - return -1; - - dev->q_out = PICO_ZALLOC(sizeof(struct pico_queue)); - if (!dev->q_out) { - PICO_FREE(dev->q_in); - return -1; - } - - pico_tree_insert(&Device_tree, dev); - if (!dev->mtu) - dev->mtu = PICO_DEVICE_DEFAULT_MTU; - - if (mac) { - ret = device_init_mac(dev, mac); - } else { - ret = device_init_nomac(dev); - } - - return ret; -} - -static void pico_queue_destroy(struct pico_queue *q) -{ - if (q) { - pico_queue_empty(q); - PICO_FREE(q); - } -} - -void pico_device_destroy(struct pico_device *dev) -{ - - pico_queue_destroy(dev->q_in); - pico_queue_destroy(dev->q_out); - - if (dev->eth) - PICO_FREE(dev->eth); - -#ifdef PICO_SUPPORT_IPV4 - pico_ipv4_cleanup_links(dev); -#endif -#ifdef PICO_SUPPORT_IPV6 - pico_ipv6_cleanup_links(dev); -#endif - pico_tree_delete(&Device_tree, dev); - - if (dev->destroy) - dev->destroy(dev); - - Devices_rr_info.node_in = NULL; - Devices_rr_info.node_out = NULL; - PICO_FREE(dev); -} - -static int check_dev_serve_interrupt(struct pico_device *dev, int loop_score) -{ - if ((dev->__serving_interrupt) && (dev->dsr)) { - /* call dsr routine */ - loop_score = dev->dsr(dev, loop_score); - } - - return loop_score; -} - -static int check_dev_serve_polling(struct pico_device *dev, int loop_score) -{ - if (dev->poll) { - loop_score = dev->poll(dev, loop_score); - } - - return loop_score; -} - -static int devloop_in(struct pico_device *dev, int loop_score) -{ - struct pico_frame *f; - while(loop_score > 0) { - if (dev->q_in->frames == 0) - break; - - /* Receive */ - f = pico_dequeue(dev->q_in); - if (f) { - if (dev->eth) { - f->datalink_hdr = f->buffer; - (void)pico_ethernet_receive(f); - } else { - f->net_hdr = f->buffer; - pico_network_receive(f); - } - - loop_score--; - } - } - return loop_score; -} - -static int devloop_sendto_dev(struct pico_device *dev, struct pico_frame *f) -{ - - if (dev->eth) { - /* Ethernet: pass management of the frame to the pico_ethernet_send() rdv function */ - return pico_ethernet_send(f); - } else { - /* non-ethernet: no post-processing needed */ - return (dev->send(dev, f->start, (int)f->len) <= 0); /* Return 0 upon success, which is dev->send() > 0 */ - } -} - -static int devloop_out(struct pico_device *dev, int loop_score) -{ - struct pico_frame *f; - while(loop_score > 0) { - if (dev->q_out->frames == 0) - break; - - /* Device dequeue + send */ - f = pico_queue_peek(dev->q_out); - if (!f) - break; - - if (devloop_sendto_dev(dev, f) == 0) { /* success. */ - f = pico_dequeue(dev->q_out); - pico_frame_discard(f); /* SINGLE POINT OF DISCARD for OUTGOING FRAMES */ - loop_score--; - } else - break; /* Don't discard */ - - } - return loop_score; -} - -static int devloop(struct pico_device *dev, int loop_score, int direction) -{ - /* If device supports interrupts, read the value of the condition and trigger the dsr */ - loop_score = check_dev_serve_interrupt(dev, loop_score); - - /* If device supports polling, give control. Loop score is managed internally, - * remaining loop points are returned. */ - loop_score = check_dev_serve_polling(dev, loop_score); - - if (direction == PICO_LOOP_DIR_OUT) - loop_score = devloop_out(dev, loop_score); - else - loop_score = devloop_in(dev, loop_score); - - return loop_score; -} - - -static struct pico_tree_node *pico_dev_roundrobin_start(int direction) -{ - if (Devices_rr_info.node_in == NULL) - Devices_rr_info.node_in = pico_tree_firstNode(Device_tree.root); - - if (Devices_rr_info.node_out == NULL) - Devices_rr_info.node_out = pico_tree_firstNode(Device_tree.root); - - if (direction == PICO_LOOP_DIR_IN) - return Devices_rr_info.node_in; - else - return Devices_rr_info.node_out; -} - -static void pico_dev_roundrobin_end(int direction, struct pico_tree_node *last) -{ - if (direction == PICO_LOOP_DIR_IN) - Devices_rr_info.node_in = last; - else - Devices_rr_info.node_out = last; -} - -#define DEV_LOOP_MIN 16 - -int pico_devices_loop(int loop_score, int direction) -{ - struct pico_device *start, *next; - struct pico_tree_node *next_node = pico_dev_roundrobin_start(direction); - - if (!next_node) - return loop_score; - - next = next_node->keyValue; - start = next; - - /* round-robin all devices, break if traversed all devices */ - while ((loop_score > DEV_LOOP_MIN) && (next != NULL)) { - loop_score = devloop(next, loop_score, direction); - next_node = pico_tree_next(next_node); - next = next_node->keyValue; - if (next == NULL) - { - next_node = pico_tree_firstNode(Device_tree.root); - next = next_node->keyValue; - } - - if (next == start) - break; - } - pico_dev_roundrobin_end(direction, next_node); - return loop_score; -} - -struct pico_device *pico_get_device(const char*name) -{ - struct pico_device *dev; - struct pico_tree_node *index; - pico_tree_foreach(index, &Device_tree){ - dev = index->keyValue; - if(strcmp(name, dev->name) == 0) - return dev; - } - return NULL; -} - -int32_t pico_device_broadcast(struct pico_frame *f) -{ - struct pico_tree_node *index; - int32_t ret = -1; - - pico_tree_foreach(index, &Device_tree) - { - struct pico_device *dev = index->keyValue; - if(dev != f->dev) - { - struct pico_frame *copy = pico_frame_copy(f); - - if(!copy) - break; - - copy->dev = dev; - copy->dev->send(copy->dev, copy->start, (int)copy->len); - pico_frame_discard(copy); - } - else - { - ret = f->dev->send(f->dev, f->start, (int)f->len); - } - } - return ret; -} - -int pico_device_link_state(struct pico_device *dev) -{ - if (!dev->link_state) - return 1; /* Not supported, assuming link is always up */ - - return dev->link_state(dev); -} diff --git a/ext/picotcp/stack/pico_frame.c b/ext/picotcp/stack/pico_frame.c deleted file mode 100644 index ef5f8d7..0000000 --- a/ext/picotcp/stack/pico_frame.c +++ /dev/null @@ -1,286 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include "pico_config.h" -#include "pico_frame.h" -#include "pico_protocol.h" -#include "pico_stack.h" - -#ifdef PICO_SUPPORT_DEBUG_MEMORY -static int n_frames_allocated; -#endif - -/** frame alloc/dealloc/copy **/ -void pico_frame_discard(struct pico_frame *f) -{ - if (!f) - return; - - (*f->usage_count)--; - if (*f->usage_count == 0) { - if (f->flags & PICO_FRAME_FLAG_EXT_USAGE_COUNTER) - PICO_FREE(f->usage_count); - -#ifdef PICO_SUPPORT_DEBUG_MEMORY - dbg("Discarded buffer @%p, caller: %p\n", f->buffer, __builtin_return_address(3)); - dbg("DEBUG MEMORY: %d frames in use.\n", --n_frames_allocated); -#endif - if (!(f->flags & PICO_FRAME_FLAG_EXT_BUFFER)) - PICO_FREE(f->buffer); - else if (f->notify_free) - f->notify_free(f->buffer); - - if (f->info) - PICO_FREE(f->info); - } - -#ifdef PICO_SUPPORT_DEBUG_MEMORY - else { - dbg("Removed frame @%p(copy), usage count now: %d\n", f, *f->usage_count); - } -#endif - PICO_FREE(f); -} - -struct pico_frame *pico_frame_copy(struct pico_frame *f) -{ - struct pico_frame *new = PICO_ZALLOC(sizeof(struct pico_frame)); - if (!new) - return NULL; - - memcpy(new, f, sizeof(struct pico_frame)); - *(new->usage_count) += 1; -#ifdef PICO_SUPPORT_DEBUG_MEMORY - dbg("Copied frame @%p, into %p, usage count now: %d\n", f, new, *new->usage_count); -#endif - new->next = NULL; - return new; -} - - -static struct pico_frame *pico_frame_do_alloc(uint32_t size, int zerocopy, int ext_buffer) -{ - struct pico_frame *p = PICO_ZALLOC(sizeof(struct pico_frame)); - uint32_t frame_buffer_size = size; - if (!p) - return NULL; - - if (ext_buffer && !zerocopy) { - /* external buffer implies zerocopy flag! */ - PICO_FREE(p); - return NULL; - } - - if (!zerocopy) { - unsigned int align = size % sizeof(uint32_t); - /* Ensure that usage_count starts on an aligned address */ - if (align) { - frame_buffer_size += (uint32_t)sizeof(uint32_t) - align; - } - - p->buffer = PICO_ZALLOC(frame_buffer_size + sizeof(uint32_t)); - if (!p->buffer) { - PICO_FREE(p); - return NULL; - } - - p->usage_count = (uint32_t *)((void *)(((uint8_t*)p->buffer) + frame_buffer_size)); - } else { - p->buffer = NULL; - p->flags |= PICO_FRAME_FLAG_EXT_USAGE_COUNTER; - p->usage_count = PICO_ZALLOC(sizeof(uint32_t)); - if (!p->usage_count) { - PICO_FREE(p); - return NULL; - } - } - - - p->buffer_len = size; - - /* By default, frame content is the full buffer. */ - p->start = p->buffer; - p->len = p->buffer_len; - *p->usage_count = 1; - - if (ext_buffer) - p->flags |= PICO_FRAME_FLAG_EXT_BUFFER; - -#ifdef PICO_SUPPORT_DEBUG_MEMORY - dbg("Allocated buffer @%p, len= %d caller: %p\n", p->buffer, p->buffer_len, __builtin_return_address(2)); - dbg("DEBUG MEMORY: %d frames in use.\n", ++n_frames_allocated); -#endif - return p; -} - -struct pico_frame *pico_frame_alloc(uint32_t size) -{ - return pico_frame_do_alloc(size, 0, 0); -} - -int pico_frame_grow(struct pico_frame *f, uint32_t size) -{ - uint8_t *oldbuf; - uint32_t usage_count, *p_old_usage; - uint32_t frame_buffer_size; - uint32_t oldsize; - unsigned int align; - int addr_diff = 0; - - if (!f || (size < f->buffer_len)) { - return -1; - } - - align = size % sizeof(uint32_t); - frame_buffer_size = size; - if (align) { - frame_buffer_size += (uint32_t)sizeof(uint32_t) - align; - } - - oldbuf = f->buffer; - oldsize = f->buffer_len; - usage_count = *(f->usage_count); - p_old_usage = f->usage_count; - f->buffer = PICO_ZALLOC(frame_buffer_size + sizeof(uint32_t)); - if (!f->buffer) { - f->buffer = oldbuf; - return -1; - } - - f->usage_count = (uint32_t *)((void *)(((uint8_t*)f->buffer) + frame_buffer_size)); - *f->usage_count = usage_count; - f->buffer_len = size; - memcpy(f->buffer, oldbuf, oldsize); - - /* Update hdr fields to new buffer*/ - addr_diff = (int)(f->buffer - oldbuf); - f->net_hdr += addr_diff; - f->datalink_hdr += addr_diff; - f->transport_hdr += addr_diff; - f->app_hdr += addr_diff; - f->start += addr_diff; - f->payload += addr_diff; - - if (f->flags & PICO_FRAME_FLAG_EXT_USAGE_COUNTER) - PICO_FREE(p_old_usage); - - if (!(f->flags & PICO_FRAME_FLAG_EXT_BUFFER)) - PICO_FREE(oldbuf); - else if (f->notify_free) - f->notify_free(oldbuf); - - f->flags = 0; - /* Now, the frame is not zerocopy anymore, and the usage counter has been moved within it */ - return 0; -} - -struct pico_frame *pico_frame_alloc_skeleton(uint32_t size, int ext_buffer) -{ - return pico_frame_do_alloc(size, 1, ext_buffer); -} - -int pico_frame_skeleton_set_buffer(struct pico_frame *f, void *buf) -{ - if (!buf) - return -1; - - f->buffer = (uint8_t *) buf; - f->start = f->buffer; - return 0; -} - -struct pico_frame *pico_frame_deepcopy(struct pico_frame *f) -{ - struct pico_frame *new = pico_frame_alloc(f->buffer_len); - int addr_diff; - unsigned char *buf; - uint32_t *uc; - if (!new) - return NULL; - - /* Save the two key pointers... */ - buf = new->buffer; - uc = new->usage_count; - - /* Overwrite all fields with originals */ - memcpy(new, f, sizeof(struct pico_frame)); - - /* ...restore the two key pointers */ - new->buffer = buf; - new->usage_count = uc; - - /* Update in-buffer pointers with offset */ - addr_diff = (int)(new->buffer - f->buffer); - new->datalink_hdr += addr_diff; - new->net_hdr += addr_diff; - new->transport_hdr += addr_diff; - new->app_hdr += addr_diff; - new->start += addr_diff; - new->payload += addr_diff; - -#ifdef PICO_SUPPORT_DEBUG_MEMORY - dbg("Deep-Copied frame @%p, into %p, usage count now: %d\n", f, new, *new->usage_count); -#endif - new->next = NULL; - return new; -} - - -static inline uint32_t pico_checksum_adder(uint32_t sum, void *data, uint32_t len) -{ - uint16_t *buf = (uint16_t *)data; - uint16_t *stop; - - if (len & 0x01) { - --len; -#ifdef PICO_BIGENDIAN - sum += (((uint8_t *)data)[len]) << 8; -#else - sum += ((uint8_t *)data)[len]; -#endif - } - - stop = (uint16_t *)((void *)(((uint8_t *)data) + len)); - - while (buf < stop) { - sum += *buf++; - } - return sum; -} - -static inline uint16_t pico_checksum_finalize(uint32_t sum) -{ - while (sum >> 16) { /* a second carry is possible! */ - sum = (sum & 0x0000FFFF) + (sum >> 16); - } - return short_be((uint16_t) ~sum); -} - -/** - * Calculate checksum of a given string - */ -uint16_t pico_checksum(void *inbuf, uint32_t len) -{ - uint32_t sum; - - sum = pico_checksum_adder(0, inbuf, len); - return pico_checksum_finalize(sum); -} - -/* WARNING: len1 MUST be an EVEN number */ -uint16_t pico_dualbuffer_checksum(void *inbuf1, uint32_t len1, void *inbuf2, uint32_t len2) -{ - uint32_t sum; - - sum = pico_checksum_adder(0, inbuf1, len1); - sum = pico_checksum_adder(sum, inbuf2, len2); - return pico_checksum_finalize(sum); -} - diff --git a/ext/picotcp/stack/pico_md5.c b/ext/picotcp/stack/pico_md5.c deleted file mode 100644 index d612bce..0000000 --- a/ext/picotcp/stack/pico_md5.c +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************************* - * PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved. - * See LICENSE and COPYING for usage. - * - * Authors: Daniele Lacamera - * *********************************************************************/ - - -#include - -#if defined (PICO_SUPPORT_CYASSL) -#include - -void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len) -{ - Md5 md5; - InitMd5(&md5); - Md5Update(&md5, src, len); - Md5Final(&md5, dst); -} - -#elif defined (PICO_SUPPORT_POLARSSL) -#include - -void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len) -{ - md5(src, len, dst); -} - -#else -static void (*do_pico_md5sum)(uint8_t *dst, const uint8_t *src, size_t len); -void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len) -{ - if (do_pico_md5sum) { - do_pico_md5sum(dst, src, len); - } -} - -void pico_register_md5sum(void (*md5)(uint8_t *, const uint8_t *, size_t)) -{ - do_pico_md5sum = md5; -} -#endif diff --git a/ext/picotcp/stack/pico_protocol.c b/ext/picotcp/stack/pico_protocol.c deleted file mode 100644 index b8afec2..0000000 --- a/ext/picotcp/stack/pico_protocol.c +++ /dev/null @@ -1,214 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include "pico_protocol.h" -#include "pico_tree.h" - -struct pico_proto_rr -{ - struct pico_tree *t; - struct pico_tree_node *node_in, *node_out; -}; - - -static int pico_proto_cmp(void *ka, void *kb) -{ - struct pico_protocol *a = ka, *b = kb; - if (a->hash < b->hash) - return -1; - - if (a->hash > b->hash) - return 1; - - return 0; -} - -PICO_TREE_DECLARE(Datalink_proto_tree, pico_proto_cmp); -PICO_TREE_DECLARE(Network_proto_tree, pico_proto_cmp); -PICO_TREE_DECLARE(Transport_proto_tree, pico_proto_cmp); -PICO_TREE_DECLARE(Socket_proto_tree, pico_proto_cmp); - -/* Static variables to keep track of the round robin loop */ -static struct pico_proto_rr proto_rr_datalink = { - &Datalink_proto_tree, NULL, NULL -}; -static struct pico_proto_rr proto_rr_network = { - &Network_proto_tree, NULL, NULL -}; -static struct pico_proto_rr proto_rr_transport = { - &Transport_proto_tree, NULL, NULL -}; -static struct pico_proto_rr proto_rr_socket = { - &Socket_proto_tree, NULL, NULL -}; - -static int proto_loop_in(struct pico_protocol *proto, int loop_score) -{ - struct pico_frame *f; - while(loop_score > 0) { - if (proto->q_in->frames == 0) - break; - - f = pico_dequeue(proto->q_in); - if ((f) && (proto->process_in(proto, f) > 0)) { - loop_score--; - } - } - return loop_score; -} - -static int proto_loop_out(struct pico_protocol *proto, int loop_score) -{ - struct pico_frame *f; - while(loop_score > 0) { - if (proto->q_out->frames == 0) - break; - - f = pico_dequeue(proto->q_out); - if ((f) && (proto->process_out(proto, f) > 0)) { - loop_score--; - } - } - return loop_score; -} - -static int proto_loop(struct pico_protocol *proto, int loop_score, int direction) -{ - - if (direction == PICO_LOOP_DIR_IN) - loop_score = proto_loop_in(proto, loop_score); - else if (direction == PICO_LOOP_DIR_OUT) - loop_score = proto_loop_out(proto, loop_score); - - return loop_score; -} - -static struct pico_tree_node *roundrobin_init(struct pico_proto_rr *rr, int direction) -{ - struct pico_tree_node *next_node = NULL; - /* Initialization (takes place only once) */ - if (rr->node_in == NULL) - rr->node_in = pico_tree_firstNode(rr->t->root); - - if (rr->node_out == NULL) - rr->node_out = pico_tree_firstNode(rr->t->root); - - if (direction == PICO_LOOP_DIR_IN) - next_node = rr->node_in; - else - next_node = rr->node_out; - - return next_node; -} - -static void roundrobin_end(struct pico_proto_rr *rr, int direction, struct pico_tree_node *last) -{ - if (direction == PICO_LOOP_DIR_IN) - rr->node_in = last; - else - rr->node_out = last; -} - -static int pico_protocol_generic_loop(struct pico_proto_rr *rr, int loop_score, int direction) -{ - struct pico_protocol *start, *next; - struct pico_tree_node *next_node = roundrobin_init(rr, direction); - - if (!next_node) - return loop_score; - - next = next_node->keyValue; - - /* init start node */ - start = next; - - /* round-robin all layer protocols, break if traversed all protocols */ - while (loop_score > 1 && next != NULL) { - loop_score = proto_loop(next, loop_score, direction); - next_node = pico_tree_next(next_node); - next = next_node->keyValue; - if (next == NULL) - { - next_node = pico_tree_firstNode(rr->t->root); - next = next_node->keyValue; - } - - if (next == start) - break; - } - roundrobin_end(rr, direction, next_node); - return loop_score; -} - -int pico_protocol_datalink_loop(int loop_score, int direction) -{ - return pico_protocol_generic_loop(&proto_rr_datalink, loop_score, direction); -} - -int pico_protocol_network_loop(int loop_score, int direction) -{ - return pico_protocol_generic_loop(&proto_rr_network, loop_score, direction); -} - -int pico_protocol_transport_loop(int loop_score, int direction) -{ - return pico_protocol_generic_loop(&proto_rr_transport, loop_score, direction); -} - -int pico_protocol_socket_loop(int loop_score, int direction) -{ - return pico_protocol_generic_loop(&proto_rr_socket, loop_score, direction); -} - -int pico_protocols_loop(int loop_score) -{ -/* - loop_score = pico_protocol_datalink_loop(loop_score); - loop_score = pico_protocol_network_loop(loop_score); - loop_score = pico_protocol_transport_loop(loop_score); - loop_score = pico_protocol_socket_loop(loop_score); - */ - return loop_score; -} - -static void proto_layer_rr_reset(struct pico_proto_rr *rr) -{ - rr->node_in = NULL; - rr->node_out = NULL; -} - -void pico_protocol_init(struct pico_protocol *p) -{ - if (!p) - return; - - p->hash = pico_hash(p->name, (uint32_t)strlen(p->name)); - switch (p->layer) { - case PICO_LAYER_DATALINK: - pico_tree_insert(&Datalink_proto_tree, p); - proto_layer_rr_reset(&proto_rr_datalink); - break; - case PICO_LAYER_NETWORK: - pico_tree_insert(&Network_proto_tree, p); - proto_layer_rr_reset(&proto_rr_network); - break; - case PICO_LAYER_TRANSPORT: - pico_tree_insert(&Transport_proto_tree, p); - proto_layer_rr_reset(&proto_rr_transport); - break; - case PICO_LAYER_SOCKET: - pico_tree_insert(&Socket_proto_tree, p); - proto_layer_rr_reset(&proto_rr_socket); - break; - } - //dbg("Protocol %s registered (layer: %d).\n", p->name, p->layer); - -} - diff --git a/ext/picotcp/stack/pico_socket.c b/ext/picotcp/stack/pico_socket.c deleted file mode 100644 index 2553703..0000000 --- a/ext/picotcp/stack/pico_socket.c +++ /dev/null @@ -1,2231 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include "pico_config.h" -#include "pico_queue.h" -#include "pico_socket.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_udp.h" -#include "pico_tcp.h" -#include "pico_stack.h" -#include "pico_icmp4.h" -#include "pico_nat.h" -#include "pico_tree.h" -#include "pico_device.h" -#include "pico_socket_multicast.h" -#include "pico_socket_tcp.h" -#include "pico_socket_udp.h" - -#if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6) -#if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP) - - -#define PROTO(s) ((s)->proto->proto_number) -#define PICO_MIN_MSS (1280) -#define TCP_STATE(s) (s->state & PICO_SOCKET_STATE_TCP) - -#ifdef PICO_SUPPORT_MUTEX -static void *Mutex = NULL; -#endif - - -#define PROTO(s) ((s)->proto->proto_number) - -#define PICO_SOCKET_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */ - -# define frag_dbg(...) do {} while(0) - - -static struct pico_sockport *sp_udp = NULL, *sp_tcp = NULL; - -struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, uint16_t len); - -static int socket_cmp_family(struct pico_socket *a, struct pico_socket *b) -{ - uint32_t a_is_ip6 = is_sock_ipv6(a); - uint32_t b_is_ip6 = is_sock_ipv6(b); - (void)a; - (void)b; - if (a_is_ip6 < b_is_ip6) - return -1; - - if (a_is_ip6 > b_is_ip6) - return 1; - - return 0; -} - - -static int socket_cmp_ipv6(struct pico_socket *a, struct pico_socket *b) -{ - int ret = 0; - (void)a; - (void)b; -#ifdef PICO_SUPPORT_IPV6 - if (!is_sock_ipv6(a) || !is_sock_ipv6(b)) - return 0; - - if ((memcmp(a->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0) || (memcmp(b->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0)) - ret = 0; - else - ret = memcmp(a->local_addr.ip6.addr, b->local_addr.ip6.addr, PICO_SIZE_IP6); - -#endif - return ret; -} - -static int socket_cmp_ipv4(struct pico_socket *a, struct pico_socket *b) -{ - int ret = 0; - (void)a; - (void)b; - if (!is_sock_ipv4(a) || !is_sock_ipv4(b)) - return 0; - -#ifdef PICO_SUPPORT_IPV4 - if ((a->local_addr.ip4.addr == PICO_IP4_ANY) || (b->local_addr.ip4.addr == PICO_IP4_ANY)) - ret = 0; - else - ret = (int)(a->local_addr.ip4.addr - b->local_addr.ip4.addr); - -#endif - return ret; -} - -static int socket_cmp_remotehost(struct pico_socket *a, struct pico_socket *b) -{ - int ret = 0; - if (is_sock_ipv6(a)) - ret = memcmp(a->remote_addr.ip6.addr, b->remote_addr.ip6.addr, PICO_SIZE_IP6); - else - ret = (int)(a->remote_addr.ip4.addr - b->remote_addr.ip4.addr); - - return ret; -} - -static int socket_cmp_addresses(struct pico_socket *a, struct pico_socket *b) -{ - int ret = 0; - /* At this point, sort by local host */ - ret = socket_cmp_ipv6(a, b); - - if (ret == 0) - ret = socket_cmp_ipv4(a, b); - - /* Sort by remote host */ - if (ret == 0) - ret = socket_cmp_remotehost(a, b); - - return 0; -} - -static int socket_cmp(void *ka, void *kb) -{ - struct pico_socket *a = ka, *b = kb; - int ret = 0; - - /* First, order by network family */ - ret = socket_cmp_family(a, b); - - /* Then, compare by source/destination addresses */ - if (ret == 0) - ret = socket_cmp_addresses(a, b); - - /* And finally by remote port. The two sockets are coincident if the quad is the same. */ - if (ret == 0) - ret = b->remote_port - a->remote_port; - - return ret; -} - - -#define INIT_SOCKPORT { {&LEAF, socket_cmp}, 0, 0 } - -static int sockport_cmp(void *ka, void *kb) -{ - struct pico_sockport *a = ka, *b = kb; - if (a->number < b->number) - return -1; - - if (a->number > b->number) - return 1; - - return 0; -} - -PICO_TREE_DECLARE(UDPTable, sockport_cmp); -PICO_TREE_DECLARE(TCPTable, sockport_cmp); - -struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port) -{ - struct pico_sockport test = INIT_SOCKPORT; - test.number = port; - - if (proto == PICO_PROTO_UDP){ - return pico_tree_findKey(&UDPTable, &test); - } - - else if (proto == PICO_PROTO_TCP){ - return pico_tree_findKey(&TCPTable, &test); - } - - else - { return NULL; - } -} - -#ifdef PICO_SUPPORT_IPV4 - -static int pico_port_in_use_by_nat(uint16_t proto, uint16_t port) -{ - int ret = 0; - (void) proto; - (void) port; -#ifdef PICO_SUPPORT_NAT - if (pico_ipv4_nat_find(port, NULL, 0, (uint8_t)proto)) { - dbg("In use by nat....\n"); - ret = 1; - } - -#endif - return ret; -} - -static int pico_port_in_use_with_this_ipv4_address(struct pico_sockport *sp, struct pico_ip4 ip) -{ - if (sp) { - struct pico_ip4 *s_local; - struct pico_tree_node *idx; - struct pico_socket *s; - pico_tree_foreach(idx, &sp->socks) { - s = idx->keyValue; - if (s->net == &pico_proto_ipv4) { - s_local = (struct pico_ip4*) &s->local_addr; - if ((s_local->addr == PICO_IPV4_INADDR_ANY) || (s_local->addr == ip.addr)) { - return 1; - } - } - } - } - - return 0; -} - - -static int pico_port_in_use_ipv4(struct pico_sockport *sp, void *addr) -{ - struct pico_ip4 ip; - /* IPv4 */ - if (addr) - ip.addr = ((struct pico_ip4 *)addr)->addr; - else - ip.addr = PICO_IPV4_INADDR_ANY; - - if (ip.addr == PICO_IPV4_INADDR_ANY) { - if (!sp) - return 0; - else { - dbg("In use, and asked for ANY\n"); - return 1; - } - } - - return pico_port_in_use_with_this_ipv4_address(sp, ip); -} -#endif - -#ifdef PICO_SUPPORT_IPV6 -static int pico_port_in_use_with_this_ipv6_address(struct pico_sockport *sp, struct pico_ip6 ip) -{ - if (sp) { - struct pico_ip6 *s_local; - struct pico_tree_node *idx; - struct pico_socket *s; - pico_tree_foreach(idx, &sp->socks) { - s = idx->keyValue; - if (s->net == &pico_proto_ipv6) { - s_local = (struct pico_ip6*) &s->local_addr; - if ((pico_ipv6_is_unspecified(s_local->addr)) || (!memcmp(s_local->addr, ip.addr, PICO_SIZE_IP6))) { - return 1; - } - } - } - } - - return 0; -} - -static int pico_port_in_use_ipv6(struct pico_sockport *sp, void *addr) -{ - struct pico_ip6 ip; - /* IPv6 */ - if (addr) - memcpy(ip.addr, ((struct pico_ip6 *)addr)->addr, sizeof(struct pico_ip6)); - else - memcpy(ip.addr, PICO_IP6_ANY, sizeof(struct pico_ip6)); - - if (memcmp(ip.addr, PICO_IP6_ANY, sizeof(struct pico_ip6)) == 0) { - if (!sp) - return 0; - else { - dbg("In use, and asked for ANY\n"); - return 1; - } - } - - return pico_port_in_use_with_this_ipv6_address(sp, ip); -} -#endif - - - -static int pico_generic_port_in_use(uint16_t proto, uint16_t port, struct pico_sockport *sp, void *addr, void *net) -{ -#ifdef PICO_SUPPORT_IPV4 - if (net == &pico_proto_ipv4) - { - if (pico_port_in_use_by_nat(proto, port)) { - return 1; - } - - if (pico_port_in_use_ipv4(sp, addr)) { - return 1; - } - } - -#endif - -#ifdef PICO_SUPPORT_IPV6 - if (net == &pico_proto_ipv6) - { - if (pico_port_in_use_ipv6(sp, addr)) { - return 1; - } - } - -#endif - - return 0; -} - -int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net) -{ - struct pico_sockport *sp; - sp = pico_get_sockport(proto, port); - - if (pico_generic_port_in_use(proto, port, sp, addr, net)) - return 0; - - return 1; -} - -static int pico_check_socket(struct pico_socket *s) -{ - struct pico_sockport *test; - struct pico_socket *found; - struct pico_tree_node *index; - - test = pico_get_sockport(PROTO(s), s->local_port); - - if (!test) { - return -1; - } - - pico_tree_foreach(index, &test->socks){ - found = index->keyValue; - if (s == found) { - return 0; - } - } - return -1; -} - -struct pico_socket *pico_sockets_find(uint16_t local, uint16_t remote) -{ - struct pico_socket *sock = NULL; - struct pico_tree_node *index = NULL; - struct pico_sockport *sp = NULL; - - sp = pico_get_sockport(PICO_PROTO_TCP, local); - if(sp) - { - pico_tree_foreach(index, &sp->socks) - { - if(((struct pico_socket *)index->keyValue)->remote_port == remote) - { - sock = (struct pico_socket *)index->keyValue; - break; - } - } - } - return sock; -} - - -int8_t pico_socket_add(struct pico_socket *s) -{ - struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port); - PICOTCP_MUTEX_LOCK(Mutex); - if (!sp) { - /* dbg("Creating sockport..%04x\n", s->local_port); / * In comment due to spam during test * / */ - sp = PICO_ZALLOC(sizeof(struct pico_sockport)); - - if (!sp) { - pico_err = PICO_ERR_ENOMEM; - PICOTCP_MUTEX_UNLOCK(Mutex); - return -1; - } - - sp->proto = PROTO(s); - sp->number = s->local_port; - sp->socks.root = &LEAF; - sp->socks.compare = socket_cmp; - - if (PROTO(s) == PICO_PROTO_UDP) - { - pico_tree_insert(&UDPTable, sp); - } - else if (PROTO(s) == PICO_PROTO_TCP) - { - pico_tree_insert(&TCPTable, sp); - } - } - - pico_tree_insert(&sp->socks, s); - s->state |= PICO_SOCKET_STATE_BOUND; - PICOTCP_MUTEX_UNLOCK(Mutex); -#ifdef DEBUG_SOCKET_TREE - { - struct pico_tree_node *index; - /* RB_FOREACH(s, socket_tree, &sp->socks) { */ - pico_tree_foreach(index, &sp->socks){ - s = index->keyValue; - dbg(">>>> List Socket lc=%hu rm=%hu\n", short_be(s->local_port), short_be(s->remote_port)); - } - - } -#endif - return 0; -} - - -static void socket_clean_queues(struct pico_socket *sock) -{ - struct pico_frame *f_in = pico_dequeue(&sock->q_in); - struct pico_frame *f_out = pico_dequeue(&sock->q_out); - while(f_in || f_out) - { - if(f_in) - { - pico_frame_discard(f_in); - f_in = pico_dequeue(&sock->q_in); - } - - if(f_out) - { - pico_frame_discard(f_out); - f_out = pico_dequeue(&sock->q_out); - } - } - pico_queue_deinit(&sock->q_in); - pico_queue_deinit(&sock->q_out); - pico_socket_tcp_cleanup(sock); -} - -static void socket_garbage_collect(pico_time now, void *arg) -{ - struct pico_socket *s = (struct pico_socket *) arg; - IGNORE_PARAMETER(now); - - socket_clean_queues(s); - PICO_FREE(s); -} - - -static void pico_socket_check_empty_sockport(struct pico_socket *s, struct pico_sockport *sp) -{ - if(pico_tree_empty(&sp->socks)) { - if (PROTO(s) == PICO_PROTO_UDP) - { - pico_tree_delete(&UDPTable, sp); - } - else if (PROTO(s) == PICO_PROTO_TCP) - { - pico_tree_delete(&TCPTable, sp); - } - - if(sp_tcp == sp) - sp_tcp = NULL; - - if(sp_udp == sp) - sp_udp = NULL; - - PICO_FREE(sp); - } -} - -int8_t pico_socket_del(struct pico_socket *s) -{ - struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port); - if (!sp) { - pico_err = PICO_ERR_ENXIO; - return -1; - } - - PICOTCP_MUTEX_LOCK(Mutex); - pico_tree_delete(&sp->socks, s); - pico_socket_check_empty_sockport(s, sp); - pico_multicast_delete(s); - pico_socket_tcp_delete(s); - s->state = PICO_SOCKET_STATE_CLOSED; - pico_timer_add((pico_time)10, socket_garbage_collect, s); - PICOTCP_MUTEX_UNLOCK(Mutex); - return 0; -} - -static void pico_socket_update_tcp_state(struct pico_socket *s, uint16_t tcp_state) -{ - if (tcp_state) { - s->state &= 0x00FF; - s->state |= tcp_state; - } -} - -static int8_t pico_socket_alter_state(struct pico_socket *s, uint16_t more_states, uint16_t less_states, uint16_t tcp_state) -{ - struct pico_sockport *sp; - if (more_states & PICO_SOCKET_STATE_BOUND) - return pico_socket_add(s); - - if (less_states & PICO_SOCKET_STATE_BOUND) - return pico_socket_del(s); - - sp = pico_get_sockport(PROTO(s), s->local_port); - if (!sp) { - pico_err = PICO_ERR_ENXIO; - return -1; - } - - s->state |= more_states; - s->state = (uint16_t)(s->state & (~less_states)); - pico_socket_update_tcp_state(s, tcp_state); - return 0; -} - - -static int pico_socket_transport_deliver(struct pico_protocol *p, struct pico_sockport *sp, struct pico_frame *f) -{ -#ifdef PICO_SUPPORT_TCP - if (p->proto_number == PICO_PROTO_TCP) - return pico_socket_tcp_deliver(sp, f); - -#endif - -#ifdef PICO_SUPPORT_UDP - if (p->proto_number == PICO_PROTO_UDP) - return pico_socket_udp_deliver(sp, f); - -#endif - - return -1; -} - - -static int pico_socket_deliver(struct pico_protocol *p, struct pico_frame *f, uint16_t localport) -{ - struct pico_sockport *sp = NULL; - struct pico_trans *tr = (struct pico_trans *) f->transport_hdr; - - if (!tr) - return -1; - - sp = pico_get_sockport(p->proto_number, localport); - if (!sp) { - //dbg("No such port %d\n", short_be(localport)); - return -1; - } - - return pico_socket_transport_deliver(p, sp, f); -} - -int pico_socket_set_family(struct pico_socket *s, uint16_t family) -{ - (void) family; - - #ifdef PICO_SUPPORT_IPV4 - if (family == PICO_PROTO_IPV4) - s->net = &pico_proto_ipv4; - - #endif - - #ifdef PICO_SUPPORT_IPV6 - if (family == PICO_PROTO_IPV6) - s->net = &pico_proto_ipv6; - - #endif - - if (s->net == NULL) - return -1; - - return 0; -} - -static struct pico_socket *pico_socket_transport_open(uint16_t proto, uint16_t family) -{ - struct pico_socket *s = NULL; - (void)family; -#ifdef PICO_SUPPORT_UDP - if (proto == PICO_PROTO_UDP) - s = pico_socket_udp_open(); - -#endif - -#ifdef PICO_SUPPORT_TCP - if (proto == PICO_PROTO_TCP) - s = pico_socket_tcp_open(family); - -#endif - - return s; - -} - -struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *)) -{ - - struct pico_socket *s = NULL; - - s = pico_socket_transport_open(proto, net); - - if (!s) { - pico_err = PICO_ERR_EPROTONOSUPPORT; - return NULL; - } - - if (pico_socket_set_family(s, net) != 0) { - PICO_FREE(s); - pico_err = PICO_ERR_ENETUNREACH; - return NULL; - } - - s->q_in.max_size = PICO_DEFAULT_SOCKETQ; - s->q_out.max_size = PICO_DEFAULT_SOCKETQ; - - s->wakeup = wakeup; - return s; -} - - -static void pico_socket_clone_assign_address(struct pico_socket *s, struct pico_socket *facsimile) -{ - -#ifdef PICO_SUPPORT_IPV4 - if (facsimile->net == &pico_proto_ipv4) { - s->net = &pico_proto_ipv4; - memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip4)); - memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip4)); - } - -#endif - -#ifdef PICO_SUPPORT_IPV6 - if (facsimile->net == &pico_proto_ipv6) { - s->net = &pico_proto_ipv6; - memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip6)); - memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip6)); - } - -#endif - -} - -struct pico_socket *pico_socket_clone(struct pico_socket *facsimile) -{ - struct pico_socket *s = NULL; - - s = pico_socket_transport_open(facsimile->proto->proto_number, facsimile->net->proto_number); - if (!s) { - pico_err = PICO_ERR_EPROTONOSUPPORT; - return NULL; - } - - s->local_port = facsimile->local_port; - s->remote_port = facsimile->remote_port; - s->state = facsimile->state; - pico_socket_clone_assign_address(s, facsimile); - if (!s->net) { - PICO_FREE(s); - pico_err = PICO_ERR_ENETUNREACH; - return NULL; - } - - s->q_in.max_size = PICO_DEFAULT_SOCKETQ; - s->q_out.max_size = PICO_DEFAULT_SOCKETQ; - s->wakeup = NULL; - return s; -} - -static int pico_socket_transport_read(struct pico_socket *s, void *buf, int len) -{ - if (PROTO(s) == PICO_PROTO_UDP) - { - /* make sure cast to uint16_t doesn't give unexpected results */ - if(len > 0xFFFF) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return pico_socket_udp_recv(s, buf, (uint16_t)len, NULL, NULL); - } - else if (PROTO(s) == PICO_PROTO_TCP) - return pico_socket_tcp_read(s, buf, (uint32_t)len); - else return 0; -} -#include - -int pico_socket_read(struct pico_socket *s, void *buf, int len) -{ - if (!s || buf == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - /* See task #178 */ - if (pico_check_socket(s) != 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - pico_err = PICO_ERR_EIO; - return -1; - } - - return pico_socket_transport_read(s, buf, len); -} - -static int pico_socket_write_check_state(struct pico_socket *s) -{ - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - pico_err = PICO_ERR_EIO; - return -1; - } - - if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) { - pico_err = PICO_ERR_ENOTCONN; - return -1; - } - - if (s->state & PICO_SOCKET_STATE_SHUT_LOCAL) { /* check if in shutdown state */ - pico_err = PICO_ERR_ESHUTDOWN; - return -1; - } - - return 0; -} - -static int pico_socket_write_attempt(struct pico_socket *s, const void *buf, int len) -{ - if (pico_socket_write_check_state(s) < 0) { - return -1; - } else { - return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port); - } -} - -int pico_socket_write(struct pico_socket *s, const void *buf, int len) -{ - if (!s || buf == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - /* See task #178 */ - if (pico_check_socket(s) != 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - return pico_socket_write_attempt(s, buf, len); -} - -static uint16_t pico_socket_high_port(uint16_t proto) -{ - uint16_t port; - if (0 || -#ifdef PICO_SUPPORT_TCP - (proto == PICO_PROTO_TCP) || -#endif -#ifdef PICO_SUPPORT_UDP - (proto == PICO_PROTO_UDP) || -#endif - 0) { - do { - uint32_t rand = pico_rand(); - port = (uint16_t) (rand & 0xFFFFU); - port = (uint16_t)((port % (65535 - 1024)) + 1024U); - if (pico_is_port_free(proto, port, NULL, NULL)) { - return short_be(port); - } - } while(1); - } - else return 0U; -} - -static void *pico_socket_sendto_get_ip4_src(struct pico_socket *s, struct pico_ip4 *dst) -{ - struct pico_ip4 *src4 = NULL; - -#ifdef PICO_SUPPORT_IPV4 - /* Check if socket is connected: destination address MUST match the - * current connected endpoint - */ - if ((s->state & PICO_SOCKET_STATE_CONNECTED)) { - src4 = &s->local_addr.ip4; - if (s->remote_addr.ip4.addr != ((struct pico_ip4 *)dst)->addr ) { - pico_err = PICO_ERR_EADDRNOTAVAIL; - return NULL; - } - } else { - - src4 = pico_ipv4_source_find(dst); - if (!src4) { - pico_err = PICO_ERR_EHOSTUNREACH; - return NULL; - } - - } - - if (src4->addr != PICO_IPV4_INADDR_ANY) - s->local_addr.ip4.addr = src4->addr; - -#else - pico_err = PICO_ERR_EPROTONOSUPPORT; -#endif - return src4; -} - -static void *pico_socket_sendto_get_ip6_src(struct pico_socket *s, struct pico_ip6 *dst) -{ - struct pico_ip6 *src6 = NULL; - (void)s; - (void)dst; - -#ifdef PICO_SUPPORT_IPV6 - - /* Check if socket is connected: destination address MUST match the - * current connected endpoint - */ - if ((s->state & PICO_SOCKET_STATE_CONNECTED)) { - src6 = &s->local_addr.ip6; - if (memcmp(&s->remote_addr, dst, PICO_SIZE_IP6)) { - pico_err = PICO_ERR_EADDRNOTAVAIL; - return NULL; - } - } else { - src6 = pico_ipv6_source_find(dst); - if (!src6) { - pico_err = PICO_ERR_EHOSTUNREACH; - return NULL; - } - - if (!pico_ipv6_is_unspecified(src6->addr)) - s->local_addr.ip6 = *src6; - } - -#else - pico_err = PICO_ERR_EPROTONOSUPPORT; -#endif - return src6; -} - - -static int pico_socket_sendto_dest_check(struct pico_socket *s, void *dst, uint16_t port) -{ - - /* For the sendto call to be valid, - * dst and remote_port should be always populated. - */ - if (!dst || !port) { - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } - - /* When coming from pico_socket_send (or _write), - * the destination is automatically assigned to the currently connected endpoint. - * This check will ensure that there is no mismatch when sendto() is called directly - * on a connected socket - */ - if ((s->state & PICO_SOCKET_STATE_CONNECTED) != 0) { - if (port != s->remote_port) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - return 0; -} - -static int pico_socket_sendto_initial_checks(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port) -{ - if (len < 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (buf == NULL || s == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return pico_socket_sendto_dest_check(s, dst, remote_port); -} - -static void *pico_socket_sendto_get_src(struct pico_socket *s, void *dst) -{ - void *src = NULL; - if (is_sock_ipv4(s)) - src = pico_socket_sendto_get_ip4_src(s, (struct pico_ip4 *)dst); - - if (is_sock_ipv6(s)) - src = pico_socket_sendto_get_ip6_src(s, (struct pico_ip6 *)dst); - - return src; -} - -static struct pico_remote_endpoint *pico_socket_sendto_destination_ipv4(struct pico_socket *s, struct pico_ip4 *dst, uint16_t port) -{ - struct pico_remote_endpoint *ep = NULL; - (void)s; - ep = PICO_ZALLOC(sizeof(struct pico_remote_endpoint)); - if (!ep) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - ep->remote_addr.ip4.addr = ((struct pico_ip4 *)dst)->addr; - ep->remote_port = port; - return ep; -} - -static void pico_endpoint_free(struct pico_remote_endpoint *ep) -{ - if (ep) - PICO_FREE(ep); -} - -static struct pico_remote_endpoint *pico_socket_sendto_destination_ipv6(struct pico_socket *s, struct pico_ip6 *dst, uint16_t port) -{ - struct pico_remote_endpoint *ep = NULL; - (void)s; - (void)dst; - (void)port; -#ifdef PICO_SUPPORT_IPV6 - ep = PICO_ZALLOC(sizeof(struct pico_remote_endpoint)); - if (!ep) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - memcpy(&ep->remote_addr.ip6, dst, sizeof(struct pico_ip6)); - ep->remote_port = port; -#endif - return ep; -} - - -static struct pico_remote_endpoint *pico_socket_sendto_destination(struct pico_socket *s, void *dst, uint16_t port) -{ - struct pico_remote_endpoint *ep = NULL; - (void)pico_socket_sendto_destination_ipv6; - /* socket remote info could change in a consecutive call, make persistent */ -# ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) { -# ifdef PICO_SUPPORT_IPV6 - if (is_sock_ipv6(s)) - ep = pico_socket_sendto_destination_ipv6(s, (struct pico_ip6 *)dst, port); - -# endif -# ifdef PICO_SUPPORT_IPV4 - if (is_sock_ipv4(s)) - ep = pico_socket_sendto_destination_ipv4(s, (struct pico_ip4 *)dst, port); - -# endif - } - -# endif - return ep; -} - -static int32_t pico_socket_sendto_set_localport(struct pico_socket *s) -{ - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - s->local_port = pico_socket_high_port(s->proto->proto_number); - if (s->local_port == 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0); - } - - return s->local_port; -} - -static int pico_socket_sendto_transport_offset(struct pico_socket *s) -{ - int header_offset = -1; - #ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP) - header_offset = pico_tcp_overhead(s); - - #endif - - #ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) - header_offset = sizeof(struct pico_udp_hdr); - - #endif - return header_offset; -} - - -static struct pico_remote_endpoint *pico_socket_set_info(struct pico_remote_endpoint *ep) -{ - struct pico_remote_endpoint *info; - info = PICO_ZALLOC(sizeof(struct pico_remote_endpoint)); - if (!info) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - memcpy(info, ep, sizeof(struct pico_remote_endpoint)); - return info; -} - -static void pico_xmit_frame_set_nofrag(struct pico_frame *f) -{ -#ifdef PICO_SUPPORT_IPV4FRAG - f->frag = PICO_IPV4_DONTFRAG; -#else - (void)f; -#endif -} - -static int pico_socket_final_xmit(struct pico_socket *s, struct pico_frame *f) -{ - if (s->proto->push(s->proto, f) > 0) { - return f->payload_len; - } else { - pico_frame_discard(f); - return 0; - } -} - -static int pico_socket_xmit_one(struct pico_socket *s, const void *buf, const int len, void *src, - struct pico_remote_endpoint *ep, struct pico_msginfo *msginfo) -{ - struct pico_frame *f; - uint16_t hdr_offset = (uint16_t)pico_socket_sendto_transport_offset(s); - int ret = 0; - (void)src; - - f = pico_socket_frame_alloc(s, (uint16_t)(len + hdr_offset)); - if (!f) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - f->payload += hdr_offset; - f->payload_len = (uint16_t)(len); - f->sock = s; - transport_flags_update(f, s); - pico_xmit_frame_set_nofrag(f); - if (ep && !f->info) { - f->info = pico_socket_set_info(ep); - if (!f->info) { - pico_frame_discard(f); - return -1; - } - } - - if (msginfo) { - f->send_ttl = (uint8_t)msginfo->ttl; - f->send_tos = (uint8_t)msginfo->tos; - f->dev = msginfo->dev; - } -#ifdef PICO_SUPPORT_IPV6 - if(IS_SOCK_IPV6(s) && ep && pico_ipv6_is_multicast(&ep->remote_addr.ip6.addr[0])) { - f->dev = pico_ipv6_link_find(src); - if(!f->dev) { - return -1; - } - } -#endif - memcpy(f->payload, (const uint8_t *)buf, f->payload_len); - /* dbg("Pushing segment, hdr len: %d, payload_len: %d\n", header_offset, f->payload_len); */ - ret = pico_socket_final_xmit(s, f); - return ret; -} - -static int pico_socket_xmit_avail_space(struct pico_socket *s); - -#ifdef PICO_SUPPORT_IPV4FRAG -static void pico_socket_xmit_first_fragment_setup(struct pico_frame *f, int space, int hdr_offset) -{ - frag_dbg("FRAG: first fragmented frame %p | len = %u offset = 0\n", f, f->payload_len); - /* transport header length field contains total length + header length */ - f->transport_len = (uint16_t)(space); - f->frag = PICO_IPV4_MOREFRAG; - f->payload += hdr_offset; -} - -static void pico_socket_xmit_next_fragment_setup(struct pico_frame *f, int hdr_offset, int total_payload_written, int len) -{ - /* no transport header in fragmented IP */ - f->payload = f->transport_hdr; - /* set offset in octets */ - f->frag = (uint16_t)((total_payload_written + (uint16_t)hdr_offset) >> 3u); /* first fragment had a header offset */ - if (total_payload_written + f->payload_len < len) { - frag_dbg("FRAG: intermediate fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag)); - f->frag |= PICO_IPV4_MOREFRAG; - } else { - frag_dbg("FRAG: last fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag)); - f->frag &= PICO_IPV4_FRAG_MASK; - } -} -#endif - -/* Implies ep discarding! */ -static int pico_socket_xmit_fragments(struct pico_socket *s, const void *buf, const int len, - void *src, struct pico_remote_endpoint *ep, struct pico_msginfo *msginfo) -{ - int space = pico_socket_xmit_avail_space(s); - int hdr_offset = pico_socket_sendto_transport_offset(s); - int total_payload_written = 0; - int retval = 0; - struct pico_frame *f = NULL; - - if (space > len) { - retval = pico_socket_xmit_one(s, buf, len, src, ep, msginfo); - pico_endpoint_free(ep); - return retval; - } - -#ifdef PICO_SUPPORT_IPV6 - /* Can't fragment IPv6 */ - if (is_sock_ipv6(s)) { - retval = pico_socket_xmit_one(s, buf, space, src, ep, msginfo); - pico_endpoint_free(ep); - return retval; - } - -#endif - -#ifdef PICO_SUPPORT_IPV4FRAG - while(total_payload_written < len) { - /* Always allocate the max space available: space + offset */ - if (len < space) - space = len; - - if (space > len - total_payload_written) /* update space for last fragment */ - space = len - total_payload_written; - - f = pico_socket_frame_alloc(s, (uint16_t)(space + hdr_offset)); - if (!f) { - pico_err = PICO_ERR_ENOMEM; - pico_endpoint_free(ep); - return -1; - } - - f->sock = s; - if (ep) { - f->info = pico_socket_set_info(ep); - if (!f->info) { - pico_frame_discard(f); - pico_endpoint_free(ep); - return -1; - } - } - - f->payload_len = (uint16_t) space; - if (total_payload_written == 0) { - /* First fragment: no payload written yet! */ - pico_socket_xmit_first_fragment_setup(f, space, hdr_offset); - space += hdr_offset; /* only first fragments contains transport header */ - hdr_offset = 0; - } else { - /* Next fragment */ - pico_socket_xmit_next_fragment_setup(f, pico_socket_sendto_transport_offset(s), total_payload_written, len); - } - - memcpy(f->payload, (const uint8_t *)buf + total_payload_written, f->payload_len); - transport_flags_update(f, s); - if (s->proto->push(s->proto, f) > 0) { - total_payload_written += f->payload_len; - } else { - pico_frame_discard(f); - break; - } - } /* while() */ - pico_endpoint_free(ep); - return total_payload_written; - -#else - /* Careful with that axe, Eugene! - * - * cropping down datagrams to the MTU value. - */ - (void) f; - (void) hdr_offset; - (void) total_payload_written; - retval = pico_socket_xmit_one(s, buf, space, src, ep, msginfo); - pico_endpoint_free(ep); - return retval; - -#endif -} - -static void get_sock_dev(struct pico_socket *s) -{ - if (0) {} - -#ifdef PICO_SUPPORT_IPV6 - else if (is_sock_ipv6(s)) - s->dev = pico_ipv6_source_dev_find(&s->remote_addr.ip6); -#endif -#ifdef PICO_SUPPORT_IPV4 - else if (is_sock_ipv4(s)) - s->dev = pico_ipv4_source_dev_find(&s->remote_addr.ip4); -#endif - -} - - -static uint32_t pico_socket_adapt_mss_to_proto(struct pico_socket *s, uint32_t mss) -{ -#ifdef PICO_SUPPORT_IPV6 - if (is_sock_ipv6(s)) - mss -= PICO_SIZE_IP6HDR; - else -#endif - mss -= PICO_SIZE_IP4HDR; - return mss; -} - -uint32_t pico_socket_get_mss(struct pico_socket *s) -{ - uint32_t mss = PICO_MIN_MSS; - if (!s) - return mss; - - if (!s->dev) - get_sock_dev(s); - - if (!s->dev) { - mss = PICO_MIN_MSS; - } else { - mss = s->dev->mtu; - } - - return pico_socket_adapt_mss_to_proto(s, mss); -} - - -static int pico_socket_xmit_avail_space(struct pico_socket *s) -{ - int transport_len; - int header_offset; - -#ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP) { - transport_len = (uint16_t)pico_tcp_get_socket_mss(s); - } else -#endif - transport_len = (uint16_t)pico_socket_get_mss(s); - header_offset = pico_socket_sendto_transport_offset(s); - if (header_offset < 0) { - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - } - - transport_len -= pico_socket_sendto_transport_offset(s); - return transport_len; -} - - -static int pico_socket_xmit(struct pico_socket *s, const void *buf, const int len, void *src, - struct pico_remote_endpoint *ep, struct pico_msginfo *msginfo) -{ - int space = pico_socket_xmit_avail_space(s); - int total_payload_written = 0; - - if (space < 0) { - pico_err = PICO_ERR_EPROTONOSUPPORT; - pico_endpoint_free(ep); - return -1; - } - - if ((PROTO(s) == PICO_PROTO_UDP) && (len > space)) { - total_payload_written = pico_socket_xmit_fragments(s, buf, len, src, ep, msginfo); - /* Implies ep discarding */ - return total_payload_written; - } - - while (total_payload_written < len) { - int w, chunk_len = len - total_payload_written; - if (chunk_len > space) - chunk_len = space; - - w = pico_socket_xmit_one(s, (const void *)((const uint8_t *)buf + total_payload_written), chunk_len, src, ep, msginfo); - if (w <= 0) { - break; - } - - total_payload_written += w; - if (PROTO(s) == PICO_PROTO_UDP) { - /* Break after the first datagram sent with at most MTU bytes. */ - break; - } - } - pico_endpoint_free(ep); - return total_payload_written; -} - -static void pico_socket_sendto_set_dport(struct pico_socket *s, uint16_t port) -{ - if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) { - s->remote_port = port; - } -} - - -int MOCKABLE pico_socket_sendto_extended(struct pico_socket *s, const void *buf, const int len, - void *dst, uint16_t remote_port, struct pico_msginfo *msginfo) -{ - struct pico_remote_endpoint *remote_endpoint = NULL; - void *src = NULL; - - if(len == 0) - return 0; - - if (pico_socket_sendto_initial_checks(s, buf, len, dst, remote_port) < 0) - return -1; - - - src = pico_socket_sendto_get_src(s, dst); - if (!src) { -#ifdef PICO_SUPPORT_IPV6 - if((s->net->proto_number == PICO_PROTO_IPV6) - && msginfo && msginfo->dev - && pico_ipv6_is_multicast(((struct pico_ip6 *)dst)->addr)) - { - src = &(pico_ipv6_linklocal_get(msginfo->dev)->address); - } - else -#endif - return -1; - } - - remote_endpoint = pico_socket_sendto_destination(s, dst, remote_port); - if (pico_socket_sendto_set_localport(s) < 0) { - pico_endpoint_free(remote_endpoint); - return -1; - } - - pico_socket_sendto_set_dport(s, remote_port); - return pico_socket_xmit(s, buf, len, src, remote_endpoint, msginfo); /* Implies discarding the endpoint */ -} - -int MOCKABLE pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port) -{ - return pico_socket_sendto_extended(s, buf, len, dst, remote_port, NULL); -} - -int pico_socket_send(struct pico_socket *s, const void *buf, int len) -{ - if (!s || buf == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - /* See task #178 */ - if (pico_check_socket(s) != 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) { - pico_err = PICO_ERR_ENOTCONN; - return -1; - } - - return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port); -} - -int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, void *orig, - uint16_t *remote_port, struct pico_msginfo *msginfo) -{ - if (!s || buf == NULL) { /* / || orig == NULL || remote_port == NULL) { */ - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - if (pico_check_socket(s) != 0) { - pico_err = PICO_ERR_EINVAL; - /* See task #178 */ - return -1; - } - } - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } - -#ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) { - /* make sure cast to uint16_t doesn't give unexpected results */ - if(len > 0xFFFF) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return pico_udp_recv(s, buf, (uint16_t)len, orig, remote_port, msginfo); - } - -#endif -#ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP) { - /* check if in shutdown state and if tcpq_in empty */ - if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) { - pico_err = PICO_ERR_ESHUTDOWN; - return -1; - } else { - /* dbg("socket tcp recv\n"); */ - return (int)pico_tcp_read(s, buf, (uint32_t)len); - } - } - -#endif - /* dbg("socket return 0\n"); */ - return 0; -} - -int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, - uint16_t *remote_port) -{ - return pico_socket_recvfrom_extended(s, buf, len, orig, remote_port, NULL); - -} - -int pico_socket_recv(struct pico_socket *s, void *buf, int len) -{ - return pico_socket_recvfrom(s, buf, len, NULL, NULL); -} - - -int pico_socket_getname(struct pico_socket *s, void *local_addr, uint16_t *port, uint16_t *proto) -{ - - if (!s || !local_addr || !port || !proto) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (is_sock_ipv4(s)) { - #ifdef PICO_SUPPORT_IPV4 - struct pico_ip4 *ip = (struct pico_ip4 *)local_addr; - ip->addr = s->local_addr.ip4.addr; - *proto = PICO_PROTO_IPV4; - #endif - } else if (is_sock_ipv6(s)) { - #ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 *ip = (struct pico_ip6 *)local_addr; - memcpy(ip->addr, s->local_addr.ip6.addr, PICO_SIZE_IP6); - *proto = PICO_PROTO_IPV6; - #endif - } else { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - *port = s->local_port; - return 0; -} - -int pico_socket_getpeername(struct pico_socket *s, void *remote_addr, uint16_t *port, uint16_t *proto) -{ - if (!s || !remote_addr || !port || !proto) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) { - pico_err = PICO_ERR_ENOTCONN; - return -1; - } - - if (is_sock_ipv4(s)) { - #ifdef PICO_SUPPORT_IPV4 - struct pico_ip4 *ip = (struct pico_ip4 *)remote_addr; - ip->addr = s->remote_addr.ip4.addr; - *proto = PICO_PROTO_IPV4; - #endif - } else if (is_sock_ipv6(s)) { - #ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 *ip = (struct pico_ip6 *)remote_addr; - memcpy(ip->addr, s->remote_addr.ip6.addr, PICO_SIZE_IP6); - *proto = PICO_PROTO_IPV6; - #endif - } else { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - *port = s->remote_port; - return 0; - -} - -int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port) -{ - if (!s || !local_addr || !port) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (is_sock_ipv4(s)) { - #ifdef PICO_SUPPORT_IPV4 - struct pico_ip4 *ip = (struct pico_ip4 *)local_addr; - if (ip->addr != PICO_IPV4_INADDR_ANY) { - if (!pico_ipv4_link_find(local_addr)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - #endif - } else if (is_sock_ipv6(s)) { - #ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 *ip = (struct pico_ip6 *)local_addr; - if (!pico_ipv6_is_unspecified(ip->addr)) { - if (!pico_ipv6_link_find(local_addr)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - #endif - } else { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* When given port = 0, get a random high port to bind to. */ - if (*port == 0) { - *port = pico_socket_high_port(PROTO(s)); - if (*port == 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if (pico_is_port_free(PROTO(s), *port, local_addr, s->net) == 0) { - pico_err = PICO_ERR_EADDRINUSE; - return -1; - } - - s->local_port = *port; - - if (is_sock_ipv4(s)) { - #ifdef PICO_SUPPORT_IPV4 - struct pico_ip4 *ip = (struct pico_ip4 *)local_addr; - s->local_addr.ip4 = *ip; - #endif - } else if (is_sock_ipv6(s)) { - #ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 *ip = (struct pico_ip6 *)local_addr; - s->local_addr.ip6 = *ip; - #endif - } else { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0); -} - - -int pico_socket_connect(struct pico_socket *s, const void *remote_addr, uint16_t remote_port) -{ - int ret = -1; - pico_err = PICO_ERR_EPROTONOSUPPORT; - if (!s || remote_addr == NULL || remote_port == 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - s->remote_port = remote_port; - - if (s->local_port == 0) { - s->local_port = pico_socket_high_port(PROTO(s)); - if (!s->local_port) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if (is_sock_ipv4(s)) { - #ifdef PICO_SUPPORT_IPV4 - struct pico_ip4 *local = NULL; - const struct pico_ip4 *ip = (const struct pico_ip4 *)remote_addr; - s->remote_addr.ip4 = *ip; - local = pico_ipv4_source_find(ip); - if (local) { - get_sock_dev(s); - s->local_addr.ip4 = *local; - } else { - pico_err = PICO_ERR_EHOSTUNREACH; - return -1; - } - - #endif - } else if (is_sock_ipv6(s)) { - #ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 *local = NULL; - const struct pico_ip6 *ip = (const struct pico_ip6 *)remote_addr; - s->remote_addr.ip6 = *ip; - local = pico_ipv6_source_find(ip); - if (local) { - get_sock_dev(s); - s->local_addr.ip6 = *local; - } else { - pico_err = PICO_ERR_EHOSTUNREACH; - return -1; - } - - #endif - } else { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0); - -#ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) { - pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED, 0, 0); - pico_err = PICO_ERR_NOERR; - ret = 0; - } - -#endif - -#ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP) { - if (pico_tcp_initconn(s) == 0) { - pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, PICO_SOCKET_STATE_CLOSED, 0); - pico_err = PICO_ERR_NOERR; - ret = 0; - } else { - pico_err = PICO_ERR_EHOSTUNREACH; - } - } - -#endif - - return ret; -} - - -#ifdef PICO_SUPPORT_TCP - -int pico_socket_listen(struct pico_socket *s, int backlog) -{ - if (!s || backlog < 1) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - /* See task #178 */ - if (pico_check_socket(s) != 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if (PROTO(s) == PICO_PROTO_UDP) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - pico_err = PICO_ERR_EISCONN; - return -1; - } - - if (PROTO(s) == PICO_PROTO_TCP) - pico_socket_alter_state(s, PICO_SOCKET_STATE_TCP_SYN_SENT, 0, PICO_SOCKET_STATE_TCP_LISTEN); - - s->max_backlog = (uint16_t)backlog; - - return 0; -} - -struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port) -{ - if (!s || !orig || !port) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - pico_err = PICO_ERR_EINVAL; - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - return NULL; - } - - if (PROTO(s) == PICO_PROTO_UDP) { - return NULL; - } - - if (TCPSTATE(s) == PICO_SOCKET_STATE_TCP_LISTEN) { - struct pico_sockport *sp = pico_get_sockport(PICO_PROTO_TCP, s->local_port); - struct pico_socket *found; - uint32_t socklen = sizeof(struct pico_ip4); - /* If at this point no incoming connection socket is found, - * the accept call is valid, but no connection is established yet. - */ - pico_err = PICO_ERR_EAGAIN; - if (sp) { - struct pico_tree_node *index; - /* RB_FOREACH(found, socket_tree, &sp->socks) { */ - pico_tree_foreach(index, &sp->socks){ - found = index->keyValue; - if ((s == found->parent) && ((found->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) { - found->parent = NULL; - pico_err = PICO_ERR_NOERR; - #ifdef PICO_SUPPORT_IPV6 - if (is_sock_ipv6(s)) - socklen = sizeof(struct pico_ip6); - - #endif - memcpy(orig, &found->remote_addr, socklen); - *port = found->remote_port; - s->number_of_pending_conn--; - return found; - } - } - } - } - - return NULL; -} - -#else - -int pico_socket_listen(struct pico_socket *s, int backlog) -{ - IGNORE_PARAMETER(s); - IGNORE_PARAMETER(backlog); - pico_err = PICO_ERR_EINVAL; - return -1; -} - -struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *local_port) -{ - IGNORE_PARAMETER(s); - IGNORE_PARAMETER(orig); - IGNORE_PARAMETER(local_port); - pico_err = PICO_ERR_EINVAL; - return NULL; -} - -#endif - - -int pico_socket_setoption(struct pico_socket *s, int option, void *value) -{ - - if (s == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - - if (PROTO(s) == PICO_PROTO_TCP) - return pico_setsockopt_tcp(s, option, value); - - if (PROTO(s) == PICO_PROTO_UDP) - return pico_setsockopt_udp(s, option, value); - - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - - -int pico_socket_getoption(struct pico_socket *s, int option, void *value) -{ - if (s == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - - if (PROTO(s) == PICO_PROTO_TCP) - return pico_getsockopt_tcp(s, option, value); - - if (PROTO(s) == PICO_PROTO_UDP) - return pico_getsockopt_udp(s, option, value); - - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - - -int pico_socket_shutdown(struct pico_socket *s, int mode) -{ - if (!s) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* Check if the socket has already been closed */ - if (s->state & PICO_SOCKET_STATE_CLOSED) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - /* unbound sockets can be deleted immediately */ - if (!(s->state & PICO_SOCKET_STATE_BOUND)) - { - socket_garbage_collect((pico_time)10, s); - return 0; - } - -#ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) { - if ((mode & PICO_SHUT_RDWR) == PICO_SHUT_RDWR) - pico_socket_alter_state(s, PICO_SOCKET_STATE_CLOSED, PICO_SOCKET_STATE_CLOSING | PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED, 0); - else if (mode & PICO_SHUT_RD) - pico_socket_alter_state(s, 0, PICO_SOCKET_STATE_BOUND, 0); - } - -#endif -#ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP) { - if ((mode & PICO_SHUT_RDWR) == PICO_SHUT_RDWR) - { - pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL | PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0); - pico_tcp_notify_closing(s); - } - else if (mode & PICO_SHUT_WR) { - pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL, 0, 0); - pico_tcp_notify_closing(s); - } else if (mode & PICO_SHUT_RD) - pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0); - - } - -#endif - return 0; -} - -int MOCKABLE pico_socket_close(struct pico_socket *s) -{ - if (!s) - return -1; - -#ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP) { - if (pico_tcp_check_listen_close(s) == 0) - return 0; - } - -#endif - return pico_socket_shutdown(s, PICO_SHUT_RDWR); -} - -#ifdef PICO_SUPPORT_CRC -static inline int pico_transport_crc_check(struct pico_frame *f) -{ - struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_udp_hdr *udp_hdr = NULL; - uint16_t checksum_invalid = 1; - - switch (net_hdr->proto) - { -#ifdef PICO_SUPPORT_TCP - case PICO_PROTO_TCP: - checksum_invalid = short_be(pico_tcp_checksum(f)); - /* dbg("TCP CRC validation == %u\n", checksum_invalid); */ - if (checksum_invalid) { - dbg("TCP CRC: validation failed!\n"); - pico_frame_discard(f); - return 0; - } - - break; -#endif /* PICO_SUPPORT_TCP */ - -#ifdef PICO_SUPPORT_UDP - case PICO_PROTO_UDP: - udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - if (short_be(udp_hdr->crc)) { -#ifdef PICO_SUPPORT_IPV4 - if (IS_IPV4(f)) - checksum_invalid = short_be(pico_udp_checksum_ipv4(f)); - -#endif -#ifdef PICO_SUPPORT_IPV6 - if (IS_IPV6(f)) - checksum_invalid = short_be(pico_udp_checksum_ipv6(f)); - -#endif - /* dbg("UDP CRC validation == %u\n", checksum_invalid); */ - if (checksum_invalid) { - /* dbg("UDP CRC: validation failed!\n"); */ - pico_frame_discard(f); - return 0; - } - } - - break; -#endif /* PICO_SUPPORT_UDP */ - - default: - /* Do nothing */ - break; - } - return 1; -} -#else -static inline int pico_transport_crc_check(struct pico_frame *f) -{ - IGNORE_PARAMETER(f); - return 1; -} -#endif /* PICO_SUPPORT_CRC */ - -int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_trans *hdr = (struct pico_trans *) f->transport_hdr; - int ret = 0; - - if (!hdr) { - pico_err = PICO_ERR_EFAULT; - return -1; - } - - ret = pico_transport_crc_check(f); - if (ret < 1) - return ret; - else - ret = 0; - - if ((hdr) && (pico_socket_deliver(self, f, hdr->dport) == 0)) - return ret; - - if (!IS_BCAST(f)) { - dbg("Socket not found... \n"); - pico_notify_socket_unreachable(f); - ret = -1; - pico_err = PICO_ERR_ENOENT; - } - - pico_frame_discard(f); - return ret; -} - -#define SL_LOOP_MIN 1 - -#ifdef PICO_SUPPORT_TCP -static int check_socket_sanity(struct pico_socket *s) -{ - - /* checking for pending connections */ - if(TCP_STATE(s) == PICO_SOCKET_STATE_TCP_SYN_RECV) { - if((PICO_TIME_MS() - s->timestamp) >= PICO_SOCKET_BOUND_TIMEOUT) - return -1; - } - return 0; -} -#endif - - -static int pico_sockets_loop_udp(int loop_score) -{ - -#ifdef PICO_SUPPORT_UDP - static struct pico_tree_node *index_udp; - struct pico_sockport *start; - struct pico_socket *s; - struct pico_frame *f; - - if (sp_udp == NULL) - { - index_udp = pico_tree_firstNode(UDPTable.root); - sp_udp = index_udp->keyValue; - } - - /* init start node */ - start = sp_udp; - - /* round-robin all transport protocols, break if traversed all protocols */ - while (loop_score > SL_LOOP_MIN && sp_udp != NULL) { - struct pico_tree_node *index; - - pico_tree_foreach(index, &sp_udp->socks){ - s = index->keyValue; - f = pico_dequeue(&s->q_out); - while (f && (loop_score > 0)) { - pico_proto_udp.push(&pico_proto_udp, f); - loop_score -= 1; - if (loop_score > 0) /* only dequeue if there is still loop_score, otherwise f might get lost */ - f = pico_dequeue(&s->q_out); - } - } - - index_udp = pico_tree_next(index_udp); - sp_udp = index_udp->keyValue; - - if (sp_udp == NULL) - { - index_udp = pico_tree_firstNode(UDPTable.root); - sp_udp = index_udp->keyValue; - } - - if (sp_udp == start) - break; - } -#endif - return loop_score; -} - -static int pico_sockets_loop_tcp(int loop_score) -{ -#ifdef PICO_SUPPORT_TCP - struct pico_sockport *start; - struct pico_socket *s; - static struct pico_tree_node *index_tcp; - if (sp_tcp == NULL) - { - index_tcp = pico_tree_firstNode(TCPTable.root); - sp_tcp = index_tcp->keyValue; - } - - /* init start node */ - start = sp_tcp; - - while (loop_score > SL_LOOP_MIN && sp_tcp != NULL) { - struct pico_tree_node *index = NULL, *safe_index = NULL; - pico_tree_foreach_safe(index, &sp_tcp->socks, safe_index){ - s = index->keyValue; - loop_score = pico_tcp_output(s, loop_score); - if ((s->ev_pending) && s->wakeup) { - s->wakeup(s->ev_pending, s); - if(!s->parent) - s->ev_pending = 0; - } - - if (loop_score <= 0) { - loop_score = 0; - break; - } - - if(check_socket_sanity(s) < 0) - { - pico_socket_del(s); - index_tcp = NULL; /* forcing the restart of loop */ - sp_tcp = NULL; - break; - } - } - - /* check if RB_FOREACH ended, if not, break to keep the cur sp_tcp */ - if (!index_tcp || (index && index->keyValue)) - break; - - index_tcp = pico_tree_next(index_tcp); - sp_tcp = index_tcp->keyValue; - - if (sp_tcp == NULL) - { - index_tcp = pico_tree_firstNode(TCPTable.root); - sp_tcp = index_tcp->keyValue; - } - - if (sp_tcp == start) - break; - } -#endif - return loop_score; - - -} - -int pico_sockets_loop(int loop_score) -{ - loop_score = pico_sockets_loop_udp(loop_score); - loop_score = pico_sockets_loop_tcp(loop_score); - return loop_score; -} - -int pico_count_sockets(uint8_t proto) -{ - struct pico_sockport *sp; - struct pico_tree_node *idx_sp, *idx_s; - int count = 0; - - if ((proto == 0) || (proto == PICO_PROTO_TCP)) { - pico_tree_foreach(idx_sp, &TCPTable) { - sp = idx_sp->keyValue; - if (sp) { - pico_tree_foreach(idx_s, &sp->socks) - count++; - } - } - } - - if ((proto == 0) || (proto == PICO_PROTO_UDP)) { - pico_tree_foreach(idx_sp, &UDPTable) { - sp = idx_sp->keyValue; - if (sp) { - pico_tree_foreach(idx_s, &sp->socks) - count++; - } - } - } - - return count; -} - - -struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, uint16_t len) -{ - struct pico_frame *f = NULL; - -#ifdef PICO_SUPPORT_IPV6 - if (is_sock_ipv6(s)) - f = pico_proto_ipv6.alloc(&pico_proto_ipv6, len); - -#endif - -#ifdef PICO_SUPPORT_IPV4 - if (is_sock_ipv4(s)) - f = pico_proto_ipv4.alloc(&pico_proto_ipv4, len); - -#endif - if (!f) { - pico_err = PICO_ERR_ENOMEM; - return f; - } - - f->payload = f->transport_hdr; - f->payload_len = len; - f->sock = s; - return f; -} - -static void pico_transport_error_set_picoerr(int code) -{ - /* dbg("SOCKET ERROR FROM ICMP NOTIFICATION. (icmp code= %d)\n\n", code); */ - switch(code) { - case PICO_ICMP_UNREACH_NET: - pico_err = PICO_ERR_ENETUNREACH; - break; - - case PICO_ICMP_UNREACH_HOST: - pico_err = PICO_ERR_EHOSTUNREACH; - break; - - case PICO_ICMP_UNREACH_PROTOCOL: - pico_err = PICO_ERR_ENOPROTOOPT; - break; - - case PICO_ICMP_UNREACH_PORT: - pico_err = PICO_ERR_ECONNREFUSED; - break; - - case PICO_ICMP_UNREACH_NET_UNKNOWN: - pico_err = PICO_ERR_ENETUNREACH; - break; - - case PICO_ICMP_UNREACH_HOST_UNKNOWN: - pico_err = PICO_ERR_EHOSTDOWN; - break; - - case PICO_ICMP_UNREACH_ISOLATED: - pico_err = PICO_ERR_ENONET; - break; - - case PICO_ICMP_UNREACH_NET_PROHIB: - case PICO_ICMP_UNREACH_HOST_PROHIB: - pico_err = PICO_ERR_EHOSTUNREACH; - break; - - default: - pico_err = PICO_ERR_EOPNOTSUPP; - } -} - -int pico_transport_error(struct pico_frame *f, uint8_t proto, int code) -{ - int ret = -1; - struct pico_trans *trans = (struct pico_trans*) f->transport_hdr; - struct pico_sockport *port = NULL; - struct pico_socket *s = NULL; - switch (proto) { - - -#ifdef PICO_SUPPORT_UDP - case PICO_PROTO_UDP: - port = pico_get_sockport(proto, trans->sport); - break; -#endif - -#ifdef PICO_SUPPORT_TCP - case PICO_PROTO_TCP: - port = pico_get_sockport(proto, trans->sport); - break; -#endif - - default: - /* Protocol not available */ - ret = -1; - } - if (port) { - struct pico_tree_node *index; - ret = 0; - - pico_tree_foreach(index, &port->socks) { - s = index->keyValue; - if (trans->dport == s->remote_port) { - if (s->wakeup) { - pico_transport_error_set_picoerr(code); - s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; - s->wakeup(PICO_SOCK_EV_ERR, s); - } - - break; - } - } - } - - pico_frame_discard(f); - return ret; -} -#endif -#endif diff --git a/ext/picotcp/stack/pico_socket_multicast.c b/ext/picotcp/stack/pico_socket_multicast.c deleted file mode 100644 index 132881c..0000000 --- a/ext/picotcp/stack/pico_socket_multicast.c +++ /dev/null @@ -1,1340 +0,0 @@ -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_socket.h" -#include "pico_socket_multicast.h" -#include "pico_tree.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_udp.h" - -#ifdef PICO_SUPPORT_MCAST -# define so_mcast_dbg(...) do { }while(0) /* ip_mcast_dbg in pico_ipv4.c */ -/* #define so_mcast_dbg dbg */ - -/* socket -* | -* MCASTListen -* | | | -* ------------ | ------------ -* | | | -* MCASTSources MCASTSources MCASTSources -* | | | | | | | | | | | | -* S S S S S S S S S S S S -* -* MCASTListen: RBTree(mcast_link, mcast_group) -* MCASTSources: RBTree(source) -*/ -struct pico_mcast_listen -{ - uint8_t filter_mode; - union pico_address mcast_link; - union pico_address mcast_group; - struct pico_tree MCASTSources; - struct pico_tree MCASTSources_ipv6; - uint16_t proto; -}; -//Parameters -struct pico_mcast -{ - struct pico_socket *s; - struct pico_ip_mreq *mreq; - struct pico_ip_mreq_source *mreq_s; - union pico_address *address; - union pico_link *mcast_link; - struct pico_mcast_listen *listen; -}; -static int mcast_listen_link_cmp(struct pico_mcast_listen *a, struct pico_mcast_listen *b) -{ - - if (a->proto < b->proto) - return -1; - - if (a->proto > b->proto) - return 1; - - return pico_address_compare(&a->mcast_link, &b->mcast_link, a->proto); -} - -static int mcast_listen_grp_cmp(struct pico_mcast_listen *a, struct pico_mcast_listen *b) -{ - if (a->mcast_group.ip4.addr < b->mcast_group.ip4.addr) - return -1; - - if (a->mcast_group.ip4.addr > b->mcast_group.ip4.addr) - return 1; - - return mcast_listen_link_cmp(a, b); -} -#ifdef PICO_SUPPORT_IPV6 -static int mcast_listen_grp_cmp_ipv6(struct pico_mcast_listen *a, struct pico_mcast_listen *b) -{ - int tmp = memcmp(&a->mcast_group.ip6, &b->mcast_group.ip6, sizeof(struct pico_ip6)); - if(!tmp) - return mcast_listen_link_cmp(a, b); - return tmp; -} -#endif - -static int mcast_listen_cmp(void *ka, void *kb) -{ - struct pico_mcast_listen *a = ka, *b = kb; - if (a->proto < b->proto) - return -1; - - if (a->proto > b->proto) - return 1; - - return mcast_listen_grp_cmp(a, b); -} -#ifdef PICO_SUPPORT_IPV6 -static int mcast_listen_cmp_ipv6(void *ka, void *kb) -{ - struct pico_mcast_listen *a = ka, *b = kb; - if (a->proto < b->proto) - return -1; - - if (a->proto > b->proto) - return 1; - - return mcast_listen_grp_cmp_ipv6(a, b); -} -#endif -static int mcast_sources_cmp(void *ka, void *kb) -{ - union pico_address *a = ka, *b = kb; - if (a->ip4.addr < b->ip4.addr) - return -1; - - if (a->ip4.addr > b->ip4.addr) - return 1; - - return 0; -} -#ifdef PICO_SUPPORT_IPV6 -static int mcast_sources_cmp_ipv6(void *ka, void *kb) -{ - union pico_address *a = ka, *b = kb; - return memcmp(&a->ip6, &b->ip6, sizeof(struct pico_ip6)); -} -#endif -static int mcast_socket_cmp(void *ka, void *kb) -{ - struct pico_socket *a = ka, *b = kb; - if (a < b) - return -1; - - if (a > b) - return 1; - - return 0; -} - -/* gather all multicast sockets to hasten filter aggregation */ -PICO_TREE_DECLARE(MCASTSockets, mcast_socket_cmp); - -static int mcast_filter_cmp(void *ka, void *kb) -{ - union pico_address *a = ka, *b = kb; - if (a->ip4.addr < b->ip4.addr) - return -1; - - if (a->ip4.addr > b->ip4.addr) - return 1; - - return 0; -} -/* gather sources to be filtered */ -PICO_TREE_DECLARE(MCASTFilter, mcast_filter_cmp); - -static int mcast_filter_cmp_ipv6(void *ka, void *kb) -{ - union pico_address *a = ka, *b = kb; - return memcmp(&a->ip6, &b->ip6, sizeof(struct pico_ip6)); -} -/* gather sources to be filtered */ -PICO_TREE_DECLARE(MCASTFilter_ipv6, mcast_filter_cmp_ipv6); - -inline static struct pico_tree *mcast_get_src_tree(struct pico_socket *s,struct pico_mcast *mcast) { - if( IS_SOCK_IPV4(s)) { - mcast->listen->MCASTSources.compare = mcast_sources_cmp; - return &mcast->listen->MCASTSources; - } -#ifdef PICO_SUPPORT_IPV6 - else if( IS_SOCK_IPV6(s) ) { - mcast->listen->MCASTSources_ipv6.compare = mcast_sources_cmp_ipv6; - return &mcast->listen->MCASTSources_ipv6; - } -#endif - return NULL; -} -inline static struct pico_tree *mcast_get_listen_tree(struct pico_socket *s) { - if( IS_SOCK_IPV4(s)) - return s->MCASTListen; -#ifdef PICO_SUPPORT_IPV6 - else if( IS_SOCK_IPV6(s) ) - return s->MCASTListen_ipv6; -#endif - return NULL; -} -inline static void mcast_set_listen_tree_p_null(struct pico_socket *s) { - if( IS_SOCK_IPV4(s)) - s->MCASTListen = NULL; -#ifdef PICO_SUPPORT_IPV6 - else if( IS_SOCK_IPV6(s) ) - s->MCASTListen_ipv6 = NULL; -#endif -} -static struct pico_mcast_listen *listen_find(struct pico_socket *s, union pico_address *lnk, union pico_address *grp) -{ - struct pico_mcast_listen ltest = { - 0 - }; - ltest.mcast_link = *lnk; - ltest.mcast_group = *grp; - - if(IS_SOCK_IPV4(s)) - return pico_tree_findKey(s->MCASTListen, <est); -#ifdef PICO_SUPPORT_IPV6 - else if(IS_SOCK_IPV6(s) ) { - ltest.proto = PICO_PROTO_IPV6; - return pico_tree_findKey(s->MCASTListen_ipv6, <est); - } -#endif - return NULL; -} -static union pico_address *pico_mcast_get_link_address(struct pico_socket *s, union pico_link *mcast_link) { - if( IS_SOCK_IPV4(s) ) - return (union pico_address *) &mcast_link->ipv4.address; -#ifdef PICO_SUPPORT_IPV6 - if( IS_SOCK_IPV6(s)) - return (union pico_address *) &mcast_link->ipv6.address; -#endif - return NULL; -} -static uint8_t pico_mcast_filter_excl_excl(struct pico_mcast_listen *listen) -{ - /* filter = intersection of EXCLUDEs */ - /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */ - /* remove from the interface EXCLUDE filter any source not in the socket EXCLUDE filter */ - struct pico_tree_node *index = NULL, *_tmp = NULL; - union pico_address *source = NULL; - if(!pico_tree_empty(&MCASTFilter)) { - pico_tree_foreach_safe(index, &MCASTFilter, _tmp) - { - source = pico_tree_findKey(&listen->MCASTSources, index->keyValue); - if (!source) - pico_tree_delete(&MCASTFilter, index->keyValue); - } - } -#ifdef PICO_SUPPORT_IPV6 - if(!pico_tree_empty(&MCASTFilter_ipv6)) { - pico_tree_foreach_safe(index, &MCASTFilter_ipv6, _tmp) - { - source = pico_tree_findKey(&listen->MCASTSources_ipv6, index->keyValue); - if (!source) - pico_tree_delete(&MCASTFilter_ipv6, index->keyValue); - } - } -#endif - return PICO_IP_MULTICAST_EXCLUDE; -} - -static uint8_t pico_mcast_filter_excl_incl(struct pico_mcast_listen *listen) -{ - /* filter = EXCLUDE - INCLUDE */ - /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */ - /* remove from the interface EXCLUDE filter any source in the socket INCLUDE filter */ - struct pico_tree_node *index = NULL, *_tmp = NULL; - union pico_address *source = NULL; - if(!pico_tree_empty(&listen->MCASTSources)) { - pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp) - { - source = pico_tree_findKey(&MCASTFilter, index->keyValue); - if (source) - pico_tree_delete(&MCASTFilter, source); - } - } -#ifdef PICO_SUPPORT_IPV6 - if(!pico_tree_empty(&listen->MCASTSources_ipv6)) { - pico_tree_foreach_safe(index, &listen->MCASTSources_ipv6, _tmp) - { - source = pico_tree_findKey(&MCASTFilter_ipv6, index->keyValue); - if (source) - pico_tree_delete(&MCASTFilter_ipv6, source); - } - } -#endif - return PICO_IP_MULTICAST_EXCLUDE; -} - -static uint8_t pico_mcast_filter_incl_excl(struct pico_mcast_listen *listen) -{ - /* filter = EXCLUDE - INCLUDE */ - /* delete from the interface INCLUDE filter any source NOT in the socket EXCLUDE filter */ - struct pico_tree_node *index = NULL, *_tmp = NULL; - union pico_address *source = NULL; - if(!pico_tree_empty(&listen->MCASTSources)) { - pico_tree_foreach_safe(index, &MCASTFilter, _tmp) - { - source = pico_tree_findKey(&listen->MCASTSources, index->keyValue); - if (!source) - pico_tree_delete(&MCASTFilter, index->keyValue); - } - } -#ifdef PICO_SUPPORT_IPV6 - if(!pico_tree_empty(&listen->MCASTSources_ipv6)) { - pico_tree_foreach_safe(index, &MCASTFilter_ipv6, _tmp) - { - source = pico_tree_findKey(&listen->MCASTSources_ipv6, index->keyValue); - if (!source) - pico_tree_delete(&MCASTFilter_ipv6, index->keyValue); - } - } -#endif - /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */ - - /* add to the interface EXCLUDE filter any socket source NOT in the former interface INCLUDE filter */ - if(!pico_tree_empty(&listen->MCASTSources)) { - pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp) - { - source = pico_tree_insert(&MCASTFilter, index->keyValue); - if (source) - pico_tree_delete(&MCASTFilter, source); - } - } -#ifdef PICO_SUPPORT_IPV6 - if(!pico_tree_empty(&listen->MCASTSources_ipv6)) { - pico_tree_foreach_safe(index, &listen->MCASTSources_ipv6, _tmp) - { - source = pico_tree_insert(&MCASTFilter_ipv6, index->keyValue); - if (source) - pico_tree_delete(&MCASTFilter_ipv6, source); - } - } -#endif - return PICO_IP_MULTICAST_EXCLUDE; -} - -static uint8_t pico_mcast_filter_incl_incl(struct pico_mcast_listen *listen) -{ - /* filter = summation of INCLUDEs */ - /* mode stays INCLUDE, add all sources to filter */ - struct pico_tree_node *index = NULL, *_tmp = NULL; - union pico_address *source = NULL; - - if( !pico_tree_empty(&listen->MCASTSources)) { - pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp) - { - source = index->keyValue; - pico_tree_insert(&MCASTFilter, source); - } - } -#ifdef PICO_SUPPORT_IPV6 - if( !pico_tree_empty(&listen->MCASTSources_ipv6)) { - pico_tree_foreach_safe(index, &listen->MCASTSources_ipv6, _tmp) - { - source = index->keyValue; - pico_tree_insert(&MCASTFilter_ipv6, source); - } - } -#endif - return PICO_IP_MULTICAST_INCLUDE; -} - -struct pico_mcast_filter_aggregation -{ - uint8_t (*call)(struct pico_mcast_listen *); -}; - -static const struct pico_mcast_filter_aggregation mcast_filter_aggr_call[2][2] = -{ - { - /* EXCL + EXCL */ {.call = pico_mcast_filter_excl_excl}, - /* EXCL + INCL */ {.call = pico_mcast_filter_excl_incl} - }, - - { - /* INCL + EXCL */ {.call = pico_mcast_filter_incl_excl}, - /* INCL + INCL */ {.call = pico_mcast_filter_incl_incl} - } -}; - -static int mcast_aggr_validate(uint8_t fm, struct pico_mcast_listen *l) -{ - if (!l) - return -1; - - if (fm > 1) - return -1; - - if (l->filter_mode > 1) - return -1; - - return 0; -} - - -/* MCASTFilter will be empty if no socket is listening on mcast_group on mcast_link anymore */ -static int pico_socket_aggregate_mcastfilters(union pico_address *mcast_link, union pico_address *mcast_group) -{ - uint8_t filter_mode = PICO_IP_MULTICAST_INCLUDE; - struct pico_mcast_listen *listen = NULL; - struct pico_socket *mcast_sock = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL; - - /* cleanup old filter */ - if(!pico_tree_empty(&MCASTFilter)) { - pico_tree_foreach_safe(index, &MCASTFilter, _tmp) - { - pico_tree_delete(&MCASTFilter, index->keyValue); - } - } -#ifdef PICO_SUPPORT_IPV6 - if(!pico_tree_empty(&MCASTFilter_ipv6)) { - pico_tree_foreach_safe(index, &MCASTFilter_ipv6, _tmp) - { - pico_tree_delete(&MCASTFilter_ipv6, index->keyValue); - } - } -#endif - /* construct new filter */ - pico_tree_foreach_safe(index, &MCASTSockets, _tmp) - { - mcast_sock = index->keyValue; - listen = listen_find(mcast_sock, mcast_link, mcast_group); - if (listen) { - if (mcast_aggr_validate(filter_mode, listen) < 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (mcast_filter_aggr_call[filter_mode][listen->filter_mode].call) { - filter_mode = mcast_filter_aggr_call[filter_mode][listen->filter_mode].call(listen); - if (filter_mode > 1) - return -1; - } - } - } - return filter_mode; -} - -static int pico_socket_mcast_filter_include(struct pico_mcast_listen *listen, union pico_address *src) -{ - struct pico_tree_node *index = NULL; -#ifdef PICO_DEBUG_MCAST - char tmp_string[PICO_IPV6_STRING]; -#endif - if(!pico_tree_empty(&listen->MCASTSources)) { - pico_tree_foreach(index, &listen->MCASTSources) - { - if (src->ip4.addr == ((union pico_address *)index->keyValue)->ip4.addr) { - so_mcast_dbg("MCAST: IP %08X in included socket source list\n", src->ip4.addr); - return 0; - } - } - } -#ifdef PICO_SUPPORT_IPV6 - if(!pico_tree_empty(&listen->MCASTSources_ipv6)) { - pico_tree_foreach(index, &listen->MCASTSources_ipv6) - { - if (memcmp(&src->ip6 , &((union pico_address *)index->keyValue)->ip6, sizeof(struct pico_ip6))) { -#ifdef PICO_DEBUG_MCAST - pico_ipv6_to_string(tmp_string, src->ip6.addr); - so_mcast_dbg("MCAST: IP %s in included socket source list\n", tmp_string); -#endif - return 0; - } - } - } -#endif - /* XXX IPV6 ADDRESS */ - so_mcast_dbg("MCAST: IP %08X NOT in included socket source list\n", src->ip4.addr); - return -1; - -} - -static int pico_socket_mcast_filter_exclude(struct pico_mcast_listen *listen, union pico_address *src) -{ - struct pico_tree_node *index = NULL; -#ifdef PICO_DEBUG_MCAST - char tmp_string[PICO_IPV6_STRING]; -#endif - if(!pico_tree_empty(&listen->MCASTSources)) { - pico_tree_foreach(index, &listen->MCASTSources) - { - if (src->ip4.addr == ((union pico_address *)index->keyValue)->ip4.addr) { - so_mcast_dbg("MCAST: IP %08X in excluded socket source list\n", src->ip4.addr); - return -1; - } - } - } -#ifdef PICO_SUPPORT_IPV6 - if(!pico_tree_empty(&listen->MCASTSources_ipv6)) { - pico_tree_foreach(index, &listen->MCASTSources_ipv6) - { - if (memcmp(&src->ip6 , &((union pico_address *)index->keyValue)->ip6, sizeof(struct pico_ip6))) { -#ifdef PICO_DEBUG_MCAST - pico_ipv6_to_string(tmp_string, src->ip6.addr); - so_mcast_dbg("MCAST: IP %s in excluded socket source list\n", tmp_string); -#endif - return 0; - } - } - } -#endif - /* XXX IPV6 ADDRESS */ - so_mcast_dbg("MCAST: IP %08X NOT in excluded socket source list\n", src->ip4.addr); - return 0; -} - -static int pico_socket_mcast_source_filtering(struct pico_mcast_listen *listen, union pico_address *src) -{ - /* perform source filtering */ - if (listen->filter_mode == PICO_IP_MULTICAST_INCLUDE) - return pico_socket_mcast_filter_include(listen, src); - - if (listen->filter_mode == PICO_IP_MULTICAST_EXCLUDE) - return pico_socket_mcast_filter_exclude(listen, src); - - return -1; -} - -static void *pico_socket_mcast_filter_link_get(struct pico_socket *s) -{ - /* check if no multicast enabled on socket */ - if (!s->MCASTListen) - return NULL; - if( IS_SOCK_IPV4(s) ) { - if (!s->local_addr.ip4.addr) - return pico_ipv4_get_default_mcastlink(); - - return pico_ipv4_link_get(&s->local_addr.ip4); - } -#ifdef PICO_SUPPORT_IPV6 - else if( IS_SOCK_IPV6(s)) { - if (pico_ipv6_is_null_address(&s->local_addr.ip6)) - return pico_ipv6_get_default_mcastlink(); - - return pico_ipv6_link_get(&s->local_addr.ip6); - } -#endif - return NULL; -} - -int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src) -{ - void *mcast_link = NULL; - struct pico_mcast_listen *listen = NULL; - mcast_link = pico_socket_mcast_filter_link_get(s); - if (!mcast_link) - return -1; - if(IS_SOCK_IPV4(s)) - listen = listen_find(s,(union pico_address *) &((struct pico_ipv4_link*)(mcast_link))->address, mcast_group); -#ifdef PICO_SUPPORT_IPV6 - else if(IS_SOCK_IPV6(s)) - listen = listen_find(s, (union pico_address *)&((struct pico_ipv6_link*)(mcast_link))->address, mcast_group); -#endif - if (!listen) - return -1; - - return pico_socket_mcast_source_filtering(listen, src); -} - - -static struct pico_ipv4_link *get_mcast_link(union pico_address *a) { - if (!a->ip4.addr) - return pico_ipv4_get_default_mcastlink(); - return pico_ipv4_link_get(&a->ip4); -} -#ifdef PICO_SUPPORT_IPV6 -static struct pico_ipv6_link *get_mcast_link_ipv6(union pico_address *a) { - - if (pico_ipv6_is_null_address(&a->ip6)) { - return pico_ipv6_get_default_mcastlink(); - } - return pico_ipv6_link_get(&a->ip6); -} -#endif - -static int pico_socket_setoption_pre_validation(struct pico_ip_mreq *mreq) - { - if (!mreq) - return -1; - - if (!mreq->mcast_group_addr.ip4.addr) - return -1; - - return 0; -} -#ifdef PICO_SUPPORT_IPV6 -static int pico_socket_setoption_pre_validation_ipv6(struct pico_ip_mreq *mreq) -{ - if (!mreq) - return -1; - - if (pico_ipv6_is_null_address((struct pico_ip6*)&mreq->mcast_group_addr)) - return -1; - - return 0; -} -#endif - -static struct pico_ipv4_link *pico_socket_setoption_validate_mreq(struct pico_ip_mreq *mreq) -{ - if (pico_socket_setoption_pre_validation(mreq) < 0) - return NULL; - - if (pico_ipv4_is_unicast(mreq->mcast_group_addr.ip4.addr)) - return NULL; - - return get_mcast_link((union pico_address *)&mreq->mcast_link_addr); -} - -#ifdef PICO_SUPPORT_IPV6 -static struct pico_ipv6_link *pico_socket_setoption_validate_mreq_ipv6(struct pico_ip_mreq *mreq) -{ - if (pico_socket_setoption_pre_validation_ipv6(mreq) < 0) - return NULL; - - if (pico_ipv6_is_unicast((struct pico_ip6 *)&mreq->mcast_group_addr)) - return NULL; - return get_mcast_link_ipv6((union pico_address *)&mreq->mcast_link_addr); -} -#endif - -static int pico_socket_setoption_pre_validation_s(struct pico_ip_mreq_source *mreq) -{ - if (!mreq) - return -1; - - if (!mreq->mcast_group_addr.ip4.addr) - return -1; - - return 0; -} -#ifdef PICO_SUPPORT_IPV6 -static int pico_socket_setoption_pre_validation_s_ipv6(struct pico_ip_mreq_source *mreq) -{ - if (!mreq) - return -1; - - if (pico_ipv6_is_null_address((struct pico_ip6 *)&mreq->mcast_group_addr)) - return -1; - - return 0; -} -#endif - -static struct pico_ipv4_link *pico_socket_setoption_validate_s_mreq(struct pico_ip_mreq_source *mreq) -{ - if (pico_socket_setoption_pre_validation_s(mreq) < 0) - return NULL; - - if (pico_ipv4_is_unicast(mreq->mcast_group_addr.ip4.addr)) - return NULL; - - if (!pico_ipv4_is_unicast(mreq->mcast_source_addr.ip4.addr)) - return NULL; - - return get_mcast_link((union pico_address *)&mreq->mcast_link_addr); -} -#ifdef PICO_SUPPORT_IPV6 -static struct pico_ipv6_link *pico_socket_setoption_validate_s_mreq_ipv6(struct pico_ip_mreq_source *mreq) -{ - if (pico_socket_setoption_pre_validation_s_ipv6(mreq) < 0) { - return NULL; - } - if (pico_ipv6_is_unicast((struct pico_ip6 *)&mreq->mcast_group_addr)){ - return NULL; - } - if (!pico_ipv6_is_unicast((struct pico_ip6 *)&mreq->mcast_source_addr)){ - return NULL; - } - - return get_mcast_link_ipv6(&mreq->mcast_link_addr); -} -#endif - -static struct pico_ipv4_link *setop_multicast_link_search(void *value, int bysource) -{ - - struct pico_ip_mreq *mreq = NULL; - struct pico_ipv4_link *mcast_link = NULL; - struct pico_ip_mreq_source *mreq_src = NULL; - if (!bysource) { - mreq = (struct pico_ip_mreq *)value; - mcast_link = pico_socket_setoption_validate_mreq(mreq); - if (!mcast_link) - return NULL; - if (!mreq->mcast_link_addr.ip4.addr) - mreq->mcast_link_addr.ip4.addr = mcast_link->address.addr; - } else { - mreq_src = (struct pico_ip_mreq_source *)value; - if (!mreq_src) { - return NULL; - } - - mcast_link = pico_socket_setoption_validate_s_mreq(mreq_src); - if (!mcast_link) { - return NULL; - } - - if (!mreq_src->mcast_link_addr.ip4.addr) - mreq_src->mcast_link_addr.ip4 = mcast_link->address; - } - - return mcast_link; -} -#ifdef PICO_SUPPORT_IPV6 -static struct pico_ipv6_link *setop_multicast_link_search_ipv6(void *value, int bysource) -{ - struct pico_ip_mreq *mreq = NULL; - struct pico_ipv6_link *mcast_link = NULL; - struct pico_ip_mreq_source *mreq_src = NULL; - if (!bysource) { - mreq = (struct pico_ip_mreq *)value; - mcast_link = pico_socket_setoption_validate_mreq_ipv6(mreq); - if (!mcast_link) { - return NULL; - } - if (pico_ipv6_is_null_address(&mreq->mcast_link_addr.ip6)) - mreq->mcast_link_addr.ip6 = mcast_link->address; - } else { - mreq_src = (struct pico_ip_mreq_source *)value; - if (!mreq_src) { - return NULL; - } - - mcast_link = pico_socket_setoption_validate_s_mreq_ipv6(mreq_src); - if (!mcast_link) { - return NULL; - } - if (pico_ipv6_is_null_address(&mreq_src->mcast_link_addr.ip6)) - mreq_src->mcast_link_addr.ip6 = mcast_link->address; - } - return mcast_link; -} -#endif -static int setop_verify_listen_tree(struct pico_socket *s, int alloc) -{ - if(!alloc) - return -1; - - if( IS_SOCK_IPV4(s) ) { - - s->MCASTListen = PICO_ZALLOC(sizeof(struct pico_tree)); - if (!s->MCASTListen) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - s->MCASTListen->root = &LEAF; - s->MCASTListen->compare = mcast_listen_cmp; - return 0; - } -#ifdef PICO_SUPPORT_IPV6 - else if( IS_SOCK_IPV6(s)){ - s->MCASTListen_ipv6 = PICO_ZALLOC(sizeof(struct pico_tree)); - if (!s->MCASTListen_ipv6) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - s->MCASTListen_ipv6->root = &LEAF; - s->MCASTListen_ipv6->compare = mcast_listen_cmp_ipv6; - return 0; - - } -#endif - return -1; -} - - -static void *setopt_multicast_check(struct pico_socket *s, void *value, int alloc, int bysource) -{ - void *mcast_link = NULL; - struct pico_tree *listen_tree = mcast_get_listen_tree(s); - if (!value) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - if(IS_SOCK_IPV4(s)) - mcast_link = setop_multicast_link_search(value, bysource); -#ifdef PICO_SUPPORT_IPV6 - else if(IS_SOCK_IPV6(s)) - mcast_link = setop_multicast_link_search_ipv6(value, bysource); -#endif - if (!mcast_link) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - if (!listen_tree) { /* No RBTree allocated yet */ - if (setop_verify_listen_tree(s, alloc) < 0) { - return NULL; - } - } - return mcast_link; -} - -void pico_multicast_delete(struct pico_socket *s) -{ - int filter_mode; - struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL; - struct pico_mcast_listen *listen = NULL; - union pico_address *source = NULL; - struct pico_tree *tree, *listen_tree; - struct pico_mcast mcast; - listen_tree = mcast_get_listen_tree(s); - if(listen_tree) { - pico_tree_delete(&MCASTSockets, s); - pico_tree_foreach_safe(index, listen_tree, _tmp) - { - listen = index->keyValue; - mcast.listen = listen; - tree = mcast_get_src_tree(s, &mcast); - if (tree) { - pico_tree_foreach_safe(index2, tree, _tmp2) - { - source = index->keyValue; - pico_tree_delete(tree, source); - PICO_FREE(source); - } - } - filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&listen->mcast_link, (union pico_address *)&listen->mcast_group); - if (filter_mode >= 0) { - if(IS_SOCK_IPV4(s)) - pico_ipv4_mcast_leave(&listen->mcast_link.ip4, &listen->mcast_group.ip4, 1, (uint8_t)filter_mode, &MCASTFilter); -#ifdef PICO_SUPPORT_IPV6 - else if(IS_SOCK_IPV6(s)) - pico_ipv6_mcast_leave(&listen->mcast_link.ip6, &listen->mcast_group.ip6, 1, (uint8_t)filter_mode, &MCASTFilter_ipv6); -#endif - } - pico_tree_delete(listen_tree, listen); - PICO_FREE(listen); - } - PICO_FREE(listen_tree); - mcast_set_listen_tree_p_null(s); - } -} - - -int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value) -{ - switch(option) { - case PICO_IP_MULTICAST_IF: - pico_err = PICO_ERR_EOPNOTSUPP; - return -1; - - case PICO_IP_MULTICAST_TTL: - if (s->proto->proto_number == PICO_PROTO_UDP) { - pico_udp_get_mc_ttl(s, (uint8_t *) value); - } else { - *(uint8_t *)value = 0; - pico_err = PICO_ERR_EINVAL; - return -1; - } - - break; - - case PICO_IP_MULTICAST_LOOP: - if (s->proto->proto_number == PICO_PROTO_UDP) { - *(uint8_t *)value = (uint8_t)PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP); - } else { - *(uint8_t *)value = 0; - pico_err = PICO_ERR_EINVAL; - return -1; - } - - break; - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return 0; -} - -static int mcast_so_loop(struct pico_socket *s, void *value) -{ - uint8_t val = (*(uint8_t *)value); - if (val == 0u) { - PICO_SOCKET_SETOPT_DIS(s, PICO_SOCKET_OPT_MULTICAST_LOOP); - return 0; - } else if (val == 1u) { - PICO_SOCKET_SETOPT_EN(s, PICO_SOCKET_OPT_MULTICAST_LOOP); - return 0; - } - - pico_err = PICO_ERR_EINVAL; - return -1; -} -static int mcast_get_param(struct pico_mcast *mcast, struct pico_socket *s, void *value,int alloc, int by_source) { - if(by_source) - mcast->mreq_s = (struct pico_ip_mreq_source *)value; - else - mcast->mreq = (struct pico_ip_mreq *)value; - mcast->mcast_link = setopt_multicast_check(s, value, alloc, by_source); - if (!mcast->mcast_link) - return -1; - mcast->address = pico_mcast_get_link_address(s, mcast->mcast_link); - if(by_source) - mcast->listen = listen_find(s, &(mcast->mreq_s)->mcast_link_addr, &mcast->mreq_s->mcast_group_addr); - else - mcast->listen = listen_find(s, &(mcast->mreq)->mcast_link_addr, &mcast->mreq->mcast_group_addr); - return 0; -} -static int mcast_so_addm(struct pico_socket *s, void *value) -{ - int filter_mode = 0; - struct pico_mcast mcast; - struct pico_tree *tree, *listen_tree; - if(mcast_get_param(&mcast, s, value, 1,0) < 0) - return -1; - - if (mcast.listen) { - if (mcast.listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) { - so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n"); - } else { - so_mcast_dbg("pico_socket_setoption: ERROR duplicate PICO_IP_ADD_MEMBERSHIP\n"); - } - pico_err = PICO_ERR_EINVAL; - return -1; - } - mcast.listen = PICO_ZALLOC(sizeof(struct pico_mcast_listen)); - if (!mcast.listen) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - mcast.listen->filter_mode = PICO_IP_MULTICAST_EXCLUDE; - mcast.listen->mcast_link = mcast.mreq->mcast_link_addr; - mcast.listen->mcast_group = mcast.mreq->mcast_group_addr; - mcast.listen->proto = s->net->proto_number; - - tree = mcast_get_src_tree(s, &mcast); - listen_tree = mcast_get_listen_tree(s); -#ifdef PICO_SUPPORT_IPV6 - if( IS_SOCK_IPV6(s)) - mcast.listen->proto = PICO_PROTO_IPV6; -#endif - tree->root = &LEAF; - pico_tree_insert(listen_tree, mcast.listen); - - pico_tree_insert(&MCASTSockets, s); - filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq->mcast_group_addr); - if (filter_mode < 0) - return -1; - so_mcast_dbg("PICO_IP_ADD_MEMBERSHIP - success, added %p\n", s); - if(IS_SOCK_IPV4(s)) - return pico_ipv4_mcast_join((struct pico_ip4*)&mcast.mreq->mcast_link_addr,(struct pico_ip4*) &mcast.mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter); -#ifdef PICO_SUPPORT_IPV6 - else if(IS_SOCK_IPV6(s)) { - return pico_ipv6_mcast_join((struct pico_ip6*)&mcast.mreq->mcast_link_addr,(struct pico_ip6*)&mcast.mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter_ipv6); - } -#endif - return -1; -} - -static int mcast_so_dropm(struct pico_socket *s, void *value) -{ - int filter_mode = 0; - union pico_address *source = NULL; - struct pico_tree_node *_tmp,*index; - struct pico_mcast mcast; - struct pico_tree *listen_tree,*tree; - if(mcast_get_param(&mcast, s, value, 0,0) < 0) - return -1; - if (!mcast.listen) { - so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n"); - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } - tree = mcast_get_src_tree(s,&mcast); - listen_tree = mcast_get_listen_tree(s); - - pico_tree_foreach_safe(index, tree, _tmp) - { - source = index->keyValue; - pico_tree_delete(tree, source); - } - pico_tree_delete(listen_tree, mcast.listen); - PICO_FREE(mcast.listen); - if (pico_tree_empty(listen_tree)) { - PICO_FREE(listen_tree); - mcast_set_listen_tree_p_null(s); - pico_tree_delete(&MCASTSockets, s); - } - - filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq->mcast_group_addr); - if (filter_mode < 0) - return -1; - if(IS_SOCK_IPV4(s)) - return pico_ipv4_mcast_leave((struct pico_ip4*) &mcast.mreq->mcast_link_addr,(struct pico_ip4 *) &mcast.mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter); -#ifdef PICO_SUPPORT_IPV6 - else if(IS_SOCK_IPV6(s)) { } - return pico_ipv6_mcast_leave((struct pico_ip6*)&mcast.mreq->mcast_link_addr,(struct pico_ip6*)&mcast.mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter_ipv6); -#endif - return -1; -} - -static int mcast_so_unblock_src(struct pico_socket *s, void *value) -{ - int filter_mode = 0; - union pico_address stest, *source = NULL; - struct pico_mcast mcast; - if(mcast_get_param(&mcast, s, value, 0,1) < 0) - return -1; - - memset(&stest, 0, sizeof(union pico_address)); - if (!mcast.listen) { - so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (mcast.listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) { - so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - stest = mcast.mreq_s->mcast_source_addr; - if( IS_SOCK_IPV4(s)) - source = pico_tree_findKey(&mcast.listen->MCASTSources, &stest); -#ifdef PICO_SUPPORT_IPV6 - else if( IS_SOCK_IPV6(s)) - source = pico_tree_findKey(&mcast.listen->MCASTSources_ipv6, &stest); -#endif - if (!source) { - so_mcast_dbg("pico_socket_setoption: ERROR address to unblock not in source list\n"); - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } - if( IS_SOCK_IPV4(s) ) - pico_tree_delete(&mcast.listen->MCASTSources, source); -#ifdef PICO_SUPPORT_IPV6 - else if( IS_SOCK_IPV6(s) ) - pico_tree_delete(&mcast.listen->MCASTSources_ipv6, source); -#endif - - filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq_s->mcast_group_addr); - if (filter_mode < 0) - return -1; - if(IS_SOCK_IPV4(s)) - return pico_ipv4_mcast_leave((struct pico_ip4 *)&mcast.mreq_s->mcast_link_addr,(struct pico_ip4*) &mcast.mreq_s->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter); -#ifdef PICO_SUPPORT_IPV6 - else if(IS_SOCK_IPV6(s)) { } - return pico_ipv6_mcast_leave((struct pico_ip6*)&mcast.mreq_s->mcast_link_addr,(struct pico_ip6*)&mcast.mreq_s->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter_ipv6); -#endif - return -1; -} - -static int mcast_so_block_src(struct pico_socket *s, void *value) -{ - int filter_mode = 0; - union pico_address stest, *source = NULL; - struct pico_mcast mcast; - if(mcast_get_param(&mcast, s, value, 0,1) < 0) - return -1; - - memset(&stest, 0, sizeof(union pico_address)); - if (!mcast.listen) { - dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (mcast.listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) { - so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - stest = mcast.mreq_s->mcast_source_addr; - if( IS_SOCK_IPV4(s)) - source = pico_tree_findKey(&mcast.listen->MCASTSources, &stest); -#ifdef PICO_SUPPORT_IPV6 - else if( IS_SOCK_IPV6(s)) - source = pico_tree_findKey(&mcast.listen->MCASTSources_ipv6, &stest); -#endif - if (source) { - so_mcast_dbg("pico_socket_setoption: ERROR address to block already in source list\n"); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - source = PICO_ZALLOC(sizeof(union pico_address)); - if (!source) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - *source = mcast.mreq_s->mcast_source_addr; - if( IS_SOCK_IPV4(s) ) - pico_tree_insert(&mcast.listen->MCASTSources, source); -#ifdef PICO_SUPPORT_IPV6 - else if( IS_SOCK_IPV6(s) ) - pico_tree_insert(&mcast.listen->MCASTSources_ipv6, source); -#endif - - filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq_s->mcast_group_addr); - if (filter_mode < 0) - return -1; - if(IS_SOCK_IPV4(s)) - return pico_ipv4_mcast_join((struct pico_ip4 *) &mcast.mreq_s->mcast_link_addr, (struct pico_ip4*)&mcast.mreq_s->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter); -#ifdef PICO_SUPPORT_IPV6 - else if(IS_SOCK_IPV6(s)) { } - return pico_ipv6_mcast_join((struct pico_ip6 *)&mcast.mreq_s->mcast_link_addr,(struct pico_ip6*)&mcast.mreq_s->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter_ipv6); -#endif - return -1; -} - -static int mcast_so_addsrcm(struct pico_socket *s, void *value) -{ - int filter_mode = 0, reference_count = 0; - union pico_address stest, *source = NULL; - struct pico_mcast mcast; - struct pico_tree *tree,*listen_tree; - if(mcast_get_param(&mcast, s, value, 1,1) < 0) - return -1; - - memset(&stest, 0, sizeof(union pico_address)); - listen_tree = mcast_get_listen_tree(s); - if (mcast.listen) { - tree = mcast_get_src_tree(s,&mcast); - if (mcast.listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) { - so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - stest = mcast.mreq_s->mcast_source_addr; - source = pico_tree_findKey(tree, &stest); - if (source) { - so_mcast_dbg("pico_socket_setoption: ERROR source address to allow already in source list\n"); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - source = PICO_ZALLOC(sizeof(union pico_address)); - if (!source) { - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } - *source = mcast.mreq_s->mcast_source_addr; - pico_tree_insert(tree, source); - - } else { - mcast.listen = PICO_ZALLOC(sizeof(struct pico_mcast_listen)); - if (!mcast.listen) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - tree = mcast_get_src_tree(s,&mcast); - mcast.listen->filter_mode = PICO_IP_MULTICAST_INCLUDE; - mcast.listen->mcast_link = mcast.mreq_s->mcast_link_addr; - mcast.listen->mcast_group = mcast.mreq_s->mcast_group_addr; - tree->root = &LEAF; - source = PICO_ZALLOC(sizeof(union pico_address)); - if (!source) { - PICO_FREE(mcast.listen); - pico_err = PICO_ERR_ENOMEM; - return -1; - } -#ifdef PICO_SUPPORT_IPV6 - if( IS_SOCK_IPV6(s)) - mcast.listen->proto = PICO_PROTO_IPV6; -#endif - *source = mcast.mreq_s->mcast_source_addr; - pico_tree_insert(tree, source); - pico_tree_insert(listen_tree, mcast.listen); - reference_count = 1; - } - pico_tree_insert(&MCASTSockets, s); - filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq_s->mcast_group_addr); - if (filter_mode < 0) - return -1; - if(IS_SOCK_IPV4(s)) - return pico_ipv4_mcast_join((struct pico_ip4 *)&mcast.mreq_s->mcast_link_addr, (struct pico_ip4*)&mcast.mreq_s->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter); -#ifdef PICO_SUPPORT_IPV6 - else if(IS_SOCK_IPV6(s)) { } - return pico_ipv6_mcast_join((struct pico_ip6 *) &mcast.mreq_s->mcast_link_addr,(struct pico_ip6*)&mcast.mreq_s->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter_ipv6); -#endif - return -1; -} - -static int mcast_so_dropsrcm(struct pico_socket *s, void *value) -{ - int filter_mode = 0, reference_count = 0; - union pico_address stest, *source = NULL; - struct pico_mcast mcast; - struct pico_tree *tree,*listen_tree; - if(mcast_get_param(&mcast, s, value, 0,1) < 0) - return -1; - - memset(&stest, 0, sizeof(union pico_address)); - listen_tree = mcast_get_listen_tree(s); - if (!mcast.listen) { - so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before PICO_IP_ADD_SOURCE_MEMBERSHIP\n"); - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } - if (mcast.listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) { - so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - tree = mcast_get_src_tree(s, &mcast); - stest = mcast.mreq_s->mcast_source_addr; - source = pico_tree_findKey(tree, &stest); - if (!source) { - so_mcast_dbg("pico_socket_setoption: ERROR address to drop not in source list\n"); - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } - pico_tree_delete(tree, source); - if (pico_tree_empty(tree)) { /* 1 if empty, 0 otherwise */ - reference_count = 1; - pico_tree_delete(listen_tree, mcast.listen); - PICO_FREE(mcast.listen); - if (pico_tree_empty(listen_tree)) { - PICO_FREE(listen_tree); - mcast_set_listen_tree_p_null(s); - pico_tree_delete(&MCASTSockets, s); - } - } - - filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq_s->mcast_group_addr); - if (filter_mode < 0) - return -1; - if(IS_SOCK_IPV4(s)) - return pico_ipv4_mcast_leave((struct pico_ip4 *) &mcast.mreq_s->mcast_link_addr, (struct pico_ip4*)&mcast.mreq_s->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter); -#ifdef PICO_SUPPORT_IPV6 - else if(IS_SOCK_IPV6(s)) { } - return pico_ipv6_mcast_leave((struct pico_ip6 *)&mcast.mreq_s->mcast_link_addr,(struct pico_ip6*)&mcast.mreq_s->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter_ipv6); -#endif - return -1; -} - - -struct pico_setsockopt_mcast_call -{ - int option; - int (*call)(struct pico_socket *, void *); -}; - -static const struct pico_setsockopt_mcast_call mcast_so_calls[1 + PICO_IP_DROP_SOURCE_MEMBERSHIP - PICO_IP_MULTICAST_IF] = -{ - { PICO_IP_MULTICAST_IF, NULL }, - { PICO_IP_MULTICAST_TTL, pico_udp_set_mc_ttl }, - { PICO_IP_MULTICAST_LOOP, mcast_so_loop }, - { PICO_IP_ADD_MEMBERSHIP, mcast_so_addm }, - { PICO_IP_DROP_MEMBERSHIP, mcast_so_dropm }, - { PICO_IP_UNBLOCK_SOURCE, mcast_so_unblock_src }, - { PICO_IP_BLOCK_SOURCE, mcast_so_block_src }, - { PICO_IP_ADD_SOURCE_MEMBERSHIP, mcast_so_addsrcm }, - { PICO_IP_DROP_SOURCE_MEMBERSHIP, mcast_so_dropsrcm } -}; - - -static int mcast_so_check_socket(struct pico_socket *s) -{ - pico_err = PICO_ERR_EINVAL; - if (!s) - return -1; - - if (!s->proto) - return -1; - - if (s->proto->proto_number != PICO_PROTO_UDP) - return -1; - - pico_err = PICO_ERR_NOERR; - return 0; -} - -int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value) -{ - int arrayn = option - PICO_IP_MULTICAST_IF; - if (option < PICO_IP_MULTICAST_IF || option > PICO_IP_DROP_SOURCE_MEMBERSHIP) { - pico_err = PICO_ERR_EOPNOTSUPP; - return -1; - } - - if (mcast_so_check_socket(s) < 0) - return -1; - - if (!mcast_so_calls[arrayn].call) { - pico_err = PICO_ERR_EOPNOTSUPP; - return -1; - } - - return (mcast_so_calls[arrayn].call(s, value)); -} - -int pico_udp_set_mc_ttl(struct pico_socket *s, void *_ttl) -{ - struct pico_socket_udp *u; - uint8_t ttl = *(uint8_t *)_ttl; - if(!s) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - u = (struct pico_socket_udp *) s; - u->mc_ttl = ttl; - return 0; -} - -int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl) -{ - struct pico_socket_udp *u; - if(!s) - return -1; - - u = (struct pico_socket_udp *) s; - *ttl = u->mc_ttl; - return 0; -} -#else -int pico_udp_set_mc_ttl(struct pico_socket *s, void *_ttl) -{ - IGNORE_PARAMETER(s); - IGNORE_PARAMETER(_ttl); - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl) -{ - IGNORE_PARAMETER(s); - IGNORE_PARAMETER(ttl); - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src) -{ - IGNORE_PARAMETER(s); - IGNORE_PARAMETER(mcast_group); - IGNORE_PARAMETER(src); - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -void pico_multicast_delete(struct pico_socket *s) -{ - (void)s; -} - -int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value) -{ - (void)s; - (void)option; - (void)value; - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value) -{ - (void)s; - (void)option; - (void)value; - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - -} -#endif /* PICO_SUPPORT_MCAST */ - diff --git a/ext/picotcp/stack/pico_stack.c b/ext/picotcp/stack/pico_stack.c deleted file mode 100644 index 118dc57..0000000 --- a/ext/picotcp/stack/pico_stack.c +++ /dev/null @@ -1,1165 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include "pico_config.h" -#include "pico_frame.h" -#include "pico_device.h" -#include "pico_protocol.h" -#include "pico_stack.h" -#include "pico_addressing.h" -#include "pico_dns_client.h" - -#include "pico_olsr.h" -#include "pico_aodv.h" -#include "pico_eth.h" -#include "pico_arp.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_icmp4.h" -#include "pico_icmp6.h" -#include "pico_igmp.h" -#include "pico_udp.h" -#include "pico_tcp.h" -#include "pico_socket.h" -#include "heap.h" - -#define IS_LIMITED_BCAST(f) (((struct pico_ipv4_hdr *) f->net_hdr)->dst.addr == PICO_IP4_BCAST) - -const uint8_t PICO_ETHADDR_ALL[6] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -# define PICO_SIZE_MCAST 3 -const uint8_t PICO_ETHADDR_MCAST[6] = { - 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 -}; - -#ifdef PICO_SUPPORT_IPV6 -# define PICO_SIZE_MCAST6 2 -const uint8_t PICO_ETHADDR_MCAST6[6] = { - 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 -}; -#endif - - -volatile pico_time pico_tick; -volatile pico_err_t pico_err; - -static uint32_t _rand_seed; - -void WEAK pico_rand_feed(uint32_t feed) -{ - if (!feed) - return; - - _rand_seed *= 1664525; - _rand_seed += 1013904223; - _rand_seed ^= ~(feed); -} - -uint32_t WEAK pico_rand(void) -{ - pico_rand_feed((uint32_t)pico_tick); - return _rand_seed; -} - -void pico_to_lowercase(char *str) -{ - int i = 0; - if (!str) - return; - - while(str[i]) { - if ((str[i] <= 'Z') && (str[i] >= 'A')) - str[i] = (char) (str[i] - (char)('A' - 'a')); - - i++; - } -} - -/* NOTIFICATIONS: distributed notifications for stack internal errors. - */ - -int pico_notify_socket_unreachable(struct pico_frame *f) -{ - if (0) {} - -#ifdef PICO_SUPPORT_ICMP4 - else if (IS_IPV4(f)) { - pico_icmp4_port_unreachable(f); - } -#endif -#ifdef PICO_SUPPORT_ICMP6 - else if (IS_IPV6(f)) { - pico_icmp6_port_unreachable(f); - } -#endif - - return 0; -} - -int pico_notify_proto_unreachable(struct pico_frame *f) -{ - if (0) {} - -#ifdef PICO_SUPPORT_ICMP4 - else if (IS_IPV4(f)) { - pico_icmp4_proto_unreachable(f); - } -#endif -#ifdef PICO_SUPPORT_ICMP6 - else if (IS_IPV6(f)) { - pico_icmp6_proto_unreachable(f); - } -#endif - return 0; -} - -int pico_notify_dest_unreachable(struct pico_frame *f) -{ - if (0) {} - -#ifdef PICO_SUPPORT_ICMP4 - else if (IS_IPV4(f)) { - pico_icmp4_dest_unreachable(f); - } -#endif -#ifdef PICO_SUPPORT_ICMP6 - else if (IS_IPV6(f)) { - pico_icmp6_dest_unreachable(f); - } -#endif - return 0; -} - -int pico_notify_ttl_expired(struct pico_frame *f) -{ - if (0) {} - -#ifdef PICO_SUPPORT_ICMP4 - else if (IS_IPV4(f)) { - pico_icmp4_ttl_expired(f); - } -#endif -#ifdef PICO_SUPPORT_ICMP6 - else if (IS_IPV6(f)) { - pico_icmp6_ttl_expired(f); - } -#endif - return 0; -} - -int pico_notify_frag_expired(struct pico_frame *f) -{ - if (0) {} - -#ifdef PICO_SUPPORT_ICMP4 - else if (IS_IPV4(f)) { - pico_icmp4_frag_expired(f); - } -#endif -#ifdef PICO_SUPPORT_ICMP6 - else if (IS_IPV6(f)) { - pico_icmp6_frag_expired(f); - } -#endif - return 0; -} - -int pico_notify_pkt_too_big(struct pico_frame *f) -{ - if (0) {} - -#ifdef PICO_SUPPORT_ICMP4 - else if (IS_IPV4(f)) { - pico_icmp4_mtu_exceeded(f); - } -#endif -#ifdef PICO_SUPPORT_ICMP6 - else if (IS_IPV6(f)) { - pico_icmp6_pkt_too_big(f); - } -#endif - return 0; -} - - -/* Transport layer */ -MOCKABLE int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto) -{ - int32_t ret = -1; - switch (proto) { - -#ifdef PICO_SUPPORT_ICMP4 - case PICO_PROTO_ICMP4: - ret = pico_enqueue(pico_proto_icmp4.q_in, f); - break; -#endif - -#ifdef PICO_SUPPORT_ICMP6 - case PICO_PROTO_ICMP6: - ret = pico_enqueue(pico_proto_icmp6.q_in, f); - break; -#endif - - -#if defined(PICO_SUPPORT_IGMP) && defined(PICO_SUPPORT_MCAST) - case PICO_PROTO_IGMP: - ret = pico_enqueue(pico_proto_igmp.q_in, f); - break; -#endif - -#ifdef PICO_SUPPORT_UDP - case PICO_PROTO_UDP: - ret = pico_enqueue(pico_proto_udp.q_in, f); - break; -#endif - -#ifdef PICO_SUPPORT_TCP - case PICO_PROTO_TCP: - ret = pico_enqueue(pico_proto_tcp.q_in, f); - break; -#endif - - default: - /* Protocol not available */ - dbg("pkt: no such protocol (%d)\n", proto); - pico_notify_proto_unreachable(f); - pico_frame_discard(f); - ret = -1; - } - return ret; -} - -int32_t pico_network_receive(struct pico_frame *f) -{ - if (0) {} - -#ifdef PICO_SUPPORT_IPV4 - else if (IS_IPV4(f)) { - pico_enqueue(pico_proto_ipv4.q_in, f); - } -#endif -#ifdef PICO_SUPPORT_IPV6 - else if (IS_IPV6(f)) { - pico_enqueue(pico_proto_ipv6.q_in, f); - } -#endif - else { - dbg("Network not found.\n"); - pico_frame_discard(f); - return -1; - } - return (int32_t)f->buffer_len; -} - -/* Network layer: interface towards socket for frame sending */ -int32_t pico_network_send(struct pico_frame *f) -{ - if (!f || !f->sock || !f->sock->net) { - pico_frame_discard(f); - return -1; - } - - return f->sock->net->push(f->sock->net, f); -} - -int pico_source_is_local(struct pico_frame *f) -{ - if (0) { } - -#ifdef PICO_SUPPORT_IPV4 - else if (IS_IPV4(f)) { - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; - if (hdr->src.addr == PICO_IPV4_INADDR_ANY) - return 1; - - if (pico_ipv4_link_find(&hdr->src)) - return 1; - } -#endif -#ifdef PICO_SUPPORT_IPV6 - else if (IS_IPV6(f)) { - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_unspecified(hdr->src.addr) || pico_ipv6_link_find(&hdr->src)) - return 1; - } -#endif - return 0; -} - -#ifdef PICO_SUPPORT_ETH -/* DATALINK LEVEL: interface from network to the device - * and vice versa. - */ - -/* The pico_ethernet_receive() function is used by - * those devices supporting ETH in order to push packets up - * into the stack. - */ - -static int destination_is_bcast(struct pico_frame *f) -{ - if (!f) - return 0; - - if (IS_IPV6(f)) - return 0; - -#ifdef PICO_SUPPORT_IPV4 - else { - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - return pico_ipv4_is_broadcast(hdr->dst.addr); - } -#else - return 0; -#endif -} - -static int destination_is_mcast(struct pico_frame *f) -{ - int ret = 0; - if (!f) - return 0; - -#ifdef PICO_SUPPORT_IPV6 - if (IS_IPV6(f)) { - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *) f->net_hdr; - ret = pico_ipv6_is_multicast(hdr->dst.addr); - } - -#endif -#ifdef PICO_SUPPORT_IPV4 - else { - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - ret = pico_ipv4_is_multicast(hdr->dst.addr); - } -#endif - - return ret; -} - -#ifdef PICO_SUPPORT_IPV4 -static int32_t pico_ipv4_ethernet_receive(struct pico_frame *f) -{ - if (IS_IPV4(f)) { - pico_enqueue(pico_proto_ipv4.q_in, f); - } else { - (void)pico_icmp4_param_problem(f, 0); - pico_frame_discard(f); - return -1; - } - - return (int32_t)f->buffer_len; -} -#endif - -#ifdef PICO_SUPPORT_IPV6 -static int32_t pico_ipv6_ethernet_receive(struct pico_frame *f) -{ - if (IS_IPV6(f)) { - pico_enqueue(pico_proto_ipv6.q_in, f); - } else { - /* Wrong version for link layer type */ - pico_frame_discard(f); - return -1; - } - - return (int32_t)f->buffer_len; -} -#endif - -static int32_t pico_ll_receive(struct pico_frame *f) -{ - struct pico_eth_hdr *hdr = (struct pico_eth_hdr *) f->datalink_hdr; - f->net_hdr = f->datalink_hdr + sizeof(struct pico_eth_hdr); - -#if (defined PICO_SUPPORT_IPV4) && (defined PICO_SUPPORT_ETH) - if (hdr->proto == PICO_IDETH_ARP) - return pico_arp_receive(f); - -#endif - -#if defined (PICO_SUPPORT_IPV4) - if (hdr->proto == PICO_IDETH_IPV4) - return pico_ipv4_ethernet_receive(f); - -#endif - -#if defined (PICO_SUPPORT_IPV6) - if (hdr->proto == PICO_IDETH_IPV6) - return pico_ipv6_ethernet_receive(f); - -#endif - - pico_frame_discard(f); - return -1; -} - -static void pico_ll_check_bcast(struct pico_frame *f) -{ - struct pico_eth_hdr *hdr = (struct pico_eth_hdr *) f->datalink_hdr; - /* Indicate a link layer broadcast packet */ - if (memcmp(hdr->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH) == 0) - f->flags |= PICO_FRAME_FLAG_BCAST; -} - -int32_t pico_ethernet_receive(struct pico_frame *f) -{ - struct pico_eth_hdr *hdr; - if (!f || !f->dev || !f->datalink_hdr) - { - pico_frame_discard(f); - return -1; - } - - hdr = (struct pico_eth_hdr *) f->datalink_hdr; - if ((memcmp(hdr->daddr, f->dev->eth->mac.addr, PICO_SIZE_ETH) != 0) && - (memcmp(hdr->daddr, PICO_ETHADDR_MCAST, PICO_SIZE_MCAST) != 0) && -#ifdef PICO_SUPPORT_IPV6 - (memcmp(hdr->daddr, PICO_ETHADDR_MCAST6, PICO_SIZE_MCAST6) != 0) && -#endif - (memcmp(hdr->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH) != 0)) - { - pico_frame_discard(f); - return -1; - } - - pico_ll_check_bcast(f); - return pico_ll_receive(f); -} - -static struct pico_eth *pico_ethernet_mcast_translate(struct pico_frame *f, uint8_t *pico_mcast_mac) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - - /* place 23 lower bits of IP in lower 23 bits of MAC */ - pico_mcast_mac[5] = (long_be(hdr->dst.addr) & 0x000000FFu); - pico_mcast_mac[4] = (uint8_t)((long_be(hdr->dst.addr) & 0x0000FF00u) >> 8u); - pico_mcast_mac[3] = (uint8_t)((long_be(hdr->dst.addr) & 0x007F0000u) >> 16u); - - return (struct pico_eth *)pico_mcast_mac; -} - - -#ifdef PICO_SUPPORT_IPV6 -static struct pico_eth *pico_ethernet_mcast6_translate(struct pico_frame *f, uint8_t *pico_mcast6_mac) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - - /* first 2 octets are 0x33, last four are the last four of dst */ - pico_mcast6_mac[5] = hdr->dst.addr[PICO_SIZE_IP6 - 1]; - pico_mcast6_mac[4] = hdr->dst.addr[PICO_SIZE_IP6 - 2]; - pico_mcast6_mac[3] = hdr->dst.addr[PICO_SIZE_IP6 - 3]; - pico_mcast6_mac[2] = hdr->dst.addr[PICO_SIZE_IP6 - 4]; - - return (struct pico_eth *)pico_mcast6_mac; -} -#endif - -static int pico_ethernet_ipv6_dst(struct pico_frame *f, struct pico_eth *const dstmac) -{ - int retval = -1; - if (!dstmac) - return -1; - - #ifdef PICO_SUPPORT_IPV6 - if (destination_is_mcast(f)) { - uint8_t pico_mcast6_mac[6] = { - 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 - }; - pico_ethernet_mcast6_translate(f, pico_mcast6_mac); - memcpy(dstmac, pico_mcast6_mac, PICO_SIZE_ETH); - retval = 0; - } else { - struct pico_eth *neighbor = pico_ipv6_get_neighbor(f); - if (neighbor) - { - memcpy(dstmac, neighbor, PICO_SIZE_ETH); - retval = 0; - } - } - - #else - (void)f; - pico_err = PICO_ERR_EPROTONOSUPPORT; - #endif - return retval; -} - - -/* Ethernet send, first attempt: try our own address. - * Returns 0 if the packet is not for us. - * Returns 1 if the packet is cloned to our own receive queue, so the caller can discard the original frame. - * */ -static int32_t pico_ethsend_local(struct pico_frame *f, struct pico_eth_hdr *hdr) -{ - if (!hdr) - return 0; - - /* Check own mac */ - if(!memcmp(hdr->daddr, hdr->saddr, PICO_SIZE_ETH)) { - struct pico_frame *clone = pico_frame_copy(f); - dbg("sending out packet destined for our own mac\n"); - (void)pico_ethernet_receive(clone); - return 1; - } - - return 0; -} - -/* Ethernet send, second attempt: try bcast. - * Returns 0 if the packet is not bcast, so it will be handled somewhere else. - * Returns 1 if the packet is handled by the pico_device_broadcast() function, so it can be discarded. - * */ -static int32_t pico_ethsend_bcast(struct pico_frame *f) -{ - if (IS_LIMITED_BCAST(f)) { - (void)pico_device_broadcast(f); /* We can discard broadcast even if it's not sent. */ - return 1; - } - - return 0; -} - -/* Ethernet send, third attempt: try unicast. - * If the device driver is busy, we return 0, so the stack won't discard the frame. - * In case of success, we can safely return 1. - */ -static int32_t pico_ethsend_dispatch(struct pico_frame *f) -{ - int ret = f->dev->send(f->dev, f->start, (int) f->len); - if (ret <= 0) - return 0; /* Failure to deliver! */ - else { - return 1; /* Frame is in flight by now. */ - } -} - - - - -/* This function looks for the destination mac address - * in order to send the frame being processed. - */ - -int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f) -{ - struct pico_eth dstmac; - uint8_t dstmac_valid = 0; - uint16_t proto = PICO_IDETH_IPV4; - -#ifdef PICO_SUPPORT_IPV6 - /* Step 1: If the frame has an IPv6 packet, - * destination address is taken from the ND tables - */ - if (IS_IPV6(f)) { - if (pico_ethernet_ipv6_dst(f, &dstmac) < 0) - { - pico_ipv6_nd_postpone(f); - return 0; /* I don't care if frame was actually postponed. If there is no room in the ND table, discard safely. */ - } - - dstmac_valid = 1; - proto = PICO_IDETH_IPV6; - } - else -#endif - - /* In case of broadcast (IPV4 only), dst mac is FF:FF:... */ - if (IS_BCAST(f) || destination_is_bcast(f)) - { - memcpy(&dstmac, PICO_ETHADDR_ALL, PICO_SIZE_ETH); - dstmac_valid = 1; - } - - /* In case of multicast, dst mac is translated from the group address */ - else if (destination_is_mcast(f)) { - uint8_t pico_mcast_mac[6] = { - 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 - }; - pico_ethernet_mcast_translate(f, pico_mcast_mac); - memcpy(&dstmac, pico_mcast_mac, PICO_SIZE_ETH); - dstmac_valid = 1; - } - -#if (defined PICO_SUPPORT_IPV4) - else { - struct pico_eth *arp_get; - arp_get = pico_arp_get(f); - if (arp_get) { - memcpy(&dstmac, arp_get, PICO_SIZE_ETH); - dstmac_valid = 1; - } else { - /* At this point, ARP will discard the frame in any case. - * It is safe to return without discarding. - */ - pico_arp_postpone(f); - return 0; - /* Same case as for IPv6 ... */ - } - - } -#endif - - /* This sets destination and source address, then pushes the packet to the device. */ - if (dstmac_valid) { - struct pico_eth_hdr *hdr; - hdr = (struct pico_eth_hdr *) f->datalink_hdr; - if ((f->start > f->buffer) && ((f->start - f->buffer) >= PICO_SIZE_ETHHDR)) - { - f->start -= PICO_SIZE_ETHHDR; - f->len += PICO_SIZE_ETHHDR; - f->datalink_hdr = f->start; - hdr = (struct pico_eth_hdr *) f->datalink_hdr; - memcpy(hdr->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH); - memcpy(hdr->daddr, &dstmac, PICO_SIZE_ETH); - hdr->proto = proto; - } - - if (pico_ethsend_local(f, hdr) || pico_ethsend_bcast(f) || pico_ethsend_dispatch(f)) { - /* one of the above functions has delivered the frame accordingly. (returned != 0) - * It is safe to directly return success. - * */ - return 0; - } - } - - /* Failure: do not dequeue the frame, keep it for later. */ - return -1; -} - -#endif /* PICO_SUPPORT_ETH */ - - -void pico_store_network_origin(void *src, struct pico_frame *f) -{ - #ifdef PICO_SUPPORT_IPV4 - struct pico_ip4 *ip4; - #endif - - #ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 *ip6; - #endif - - #ifdef PICO_SUPPORT_IPV4 - if (IS_IPV4(f)) { - struct pico_ipv4_hdr *hdr; - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - ip4 = (struct pico_ip4 *) src; - ip4->addr = hdr->src.addr; - } - - #endif - #ifdef PICO_SUPPORT_IPV6 - if (IS_IPV6(f)) { - struct pico_ipv6_hdr *hdr; - hdr = (struct pico_ipv6_hdr *) f->net_hdr; - ip6 = (struct pico_ip6 *) src; - memcpy(ip6->addr, hdr->src.addr, PICO_SIZE_IP6); - } - - #endif -} - -int pico_address_compare(union pico_address *a, union pico_address *b, uint16_t proto) -{ - #ifdef PICO_SUPPORT_IPV6 - if (proto == PICO_PROTO_IPV6) { - return pico_ipv6_compare(&a->ip6, &b->ip6); - } - - #endif - #ifdef PICO_SUPPORT_IPV4 - if (proto == PICO_PROTO_IPV4) { - return pico_ipv4_compare(&a->ip4, &b->ip4); - } - - #endif - return 0; - -} - -int pico_frame_dst_is_unicast(struct pico_frame *f) -{ - if (0) { - return 0; - } - -#ifdef PICO_SUPPORT_IPV4 - if (IS_IPV4(f)) { - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; - if (pico_ipv4_is_multicast(hdr->dst.addr) || pico_ipv4_is_broadcast(hdr->dst.addr)) - return 0; - - return 1; - } - -#endif - -#ifdef PICO_SUPPORT_IPV6 - if (IS_IPV6(f)) { - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr) || pico_ipv6_is_unspecified(hdr->dst.addr)) - return 0; - - return 1; - } - -#endif - else return 0; -} - - -/* LOWEST LEVEL: interface towards devices. */ -/* Device driver will call this function which returns immediately. - * Incoming packet will be processed later on in the dev loop. - */ -int32_t pico_stack_recv(struct pico_device *dev, uint8_t *buffer, uint32_t len) -{ - struct pico_frame *f; - int32_t ret; - if (len == 0) - return -1; - - f = pico_frame_alloc(len); - if (!f) - { - dbg("Cannot alloc incoming frame!\n"); - return -1; - } - - /* Association to the device that just received the frame. */ - f->dev = dev; - - /* Setup the start pointer, length. */ - f->start = f->buffer; - f->len = f->buffer_len; - if (f->len > 8) { - uint32_t rand, mid_frame = (f->buffer_len >> 2) << 1; - mid_frame -= (mid_frame % 4); - memcpy(&rand, f->buffer + mid_frame, sizeof(uint32_t)); - pico_rand_feed(rand); - } - - memcpy(f->buffer, buffer, len); - ret = pico_enqueue(dev->q_in, f); - if (ret <= 0) { - pico_frame_discard(f); - } - - return ret; -} - -static int32_t _pico_stack_recv_zerocopy(struct pico_device *dev, uint8_t *buffer, uint32_t len, int ext_buffer, void (*notify_free)(uint8_t *)) -{ - struct pico_frame *f; - int ret; - if (len == 0) - return -1; - - f = pico_frame_alloc_skeleton(len, ext_buffer); - if (!f) - { - dbg("Cannot alloc incoming frame!\n"); - return -1; - } - - if (pico_frame_skeleton_set_buffer(f, buffer) < 0) - { - dbg("Invalid zero-copy buffer!\n"); - PICO_FREE(f->usage_count); - PICO_FREE(f); - return -1; - } - - if (notify_free) { - f->notify_free = notify_free; - } - - f->dev = dev; - ret = pico_enqueue(dev->q_in, f); - if (ret <= 0) { - pico_frame_discard(f); - } - - return ret; -} - -int32_t pico_stack_recv_zerocopy(struct pico_device *dev, uint8_t *buffer, uint32_t len) -{ - return _pico_stack_recv_zerocopy(dev, buffer, len, 0, NULL); -} - -int32_t pico_stack_recv_zerocopy_ext_buffer(struct pico_device *dev, uint8_t *buffer, uint32_t len) -{ - return _pico_stack_recv_zerocopy(dev, buffer, len, 1, NULL); -} - -int32_t pico_stack_recv_zerocopy_ext_buffer_notify(struct pico_device *dev, uint8_t *buffer, uint32_t len, void (*notify_free)(uint8_t *buffer)) -{ - return _pico_stack_recv_zerocopy(dev, buffer, len, 1, notify_free); -} - -int32_t pico_sendto_dev(struct pico_frame *f) -{ - if (!f->dev) { - pico_frame_discard(f); - return -1; - } else { - if (f->len > 8) { - uint32_t rand, mid_frame = (f->buffer_len >> 2) << 1; - mid_frame -= (mid_frame % 4); - memcpy(&rand, f->buffer + mid_frame, sizeof(uint32_t)); - pico_rand_feed(rand); - } - - return pico_enqueue(f->dev->q_out, f); - } -} - -struct pico_timer -{ - void *arg; - void (*timer)(pico_time timestamp, void *arg); -}; - - -static uint32_t tmr_id = 0u; -struct pico_timer_ref -{ - pico_time expire; - uint32_t id; - struct pico_timer *tmr; -}; - -typedef struct pico_timer_ref pico_timer_ref; - -DECLARE_HEAP(pico_timer_ref, expire); - -static heap_pico_timer_ref *Timers; - -int32_t pico_seq_compare(uint32_t a, uint32_t b) -{ - uint32_t thresh = ((uint32_t)(-1)) >> 1; - - if (a > b) /* return positive number, if not wrapped */ - { - if ((a - b) > thresh) /* b wrapped */ - return -(int32_t)(b - a); /* b = very small, a = very big */ - else - return (int32_t)(a - b); /* a = biggest, b = a bit smaller */ - - } - - if (a < b) /* return negative number, if not wrapped */ - { - if ((b - a) > thresh) /* a wrapped */ - return (int32_t)(a - b); /* a = very small, b = very big */ - else - return -(int32_t)(b - a); /* b = biggest, a = a bit smaller */ - - } - - return 0; -} - -static void pico_check_timers(void) -{ - struct pico_timer *t; - struct pico_timer_ref tref_unused, *tref = heap_first(Timers); - pico_tick = PICO_TIME_MS(); - while((tref) && (tref->expire < pico_tick)) { - t = tref->tmr; - if (t && t->timer) - t->timer(pico_tick, t->arg); - - if (t) - { - PICO_FREE(t); - } - - t = NULL; - heap_peek(Timers, &tref_unused); - tref = heap_first(Timers); - } -} - -void MOCKABLE pico_timer_cancel(uint32_t id) -{ - uint32_t i; - struct pico_timer_ref *tref = Timers->top; - if (id == 0u) - return; - for (i = 1; i <= Timers->n; i++) { - if (tref[i].id == id) { - PICO_FREE(Timers->top[i].tmr); - Timers->top[i].tmr = NULL; - break; - } - } -} - -#define PROTO_DEF_NR 11 -#define PROTO_DEF_AVG_NR 4 -#define PROTO_DEF_SCORE 32 -#define PROTO_MIN_SCORE 32 -#define PROTO_MAX_SCORE 128 -#define PROTO_LAT_IND 3 /* latency indication 0-3 (lower is better latency performance), x1, x2, x4, x8 */ -#define PROTO_MAX_LOOP (PROTO_MAX_SCORE << PROTO_LAT_IND) /* max global loop score, so per tick */ - -static int calc_score(int *score, int *index, int avg[][PROTO_DEF_AVG_NR], int *ret) -{ - int temp, i, j, sum; - int max_total = PROTO_MAX_LOOP, total = 0; - - /* dbg("USED SCORES> "); */ - - for (i = 0; i < PROTO_DEF_NR; i++) { - - /* if used looped score */ - if (ret[i] < score[i]) { - temp = score[i] - ret[i]; /* remaining loop score */ - - /* dbg("%3d - ",temp); */ - - if (index[i] >= PROTO_DEF_AVG_NR) - index[i] = 0; /* reset index */ - - j = index[i]; - avg[i][j] = temp; - - index[i]++; - - if (ret[i] == 0 && ((score[i] * 2) <= PROTO_MAX_SCORE) && ((total + (score[i] * 2)) < max_total)) { /* used all loop score -> increase next score directly */ - score[i] *= 2; - total += score[i]; - continue; - } - - sum = 0; - for (j = 0; j < PROTO_DEF_AVG_NR; j++) - sum += avg[i][j]; /* calculate sum */ - - sum /= 4; /* divide by 4 to get average used score */ - - /* criterion to increase next loop score */ - if (sum > (score[i] - (score[i] / 4)) && ((score[i] * 2) <= PROTO_MAX_SCORE) && ((total + (score[i] / 2)) < max_total)) { /* > 3/4 */ - score[i] *= 2; /* double loop score */ - total += score[i]; - continue; - } - - /* criterion to decrease next loop score */ - if ((sum < (score[i] / 4)) && ((score[i] / 2) >= PROTO_MIN_SCORE)) { /* < 1/4 */ - score[i] /= 2; /* half loop score */ - total += score[i]; - continue; - } - - /* also add non-changed scores */ - total += score[i]; - } - else if (ret[i] == score[i]) { - /* no used loop score - gradually decrease */ - - /* dbg("%3d - ",0); */ - - if (index[i] >= PROTO_DEF_AVG_NR) - index[i] = 0; /* reset index */ - - j = index[i]; - avg[i][j] = 0; - - index[i]++; - - sum = 0; - for (j = 0; j < PROTO_DEF_AVG_NR; j++) - sum += avg[i][j]; /* calculate sum */ - - sum /= 2; /* divide by 4 to get average used score */ - - if ((sum == 0) && ((score[i] / 2) >= PROTO_MIN_SCORE)) { - score[i] /= 2; /* half loop score */ - total += score[i]; - for (j = 0; j < PROTO_DEF_AVG_NR; j++) - avg[i][j] = score[i]; - } - - } - } - /* dbg("\n"); */ - - return 0; -} - -void pico_stack_tick(void) -{ - static int score[PROTO_DEF_NR] = { - PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE - }; - static int index[PROTO_DEF_NR] = { - 0, 0, 0, 0, 0, 0 - }; - static int avg[PROTO_DEF_NR][PROTO_DEF_AVG_NR]; - static int ret[PROTO_DEF_NR] = { - 0 - }; - - pico_check_timers(); - - /* dbg("LOOP_SCORES> %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d\n",score[0],score[1],score[2],score[3],score[4],score[5],score[6],score[7],score[8],score[9],score[10]); */ - - /* score = pico_protocols_loop(100); */ - - ret[0] = pico_devices_loop(score[0], PICO_LOOP_DIR_IN); - pico_rand_feed((uint32_t)ret[0]); - - ret[1] = pico_protocol_datalink_loop(score[1], PICO_LOOP_DIR_IN); - pico_rand_feed((uint32_t)ret[1]); - - ret[2] = pico_protocol_network_loop(score[2], PICO_LOOP_DIR_IN); - pico_rand_feed((uint32_t)ret[2]); - - ret[3] = pico_protocol_transport_loop(score[3], PICO_LOOP_DIR_IN); - pico_rand_feed((uint32_t)ret[3]); - - - ret[5] = score[5]; -#if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6) -#if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP) - ret[5] = pico_sockets_loop(score[5]); /* swapped */ - pico_rand_feed((uint32_t)ret[5]); -#endif -#endif - - ret[4] = pico_protocol_socket_loop(score[4], PICO_LOOP_DIR_IN); - pico_rand_feed((uint32_t)ret[4]); - - - ret[6] = pico_protocol_socket_loop(score[6], PICO_LOOP_DIR_OUT); - pico_rand_feed((uint32_t)ret[6]); - - ret[7] = pico_protocol_transport_loop(score[7], PICO_LOOP_DIR_OUT); - pico_rand_feed((uint32_t)ret[7]); - - ret[8] = pico_protocol_network_loop(score[8], PICO_LOOP_DIR_OUT); - pico_rand_feed((uint32_t)ret[8]); - - ret[9] = pico_protocol_datalink_loop(score[9], PICO_LOOP_DIR_OUT); - pico_rand_feed((uint32_t)ret[9]); - - ret[10] = pico_devices_loop(score[10], PICO_LOOP_DIR_OUT); - pico_rand_feed((uint32_t)ret[10]); - - /* calculate new loop scores for next iteration */ - calc_score(score, index, (int (*)[])avg, ret); -} - -void pico_stack_loop(void) -{ - while(1) { - pico_stack_tick(); - PICO_IDLE(); - } -} - -MOCKABLE uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - struct pico_timer *t = PICO_ZALLOC(sizeof(struct pico_timer)); - struct pico_timer_ref tref; - - /* zero is guard for timers */ - if (tmr_id == 0u) - tmr_id++; - - if (!t) { - pico_err = PICO_ERR_ENOMEM; - return 0; - } - - tref.expire = PICO_TIME_MS() + expire; - t->arg = arg; - t->timer = timer; - tref.tmr = t; - tref.id = tmr_id++; - heap_insert(Timers, &tref); - if (Timers->n > PICO_MAX_TIMERS) { - dbg("Warning: I have %d timers\n", (int)Timers->n); - } - - return tref.id; -} - -int pico_stack_init(void) -{ - -#ifdef PICO_SUPPORT_IPV4 - pico_protocol_init(&pico_proto_ipv4); -#endif - -#ifdef PICO_SUPPORT_IPV6 - pico_protocol_init(&pico_proto_ipv6); -#endif - -#ifdef PICO_SUPPORT_ICMP4 - pico_protocol_init(&pico_proto_icmp4); -#endif - -#ifdef PICO_SUPPORT_ICMP6 - pico_protocol_init(&pico_proto_icmp6); -#endif - -#if defined(PICO_SUPPORT_IGMP) && defined(PICO_SUPPORT_MCAST) - pico_protocol_init(&pico_proto_igmp); -#endif - -#ifdef PICO_SUPPORT_UDP - pico_protocol_init(&pico_proto_udp); -#endif - -#ifdef PICO_SUPPORT_TCP - pico_protocol_init(&pico_proto_tcp); -#endif - -#ifdef PICO_SUPPORT_DNS_CLIENT - pico_dns_client_init(); -#endif - - pico_rand_feed(123456); - - /* Initialize timer heap */ - Timers = heap_init(); - if (!Timers) - return -1; - -#if ((defined PICO_SUPPORT_IPV4) && (defined PICO_SUPPORT_ETH)) - /* Initialize ARP module */ - pico_arp_init(); -#endif - -#ifdef PICO_SUPPORT_IPV6 - /* Initialize Neighbor discovery module */ - pico_ipv6_nd_init(); -#endif - -#ifdef PICO_SUPPORT_OLSR - pico_olsr_init(); -#endif -#ifdef PICO_SUPPORT_AODV - pico_aodv_init(); -#endif - - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - return 0; -} - diff --git a/ext/picotcp/stack/pico_tree.c b/ext/picotcp/stack/pico_tree.c deleted file mode 100644 index 8af9845..0000000 --- a/ext/picotcp/stack/pico_tree.c +++ /dev/null @@ -1,575 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Author: Andrei Carp - *********************************************************************/ - -#include "pico_tree.h" -#include "pico_config.h" -#include "pico_protocol.h" -#include "pico_mm.h" - -#define RED 0 -#define BLACK 1 - -/* By default the null leafs are black */ -struct pico_tree_node LEAF = { - NULL, /* key */ - &LEAF, &LEAF, &LEAF, /* parent, left,right */ - BLACK, /* color */ -}; - -#define IS_LEAF(x) (x == &LEAF) -#define IS_NOT_LEAF(x) (x != &LEAF) -#define INIT_LEAF (&LEAF) - -#define AM_I_LEFT_CHILD(x) (x == x->parent->leftChild) -#define AM_I_RIGHT_CHILD(x) (x == x->parent->rightChild) - -#define PARENT(x) (x->parent) -#define GRANPA(x) (x->parent->parent) - -/* - * Local Functions - */ -static struct pico_tree_node *create_node(struct pico_tree *tree, void *key, uint8_t allocator); -static void rotateToLeft(struct pico_tree*tree, struct pico_tree_node*node); -static void rotateToRight(struct pico_tree*root, struct pico_tree_node*node); -static void fix_insert_collisions(struct pico_tree*tree, struct pico_tree_node*node); -static void fix_delete_collisions(struct pico_tree*tree, struct pico_tree_node *node); -static void switchNodes(struct pico_tree*tree, struct pico_tree_node*nodeA, struct pico_tree_node*nodeB); -void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator); -void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator); - -#ifdef PICO_SUPPORT_MM -/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has. - * These nodes should be placed in the manager page which is in a different memory region then the nodes - * which are used for the pico stack in general. - * Therefore the following 2 functions are created so that pico_tree can use them to to put these nodes - * into the correct memory regions. - * If pico_tree_insert is called from the memory manager module, then create_node should use - * pico_mem_page0_zalloc to create a node. The same for pico_tree_delete. - */ -extern void*pico_mem_page0_zalloc(size_t len); -extern void pico_mem_page0_free(void*ptr); -#endif /* PICO_SUPPORT_MM */ - -/* - * Exported functions - */ - -struct pico_tree_node *pico_tree_firstNode(struct pico_tree_node *node) -{ - while(IS_NOT_LEAF(node->leftChild)) - node = node->leftChild; - return node; -} - -struct pico_tree_node *pico_tree_lastNode(struct pico_tree_node *node) -{ - while(IS_NOT_LEAF(node->rightChild)) - node = node->rightChild; - return node; -} - -struct pico_tree_node *pico_tree_next(struct pico_tree_node *node) -{ - if (!node) - return NULL; - if(IS_NOT_LEAF(node->rightChild)) - { - node = node->rightChild; - while(IS_NOT_LEAF(node->leftChild)) - node = node->leftChild; - } - else - { - if (IS_NOT_LEAF(node->parent) && AM_I_LEFT_CHILD(node)) - node = node->parent; - else { - while (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node)) - node = node->parent; - node = node->parent; - } - } - - return node; -} - -struct pico_tree_node *pico_tree_prev(struct pico_tree_node *node) -{ - if (IS_NOT_LEAF(node->leftChild)) { - node = node->leftChild; - while (IS_NOT_LEAF(node->rightChild)) - node = node->rightChild; - } else { - if (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node)) - node = node->parent; - else { - while (IS_NOT_LEAF(node) && AM_I_LEFT_CHILD(node)) - node = node->parent; - node = node->parent; - } - } - - return node; -} - -/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has. - * These nodes should be placed in the manager page which is in a different memory region then the nodes - * which are used for the pico stack in general. - * Therefore the following wrapper for pico_tree_insert is created. - * The actual implementation can be found in pico_tree_insert_implementation. - */ -void *pico_tree_insert(struct pico_tree *tree, void *key) -{ - return pico_tree_insert_implementation(tree, key, USE_PICO_ZALLOC); -} - -void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator) -{ - struct pico_tree_node *last_node = INIT_LEAF; - struct pico_tree_node *temp = tree->root; - struct pico_tree_node *insert; - void *LocalKey; - int result = 0; - - LocalKey = (IS_NOT_LEAF(tree->root) ? pico_tree_findKey(tree, key) : NULL); - - /* if node already in, bail out */ - if(LocalKey) { - return LocalKey; - } - else - { - if(allocator == USE_PICO_PAGE0_ZALLOC) - insert = create_node(tree, key, USE_PICO_PAGE0_ZALLOC); - else - insert = create_node(tree, key, USE_PICO_ZALLOC); - - if(!insert) - { - pico_err = PICO_ERR_ENOMEM; - /* to let the user know that it couldn't insert */ - return (void *)&LEAF; - } - } - - /* search for the place to insert the new node */ - while(IS_NOT_LEAF(temp)) - { - last_node = temp; - result = tree->compare(insert->keyValue, temp->keyValue); - - temp = (result < 0) ? (temp->leftChild) : (temp->rightChild); - } - /* make the needed connections */ - insert->parent = last_node; - - if(IS_LEAF(last_node)) - tree->root = insert; - else{ - result = tree->compare(insert->keyValue, last_node->keyValue); - if(result < 0) - last_node->leftChild = insert; - else - last_node->rightChild = insert; - } - - /* fix colour issues */ - fix_insert_collisions(tree, insert); - - return NULL; -} - -struct pico_tree_node *pico_tree_findNode(struct pico_tree *tree, void *key) -{ - struct pico_tree_node *found; - - found = tree->root; - - while(IS_NOT_LEAF(found)) - { - int result; - result = tree->compare(found->keyValue, key); - if(result == 0) - { - return found; - } - else if(result < 0) - found = found->rightChild; - else - found = found->leftChild; - } - return NULL; -} - -void *pico_tree_findKey(struct pico_tree *tree, void *key) -{ - struct pico_tree_node *found; - - - found = tree->root; - while(IS_NOT_LEAF(found)) - { - int result; - - result = tree->compare(found->keyValue, key); - if(result == 0) - return found->keyValue; - else if(result < 0) - found = found->rightChild; - else - found = found->leftChild; - - } - return NULL; -} - -void *pico_tree_first(struct pico_tree *tree) -{ - return pico_tree_firstNode(tree->root)->keyValue; -} - -void *pico_tree_last(struct pico_tree *tree) -{ - return pico_tree_lastNode(tree->root)->keyValue; -} - -static uint8_t pico_tree_delete_node(struct pico_tree *tree, struct pico_tree_node *d, struct pico_tree_node **temp) -{ - struct pico_tree_node *min; - struct pico_tree_node *ltemp = d; - uint8_t nodeColor; - min = pico_tree_firstNode(d->rightChild); - nodeColor = min->color; - - *temp = min->rightChild; - if(min->parent == ltemp && IS_NOT_LEAF(*temp)) - (*temp)->parent = min; - else{ - switchNodes(tree, min, min->rightChild); - min->rightChild = ltemp->rightChild; - if(IS_NOT_LEAF(min->rightChild)) min->rightChild->parent = min; - } - - switchNodes(tree, ltemp, min); - min->leftChild = ltemp->leftChild; - - if(IS_NOT_LEAF(min->leftChild)) - min->leftChild->parent = min; - - min->color = ltemp->color; - return nodeColor; -} - -static uint8_t pico_tree_delete_check_switch(struct pico_tree *tree, struct pico_tree_node *delete, struct pico_tree_node **temp) -{ - struct pico_tree_node *ltemp = delete; - uint8_t nodeColor = delete->color; - if(IS_LEAF(delete->leftChild)) - { - *temp = ltemp->rightChild; - switchNodes(tree, ltemp, ltemp->rightChild); - } - else - if(IS_LEAF(delete->rightChild)) - { - struct pico_tree_node *_ltemp = delete; - *temp = _ltemp->leftChild; - switchNodes(tree, _ltemp, _ltemp->leftChild); - } - else{ - nodeColor = pico_tree_delete_node(tree, delete, temp); - } - - return nodeColor; - -} - -/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has. - * These nodes should be placed in the manager page which is in a different memory region then the nodes - * which are used for the pico stack in general. - * Therefore the following wrapper for pico_tree_delete is created. - * The actual implementation can be found in pico_tree_delete_implementation. - */ -void *pico_tree_delete(struct pico_tree *tree, void *key) -{ - return pico_tree_delete_implementation(tree, key, USE_PICO_ZALLOC); -} - -static inline void if_nodecolor_black_fix_collisions(struct pico_tree *tree, struct pico_tree_node *temp, uint8_t nodeColor) -{ - /* deleted node is black, this will mess up the black path property */ - if(nodeColor == BLACK) - fix_delete_collisions(tree, temp); -} - -void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator) -{ - struct pico_tree_node *temp; - uint8_t nodeColor; /* keeps the color of the node to be deleted */ - void *lkey; /* keeps a copy of the key which will be removed */ - struct pico_tree_node *delete; /* keeps a copy of the node to be extracted */ - if (!key) - return NULL; - delete = pico_tree_findNode(tree, key); - - /* this key isn't in the tree, bail out */ - if(!delete) - return NULL; - - lkey = delete->keyValue; - nodeColor = pico_tree_delete_check_switch(tree, delete, &temp); - - if_nodecolor_black_fix_collisions(tree, temp, nodeColor); - - if(allocator == USE_PICO_ZALLOC) - PICO_FREE(delete); - -#ifdef PICO_SUPPORT_MM - else - pico_mem_page0_free(delete); -#endif - return lkey; -} - -int pico_tree_empty(struct pico_tree *tree) -{ - return (!tree->root || IS_LEAF(tree->root)); -} - -/* - * Private functions - */ -static void rotateToLeft(struct pico_tree*tree, struct pico_tree_node*node) -{ - struct pico_tree_node*temp; - - temp = node->rightChild; - - if(temp == &LEAF) return; - - node->rightChild = temp->leftChild; - - if(IS_NOT_LEAF(temp->leftChild)) - temp->leftChild->parent = node; - - temp->parent = node->parent; - - if(IS_LEAF(node->parent)) - tree->root = temp; - else - if(node == node->parent->leftChild) - node->parent->leftChild = temp; - else - node->parent->rightChild = temp; - - temp->leftChild = node; - node->parent = temp; -} - - -static void rotateToRight(struct pico_tree *tree, struct pico_tree_node *node) -{ - struct pico_tree_node*temp; - - temp = node->leftChild; - node->leftChild = temp->rightChild; - - if(temp == &LEAF) return; - - if(IS_NOT_LEAF(temp->rightChild)) - temp->rightChild->parent = node; - - temp->parent = node->parent; - - if(IS_LEAF(node->parent)) - tree->root = temp; - else - if(node == node->parent->rightChild) - node->parent->rightChild = temp; - else - node->parent->leftChild = temp; - - temp->rightChild = node; - node->parent = temp; - return; -} - -static struct pico_tree_node *create_node(struct pico_tree *tree, void*key, uint8_t allocator) -{ - struct pico_tree_node *temp = NULL; - IGNORE_PARAMETER(tree); - if(allocator == USE_PICO_ZALLOC) - temp = (struct pico_tree_node *)PICO_ZALLOC(sizeof(struct pico_tree_node)); - -#ifdef PICO_SUPPORT_MM - else - temp = (struct pico_tree_node *)pico_mem_page0_zalloc(sizeof(struct pico_tree_node)); -#endif - - if(!temp) - return NULL; - - temp->keyValue = key; - temp->parent = &LEAF; - temp->leftChild = &LEAF; - temp->rightChild = &LEAF; - /* by default every new node is red */ - temp->color = RED; - return temp; -} - -/* - * This function fixes the possible collisions in the tree. - * Eg. if a node is red his children must be black ! - */ -static void fix_insert_collisions(struct pico_tree*tree, struct pico_tree_node*node) -{ - struct pico_tree_node*temp; - - while(node->parent->color == RED && IS_NOT_LEAF(GRANPA(node))) - { - if(AM_I_RIGHT_CHILD(node->parent)) - { - temp = GRANPA(node)->leftChild; - if(temp->color == RED) { - node->parent->color = BLACK; - temp->color = BLACK; - GRANPA(node)->color = RED; - node = GRANPA(node); - } - else if(temp->color == BLACK) { - if(node == node->parent->leftChild) { - node = node->parent; - rotateToRight(tree, node); - } - - node->parent->color = BLACK; - GRANPA(node)->color = RED; - rotateToLeft(tree, GRANPA(node)); - } - } - else if(AM_I_LEFT_CHILD(node->parent)) - { - temp = GRANPA(node)->rightChild; - if(temp->color == RED) { - node->parent->color = BLACK; - temp->color = BLACK; - GRANPA(node)->color = RED; - node = GRANPA(node); - } - else if(temp->color == BLACK) { - if(AM_I_RIGHT_CHILD(node)) { - node = node->parent; - rotateToLeft(tree, node); - } - - node->parent->color = BLACK; - GRANPA(node)->color = RED; - rotateToRight(tree, GRANPA(node)); - } - } - } - /* make sure that the root of the tree stays black */ - tree->root->color = BLACK; -} - -static void switchNodes(struct pico_tree*tree, struct pico_tree_node*nodeA, struct pico_tree_node*nodeB) -{ - - if(IS_LEAF(nodeA->parent)) - tree->root = nodeB; - else - if(IS_NOT_LEAF(nodeA)) - { - if(AM_I_LEFT_CHILD(nodeA)) - nodeA->parent->leftChild = nodeB; - else - nodeA->parent->rightChild = nodeB; - } - - if(IS_NOT_LEAF(nodeB)) nodeB->parent = nodeA->parent; - -} - -/* - * This function fixes the possible collisions in the tree. - * Eg. if a node is red his children must be black ! - * In this case the function fixes the constant black path property. - */ -static void fix_delete_collisions(struct pico_tree*tree, struct pico_tree_node *node) -{ - struct pico_tree_node*temp; - - while( node != tree->root && node->color == BLACK && IS_NOT_LEAF(node)) - { - if(AM_I_LEFT_CHILD(node)) { - - temp = node->parent->rightChild; - if(temp->color == RED) - { - temp->color = BLACK; - node->parent->color = RED; - rotateToLeft(tree, node->parent); - temp = node->parent->rightChild; - } - - if(temp->leftChild->color == BLACK && temp->rightChild->color == BLACK) - { - temp->color = RED; - node = node->parent; - } - else - { - if(temp->rightChild->color == BLACK) - { - temp->leftChild->color = BLACK; - temp->color = RED; - rotateToRight(tree, temp); - temp = temp->parent->rightChild; - } - - temp->color = node->parent->color; - node->parent->color = BLACK; - temp->rightChild->color = BLACK; - rotateToLeft(tree, node->parent); - node = tree->root; - } - } - else{ - temp = node->parent->leftChild; - if(temp->color == RED) - { - temp->color = BLACK; - node->parent->color = RED; - rotateToRight(tree, node->parent); - temp = node->parent->leftChild; - } - - if(temp->rightChild->color == BLACK && temp->leftChild->color == BLACK) - { - temp->color = RED; - node = node->parent; - } - else{ - if(temp->leftChild->color == BLACK) - { - temp->rightChild->color = BLACK; - temp->color = RED; - rotateToLeft(tree, temp); - temp = temp->parent->leftChild; - } - - temp->color = node->parent->color; - node->parent->color = BLACK; - temp->leftChild->color = BLACK; - rotateToRight(tree, node->parent); - node = tree->root; - } - } - } - node->color = BLACK; -} diff --git a/ext/picotcp/uncrustify.cfg b/ext/picotcp/uncrustify.cfg deleted file mode 100644 index ba664df..0000000 --- a/ext/picotcp/uncrustify.cfg +++ /dev/null @@ -1,1579 +0,0 @@ -# Uncrustify 0.60 - -# -# General options -# - -# The type of line endings -newlines = lf # auto/lf/crlf/cr - -# The original size of tabs in the input -input_tab_size = 4 # number - -# The size of tabs in the output (only used if align_with_tabs=true) -output_tab_size = 4 # number - -# The ASCII value of the string escape char, usually 92 (\) or 94 (^). (Pawn) -string_escape_char = 92 # number - -# Alternate string escape char for Pawn. Only works right before the quote char. -string_escape_char2 = 0 # number - -# Allow interpreting '>=' and '>>=' as part of a template in 'void f(list>=val);'. -# If true (default), 'assert(x<0 && y>=3)' will be broken. -# Improvements to template detection may make this option obsolete. -tok_split_gte = false # false/true - -# Control what to do with the UTF-8 BOM (recommend 'remove') -utf8_bom = ignore # ignore/add/remove/force - -# If the file contains bytes with values between 128 and 255, but is not UTF-8, then output as UTF-8 -utf8_byte = false # false/true - -# Force the output encoding to UTF-8 -utf8_force = false # false/true - -# -# Indenting -# - -# The number of columns to indent per level. -# Usually 2, 3, 4, or 8. -indent_columns = 4 # number - -# The continuation indent. If non-zero, this overrides the indent of '(' and '=' continuation indents. -# For FreeBSD, this is set to 4. Negative value is absolute and not increased for each ( level -indent_continue = 0 # number - -# How to use tabs when indenting code -# 0=spaces only -# 1=indent with tabs to brace level, align with spaces -# 2=indent and align with tabs, using spaces when not on a tabstop -indent_with_tabs = 0 # number - -# Comments that are not a brace level are indented with tabs on a tabstop. -# Requires indent_with_tabs=2. If false, will use spaces. -indent_cmt_with_tabs = false # false/true - -# Whether to indent strings broken by '\' so that they line up -indent_align_string = false # false/true - -# The number of spaces to indent multi-line XML strings. -# Requires indent_align_string=True -indent_xml_string = 0 # number - -# Spaces to indent '{' from level -indent_brace = 0 # number - -# Whether braces are indented to the body level -indent_braces = false # false/true - -# Disabled indenting function braces if indent_braces is true -indent_braces_no_func = false # false/true - -# Disabled indenting class braces if indent_braces is true -indent_braces_no_class = false # false/true - -# Disabled indenting struct braces if indent_braces is true -indent_braces_no_struct = false # false/true - -# Indent based on the size of the brace parent, i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. -indent_brace_parent = false # false/true - -# Whether the 'namespace' body is indented -indent_namespace = false # false/true - -# The number of spaces to indent a namespace block -indent_namespace_level = 0 # number - -# If the body of the namespace is longer than this number, it won't be indented. -# Requires indent_namespace=true. Default=0 (no limit) -indent_namespace_limit = 0 # number - -# Whether the 'extern "C"' body is indented -indent_extern = false # false/true - -# Whether the 'class' body is indented -indent_class = false # false/true - -# Whether to indent the stuff after a leading class colon -indent_class_colon = false # false/true - -# Virtual indent from the ':' for member initializers. Default is 2 -indent_ctor_init_leading = 2 # number - -# Additional indenting for constructor initializer list -indent_ctor_init = 0 # number - -# False=treat 'else\nif' as 'else if' for indenting purposes -# True=indent the 'if' one level -indent_else_if = false # false/true - -# Amount to indent variable declarations after a open brace. neg=relative, pos=absolute -indent_var_def_blk = 0 # number - -# Indent continued variable declarations instead of aligning. -indent_var_def_cont = false # false/true - -# True: force indentation of function definition to start in column 1 -# False: use the default behavior -indent_func_def_force_col1 = false # false/true - -# True: indent continued function call parameters one indent level -# False: align parameters under the open paren -indent_func_call_param = false # false/true - -# Same as indent_func_call_param, but for function defs -indent_func_def_param = false # false/true - -# Same as indent_func_call_param, but for function protos -indent_func_proto_param = false # false/true - -# Same as indent_func_call_param, but for class declarations -indent_func_class_param = false # false/true - -# Same as indent_func_call_param, but for class variable constructors -indent_func_ctor_var_param = false # false/true - -# Same as indent_func_call_param, but for templates -indent_template_param = false # false/true - -# Double the indent for indent_func_xxx_param options -indent_func_param_double = false # false/true - -# Indentation column for standalone 'const' function decl/proto qualifier -indent_func_const = 0 # number - -# Indentation column for standalone 'throw' function decl/proto qualifier -indent_func_throw = 0 # number - -# The number of spaces to indent a continued '->' or '.' -# Usually set to 0, 1, or indent_columns. -indent_member = 0 # number - -# Spaces to indent single line ('//') comments on lines before code -indent_sing_line_comments = 0 # number - -# If set, will indent trailing single line ('//') comments relative -# to the code instead of trying to keep the same absolute column -indent_relative_single_line_comments = false # false/true - -# Spaces to indent 'case' from 'switch' -# Usually 0 or indent_columns. -indent_switch_case = 0 # number - -# Spaces to shift the 'case' line, without affecting any other lines -# Usually 0. -indent_case_shift = 0 # number - -# Spaces to indent '{' from 'case'. -# By default, the brace will appear under the 'c' in case. -# Usually set to 0 or indent_columns. -indent_case_brace = 0 # number - -# Whether to indent comments found in first column -indent_col1_comment = false # false/true - -# How to indent goto labels -# >0 : absolute column where 1 is the leftmost column -# <=0 : subtract from brace indent -indent_label = 1 # number - -# Same as indent_label, but for access specifiers that are followed by a colon -indent_access_spec = 1 # number - -# Indent the code after an access specifier by one level. -# If set, this option forces 'indent_access_spec=0' -indent_access_spec_body = false # false/true - -# If an open paren is followed by a newline, indent the next line so that it lines up after the open paren (not recommended) -indent_paren_nl = false # false/true - -# Controls the indent of a close paren after a newline. -# 0: Indent to body level -# 1: Align under the open paren -# 2: Indent to the brace level -indent_paren_close = 0 # number - -# Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren -indent_comma_paren = false # false/true - -# Controls the indent of a BOOL operator when inside a paren.If TRUE, aligns under the open paren -indent_bool_paren = false # false/true - -# If 'indent_bool_paren' is true, controls the indent of the first expression. If TRUE, aligns the first expression to the following ones -indent_first_bool_expr = false # false/true - -# If an open square is followed by a newline, indent the next line so that it lines up after the open square (not recommended) -indent_square_nl = false # false/true - -# Don't change the relative indent of ESQL/C 'EXEC SQL' bodies -indent_preserve_sql = false # false/true - -# Align continued statements at the '='. Default=True -# If FALSE or the '=' is followed by a newline, the next line is indent one tab. -indent_align_assign = true # false/true - -# Indent OC blocks at brace level instead of usual rules. -indent_oc_block = false # false/true - -# Indent OC blocks in a message relative to the parameter name. -# 0=use indent_oc_block rules, 1+=spaces to indent -indent_oc_block_msg = 0 # number - -# Minimum indent for subsequent parameters -indent_oc_msg_colon = 0 # number - -# -# Spacing options -# - -# Add or remove space around arithmetic operator '+', '-', '/', '*', etc -sp_arith = add # ignore/add/remove/force - -# Add or remove space around assignment operator '=', '+=', etc -sp_assign = add # ignore/add/remove/force - -# Add or remove space around '=' in C++11 lambda capture specifications. Overrides sp_assign -sp_cpp_lambda_assign = ignore # ignore/add/remove/force - -# Add or remove space after the capture specification in C++11 lambda. -sp_cpp_lambda_paren = ignore # ignore/add/remove/force - -# Add or remove space around assignment operator '=' in a prototype -sp_assign_default = add # ignore/add/remove/force - -# Add or remove space before assignment operator '=', '+=', etc. Overrides sp_assign. -sp_before_assign = add # ignore/add/remove/force - -# Add or remove space after assignment operator '=', '+=', etc. Overrides sp_assign. -sp_after_assign = add # ignore/add/remove/force - -# Add or remove space around assignment '=' in enum -sp_enum_assign = add # ignore/add/remove/force - -# Add or remove space before assignment '=' in enum. Overrides sp_enum_assign. -sp_enum_before_assign = add # ignore/add/remove/force - -# Add or remove space after assignment '=' in enum. Overrides sp_enum_assign. -sp_enum_after_assign = add # ignore/add/remove/force - -# Add or remove space around preprocessor '##' concatenation operator. Default=Add -sp_pp_concat = add # ignore/add/remove/force - -# Add or remove space after preprocessor '#' stringify operator. Also affects the '#@' charizing operator. -sp_pp_stringify = ignore # ignore/add/remove/force - -# Add or remove space before preprocessor '#' stringify operator as in '#define x(y) L#y'. -sp_before_pp_stringify = ignore # ignore/add/remove/force - -# Add or remove space around boolean operators '&&' and '||' -sp_bool = add # ignore/add/remove/force - -# Add or remove space around compare operator '<', '>', '==', etc -sp_compare = add # ignore/add/remove/force - -# Add or remove space inside '(' and ')' -sp_inside_paren = remove # ignore/add/remove/force - -# Add or remove space between nested parens -sp_paren_paren = remove # ignore/add/remove/force - -# Whether to balance spaces inside nested parens -sp_balance_nested_parens = false # false/true - -# Add or remove space between ')' and '{' -sp_paren_brace = ignore # ignore/add/remove/force - -# Add or remove space before pointer star '*' -sp_before_ptr_star = ignore # ignore/add/remove/force - -# Add or remove space before pointer star '*' that isn't followed by a variable name -# If set to 'ignore', sp_before_ptr_star is used instead. -sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force - -# Add or remove space between pointer stars '*' -sp_between_ptr_star = ignore # ignore/add/remove/force - -# Add or remove space after pointer star '*', if followed by a word. -sp_after_ptr_star = remove # ignore/add/remove/force - -# Add or remove space after a pointer star '*', if followed by a func proto/def. -sp_after_ptr_star_func = ignore # ignore/add/remove/force - -# Add or remove space after a pointer star '*', if followed by an open paren (function types). -sp_ptr_star_paren = ignore # ignore/add/remove/force - -# Add or remove space before a pointer star '*', if followed by a func proto/def. -sp_before_ptr_star_func = ignore # ignore/add/remove/force - -# Add or remove space before a reference sign '&' -sp_before_byref = ignore # ignore/add/remove/force - -# Add or remove space before a reference sign '&' that isn't followed by a variable name -# If set to 'ignore', sp_before_byref is used instead. -sp_before_unnamed_byref = ignore # ignore/add/remove/force - -# Add or remove space after reference sign '&', if followed by a word. -sp_after_byref = remove # ignore/add/remove/force - -# Add or remove space after a reference sign '&', if followed by a func proto/def. -sp_after_byref_func = remove # ignore/add/remove/force - -# Add or remove space before a reference sign '&', if followed by a func proto/def. -sp_before_byref_func = ignore # ignore/add/remove/force - -# Add or remove space between type and word. Default=Force -sp_after_type = force # ignore/add/remove/force - -# Add or remove space before the paren in the D constructs 'template Foo(' and 'class Foo('. -sp_before_template_paren = ignore # ignore/add/remove/force - -# Add or remove space in 'template <' vs 'template<'. -# If set to ignore, sp_before_angle is used. -sp_template_angle = ignore # ignore/add/remove/force - -# Add or remove space before '<>' -sp_before_angle = ignore # ignore/add/remove/force - -# Add or remove space inside '<' and '>' -sp_inside_angle = ignore # ignore/add/remove/force - -# Add or remove space after '<>' -sp_after_angle = ignore # ignore/add/remove/force - -# Add or remove space between '<>' and '(' as found in 'new List();' -sp_angle_paren = ignore # ignore/add/remove/force - -# Add or remove space between '<>' and a word as in 'List m;' -sp_angle_word = ignore # ignore/add/remove/force - -# Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add -sp_angle_shift = add # ignore/add/remove/force - -# Permit removal of the space between '>>' in 'foo >' (C++11 only). Default=False -# sp_angle_shift cannot remove the space without this option. -sp_permit_cpp11_shift = false # false/true - -# Add or remove space before '(' of 'if', 'for', 'switch', and 'while' -sp_before_sparen = ignore # ignore/add/remove/force - -# Add or remove space inside if-condition '(' and ')' -sp_inside_sparen = ignore # ignore/add/remove/force - -# Add or remove space before if-condition ')'. Overrides sp_inside_sparen. -sp_inside_sparen_close = ignore # ignore/add/remove/force - -# Add or remove space before if-condition '('. Overrides sp_inside_sparen. -sp_inside_sparen_open = ignore # ignore/add/remove/force - -# Add or remove space after ')' of 'if', 'for', 'switch', and 'while' -sp_after_sparen = ignore # ignore/add/remove/force - -# Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while' -sp_sparen_brace = ignore # ignore/add/remove/force - -# Add or remove space between 'invariant' and '(' in the D language. -sp_invariant_paren = ignore # ignore/add/remove/force - -# Add or remove space after the ')' in 'invariant (C) c' in the D language. -sp_after_invariant_paren = ignore # ignore/add/remove/force - -# Add or remove space before empty statement ';' on 'if', 'for' and 'while' -sp_special_semi = ignore # ignore/add/remove/force - -# Add or remove space before ';'. Default=Remove -sp_before_semi = remove # ignore/add/remove/force - -# Add or remove space before ';' in non-empty 'for' statements -sp_before_semi_for = ignore # ignore/add/remove/force - -# Add or remove space before a semicolon of an empty part of a for statement. -sp_before_semi_for_empty = ignore # ignore/add/remove/force - -# Add or remove space after ';', except when followed by a comment. Default=Add -sp_after_semi = remove # ignore/add/remove/force - -# Add or remove space after ';' in non-empty 'for' statements. Default=Force -sp_after_semi_for = force # ignore/add/remove/force - -# Add or remove space after the final semicolon of an empty part of a for statement: for ( ; ; ). -sp_after_semi_for_empty = ignore # ignore/add/remove/force - -# Add or remove space before '[' (except '[]') -sp_before_square = ignore # ignore/add/remove/force - -# Add or remove space before '[]' -sp_before_squares = ignore # ignore/add/remove/force - -# Add or remove space inside a non-empty '[' and ']' -sp_inside_square = ignore # ignore/add/remove/force - -# Add or remove space after ',' -sp_after_comma = add # ignore/add/remove/force - -# Add or remove space before ',' -sp_before_comma = remove # ignore/add/remove/force - -# Add or remove space between an open paren and comma: '(,' vs '( ,' -sp_paren_comma = force # ignore/add/remove/force - -# Add or remove space before the variadic '...' when preceded by a non-punctuator -sp_before_ellipsis = ignore # ignore/add/remove/force - -# Add or remove space after class ':' -sp_after_class_colon = ignore # ignore/add/remove/force - -# Add or remove space before class ':' -sp_before_class_colon = ignore # ignore/add/remove/force - -# Add or remove space before case ':'. Default=Remove -sp_before_case_colon = remove # ignore/add/remove/force - -# Add or remove space between 'operator' and operator sign -sp_after_operator = ignore # ignore/add/remove/force - -# Add or remove space between the operator symbol and the open paren, as in 'operator ++(' -sp_after_operator_sym = ignore # ignore/add/remove/force - -# Add or remove space after C/D cast, i.e. 'cast(int)a' vs 'cast(int) a' or '(int)a' vs '(int) a' -sp_after_cast = ignore # ignore/add/remove/force - -# Add or remove spaces inside cast parens -sp_inside_paren_cast = ignore # ignore/add/remove/force - -# Add or remove space between the type and open paren in a C++ cast, i.e. 'int(exp)' vs 'int (exp)' -sp_cpp_cast_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'sizeof' and '(' -sp_sizeof_paren = ignore # ignore/add/remove/force - -# Add or remove space after the tag keyword (Pawn) -sp_after_tag = ignore # ignore/add/remove/force - -# Add or remove space inside enum '{' and '}' -sp_inside_braces_enum = ignore # ignore/add/remove/force - -# Add or remove space inside struct/union '{' and '}' -sp_inside_braces_struct = ignore # ignore/add/remove/force - -# Add or remove space inside '{' and '}' -sp_inside_braces = ignore # ignore/add/remove/force - -# Add or remove space inside '{}' -sp_inside_braces_empty = ignore # ignore/add/remove/force - -# Add or remove space between return type and function name -# A minimum of 1 is forced except for pointer return types. -sp_type_func = ignore # ignore/add/remove/force - -# Add or remove space between function name and '(' on function declaration -sp_func_proto_paren = ignore # ignore/add/remove/force - -# Add or remove space between function name and '(' on function definition -sp_func_def_paren = ignore # ignore/add/remove/force - -# Add or remove space inside empty function '()' -sp_inside_fparens = ignore # ignore/add/remove/force - -# Add or remove space inside function '(' and ')' -sp_inside_fparen = ignore # ignore/add/remove/force - -# Add or remove space inside the first parens in the function type: 'void (*x)(...)' -sp_inside_tparen = ignore # ignore/add/remove/force - -# Add or remove between the parens in the function type: 'void (*x)(...)' -sp_after_tparen_close = ignore # ignore/add/remove/force - -# Add or remove space between ']' and '(' when part of a function call. -sp_square_fparen = ignore # ignore/add/remove/force - -# Add or remove space between ')' and '{' of function -sp_fparen_brace = ignore # ignore/add/remove/force - -# Add or remove space between function name and '(' on function calls -sp_func_call_paren = ignore # ignore/add/remove/force - -# Add or remove space between function name and '()' on function calls without parameters. -# If set to 'ignore' (the default), sp_func_call_paren is used. -sp_func_call_paren_empty = ignore # ignore/add/remove/force - -# Add or remove space between the user function name and '(' on function calls -# You need to set a keyword to be a user function, like this: 'set func_call_user _' in the config file. -sp_func_call_user_paren = ignore # ignore/add/remove/force - -# Add or remove space between a constructor/destructor and the open paren -sp_func_class_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'return' and '(' -sp_return_paren = ignore # ignore/add/remove/force - -# Add or remove space between '__attribute__' and '(' -sp_attribute_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'defined' and '(' in '#if defined (FOO)' -sp_defined_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'throw' and '(' in 'throw (something)' -sp_throw_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'throw' and anything other than '(' as in '@throw [...];' -sp_after_throw = ignore # ignore/add/remove/force - -# Add or remove space between 'catch' and '(' in 'catch (something) { }' -# If set to ignore, sp_before_sparen is used. -sp_catch_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'version' and '(' in 'version (something) { }' (D language) -# If set to ignore, sp_before_sparen is used. -sp_version_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'scope' and '(' in 'scope (something) { }' (D language) -# If set to ignore, sp_before_sparen is used. -sp_scope_paren = ignore # ignore/add/remove/force - -# Add or remove space between macro and value -sp_macro = ignore # ignore/add/remove/force - -# Add or remove space between macro function ')' and value -sp_macro_func = ignore # ignore/add/remove/force - -# Add or remove space between 'else' and '{' if on the same line -sp_else_brace = ignore # ignore/add/remove/force - -# Add or remove space between '}' and 'else' if on the same line -sp_brace_else = ignore # ignore/add/remove/force - -# Add or remove space between '}' and the name of a typedef on the same line -sp_brace_typedef = ignore # ignore/add/remove/force - -# Add or remove space between 'catch' and '{' if on the same line -sp_catch_brace = ignore # ignore/add/remove/force - -# Add or remove space between '}' and 'catch' if on the same line -sp_brace_catch = ignore # ignore/add/remove/force - -# Add or remove space between 'finally' and '{' if on the same line -sp_finally_brace = ignore # ignore/add/remove/force - -# Add or remove space between '}' and 'finally' if on the same line -sp_brace_finally = ignore # ignore/add/remove/force - -# Add or remove space between 'try' and '{' if on the same line -sp_try_brace = ignore # ignore/add/remove/force - -# Add or remove space between get/set and '{' if on the same line -sp_getset_brace = ignore # ignore/add/remove/force - -# Add or remove space before the '::' operator -sp_before_dc = ignore # ignore/add/remove/force - -# Add or remove space after the '::' operator -sp_after_dc = ignore # ignore/add/remove/force - -# Add or remove around the D named array initializer ':' operator -sp_d_array_colon = ignore # ignore/add/remove/force - -# Add or remove space after the '!' (not) operator. Default=Remove -sp_not = remove # ignore/add/remove/force - -# Add or remove space after the '~' (invert) operator. Default=Remove -sp_inv = remove # ignore/add/remove/force - -# Add or remove space after the '&' (address-of) operator. Default=Remove -# This does not affect the spacing after a '&' that is part of a type. -sp_addr = remove # ignore/add/remove/force - -# Add or remove space around the '.' or '->' operators. Default=Remove -sp_member = remove # ignore/add/remove/force - -# Add or remove space after the '*' (dereference) operator. Default=Remove -# This does not affect the spacing after a '*' that is part of a type. -sp_deref = remove # ignore/add/remove/force - -# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. Default=Remove -sp_sign = remove # ignore/add/remove/force - -# Add or remove space before or after '++' and '--', as in '(--x)' or 'y++;'. Default=Remove -sp_incdec = remove # ignore/add/remove/force - -# Add or remove space before a backslash-newline at the end of a line. Default=Add -sp_before_nl_cont = add # ignore/add/remove/force - -# Add or remove space after the scope '+' or '-', as in '-(void) foo;' or '+(int) bar;' -sp_after_oc_scope = ignore # ignore/add/remove/force - -# Add or remove space after the colon in message specs -# '-(int) f:(int) x;' vs '-(int) f: (int) x;' -sp_after_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space before the colon in message specs -# '-(int) f: (int) x;' vs '-(int) f : (int) x;' -sp_before_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space after the colon in immutable dictionary expression -# 'NSDictionary *test = @{@"foo" :@"bar"};' -sp_after_oc_dict_colon = ignore # ignore/add/remove/force - -# Add or remove space before the colon in immutable dictionary expression -# 'NSDictionary *test = @{@"foo" :@"bar"};' -sp_before_oc_dict_colon = ignore # ignore/add/remove/force - -# Add or remove space after the colon in message specs -# '[object setValue:1];' vs '[object setValue: 1];' -sp_after_send_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space before the colon in message specs -# '[object setValue:1];' vs '[object setValue :1];' -sp_before_send_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space after the (type) in message specs -# '-(int)f: (int) x;' vs '-(int)f: (int)x;' -sp_after_oc_type = ignore # ignore/add/remove/force - -# Add or remove space after the first (type) in message specs -# '-(int) f:(int)x;' vs '-(int)f:(int)x;' -sp_after_oc_return_type = ignore # ignore/add/remove/force - -# Add or remove space between '@selector' and '(' -# '@selector(msgName)' vs '@selector (msgName)' -# Also applies to @protocol() constructs -sp_after_oc_at_sel = ignore # ignore/add/remove/force - -# Add or remove space between '@selector(x)' and the following word -# '@selector(foo) a:' vs '@selector(foo)a:' -sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force - -# Add or remove space inside '@selector' parens -# '@selector(foo)' vs '@selector( foo )' -# Also applies to @protocol() constructs -sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force - -# Add or remove space before a block pointer caret -# '^int (int arg){...}' vs. ' ^int (int arg){...}' -sp_before_oc_block_caret = ignore # ignore/add/remove/force - -# Add or remove space after a block pointer caret -# '^int (int arg){...}' vs. '^ int (int arg){...}' -sp_after_oc_block_caret = ignore # ignore/add/remove/force - -# Add or remove space between the receiver and selector in a message. -# '[receiver selector ...]' -sp_after_oc_msg_receiver = ignore # ignore/add/remove/force - -# Add or remove space after @property. -sp_after_oc_property = ignore # ignore/add/remove/force - -# Add or remove space around the ':' in 'b ? t : f' -sp_cond_colon = ignore # ignore/add/remove/force - -# Add or remove space around the '?' in 'b ? t : f' -sp_cond_question = ignore # ignore/add/remove/force - -# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make sense here. -sp_case_label = ignore # ignore/add/remove/force - -# Control the space around the D '..' operator. -sp_range = ignore # ignore/add/remove/force - -# Control the spacing after ':' in 'for (TYPE VAR : EXPR)' (Java) -sp_after_for_colon = ignore # ignore/add/remove/force - -# Control the spacing before ':' in 'for (TYPE VAR : EXPR)' (Java) -sp_before_for_colon = ignore # ignore/add/remove/force - -# Control the spacing in 'extern (C)' (D) -sp_extern_paren = ignore # ignore/add/remove/force - -# Control the space after the opening of a C++ comment '// A' vs '//A' -sp_cmt_cpp_start = ignore # ignore/add/remove/force - -# Controls the spaces between #else or #endif and a trailing comment -sp_endif_cmt = ignore # ignore/add/remove/force - -# Controls the spaces after 'new', 'delete', and 'delete[]' -sp_after_new = ignore # ignore/add/remove/force - -# Controls the spaces before a trailing or embedded comment -sp_before_tr_emb_cmt = ignore # ignore/add/remove/force - -# Number of spaces before a trailing or embedded comment -sp_num_before_tr_emb_cmt = 0 # number - -# Control space between a Java annotation and the open paren. -sp_annotation_paren = ignore # ignore/add/remove/force - -# -# Code alignment (not left column spaces/tabs) -# - -# Whether to keep non-indenting tabs -align_keep_tabs = false # false/true - -# Whether to use tabs for aligning -align_with_tabs = false # false/true - -# Whether to bump out to the next tab when aligning -align_on_tabstop = false # false/true - -# Whether to left-align numbers -align_number_left = false # false/true - -# Align variable definitions in prototypes and functions -align_func_params = false # false/true - -# Align parameters in single-line functions that have the same name. -# The function names must already be aligned with each other. -align_same_func_call_params = false # false/true - -# The span for aligning variable definitions (0=don't align) -align_var_def_span = 0 # number - -# How to align the star in variable definitions. -# 0=Part of the type 'void * foo;' -# 1=Part of the variable 'void *foo;' -# 2=Dangling 'void *foo;' -align_var_def_star_style = 1 # number - -# How to align the '&' in variable definitions. -# 0=Part of the type -# 1=Part of the variable -# 2=Dangling -align_var_def_amp_style = 1 # number - -# The threshold for aligning variable definitions (0=no limit) -align_var_def_thresh = 0 # number - -# The gap for aligning variable definitions -align_var_def_gap = 0 # number - -# Whether to align the colon in struct bit fields -align_var_def_colon = false # false/true - -# Whether to align any attribute after the variable name -align_var_def_attribute = false # false/true - -# Whether to align inline struct/enum/union variable definitions -align_var_def_inline = false # false/true - -# The span for aligning on '=' in assignments (0=don't align) -align_assign_span = 0 # number - -# The threshold for aligning on '=' in assignments (0=no limit) -align_assign_thresh = 0 # number - -# The span for aligning on '=' in enums (0=don't align) -align_enum_equ_span = 0 # number - -# The threshold for aligning on '=' in enums (0=no limit) -align_enum_equ_thresh = 0 # number - -# The span for aligning struct/union (0=don't align) -align_var_struct_span = 0 # number - -# The threshold for aligning struct/union member definitions (0=no limit) -align_var_struct_thresh = 0 # number - -# The gap for aligning struct/union member definitions -align_var_struct_gap = 0 # number - -# The span for aligning struct initializer values (0=don't align) -align_struct_init_span = 0 # number - -# The minimum space between the type and the synonym of a typedef -align_typedef_gap = 0 # number - -# The span for aligning single-line typedefs (0=don't align) -align_typedef_span = 0 # number - -# How to align typedef'd functions with other typedefs -# 0: Don't mix them at all -# 1: align the open paren with the types -# 2: align the function type name with the other type names -align_typedef_func = 0 # number - -# Controls the positioning of the '*' in typedefs. Just try it. -# 0: Align on typedef type, ignore '*' -# 1: The '*' is part of type name: typedef int *pint; -# 2: The '*' is part of the type, but dangling: typedef int *pint; -align_typedef_star_style = 0 # number - -# Controls the positioning of the '&' in typedefs. Just try it. -# 0: Align on typedef type, ignore '&' -# 1: The '&' is part of type name: typedef int &pint; -# 2: The '&' is part of the type, but dangling: typedef int &pint; -align_typedef_amp_style = 0 # number - -# The span for aligning comments that end lines (0=don't align) -align_right_cmt_span = 0 # number - -# If aligning comments, mix with comments after '}' and #endif with less than 3 spaces before the comment -align_right_cmt_mix = false # false/true - -# If a trailing comment is more than this number of columns away from the text it follows, -# it will qualify for being aligned. This has to be > 0 to do anything. -align_right_cmt_gap = 0 # number - -# Align trailing comment at or beyond column N; 'pulls in' comments as a bonus side effect (0=ignore) -align_right_cmt_at_col = 0 # number - -# The span for aligning function prototypes (0=don't align) -align_func_proto_span = 0 # number - -# Minimum gap between the return type and the function name. -align_func_proto_gap = 0 # number - -# Align function protos on the 'operator' keyword instead of what follows -align_on_operator = false # false/true - -# Whether to mix aligning prototype and variable declarations. -# If true, align_var_def_XXX options are used instead of align_func_proto_XXX options. -align_mix_var_proto = false # false/true - -# Align single-line functions with function prototypes, uses align_func_proto_span -align_single_line_func = false # false/true - -# Aligning the open brace of single-line functions. -# Requires align_single_line_func=true, uses align_func_proto_span -align_single_line_brace = false # false/true - -# Gap for align_single_line_brace. -align_single_line_brace_gap = 0 # number - -# The span for aligning ObjC msg spec (0=don't align) -align_oc_msg_spec_span = 0 # number - -# Whether to align macros wrapped with a backslash and a newline. -# This will not work right if the macro contains a multi-line comment. -align_nl_cont = false # false/true - -# # Align macro functions and variables together -align_pp_define_together = false # false/true - -# The minimum space between label and value of a preprocessor define -align_pp_define_gap = 0 # number - -# The span for aligning on '#define' bodies (0=don't align) -align_pp_define_span = 0 # number - -# Align lines that start with '<<' with previous '<<'. Default=true -align_left_shift = true # false/true - -# Span for aligning parameters in an Obj-C message call on the ':' (0=don't align) -align_oc_msg_colon_span = 0 # number - -# If true, always align with the first parameter, even if it is too short. -align_oc_msg_colon_first = false # false/true - -# Aligning parameters in an Obj-C '+' or '-' declaration on the ':' -align_oc_decl_colon = false # false/true - -# -# Newline adding and removing options -# - -# Whether to collapse empty blocks between '{' and '}' -nl_collapse_empty_body = false # false/true - -# Don't split one-line braced assignments - 'foo_t f = { 1, 2 };' -nl_assign_leave_one_liners = false # false/true - -# Don't split one-line braced statements inside a class xx { } body -nl_class_leave_one_liners = false # false/true - -# Don't split one-line enums: 'enum foo { BAR = 15 };' -nl_enum_leave_one_liners = false # false/true - -# Don't split one-line get or set functions -nl_getset_leave_one_liners = false # false/true - -# Don't split one-line function definitions - 'int foo() { return 0; }' -nl_func_leave_one_liners = false # false/true - -# Don't split one-line if/else statements - 'if(a) b++;' -nl_if_leave_one_liners = false # false/true - -# Don't split one-line OC messages -nl_oc_msg_leave_one_liner = false # false/true - -# Add or remove newlines at the start of the file -nl_start_of_file = ignore # ignore/add/remove/force - -# The number of newlines at the start of the file (only used if nl_start_of_file is 'add' or 'force' -nl_start_of_file_min = 0 # number - -# Add or remove newline at the end of the file -nl_end_of_file = ignore # ignore/add/remove/force - -# The number of newlines at the end of the file (only used if nl_end_of_file is 'add' or 'force') -nl_end_of_file_min = 0 # number - -# Add or remove newline between '=' and '{' -nl_assign_brace = ignore # ignore/add/remove/force - -# Add or remove newline between '=' and '[' (D only) -nl_assign_square = ignore # ignore/add/remove/force - -# Add or remove newline after '= [' (D only). Will also affect the newline before the ']' -nl_after_square_assign = ignore # ignore/add/remove/force - -# The number of blank lines after a block of variable definitions at the top of a function body -# 0 = No change (default) -nl_func_var_def_blk = 0 # number - -# The number of newlines before a block of typedefs -# 0 = No change (default) -nl_typedef_blk_start = 0 # number - -# The number of newlines after a block of typedefs -# 0 = No change (default) -nl_typedef_blk_end = 0 # number - -# The maximum consecutive newlines within a block of typedefs -# 0 = No change (default) -nl_typedef_blk_in = 0 # number - -# The number of newlines before a block of variable definitions not at the top of a function body -# 0 = No change (default) -nl_var_def_blk_start = 0 # number - -# The number of newlines after a block of variable definitions not at the top of a function body -# 0 = No change (default) -nl_var_def_blk_end = 0 # number - -# The maximum consecutive newlines within a block of variable definitions -# 0 = No change (default) -nl_var_def_blk_in = 0 # number - -# Add or remove newline between a function call's ')' and '{', as in: -# list_for_each(item, &list) { } -nl_fcall_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'enum' and '{' -nl_enum_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'struct and '{' -nl_struct_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'union' and '{' -nl_union_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'if' and '{' -nl_if_brace = ignore # ignore/add/remove/force - -# Add or remove newline between '}' and 'else' -nl_brace_else = ignore # ignore/add/remove/force - -# Add or remove newline between 'else if' and '{' -# If set to ignore, nl_if_brace is used instead -nl_elseif_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'else' and '{' -nl_else_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'else' and 'if' -nl_else_if = ignore # ignore/add/remove/force - -# Add or remove newline between '}' and 'finally' -nl_brace_finally = ignore # ignore/add/remove/force - -# Add or remove newline between 'finally' and '{' -nl_finally_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'try' and '{' -nl_try_brace = ignore # ignore/add/remove/force - -# Add or remove newline between get/set and '{' -nl_getset_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'for' and '{' -nl_for_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'catch' and '{' -nl_catch_brace = ignore # ignore/add/remove/force - -# Add or remove newline between '}' and 'catch' -nl_brace_catch = ignore # ignore/add/remove/force - -# Add or remove newline between 'while' and '{' -nl_while_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'scope (x)' and '{' (D) -nl_scope_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'unittest' and '{' (D) -nl_unittest_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'version (x)' and '{' (D) -nl_version_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'using' and '{' -nl_using_brace = ignore # ignore/add/remove/force - -# Add or remove newline between two open or close braces. -# Due to general newline/brace handling, REMOVE may not work. -nl_brace_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'do' and '{' -nl_do_brace = ignore # ignore/add/remove/force - -# Add or remove newline between '}' and 'while' of 'do' statement -nl_brace_while = ignore # ignore/add/remove/force - -# Add or remove newline between 'switch' and '{' -nl_switch_brace = ignore # ignore/add/remove/force - -# Add a newline between ')' and '{' if the ')' is on a different line than the if/for/etc. -# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch, and nl_catch_brace. -nl_multi_line_cond = false # false/true - -# Force a newline in a define after the macro name for multi-line defines. -nl_multi_line_define = false # false/true - -# Whether to put a newline before 'case' statement -nl_before_case = false # false/true - -# Add or remove newline between ')' and 'throw' -nl_before_throw = ignore # ignore/add/remove/force - -# Whether to put a newline after 'case' statement -nl_after_case = false # false/true - -# Add or remove a newline between a case ':' and '{'. Overrides nl_after_case. -nl_case_colon_brace = ignore # ignore/add/remove/force - -# Newline between namespace and { -nl_namespace_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'template<>' and whatever follows. -nl_template_class = ignore # ignore/add/remove/force - -# Add or remove newline between 'class' and '{' -nl_class_brace = ignore # ignore/add/remove/force - -# Add or remove newline after each ',' in the constructor member initialization -nl_class_init_args = ignore # ignore/add/remove/force - -# Add or remove newline between return type and function name in a function definition -nl_func_type_name = ignore # ignore/add/remove/force - -# Add or remove newline between return type and function name inside a class {} -# Uses nl_func_type_name or nl_func_proto_type_name if set to ignore. -nl_func_type_name_class = ignore # ignore/add/remove/force - -# Add or remove newline between function scope and name in a definition -# Controls the newline after '::' in 'void A::f() { }' -nl_func_scope_name = ignore # ignore/add/remove/force - -# Add or remove newline between return type and function name in a prototype -nl_func_proto_type_name = ignore # ignore/add/remove/force - -# Add or remove newline between a function name and the opening '(' -nl_func_paren = remove # ignore/add/remove/force - -# Add or remove newline between a function name and the opening '(' in the definition -nl_func_def_paren = remove # ignore/add/remove/force - -# Add or remove newline after '(' in a function declaration -nl_func_decl_start = remove # ignore/add/remove/force - -# Add or remove newline after '(' in a function definition -nl_func_def_start = remove # ignore/add/remove/force - -# Overrides nl_func_decl_start when there is only one parameter. -nl_func_decl_start_single = ignore # ignore/add/remove/force - -# Overrides nl_func_def_start when there is only one parameter. -nl_func_def_start_single = ignore # ignore/add/remove/force - -# Add or remove newline after each ',' in a function declaration -nl_func_decl_args = ignore # ignore/add/remove/force - -# Add or remove newline after each ',' in a function definition -nl_func_def_args = ignore # ignore/add/remove/force - -# Add or remove newline before the ')' in a function declaration -nl_func_decl_end = ignore # ignore/add/remove/force - -# Add or remove newline before the ')' in a function definition -nl_func_def_end = remove # ignore/add/remove/force - -# Overrides nl_func_decl_end when there is only one parameter. -nl_func_decl_end_single = ignore # ignore/add/remove/force - -# Overrides nl_func_def_end when there is only one parameter. -nl_func_def_end_single = ignore # ignore/add/remove/force - -# Add or remove newline between '()' in a function declaration. -nl_func_decl_empty = ignore # ignore/add/remove/force - -# Add or remove newline between '()' in a function definition. -nl_func_def_empty = ignore # ignore/add/remove/force - -# Whether to put each OC message parameter on a separate line -# See nl_oc_msg_leave_one_liner -nl_oc_msg_args = false # false/true - -# Add or remove newline between function signature and '{' -nl_fdef_brace = add # ignore/add/remove/force - -# Add or remove a newline between the return keyword and return expression. -nl_return_expr = ignore # ignore/add/remove/force - -# Whether to put a newline after semicolons, except in 'for' statements -nl_after_semicolon = true # false/true - -# Whether to put a newline after brace open. -# This also adds a newline before the matching brace close. -nl_after_brace_open = true # false/true - -# If nl_after_brace_open and nl_after_brace_open_cmt are true, a newline is -# placed between the open brace and a trailing single-line comment. -nl_after_brace_open_cmt = false # false/true - -# Whether to put a newline after a virtual brace open with a non-empty body. -# These occur in un-braced if/while/do/for statement bodies. -nl_after_vbrace_open = false # false/true - -# Whether to put a newline after a virtual brace open with an empty body. -# These occur in un-braced if/while/do/for statement bodies. -nl_after_vbrace_open_empty = false # false/true - -# Whether to put a newline after a brace close. -# Does not apply if followed by a necessary ';'. -nl_after_brace_close = false # false/true - -# Whether to put a newline after a virtual brace close. -# Would add a newline before return in: 'if (foo) a++; return;' -nl_after_vbrace_close = false # false/true - -# Control the newline between the close brace and 'b' in: 'struct { int a; } b;' -# Affects enums, unions, and structures. If set to ignore, uses nl_after_brace_close -nl_brace_struct_var = ignore # ignore/add/remove/force - -# Whether to alter newlines in '#define' macros -nl_define_macro = false # false/true - -# Whether to not put blanks after '#ifxx', '#elxx', or before '#endif' -nl_squeeze_ifdef = false # false/true - -# Add or remove blank line before 'if' -nl_before_if = ignore # ignore/add/remove/force - -# Add or remove blank line after 'if' statement -nl_after_if = add # ignore/add/remove/force - -# Add or remove blank line before 'for' -nl_before_for = ignore # ignore/add/remove/force - -# Add or remove blank line after 'for' statement -nl_after_for = remove # ignore/add/remove/force - -# Add or remove blank line before 'while' -nl_before_while = ignore # ignore/add/remove/force - -# Add or remove blank line after 'while' statement -nl_after_while = remove # ignore/add/remove/force - -# Add or remove blank line before 'switch' -nl_before_switch = ignore # ignore/add/remove/force - -# Add or remove blank line after 'switch' statement -nl_after_switch = ignore # ignore/add/remove/force - -# Add or remove blank line before 'do' -nl_before_do = ignore # ignore/add/remove/force - -# Add or remove blank line after 'do/while' statement -nl_after_do = ignore # ignore/add/remove/force - -# Whether to double-space commented-entries in struct/enum -nl_ds_struct_enum_cmt = false # false/true - -# Whether to double-space before the close brace of a struct/union/enum -# (lower priority than 'eat_blanks_before_close_brace') -nl_ds_struct_enum_close_brace = false # false/true - -# Add or remove a newline around a class colon. -# Related to pos_class_colon, nl_class_init_args, and pos_comma. -nl_class_colon = ignore # ignore/add/remove/force - -# Change simple unbraced if statements into a one-liner -# 'if(b)\n i++;' => 'if(b) i++;' -nl_create_if_one_liner = false # false/true - -# Change simple unbraced for statements into a one-liner -# 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);' -nl_create_for_one_liner = false # false/true - -# Change simple unbraced while statements into a one-liner -# 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);' -nl_create_while_one_liner = false # false/true - -# -# Positioning options -# - -# The position of arithmetic operators in wrapped expressions -pos_arith = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of assignment in wrapped expressions. -# Do not affect '=' followed by '{' -pos_assign = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of boolean operators in wrapped expressions -pos_bool = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of comparison operators in wrapped expressions -pos_compare = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of conditional (b ? t : f) operators in wrapped expressions -pos_conditional = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of the comma in wrapped expressions -pos_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of the comma in the constructor initialization list -pos_class_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of colons between constructor and member initialization -pos_class_colon = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# -# Line Splitting options -# - -# Try to limit code width to N number of columns -code_width = 0 # number - -# Whether to fully split long 'for' statements at semi-colons -ls_for_split_full = false # false/true - -# Whether to fully split long function protos/calls at commas -ls_func_split_full = false # false/true - -# Whether to split lines as close to code_width as possible and ignore some groupings -ls_code_width = false # false/true - -# -# Blank line options -# - -# The maximum consecutive newlines -nl_max = 0 # number - -# The number of newlines after a function prototype, if followed by another function prototype -nl_after_func_proto = 0 # number - -# The number of newlines after a function prototype, if not followed by another function prototype -nl_after_func_proto_group = 0 # number - -# The number of newlines after '}' of a multi-line function body -nl_after_func_body = 0 # number - -# The number of newlines after '}' of a multi-line function body in a class declaration -nl_after_func_body_class = 0 # number - -# The number of newlines after '}' of a single line function body -nl_after_func_body_one_liner = 0 # number - -# The minimum number of newlines before a multi-line comment. -# Doesn't apply if after a brace open or another multi-line comment. -nl_before_block_comment = 0 # number - -# The minimum number of newlines before a single-line C comment. -# Doesn't apply if after a brace open or other single-line C comments. -nl_before_c_comment = 0 # number - -# The minimum number of newlines before a CPP comment. -# Doesn't apply if after a brace open or other CPP comments. -nl_before_cpp_comment = 0 # number - -# Whether to force a newline after a multi-line comment. -nl_after_multiline_comment = false # false/true - -# The number of newlines after '}' or ';' of a struct/enum/union definition -nl_after_struct = 0 # number - -# The number of newlines after '}' or ';' of a class definition -nl_after_class = 0 # number - -# The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. -# Will not change the newline count if after a brace open. -# 0 = No change. -nl_before_access_spec = 0 # number - -# The number of newlines after a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. -# 0 = No change. -nl_after_access_spec = 0 # number - -# The number of newlines between a function def and the function comment. -# 0 = No change. -nl_comment_func_def = 0 # number - -# The number of newlines after a try-catch-finally block that isn't followed by a brace close. -# 0 = No change. -nl_after_try_catch_finally = 0 # number - -# The number of newlines before and after a property, indexer or event decl. -# 0 = No change. -nl_around_cs_property = 0 # number - -# The number of newlines between the get/set/add/remove handlers in C#. -# 0 = No change. -nl_between_get_set = 0 # number - -# Add or remove newline between C# property and the '{' -nl_property_brace = ignore # ignore/add/remove/force - -# Whether to remove blank lines after '{' -eat_blanks_after_open_brace = false # false/true - -# Whether to remove blank lines before '}' -eat_blanks_before_close_brace = false # false/true - -# How aggressively to remove extra newlines not in preproc. -# 0: No change -# 1: Remove most newlines not handled by other config -# 2: Remove all newlines and reformat completely by config -nl_remove_extra_newlines = 0 # number - -# Whether to put a blank line before 'return' statements, unless after an open brace. -nl_before_return = false # false/true - -# Whether to put a blank line after 'return' statements, unless followed by a close brace. -nl_after_return = false # false/true - -# Whether to put a newline after a Java annotation statement. -# Only affects annotations that are after a newline. -nl_after_annotation = ignore # ignore/add/remove/force - -# Controls the newline between two annotations. -nl_between_annotation = ignore # ignore/add/remove/force - -# -# Code modifying options (non-whitespace) -# - -# Add or remove braces on single-line 'do' statement -mod_full_brace_do = ignore # ignore/add/remove/force - -# Add or remove braces on single-line 'for' statement -mod_full_brace_for = ignore # ignore/add/remove/force - -# Add or remove braces on single-line function definitions. (Pawn) -mod_full_brace_function = ignore # ignore/add/remove/force - -# Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'. -mod_full_brace_if = ignore # ignore/add/remove/force - -# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if. -# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. -mod_full_brace_if_chain = false # false/true - -# Don't remove braces around statements that span N newlines -mod_full_brace_nl = 0 # number - -# Add or remove braces on single-line 'while' statement -mod_full_brace_while = ignore # ignore/add/remove/force - -# Add or remove braces on single-line 'using ()' statement -mod_full_brace_using = ignore # ignore/add/remove/force - -# Add or remove unnecessary paren on 'return' statement -mod_paren_on_return = ignore # ignore/add/remove/force - -# Whether to change optional semicolons to real semicolons -mod_pawn_semicolon = false # false/true - -# Add parens on 'while' and 'if' statement around bools -mod_full_paren_if_bool = false # false/true - -# Whether to remove superfluous semicolons -mod_remove_extra_semicolon = false # false/true - -# If a function body exceeds the specified number of newlines and doesn't have a comment after -# the close brace, a comment will be added. -mod_add_long_function_closebrace_comment = 0 # number - -# If a switch body exceeds the specified number of newlines and doesn't have a comment after -# the close brace, a comment will be added. -mod_add_long_switch_closebrace_comment = 0 # number - -# If an #ifdef body exceeds the specified number of newlines and doesn't have a comment after -# the #endif, a comment will be added. -mod_add_long_ifdef_endif_comment = 0 # number - -# If an #ifdef or #else body exceeds the specified number of newlines and doesn't have a comment after -# the #else, a comment will be added. -mod_add_long_ifdef_else_comment = 0 # number - -# If TRUE, will sort consecutive single-line 'import' statements [Java, D] -mod_sort_import = false # false/true - -# If TRUE, will sort consecutive single-line 'using' statements [C#] -mod_sort_using = false # false/true - -# If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C] -# This is generally a bad idea, as it may break your code. -mod_sort_include = false # false/true - -# If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace. -mod_move_case_break = false # false/true - -# Will add or remove the braces around a fully braced case statement. -# Will only remove the braces if there are no variable declarations in the block. -mod_case_brace = ignore # ignore/add/remove/force - -# If TRUE, it will remove a void 'return;' that appears as the last statement in a function. -mod_remove_empty_return = false # false/true - -# -# Comment modifications -# - -# Try to wrap comments at cmt_width columns -cmt_width = 0 # number - -# Set the comment reflow mode (default: 0) -# 0: no reflowing (apart from the line wrapping due to cmt_width) -# 1: no touching at all -# 2: full reflow -cmt_reflow_mode = 0 # number - -# If false, disable all multi-line comment changes, including cmt_width. keyword substitution, and leading chars. -# Default is true. -cmt_indent_multi = true # false/true - -# Whether to group c-comments that look like they are in a block -cmt_c_group = false # false/true - -# Whether to put an empty '/*' on the first line of the combined c-comment -cmt_c_nl_start = false # false/true - -# Whether to put a newline before the closing '*/' of the combined c-comment -cmt_c_nl_end = false # false/true - -# Whether to group cpp-comments that look like they are in a block -cmt_cpp_group = false # false/true - -# Whether to put an empty '/*' on the first line of the combined cpp-comment -cmt_cpp_nl_start = false # false/true - -# Whether to put a newline before the closing '*/' of the combined cpp-comment -cmt_cpp_nl_end = false # false/true - -# Whether to change cpp-comments into c-comments -cmt_cpp_to_c = true # false/true - -# Whether to put a star on subsequent comment lines -cmt_star_cont = false # false/true - -# The number of spaces to insert at the start of subsequent comment lines -cmt_sp_before_star_cont = 0 # number - -# The number of spaces to insert after the star on subsequent comment lines -cmt_sp_after_star_cont = 0 # number - -# For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of -# the comment are the same length. Default=True -cmt_multi_check_last = false # false/true - -# The filename that contains text to insert at the head of a file if the file doesn't start with a C/C++ comment. -# Will substitute $(filename) with the current file's name. -cmt_insert_file_header = "" # string - -# The filename that contains text to insert at the end of a file if the file doesn't end with a C/C++ comment. -# Will substitute $(filename) with the current file's name. -cmt_insert_file_footer = "" # string - -# The filename that contains text to insert before a function implementation if the function isn't preceded with a C/C++ comment. -# Will substitute $(function) with the function name and $(javaparam) with the javadoc @param and @return stuff. -# Will also substitute $(fclass) with the class name: void CFoo::Bar() { ... } -cmt_insert_func_header = "" # string - -# The filename that contains text to insert before a class if the class isn't preceded with a C/C++ comment. -# Will substitute $(class) with the class name. -cmt_insert_class_header = "" # string - -# The filename that contains text to insert before a Obj-C message specification if the method isn't preceeded with a C/C++ comment. -# Will substitute $(message) with the function name and $(javaparam) with the javadoc @param and @return stuff. -cmt_insert_oc_msg_header = "" # string - -# If a preprocessor is encountered when stepping backwards from a function name, then -# this option decides whether the comment should be inserted. -# Affects cmt_insert_oc_msg_header, cmt_insert_func_header and cmt_insert_class_header. -cmt_insert_before_preproc = false # false/true - -# -# Preprocessor options -# - -# Control indent of preprocessors inside #if blocks at brace level 0 -pp_indent = ignore # ignore/add/remove/force - -# Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false) -pp_indent_at_level = false # false/true - -# If pp_indent_at_level=false, specifies the number of columns to indent per level. Default=1. -pp_indent_count = 1 # number - -# Add or remove space after # based on pp_level of #if blocks -pp_space = ignore # ignore/add/remove/force - -# Sets the number of spaces added with pp_space -pp_space_count = 0 # number - -# The indent for #region and #endregion in C# and '#pragma region' in C/C++ -pp_indent_region = 0 # number - -# Whether to indent the code between #region and #endregion -pp_region_indent_code = false # false/true - -# If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level -pp_indent_if = 0 # number - -# Control whether to indent the code between #if, #else and #endif when not at file-level -pp_if_indent_code = false # false/true - -# Whether to indent '#define' at the brace level (true) or from column 1 (false) -pp_define_at_level = false # false/true - -# You can force a token to be a type with the 'type' option. -# Example: -# type myfoo1 myfoo2 -# -# You can create custom macro-based indentation using macro-open, -# macro-else and macro-close. -# Example: -# macro-open BEGIN_TEMPLATE_MESSAGE_MAP -# macro-open BEGIN_MESSAGE_MAP -# macro-close END_MESSAGE_MAP -# -# You can assign any keyword to any type with the set option. -# set func_call_user _ N_ -# -# The full syntax description of all custom definition config entries -# is shown below: -# -# define custom tokens as: -# - embed whitespace in token using '' escape character, or -# put token in quotes -# - these: ' " and ` are recognized as quote delimiters -# -# type token1 token2 token3 ... -# ^ optionally specify multiple tokens on a single line -# define def_token output_token -# ^ output_token is optional, then NULL is assumed -# macro-open token -# macro-close token -# macro-else token -# set id token1 token2 ... -# ^ optionally specify multiple tokens on a single line -# ^ id is one of the names in token_enum.h sans the CT_ prefix, -# e.g. PP_PRAGMA -# -# all tokens are separated by any mix of ',' commas, '=' equal signs -# and whitespace (space, tab) -# -set IF IF_APPNAME diff --git a/integrations/README.md b/integrations/README.md deleted file mode 100644 index 264555c..0000000 --- a/integrations/README.md +++ /dev/null @@ -1,59 +0,0 @@ -ZeroTier Integrations -==== - -If you want everything built at once, type `make all` and go play outside for a few minutes, we'll copy all of the targets into the `build` directory for you along with specific instructions contained in a `README.md` on how to use each binary. You can then use `make -s check` to check the build status of each binary target. - -*NOTE for Apple platforms: In order to build iOS/OSX Frameworks and Bundles you will need XCode command line tools `xcode-select --install`* - -*NOTE: For Android JNI libraries to build you'll need to install [Android Studio](https://developer.android.com/studio/index.html) the [Android NDK](https://developer.android.com/ndk/index.html). Currently only Android NDK r10e is supported and can be found [here for OSX](http://dl.google.com/android/repository/android-ndk-r10e-darwin-x86_64.zip) and [here for Linux](http://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip). You'll need to tell our project where you put it by putting the path in [this file](android/proj/local.properties), you'll need to install the Android Build-Tools (this can typically be done through the editor the first time you start it up), and finally you should probably upgrade your Gradle plugin if it asks you to. If you don't have these things installed and configured we will detect that and just skip those builds automatically. Additionally, you can specify the target architectures you wish to build for by editing [Application.mk](android/android_jni_lib/java/jni/Application.mk). By default it will build `arm64-v8a`, `armeabi`, `armeabi-v7a`, `mips`, `mips64`, `x86`, and `x86_64`* - -Below are the specific instructions for each integration requiring *little to no modification to your code*. Remember, with a full build we'll put a copy of the appropriate integration instructions in the resultant binary's folder for you anyway. - -For more support on these integrations, or if you'd like help creating a new integration, stop by our [community section](https://www.zerotier.com/community/)! - -*** -## Important Build Flags - -- `SDK_IPV4=1` - Enable IPv4 support -- `SDK_IPV6=1` - Enable IPv6 support - -- `SDK_DEBUG=1` - Enables SDK debugging - -- `SDK_PICOTCP=1` - Enable the use of `picoTCP` (recommended) -- `SDK_PICO_DEBUG=1` - Enables debug output for the `picoTCP` network stack - -- `SDK_LWIP=1` - Enable the use of `lwIP` (deprecated) -- `SDK_LWIP_DEBUG=1` - Enables debug output for the `lwIP` library. - -*** - -### Apple - - For everything: `make apple ` - -##### iOS - - [Embedding within an app](apple/example_app/iOS) `make ios_app_framework` -> `build/ios_app_framework/*` - - Unity3D plugin `make ios_unity3d_bundle` -> `build/ios_unity3d_bundle/*` - -##### OSX - - [Linking into an app at compiletime](../docs/osx.md) `make osx_static_lib` -> `build/libzt.a` - - [Embedding within an app with Xcode](apple/example_app/OSX) `make osx_app_framework` -> `build/osx_app_framework/*` - - [Dynamic-linking into an app/service at runtime](../docs/osx.md) `make osx_service_and_intercept` -> { `build/zerotier-sdk-service` + `build/libztintercept.so` } - - [Intercept library](../docs/osx.md) `make osx_sdk_service` -> `build/zerotier-sdk-service` - - [SDK Service](../docs/osx.md) `make osx_intercept` -> `build/libztintercept.so` - - [Unity3D plugin](apple/ZeroTierSDK_Apple) `make osx_unity3d_bundle` - -*** -### Linux - - For everything: `make linux ` - - [Dynamic-linking into an app/service at runtime](../docs/linux.md) `make linux_shared_lib` - - Service and Intercept `make linux_service_and_intercept` -> { `build/zerotier-sdk-service` + `build/libztintercept.so` } - - [Using the SDK with Docker](docker) - -### Android - - For everything: `make android` - - - [Embedding within an app](android) `make android_jni_lib` -> `build/android_jni_lib/YOUR_ARCH/libZeroTierOneJNI.so` - -*** -### Windows - - Not yet. diff --git a/integrations/Unity3D/Assembly-CSharp-Editor.csproj b/integrations/Unity3D/Assembly-CSharp-Editor.csproj deleted file mode 100644 index c406b12..0000000 --- a/integrations/Unity3D/Assembly-CSharp-Editor.csproj +++ /dev/null @@ -1,109 +0,0 @@ - - - - Debug - AnyCPU - 10.0.20506 - 2.0 - - {CCA76E42-E9D5-4CBF-3222-F488C499DCF3} - Library - Properties - Assembly-CSharp-Editor - v3.5 - 512 - Assets - - - true - full - false - Temp\bin\Debug\ - DEBUG;TRACE;UNITY_5_3_OR_NEWER;UNITY_5_3_5;UNITY_5_3;UNITY_5;ENABLE_NEW_BUGREPORTER;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_DUCK_TYPING;ENABLE_FRAME_DEBUGGER;ENABLE_GENERICS;ENABLE_HOME_SCREEN;ENABLE_IMAGEEFFECTS;ENABLE_LIGHT_PROBES_LEGACY;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_PLUGIN_INSPECTOR;ENABLE_SHADOWS;ENABLE_SINGLE_INSTANCE_BUILD_SETTING;ENABLE_SPRITERENDERER_FLIPPING;ENABLE_SPRITES;ENABLE_SPRITE_POLYGON;ENABLE_TERRAIN;ENABLE_RAKNET;ENABLE_UNET;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_HUB;ENABLE_CLOUD_PROJECT_ID;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_METRICS;ENABLE_EDITOR_METRICS_CACHING;INCLUDE_DYNAMIC_GI;INCLUDE_GI;INCLUDE_IL2CPP;INCLUDE_DIRECTX12;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_LOCALIZATION;ENABLE_ANDROID_ATLAS_ETC1_COMPRESSION;ENABLE_EDITOR_TESTS_RUNNER;UNITY_STANDALONE_OSX;UNITY_STANDALONE;ENABLE_SUBSTANCE;ENABLE_GAMECENTER;ENABLE_TEXTUREID_MAP;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_LOG_MIXED_STACKTRACE;ENABLE_UNITYWEBREQUEST;ENABLE_CLUSTERINPUT;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_OSX;UNITY_TEAM_LICENSE - prompt - 4 - 0169 - - - pdbonly - true - Temp\bin\Release\ - prompt - 4 - 0169 - - - - - - - - /Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll - - - /Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEditor.dll - - - - - - - /Users/Joseph/code/ZeroTierSDK/integrations/Unity3D/Library/ScriptAssemblies/Assembly-UnityScript.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/Networking/UnityEngine.Networking.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/Networking/Editor/UnityEditor.Networking.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/GUISystem/UnityEngine.UI.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/GUISystem/Editor/UnityEditor.UI.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/Advertisements/Editor/UnityEditor.Advertisements.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/EditorTestsRunner/Editor/nunit.framework.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/EditorTestsRunner/Editor/UnityEditor.EditorTestsRunner.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/TreeEditor/Editor/UnityEditor.TreeEditor.dll - - - /Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEditor.Graphs.dll - - - /Applications/Unity/PlaybackEngines/AndroidPlayer/UnityEditor.Android.Extensions.dll - - - /Applications/Unity/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.dll - - - /Applications/Unity/PlaybackEngines/MacStandaloneSupport/UnityEditor.OSXStandalone.Extensions.dll - - - /Applications/Unity/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Xcode.dll - - - /Applications/Unity/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Common.dll - - - - - {7214E491-EE9D-B906-A42D-2F3EA3DCD8FE} Assembly-CSharp - - - - - diff --git a/integrations/Unity3D/Assembly-CSharp.csproj b/integrations/Unity3D/Assembly-CSharp.csproj deleted file mode 100644 index 8f15e50..0000000 --- a/integrations/Unity3D/Assembly-CSharp.csproj +++ /dev/null @@ -1,81 +0,0 @@ - - - - Debug - AnyCPU - 10.0.20506 - 2.0 - - {7214E491-EE9D-B906-A42D-2F3EA3DCD8FE} - Library - Properties - Assembly-CSharp - v3.5 - 512 - Assets - - - true - full - false - Temp\bin\Debug\ - DEBUG;TRACE;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_5_0;UNITY_5_5;UNITY_5;UNITY_64;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_DUCK_TYPING;ENABLE_GENERICS;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_SPRITERENDERER_FLIPPING;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_RAKNET;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_WEBCAM;ENABLE_WWW;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_HUB;ENABLE_CLOUD_PROJECT_ID;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_METRICS;ENABLE_EDITOR_METRICS_CACHING;INCLUDE_DYNAMIC_GI;INCLUDE_GI;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;INCLUDE_PUBNUB;ENABLE_PLAYMODE_TESTS_RUNNER;ENABLE_SCRIPTING_NEW_CSHARP_COMPILER;UNITY_STANDALONE_OSX;UNITY_STANDALONE;ENABLE_SUBSTANCE;ENABLE_GAMECENTER;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITYWEBREQUEST;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_VIDEO;ENABLE_VR;ENABLE_CLUSTERINPUT;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_OSX;UNITY_TEAM_LICENSE - prompt - 4 - 0169 - - - pdbonly - true - Temp\bin\Release\ - prompt - 4 - 0169 - - - - - - - - - /Applications/Unity/Unity.app/Contents/Managed/UnityEngine.dll - - - /Applications/Unity/Unity.app/Contents/Managed/UnityEditor.dll - - - - - - - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/GUISystem/UnityEngine.UI.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/Networking/UnityEngine.Networking.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/PlaymodeTestsRunner/UnityEngine.PlaymodeTestsRunner.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/UnityAnalytics/UnityEngine.Analytics.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/UnityHoloLens/RuntimeEditor/UnityEngine.HoloLens.dll - - - /Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/UnityVR/RuntimeEditor/UnityEngine.VR.dll - - - - - - diff --git a/integrations/Unity3D/Assets/CameraControl.js b/integrations/Unity3D/Assets/CameraControl.js deleted file mode 100644 index 5585fbf..0000000 --- a/integrations/Unity3D/Assets/CameraControl.js +++ /dev/null @@ -1,194 +0,0 @@ - -var zoomSpeed : float = 3.0f; -var moveSpeed : float = 3.0f; -var rotateSpeed : float = 6.0f; - -var optionalMaterialForSelection : Material; - -// Some internal placeholders -private var orbitVector : GameObject; -private var materialForSelection : Material; -private var selectedObjects = new ArrayList(); -private var selectedObjectsMaterial = new ArrayList(); - -function Start() { - // Create a capsule (which will be the lookAt target and global orbit vector) - orbitVector = GameObject.CreatePrimitive(PrimitiveType.Capsule); - orbitVector.transform.position = Vector3.zero; - // Snap the camera to align with the grid in set starting position (otherwise everything gets a bit wonky) - transform.position = Vector3(4, 4, 4); - // Point the camera towards the capsule - transform.LookAt(orbitVector.transform.position, Vector3.up); - // Hide the capsule (disable the mesh renderer) - orbitVector.GetComponent.().enabled = false; - // Create material to apply for selections (or use material supplied by user) - if (optionalMaterialForSelection) { - materialForSelection = optionalMaterialForSelection; - } else { - materialForSelection = new Material(Shader.Find("Diffuse")); - materialForSelection.color = Color.green; - } -} - -function Update(){ - -orbitVector.transform.position = Vector3.zero; - - if (Input.GetAxis("Mouse ScrollWheel") < 0) { - var currentZoomSpeedin = -10; - transform.Translate(Vector3.forward * ( currentZoomSpeedin)); - } - if (Input.GetAxis("Mouse ScrollWheel") > 0) { - var currentZoomSpeedout = 10; - transform.Translate(Vector3.forward * ( currentZoomSpeedout)); - } -} - -// Call all of our functionality in LateUpdate() to avoid weird behaviour (as seen in Update()) -function LateUpdate() { - // Get mouse vectors - var x = Input.GetAxis("Mouse X"); - var y = Input.GetAxis("Mouse Y"); - - // ALT is pressed, start navigation - //if (Input.GetKey(KeyCode.RightAlt) || Input.GetKey(KeyCode.LeftAlt)) { - - // Distance between camera and orbitVector. We'll need this in a few places - var distanceToOrbit = Vector3.Distance(transform.position, orbitVector.transform.position); - - //RMB - ZOOM - if (Input.GetMouseButton(2)) { - - // Refine the rotateSpeed based on distance to orbitVector - var currentZoomSpeed = Mathf.Clamp(zoomSpeed * (distanceToOrbit / 50), 0.1f, 2.0f); - - // Move the camera in/out - transform.Translate(Vector3.forward * (x * currentZoomSpeed)); - - // If about to collide with the orbitVector, repulse the orbitVector slightly to keep it in front of us - if (Vector3.Distance(transform.position, orbitVector.transform.position) < 3) { - orbitVector.transform.Translate(Vector3.forward, transform); - } - - - //LMB - PIVOT - } else if (Input.GetMouseButton(1)) { - - // Refine the rotateSpeed based on distance to orbitVector - var currentRotateSpeed = Mathf.Clamp(rotateSpeed * (distanceToOrbit / 50), 1.0f, rotateSpeed); - - // Temporarily parent the camera to orbitVector and rotate orbitVector as desired - transform.parent = orbitVector.transform; - orbitVector.transform.Rotate(Vector3.right * (y * currentRotateSpeed)); - orbitVector.transform.Rotate(Vector3.up * (x * currentRotateSpeed), Space.World); - transform.parent = null; - - - //MMB - PAN - } else if (Input.GetMouseButton(0)) { - - // Calculate move speed - var translateX = Vector3.right * (x * moveSpeed) * -1; - var translateY = Vector3.up * (y * moveSpeed) * -1; - - // Move the camera - transform.Translate(translateX); - transform.Translate(translateY); - - // Move the orbitVector with the same values, along the camera's axes. In effect causing it to behave as if temporarily parented. - orbitVector.transform.Translate(translateX, transform); - orbitVector.transform.Translate(translateY, transform); - } - - - /* - // If we're not currently navigating, grab selection if something is clicked - } else if (Input.GetMouseButtonDown(0)) { - var hitInfo : RaycastHit; - var ray : Ray = camera.ScreenPointToRay(Input.mousePosition); - var allowMultiSelect : boolean = false; - - // See if the user is holding in CTRL or SHIFT. If so, enable multiselection - if(Input.GetKey(KeyCode.RightShift) || Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightControl) || Input.GetKey(KeyCode.LeftControl)) { - allowMultiSelect = true; - } - - // Something was clicked. Fetch. - if (Physics.Raycast(ray, hitInfo, camera.farClipPlane)) { - target = hitInfo.transform; - - // If NOT multiselection, remove all prior selections - if (!allowMultiSelect) { - deselectAll(); - } - - //Toggle between selected and unselected (depending on current state) - if (target.renderer.sharedMaterial != materialForSelection) { - selectedObjects.Add(target.gameObject); - selectedObjectsMaterial.Add(target.gameObject.renderer.sharedMaterial); - target.gameObject.renderer.sharedMaterial = materialForSelection; - - } else { - var arrayLocation : int = selectedObjects.IndexOf(target.gameObject); - if (arrayLocation == -1) {return;}; //this shouldn't happen. Ever. But still. - - target.gameObject.renderer.sharedMaterial = selectedObjectsMaterial[arrayLocation]; - selectedObjects.RemoveAt(arrayLocation); - selectedObjectsMaterial.RemoveAt(arrayLocation); - - } - - // Else deselect all selected objects (ie. click on empty background) - } else { - - // Don't deselect if allowMultiSelect is true - if (!allowMultiSelect) {deselectAll();}; - } - - - - // Fetch input of the F-button (focus) -- this is a very dodgy implementation... - } else if (Input.GetKeyDown("f")) { - var backtrack = Vector3(0, 0, -15); - var selectedObject : GameObject; - - // If dealing with only one selected object - if (selectedObjects.Count == 1) { - selectedObject = selectedObjects[0]; - transform.position = selectedObject.transform.position; - orbitVector.transform.position = selectedObject.transform.position; - transform.Translate(backtrack); - - // Else we need to average out the position vectors (this is the proper dodgy part of the implementation) - } else if (selectedObjects.Count > 1) { - selectedObject = selectedObjects[0]; - var average = selectedObject.transform.position; - - for (var i = 1; i < selectedObjects.Count; i++) { - selectedObject = selectedObjects[i]; - average = (average + selectedObject.transform.position) / 2; - } - - transform.position = average; - orbitVector.transform.position = average; - transform.Translate(backtrack); - } - } - */ -} - - - -// Function to handle the de-selection of all objects in scene -function deselectAll() { - - // Run through the list of selected objects and restore their original materials - for (var currentItem = 0; currentItem < selectedObjects.Count; currentItem++) { - var selectedObject : GameObject = selectedObjects[currentItem]; - selectedObject.GetComponent.().sharedMaterial = selectedObjectsMaterial[currentItem]; - } - - // Clear both arrays - selectedObjects.Clear(); - selectedObjectsMaterial.Clear(); -} \ No newline at end of file diff --git a/integrations/Unity3D/Assets/MainScene.unity b/integrations/Unity3D/Assets/MainScene.unity deleted file mode 100644 index aec336874b2d9afbc11643cb27c1132ab4c63e8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75472 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. - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -using UnityEngine; -using System.Collections; -using UnityEngine.UI; -using System; - - -// Handles the switching of APIs -public class WorldMain : MonoBehaviour { - void Start() { - } - - public void API_selection() - { - GameObject go = GameObject.Find ("dropdownAPI"); - Dropdown dd = go.GetComponents () [0]; - Debug.Log("API selected: " + dd.captionText.text); - } -} diff --git a/integrations/Unity3D/Assets/ZT.mat b/integrations/Unity3D/Assets/ZT.mat deleted file mode 100755 index 584ed8ed265d2f8b7c060032c11aae4896d71013..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4888 zcmeI0%X1V(9LImNn`}bxg$M)ziSKt1F+L*+c>%(bU;Z^Ce+Rz@$DHQW&dFb}u^(gV=iB%&>^y^U ze>O*L{yxb`@^faVw@ts@4*g5DbJA|7&u~YM!T#5-f6Sx9j+Z z;dUM0G~BM^Ti~13agao@a68^3OV-S%c%oTJV{>6xSI1X{z z_^ph;)4^|N{6q)m$!OKPPJDi6ak#{D%H5=uFUvuh2zOa6bH3;RUIo&H&jDO6o+2D zvfx&V?uwkLd-3XA7_6u;UY)Nh71OADK`mv_Q?#<6n$z_Qk<{IqO4p<$or)Ww;q zD{0Cq`m@W+k+wDC2X3q#3H%_8B$SFQipzwE3~e3aLASwty4Bc$3rqv<4NTMj@Ul^; zqM#9$Rdk?1?@Nmf&yT%&Nj2lp#ZG4DcmJH9Jhk@Ccfo=x68R%x9 zn}Kcy{$B?8@Auq7x=rFXyw&)s%`Gp-TOiy$b&s#9vfP!3I}s{cSK+Dk3Mo@0E}GK@@FR01bN$eP?}2 z^I>_y$Nmp}>S#6<#dnzCWej?gjW}3drc$cY$|=CWm9Iv%&bjwOFIFJQn2uNb;?-3Y z>2(A6TVjpVt)SN9Cx$yYpN~UTuf$cVCu96<&{=D<6!ZLiQ#x~YUX`gYcuByx7%b5P hHXTbVFDcTWl=#`C)T-MgH=fy~Ib^oYTq}3!@jry09?bv% diff --git a/integrations/Unity3D/Assets/ZTSDK.cs b/integrations/Unity3D/Assets/ZTSDK.cs deleted file mode 100755 index 025be87..0000000 --- a/integrations/Unity3D/Assets/ZTSDK.cs +++ /dev/null @@ -1,417 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -using UnityEngine; -using UnityEngine.UI; -using UnityEngine.Networking; - -using System; -using System.Collections; -using System.Runtime.InteropServices; -using System.Threading; -using System.Net.Sockets; -using System.Net; -using System.IO; -using System.Collections.Generic; -using System.Globalization; - -// TODO: -/* - * check for mem leaks surrounding managed/unmanaged barrier - * find root of 2X buffer size requirement issue - * check that cross-thread oprations are handled correctly - * check that .IsRunning() doesn't bork the entire system anymore - * Allow max packet size configuration - * Handle exceptions from unmanaged code - * */ - -// Provides a bare-bones interface to ZeroTier-administered sockets -public class ZTSDK { - - // ZeroTier background thread - protected Thread ztThread; - protected List connections = new List (); - protected int MaxPacketSize; - - // Only allow one network at a time for BETA - protected bool joined_to_network = false; - protected string nwid = ""; - protected string path = ""; - - // Platform-specific paths and bundle/libary names - #if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX - const string DLL_PATH = "ZeroTierSDK_Unity3D_OSX"; - protected string rpc_path = "/Library/Application\\ Support/ZeroTier/SDK/"; - #endif - #if UNITY_IOS || UNITY_IPHONE - const string DLL_PATH = "ZeroTierSDK_Unity3D_iOS"; - protected string rpc_path = "ZeroTier/One/"; - #endif - #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN - const string DLL_PATH = "ZeroTierSDK_Unity3D_WIN"; - protected string rpc_path = ""; - #endif - #if UNITY_STANDALONE_LINUX - const string DLL_PATH = "ZeroTierSDK_Unity3D_LINUX"; - protected string rpc_path = ""; - #endif - #if UNITY_ANDROID - const string DLL_PATH = "ZeroTierSDK_Unity3D_ANDROID"; - protected string rpc_path = "ZeroTier/One/"; - #endif - -#region DLL Imports - // ZeroTier service / debug initialization - [DllImport (DLL_PATH)] - public static extern void SetDebugFunction( IntPtr fp ); - [DllImport (DLL_PATH)] - private static extern int unity_start_service(string path); - [DllImport (DLL_PATH)] - private static extern int unity_start_service_and_rpc(string path, string nwid); - [DllImport (DLL_PATH)] - protected static extern bool zts_is_running(); - [DllImport (DLL_PATH)] - protected static extern void zts_stop_service(); - - // Connection calls - [DllImport (DLL_PATH)] - protected static extern int zts_socket(int family, int type, int protocol); - - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_bind(int sockfd, System.IntPtr addr, int addrlen); - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_connect(int sockfd, System.IntPtr addr, int addrlen); - - [DllImport (DLL_PATH)] - protected static extern int zts_accept(int sockfd); - [DllImport (DLL_PATH)] - protected static extern int zts_listen(int sockfd, int backlog); - [DllImport (DLL_PATH)] - protected static extern int zts_close(int sockfd); - - // RX / TX - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_recv(int sockfd, [In, Out] IntPtr buf, int len); - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_send(int sockfd, IntPtr buf, int len); - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_set_nonblock(int sockfd); - - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_sendto(int fd, IntPtr buf, int len, int flags, System.IntPtr addr, int addrlen); - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_recvfrom(int fd, [In, Out] IntPtr buf, int len, int flags, System.IntPtr addr, int addrlen); - - // ZT Network controls - [DllImport (DLL_PATH)] - protected static extern void zts_join_network(string nwid); - [DllImport (DLL_PATH)] - protected static extern void zts_leave_network(string nwid); -#endregion - - // Interop structures - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi)] - public struct sockaddr { - /// u_short->unsigned short - public ushort sa_family; - /// char[14] - [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=14)] - public string sa_data; - } - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void MyDelegate(string str); - - // Debug output callback - static void CallBackFunction(string str) { - Debug.Log("ZeroTier: " + str); - } - - - // Returns a path for RPC communications to the service - private string rpcCommPath() - { - if(path != "" && nwid != "") { - return path + "nc_" + nwid; - } - return ""; - } - - // Thread which starts the ZeroTier service - protected void zt_service_thread() - { - // Set up debug callback - MyDelegate callback_delegate = new MyDelegate( CallBackFunction ); - IntPtr intptr_delegate = Marshal.GetFunctionPointerForDelegate(callback_delegate); - SetDebugFunction( intptr_delegate ); - - // Start service - /* This new instance will communicate via a named pipe, so any - * API calls (ZeroTier.Connect(), ZeroTier.Send(), etc) will be sent to the service - * via this pipe. - */ - if(nwid.Length > 0) { - unity_start_service_and_rpc (path, nwid); - } - else { - unity_start_service(rpcCommPath()); - } - } - - // Returns the nwid of the network you're currently connected to - public string GetNetworkID() { - return nwid; - } - - // Returns whether you're currently connected to a network - public bool IsConnected() { - return nwid != ""; - } - - // Start the ZeroTier service - protected void Init() - { - ztThread = new Thread(() => { - try { - zt_service_thread(); - } catch(Exception e) { - Debug.Log(e.Message.ToString()); - } - }); - ztThread.IsBackground = true; // Allow the thread to be aborted safely - ztThread.Start(); - } - - // Initialize the ZeroTier service with a given path - public ZTSDK(string path, string nwid) { - Debug.Log("ZTSDK(): " + nwid); - - this.path = path; - this.nwid = nwid; - Init(); - } - - public ZTSDK (string path) { - this.path = path; - Init(); - } - - // Initialize the ZeroTier service - public ZTSDK() { - Init(); - } - -#region Network Handling - // Joins a ZeroTier virtual network - public bool JoinNetwork(string nwid) - { - if(!joined_to_network) { - zts_join_network(nwid); - return true; - } - return false; - } - - // Leaves a ZeroTier virtual network - public bool LeaveNetwork(string nwid) - { - if(!joined_to_network) { - return false; - } - else { - zts_leave_network(nwid); - return true; - } - } -#endregion - - // Creates a new ZeroTier-administered socket - public int Socket(int family, int type, int protocol) - { - return zts_socket (family, type, protocol); - } - - // Binds to a specific address - public int Bind(int fd, string addr, int port) - { - GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port); - IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject (); - int addrlen = Marshal.SizeOf (pSockAddr); - return zts_bind (fd, pSockAddr, addrlen); - } - - // Listens for an incoming connection request - public int Listen(int fd, int backlog) - { - return zts_listen(fd, backlog); - } - - // Accepts an incoming connection - public int Accept(int fd) - { - return zts_accept (fd); - } - - // Closes a connection - public int Close(int fd) - { - return Close (fd); - } - - // Connects to a remote host - public int Connect(int fd, string addr, int port) - { - GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port); - IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject (); - int addrlen = Marshal.SizeOf (pSockAddr); - return zts_connect (fd, pSockAddr, addrlen); - } - - public int Read(int fd, ref char[] buf, int len) - { - GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); - IntPtr ptr = handle.AddrOfPinnedObject(); - int bytes_read = zts_recv (fd, ptr, len*2); - string str = Marshal.PtrToStringAuto(ptr); - //Marshal.Copy (ptr, buf, 0, bytes_read); - buf = Marshal.PtrToStringAnsi(ptr).ToCharArray(); - return bytes_read; - } - - public int Write(int fd, char[] buf, int len) - { - GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); - IntPtr ptr = handle.AddrOfPinnedObject(); - //error = 0; - int bytes_written; - // FIXME: Sending a length of 2X the buffer size seems to fix the object pinning issue - if((bytes_written = zts_send(fd, ptr, len*2)) < 0) { - //error = (byte)bytes_written; - } - return bytes_written; - } - - // Sends data to an address - public int SendTo(int fd, char[] buf, int len, int flags, string addr, int port) - { - GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); - IntPtr ptr = handle.AddrOfPinnedObject(); - int bytes_written; - - // Form address structure - GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port); - IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject (); - int addrlen = Marshal.SizeOf (pSockAddr); - - if((bytes_written = zts_sendto(fd, ptr, len*2, flags, pSockAddr, addrlen)) < 0) { - //error = (byte)bytes_written; - } - return bytes_written; - } - - // Receives data from an address - public int RecvFrom(int fd, ref char[] buf, int len, int flags, string addr, int port) - { - GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); - IntPtr ptr = handle.AddrOfPinnedObject(); - - // Form address structure - GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port); - IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject (); - int addrlen = Marshal.SizeOf (pSockAddr); - - int bytes_read = zts_recvfrom(fd, ptr, len*2, flags, pSockAddr, addrlen); - string str = Marshal.PtrToStringAuto(ptr); - //Marshal.Copy (ptr, buf, 0, bytes_read); - buf = Marshal.PtrToStringAnsi(ptr).ToCharArray(); - return bytes_read; - } - -#region Service-Related calls - // Returns whether the ZeroTier service is currently running - public bool IsRunning() - { - return zts_is_running (); - } - - // Terminates the ZeroTier service - public void Terminate() - { - zts_stop_service (); - } -#endregion - - -// --- Utilities --- - - - // Handles IPv4 and IPv6 notation. - public static IPEndPoint CreateIPEndPoint(string endPoint) - { - string[] ep = endPoint.Split(':'); - if (ep.Length < 2) throw new FormatException("Invalid endpoint format"); - IPAddress ip; - if (ep.Length > 2) { - if (!IPAddress.TryParse(string.Join(":", ep, 0, ep.Length - 1), out ip)) { - throw new FormatException("Invalid ip-adress"); - } - } - else { - if (!IPAddress.TryParse(ep[0], out ip)) { - throw new FormatException("Invalid ip-adress"); - } - } - int port; - if (!int.TryParse(ep[ep.Length - 1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port)) { - throw new FormatException("Invalid port"); - } - return new IPEndPoint(ip, port); - } - - // Generates an unmanaged sockaddr structure from a string-formatted endpoint - public static GCHandle Generate_unmananged_sockaddr(string endpoint_str) - { - IPEndPoint ipEndPoint; - ipEndPoint = CreateIPEndPoint (endpoint_str); - SocketAddress socketAddress = ipEndPoint.Serialize (); - - // use an array of bytes instead of the sockaddr structure - byte[] sockAddrStructureBytes = new byte[socketAddress.Size]; - GCHandle sockAddrHandle = GCHandle.Alloc (sockAddrStructureBytes, GCHandleType.Pinned); - for (int i = 0; i < socketAddress.Size; ++i) { - sockAddrStructureBytes [i] = socketAddress [i]; - } - return sockAddrHandle; - } - - public static GCHandle Generate_unmanaged_buffer(byte[] buf) - { - // use an array of bytes instead of the sockaddr structure - GCHandle sockAddrHandle = GCHandle.Alloc (buf, GCHandleType.Pinned); - return sockAddrHandle; - } -} diff --git a/integrations/Unity3D/Assets/ZeroTierSockets_Demo.cs b/integrations/Unity3D/Assets/ZeroTierSockets_Demo.cs deleted file mode 100644 index 0de2d9f..0000000 --- a/integrations/Unity3D/Assets/ZeroTierSockets_Demo.cs +++ /dev/null @@ -1,301 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -using UnityEngine; -using System.Collections; -using System.Threading; -using System.Runtime.Serialization.Formatters.Binary; -using System.IO; -using UnityEngine.UI; -using UnityEngine.Networking; - -// Demonstrates the usage of bare-bones ZeroTier-administered sockets -using System.Net.Sockets; -using System.Runtime.InteropServices; -using System; - - -public class ZeroTierSockets_Demo : MonoBehaviour -{ - public float speed = 300f; - - private ZTSDK zt; - string nwid = ""; - - int sock; // The "connection id" - int host_socket; - - // Demo button methods - public void Join() - { - GameObject go = GameObject.Find ("inputNetworkID"); - InputField input = go.GetComponents () [0]; - Debug.Log ("Joining: " + input.text); - zt.JoinNetwork (input.text); - } - - public void Leave() - { - GameObject go = GameObject.Find ("inputNetworkID"); - InputField input = go.GetComponents () [0]; - Debug.Log ("Leaving: " + input.text); - zt.LeaveNetwork (input.text); - } - - // 1. Create ZeroTier-socket - // 2. Connect to remote host (on ZeroTier network) via socket - public void Connect() - { - GameObject addr_go = GameObject.Find ("inputServerAddress"); - GameObject port_go = GameObject.Find ("inputServerPort"); - InputField addr = addr_go.GetComponents () [0]; - InputField port = port_go.GetComponents () [0]; - Debug.Log ("Connecting to: " + addr.text + ":" + port.text); - - Thread connectThread = new Thread(() => { - int sockfd = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Stream, (int)ProtocolType.Unspecified); - Debug.Log ("sockfd = " + sockfd); - int port_num; - int.TryParse(port.text,out port_num); - zt.Connect (sockfd, addr.text,port_num); - Debug.Log ("sock = " + sock); - }); - connectThread.IsBackground = true; - connectThread.Start(); - } - - public void Bind() - { - GameObject addr_go = GameObject.Find ("inputServerAddress"); - GameObject port_go = GameObject.Find ("inputServerPort"); - InputField addr = addr_go.GetComponents () [0]; - InputField port = port_go.GetComponents () [0]; - Debug.Log ("Binding to: " + addr.text + ":" + port.text); - - // Get protocol type from GUI - GameObject go = GameObject.Find ("dropdownProtocol"); - Dropdown dd = go.GetComponents () [0]; - Debug.Log("Protocol selected: " + dd.captionText.text); - SocketType type = dd.captionText.text == "UDP" ? SocketType.Dgram : SocketType.Stream; - - Thread connectThread = new Thread(() => { - - // TCP - if(type == SocketType.Stream) { - // Socket() - sock = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Stream, (int)ProtocolType.Unspecified); - Debug.Log ("sock = " + sock); - - // Bind() - int port_num; - int.TryParse(port.text,out port_num); - int bind_res = zt.Bind(sock, "0.0.0.0", port_num); - Debug.Log ("bind_res = " + bind_res); - - // Listen() - int listen_res = zt.Listen(sock, 1); - Debug.Log ("listen_res = " + listen_res); - - // Accept() loop - Debug.Log("entering accept() loop"); - int accept_res = -1; - while(accept_res < 0) - { - accept_res = zt.Accept(sock); - Debug.Log ("accept_res = " + accept_res); - } - - // RX message - char[] msg = new char[1024]; - int bytes_read = 0; - while(bytes_read >= 0) - { - bytes_read = zt.Read(accept_res, ref msg, 80); - string msgstr = new string(msg); - Debug.Log("MSG (" + bytes_read + "):" + msgstr); - } - } - - // UDP - else if(type == SocketType.Dgram) - { - // Socket() - sock = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Dgram, (int)ProtocolType.Unspecified); - Debug.Log ("sock = " + sock); - - // Bind() - int port_num; - int.TryParse(port.text,out port_num); - int bind_res = zt.Bind(sock, "0.0.0.0", port_num); - Debug.Log ("bind_res = " + bind_res); - - // RX message - int bytes_read = 0, flags = 0, msg_len = 1024; - char[] msg = new char[msg_len]; - while(bytes_read >= 0) - { - bytes_read = zt.RecvFrom(sock, ref msg, msg_len, flags, "0.0.0.0", port_num); - string msgstr = new string(msg); - Debug.Log("MSG (" + bytes_read + "):" + msgstr); - } - } - }); - connectThread.IsBackground = true; - connectThread.Start(); - } - - public void Disconnect() - { - GameObject addr_go = GameObject.Find ("inputServerAddress"); - GameObject port_go = GameObject.Find ("inputServerAddress"); - InputField addr = addr_go.GetComponents () [0]; - InputField port = port_go.GetComponents () [0]; - Debug.Log ("Disconnecting from: " + addr.text + ":" + port.text); - Debug.Log ("Disconnect(): " + zt.Close (sock)); - } - - public void SendMessage() - { - // Get info from GUI - GameObject go = GameObject.Find ("dropdownProtocol"); - Dropdown dd = go.GetComponents () [0]; - Debug.Log("Protocol selected: " + dd.captionText.text); - SocketType type = dd.captionText.text == "UDP" ? SocketType.Dgram : SocketType.Stream; - - GameObject input = GameObject.Find ("inputMessage"); - InputField msg = input.GetComponents () [0]; - - // Get port number from UI - GameObject port_go = GameObject.Find ("inputServerPort"); - InputField port = port_go.GetComponents () [0]; - int port_num; - int.TryParse(port.text,out port_num); - - int bytes_written = 0; - - Thread sendThread = new Thread(() => { - // TCP - if(type == SocketType.Stream) { - bytes_written = zt.Write (sock, msg.text.ToCharArray(), msg.text.Length); - } - - // UDP - else if(type == SocketType.Dgram) { - int flags = 0; - string addr = "0.0.0.0"; - bytes_written = zt.SendTo(sock, msg.text.ToCharArray(), msg.text.Length, flags, addr, port_num); - } - Debug.Log ("bytes_written = " + bytes_written); - }); - sendThread.IsBackground = true; - sendThread.Start(); - } - - void Start() - { - Debug.Log ("Start()"); - // Set defaults - InputField input; - GameObject go; - go = GameObject.Find ("inputNetworkID"); - input = go.GetComponents () [0]; - input.text = "8056c2e21c000001"; - go = GameObject.Find ("inputServerAddress"); - input = go.GetComponents () [0]; - input.text = "10.9.9.203"; - go = GameObject.Find ("inputServerPort"); - input = go.GetComponents () [0]; - input.text = "8080"; - go = GameObject.Find ("inputMessage"); - input = go.GetComponents () [0]; - input.text = "Welcome to the machine"; - - // Create new instance of ZeroTier in separate thread - zt = new ZTSDK (".", "8056c2e21c000001"); - } - - // Terminate the ZeroTier service when the application quits - void OnApplicationQuit() { - Debug.Log ("OnApplicationQuit()"); - zt.Terminate (); - } - - // Update is called once per frame - void Update () { - /* - if (text) { - text.text = IsRunning() ? "ZeroTier Status: Online" : "ZeroTier Status: Offline"; - } - */ - - // --- - /* - int recHostId; - int connectionId; - int channelId; - byte[] recBuffer = new byte[1024]; - int bufferSize = 1024; - int dataSize; - byte error; - NetworkEventType recData = zt.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error); - switch (recData) - { - case NetworkEventType.Nothing: - break; - case NetworkEventType.ConnectEvent: - Debug.Log("NetworkEventType.ConnectEvent"); - break; - case NetworkEventType.DataEvent: - Debug.Log("NetworkEventType.DataEvent"); - break; - case NetworkEventType.DisconnectEvent: - Debug.Log("NetworkEventType.DisconnectEvent"); - break; - } - */ - // --- - - /* - GameObject go = GameObject.Find ("_txtStatusIndicator"); - Text text = go.GetComponents () [0]; - text.text = zt.IsRunning () ? "ZeroTier Service: ONLINE" : "ZeroTier Service: OFFLINE"; - */ - - // Rotate ZTCube when ZT is running - /* - if (zt.IsRunning ()) { - - - go = GameObject.Find ("ZTCube"); - Vector3 rotvec = new Vector3 (10f, 10f, 10f); - go.transform.Rotate (rotvec, speed * Time.deltaTime); - } - GameObject go = GameObject.Find("ZTCube"); - Text text = go.GetComponents ()[0]; - */ - } -} \ No newline at end of file diff --git a/integrations/Unity3D/Assets/smcs.rsp b/integrations/Unity3D/Assets/smcs.rsp deleted file mode 100755 index 46ef843..0000000 --- a/integrations/Unity3D/Assets/smcs.rsp +++ /dev/null @@ -1 +0,0 @@ --unsafe \ No newline at end of file diff --git a/integrations/Unity3D/Assets/zerotier-icon.png b/integrations/Unity3D/Assets/zerotier-icon.png deleted file mode 100644 index 4d9641b344329a3790f94206d012f2a9ce2e0750..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26898 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 diff --git a/integrations/Unity3D/ProjectSettings/AudioManager.asset b/integrations/Unity3D/ProjectSettings/AudioManager.asset deleted file mode 100644 index d2a92d77828b2d0dd0af3c9f6661e200b177b7df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4140 zcmeH~v1%JZ5QgWZ#Id8uPL;;Zfl~&95JHV1vMqv(2y7iz8#dCOxOjCdE_X#zUF|L} z5J({D+_=iqxH9-HeE$DEU*i`@vjfA<|K02|`*Y2Tw7!VEekUS3Sh0u<_WS#TxF`2j zRRsY+2YLHv@?*GncaZ+;X1`Nepj)nx{LUDPl<2RVD9Ho)+m`Y=kn$NI`|1qj7kazU zL(ytt2|K#JF-(# zER&Q6C12HNqurS9BK37RJ%c|OE$P5CY9HPK?|^r}JK!Dg4tNK=1Kt7efOo(<@IM?V S-{ZyU(mltU5g@{*#`*w-^>-Qo diff --git a/integrations/Unity3D/ProjectSettings/ClusterInputManager.asset b/integrations/Unity3D/ProjectSettings/ClusterInputManager.asset deleted file mode 100644 index de328e54b63137f319ce1e898a42e60c12fbf15f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4104 zcmeH_yGjE=6o$|2=HmTsCBA?~AV{zc#6k-Nk=RO*QIsUe=28!6ZR;DD!p?UQA&8BZ zc?Q@2-&s}`Q(K*Z!@=n~>9>%-4Pe+hY-K3;38KA&)!{%Xbx$@ku+@3IEY zLEq?eIq*KOdn}Fipx3w2VfS{>KWcSbS2mK)c~bUri=g{y-~)fD&eQ>QKpjvA)B$xs9Z(0<0d+tfPzV0QfgebudzJtI diff --git a/integrations/Unity3D/ProjectSettings/DynamicsManager.asset b/integrations/Unity3D/ProjectSettings/DynamicsManager.asset deleted file mode 100644 index 188d025e5718e1a6aed3778de502a2f44d23b2ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4276 zcmeH~ziSjh6vyA*`Sbj(SV$BD_6I>j3WG#1ITK9CiYcs=@iLbiS$D(i+>tZQ{Rtvy zFQQ;8)`p;ef|AZgtgKTBp5O28M6a+HWM+BHo6o#`@6C6&8IkG%k(2L4_75&`Bn(>EWWuB5h^t?un!Sk~JP56vILWn`mx=-Pg zvnLMnMesL;FLJD)fB1XPkCV@o{4@Iege7&Rex;t3Xaad?TZmVwM_7F(Z zBzj>MPOMy~aBgJXw53-%R_C28S;f|!MCt^jVwt_js$4anhh@x&g}<( ze*WT95O$A+IVcbm2nqxRf&xK-pg>R{C=e6~3jD7MeAqp|{g<=N)OKE8t?gWz<~5qv M%5fO4ng4S90!s56KmY&$ diff --git a/integrations/Unity3D/ProjectSettings/EditorBuildSettings.asset b/integrations/Unity3D/ProjectSettings/EditorBuildSettings.asset deleted file mode 100644 index 84a3acf47b51abcc48b5a3583a11c439386c2a77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4104 zcmeH@Jx&8L6okjwP53K9K`KN=35tkNNE;y`QP7|q00q{BMPWf?sc}og0dfE;8n_EB z7vK&oGiE8$Q$Aax=Qn;o(g(O_V0{@tn~?$NclW#f%O1X~s&bA-Ck6ccZSvJF4+c;3 z>~;4MYxMW12Bk9q0_&@o1ivS z;gp@)t9-TgkFvbHy+3@&r`gDtWnN5XxH%hL_`=T+1AH+)pZW}Ubv;RZKAe diff --git a/integrations/Unity3D/ProjectSettings/EditorSettings.asset b/integrations/Unity3D/ProjectSettings/EditorSettings.asset deleted file mode 100644 index d32ad8cee0a07e563d28ac5708978f1dcd9349c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4212 zcmeHKJ#Q015S@$pO!)pRpa@M$TTv7t;U*#&oFd4<0?KG}H%>0x?OJ<#*rwqs{sDD5 zL`|6riT{CUk!bP)eO^1kCpvtWJ@~K7I*b1X>es+k zeJ?kGmtN(+HN{&|?2PTQbFtpdDBW%i9b2uE7i_cG=yju=HAy$`_lqs3?+tJ7&OEI6BtsbLgJ1W?LSpy5T27^I89YrQpv95`#l)3(L9 zcQ|h1ZbD~Vu7Q$|d#AyLxOX|;yWaiUM=>sAWb6DHbTZbQl8<}P;6mI(j`zmBNBbzo zz1MNG-W$*v_dYaAKJNVn7vl0^q~z=TfM&(G4?1q*ehr;*kDyWVagQ2YhBoXq0^1M+`2+J>ht7+()&K;(8x*+{FC_I^#Z$M#;y0!r($& zoo@2;?-?DeExoUBU)pt*de-%#;4}5Tcd5679*r6Y@ zzc+2%i{y}$50*@xvj%H^2y6(Acl>MQ9oi4*{LfkYIdVwKuUh}uBQ50F{aVQJ%kYCK z;!=)Bmh(9hWs@iUd}4XUaZ}Ih;Qe4%$RTN+zp{MMV9n|02kWPrWY;O3qR#hd5AFj8= zMB5M0t8U1;iXCmNOsO>$$Eq$GD+^IwiAp7j$BfklFw;Y4#t+o&6gm}|Z0Jrpb5X4Y zs+Ras*y4m*tW;QS%9`TbXp?YWt;^bWIssrxHIt1?QQVLL#}^__Uxt?`*7pATMsiUG zk)9j2W&#;2^v8oux!sx#YeBoN>LxeZS7H@JSeQeZRV>Tcmtis)1vX2)tY+*ds)dYX zJ4hB}qF@w=C11sb$~9Jq(~@cBjEGf;I-;^HhiJFdq-@pF45G~i*<@aYiNm|W5kQ;C zVvk#g7ot^^KR=lDu2WBQggsd85nNzA+ z38Wuprjbqg@nqCk^+Wy8X00(&RZSUVJM(k4L)q|aySg(&|KZgcWSk>s<}!~gB8)muGORBH97)~@sT|HInXV9gxlJWjt*9N>RO?hb#15>in)AD&wvt$;Mth%o71*o5 z|EU1a9h-iCvVH3My(XiV(Wj*L`u#7X>-WTrzVrTL=J=cpN$0N_)%}0I^Zz&o^vkQY g&Gbu|{=t*R0sS4feG=-W%vc(4w@=!q;-v!cFPL*5%K!iX diff --git a/integrations/Unity3D/ProjectSettings/InputManager.asset b/integrations/Unity3D/ProjectSettings/InputManager.asset deleted file mode 100644 index 9eeb05c5ccd1df3eec107ebe7b8dc2fcb771e3bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5520 zcmeI0%W4!s6oyZmiTAt4#CVJM%OV&>1VN1&Llg~)cmqM&nM%@erhDk_iAit~aFdm0 z;{%A`M%=h@=MzL+xfQ{k4`KZO>dQ+Z2nLHmje-nyI@nM402ZOn;S z_32hI2$l)bxMLO`?iO0#f zeQHAEZnHy1)F@%dtItW{Qa=WUynK(H_P9^ z{s#U=>IOdJ5$O@XA2#`$QJeT!EhC>xXyR{6^@u+VoBZvlP5d3~ZPdc?mE zoBUml%=k&L+exyaeh5qn?ugKAy{vp2d$DLAs zDB(<9iOq>kdNZSqnvPU-QFFUt$8`m@$l##2{nZ85Y-=spVaNmg zEAEt=R5B~x3zu8}Mm^#Mc&6_QT+8t|k737GI3~yxZqGT-zH;a%)8`hy<~0J(hcb>Z66Tp)1Lv-p*nP06$>ZoN^Ul(#r7*^t7fd)~n%K(Z=mko3>{ zp6MN~&cG(O{Te0Ad@h=p*>P89=JV0S%#PchY05_vFFR&?9*^nnHJ;U+_`67AMcr3n z!*?UaGzP!!q^bW3~oKY|II A761SM diff --git a/integrations/Unity3D/ProjectSettings/NavMeshAreas.asset b/integrations/Unity3D/ProjectSettings/NavMeshAreas.asset deleted file mode 100644 index f3360b06113db6d6bd765dd940781dfe8365b89f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4384 zcmeH~y-EW?6ot=Zf8tL>gQd-ajUWbs1j{H`1i^rn^(ZT%8zb&&8MYJ)OAD=Rd;lLs zv6YCAVDEbFtc0Yuk~_y6e?6W>Kq7(-#eSiSvx zNovFU=rxOq~60KwA{45mAdJOPdMREYZ&Jr zVvpY9FMUssbRUn@R+vjKGYsjcYp-_W^mywcwkfQe$E0nWS)AEkjKhAK@uxD%*=-Rq z5zGTNT`D>&0VSXWlzl5wrkA0{VW>S T7M_|9$-dOek-D diff --git a/integrations/Unity3D/ProjectSettings/NetworkManager.asset b/integrations/Unity3D/ProjectSettings/NetworkManager.asset deleted file mode 100644 index 4488849d92283fe5e57a0a646e7ae6c22d87e289..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4112 zcmeH_&q@MO6vodTwbK5%FK8KUBr|DO2vP|B5eiy_)D^F0nZ`KTc6x#!aMj99>uB3c z^aAw`MZ2KsJ2TTHK0%9f;mkSrHy`($`^^wp>qO}^5zQha5#=+vOun9_Z_o3T0_Y=d zlfBowkLS|k&C=k@{!}b&BKSS8H6j;!FW50x^bjNWNs$`|WL*%7-k?P{Vs0ULv3>wP zkD7UmAr|v@@I};o{@+=a%7Sw+PxxBa$Ncl>(3`bmLwvy^_Y8XOF&^zu9b=QV~U2JEthPS?M^?oLW`%gKxW z1>O|vS;V6kDX0haqQ#5)Hwfavi}Cw*cKZ|0UiKxAdG9lC-p;-^1SUisZ-|b3CZfX_ zF%XRoogW%q8m2$3R?Be!dZB$!dd~iw|GoO~>Dv0oR-=0W>=P#2FtS`AY9hWBIZYx5 zpJ(mVeBn^D1CaArb?7VjQTY3zcKsmc+UPNIa9)mYhZ1e_Gw_(RTJB($=pytWbPtq; z^L$61E3i3sZ^SGg!gF2t{M>yT+==3E!smFNW8wXCo_nyFA7BV!&ilL%n|UWgNWve% zX5PgRlJMuSne$#*68;u8^KOQagnxt0{18J(!hgVKj&4Pg@Gi%4+rrKGftdH~h`$tb z?gLAbXEx^CbC!hPiuo~%Bc3N}E`#GseLMJrm>=K4S7UyH`J~Oij=sDC=ks$CnDe2J z&M@+`GC#G!+oQhpV-45g^cK$N?GECZ_s6_YX@sg2j$~bFjPlAMRTpLhv8+skR;WRR zf(gdrpgCb=poAXDjw327mqcBg1cJ;cEpu5I1z{?YaYJgqgj6{!6h`?Tr!V-SVtX4* zB8!zkh815gB5+QuDX#lwJ5pXjdeYbp z&G-R4q4B!ag=tZ*mPKHsTM}As1w~brSC?|tnkboMl3CGrwUjl4+MPyT(bsrguf!SR zt?uI2>L{fQFDp|FRJkkzu1pMFgFWQDjIXs?v@@BC@XFFPel5%ht#6CcU0#qE4TP1g@3&Gxc1@zB`h7&3ZxZCE09(otw36Vv;t`b(h8&%_;&@?ehs|d vI?LB!dj)S!e0ZN9hdV{|Zkp(2rt{0WG0P?=z$e(pILZGN48q{++W(ZlqMwU{ diff --git a/integrations/Unity3D/ProjectSettings/ProjectSettings.asset b/integrations/Unity3D/ProjectSettings/ProjectSettings.asset deleted file mode 100644 index a97930ab25eaa172d4b6e380f05fae8109ea1772..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37361 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 PS=aG&au{ta=rR8d+y)O* diff --git a/integrations/Unity3D/ProjectSettings/TagManager.asset b/integrations/Unity3D/ProjectSettings/TagManager.asset deleted file mode 100644 index 239cc3a87eff3812aa36e663dc72d8e7ba89ad74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4308 zcmeH~y-piJ6ov2l4-)==0*PoW8aD_DAqyczkqaPLBA^f>=+MZlR|YeN-F4w^%REC0 z=qPv$DjpzdQshBW#5rdcuUKho8fL8B@%?=F`rI?yT#?*gk?EfzGKC$RNOg66wc1*f ze}lomaRByl-QJ%+EdSOkKMrmxt&fijAD(y)JJ*Itg#3XCA`u6lUwMhf0LWQKzLV#i zHRSRlH_scMmp@=jc&32VJo87HpO;;*^QV0N7S}1H>J)*UUFH{4bxP!>PEo$12J2AE zNWx>CY@K?LnyK?m!qYn6l4s~--&s1xfwOc@kZ0(eOn9tw5ixb*w9pCrP5Wt%(D1a* z8Rlcr&kFXTpRFm|sfy{EpmQrIgPL2`|VU&hZmso+10- z;{WbJ!DsVbz-TRl1{gI;hq^~@r~uN_`>tG-bb^H?XnJ72do3u0qcNuz&cB))@}cTCRS*JTaqK=;A*M7Dj`Bx!++Ju6 L$M~V{;otrTTO6sT diff --git a/integrations/Unity3D/ProjectSettings/TimeManager.asset b/integrations/Unity3D/ProjectSettings/TimeManager.asset deleted file mode 100644 index a25d708ef3c316e4bbf621f05b06250cc3a2f2b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4112 zcmZQzVB}+95D;KsVBiPRK#GCERL@w?G|iCV-~a#r85w~BtU$c@RmvB^9M=<_(`^;r zz8Aa#5_14zkUR*OGcYtjv_treK$&IC3=NwY85&rCLLhYz%*e11sFnxF2Z=KQF#`uk z4k9iM6=y~hH-US6ov0JYW=BI!JXTRyFx9+ZM!I1P*iGlB@#(0kv5TLy3kc#!52{6xYvb` z;?g(Kc+MnMM4v!r;LhCp&CSW=%qk*<8Ik2x5m~~DMWj)!R~!ABe57fr6hH;j?aNdB zp?Grlx_*3LdheCX;4Xsu99tp@`cqRRE$T_v7nQ`iGq9mI}a8PFlyp5da!Ph~Ryr62x801A@)g*W14Qvh1P-m9hgd>OG zmk8E#Up&*tp3$Gj`j`F!`M!QJ7Y6#e<;7iJ>ma;{Wq8&B3fw_(kS suBiO_CL4CO4p;}Q1J(iSfOWt+U>&dySO=^F)`9=!0RH{>OFa3gPttQ@{r~^~ diff --git a/integrations/Unity3D/ProjectSettings/UnityConnectSettings.asset b/integrations/Unity3D/ProjectSettings/UnityConnectSettings.asset deleted file mode 100644 index ec04bc797d6203c3003eb46678cbe1bf16752d2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4116 zcmeH~y-EW?6ov03@h|@WRkjv327)A7Mnq6hqQsOUOWeejxCy%xAy!-1_zV_yb~fSz z_!>4gcD{j)>p8od7%;Wf4BVZ2zqxy6I6KXXq&$(iB@vm$j7g-B+sGB_dHD{*P$_^S z9uL{Ox5XFlYvE(H{dxbiHV=M_;5x^qNPzw@DgtsPk7)^>l>`|;_Qj!O895`Bgalkm z$pJJ@(a*j#f}_XRqg;eqQX*Hfg_Oa4M=%f5870T)>6D{fWGte;yr(}-UW)l1&Tpfn z{sehIo>qBe4Du|nDv@X89c%^f@Qjn>QDo#8{1U->s?SqGeT|wr)0pM;ul@}1FnxTj zq5AxU+^6a~y1UbIUAv|$w$_f@@MCz?@oE>A576gVXD7C=4_oJU+_LRj&8~K8{y@h* z1RbmC+}LHeqAgE%+7iFFdu_YA>NS%Ro7SBMYn}rmnWCH*jn}EDlB*I?^Dqt=2aE&8 a0poyiz&KzWFb)_8j047je{*2qC+!C&rFX&r diff --git a/integrations/Unity3D/README.md b/integrations/Unity3D/README.md deleted file mode 100644 index fd56965..0000000 --- a/integrations/Unity3D/README.md +++ /dev/null @@ -1,103 +0,0 @@ -Unity3D OSX + ZeroTier SDK -==== - -Welcome! - -We want your Unity apps to talk *directly* over a flat, secure, no-config virtual network without sending everything into the "cloud". Thus, we introduce the ZeroTier-Unity3D integration! - -Our implementation currently intends to be the bare minimum required to get your Unity application to talk over ZeroTier virtual networks. As a result, we've created an API that is very similar to the classic BSD-style sockets API. With this basic API it is possible to construct more abstracted network layers much like Unity's LLAPI and HLAPI. - -*** -## API - -- `Join(nwid)`: Joins a ZeroTier virtual network -- `Leave(nwid)`: Leaves a ZeroTier virtual network -- `Socket(family, type, protocol)`: Creates a ZeroTier-administered socket (returns an `fd`) -- `Bind(fd, addr, port)`: Binds to that socket on the address and port given -- `Listen(fd, backlog)`: Puts a socket into a listening state -- `Accept(fd)`: Accepts an incoming connection -- `Connect(fd, addr, port)`: Connects to an endpoint associated with the given `fd` -- `Write(fd, buf, len)`: Sends data to the endpoint associated with the given `fd` -- `Read(fd, buf, len)`: Receives data from an endpoint associated with the given `fd` -- `SendTo(fd, buf, len, flags, addr, port)`: Sends data to a given address -- `RecvFrom(fd, ref buf, len, flags, addr, port)`: Receives data -- `Close(fd)`: Closes a connection to an endpoint - -*** -## Adding ZeroTier to your Unity app - -**Step 1: Create virtual ZeroTier [virtual network](https://my.zerotier.com/)** - -**Step 2: Add plugin to Unity project** - - Create folder `Assets/Plugins` - - Place `ZeroTierSDK_Unity3D_OSX.bundle` in folder - -**Step 3: Include wrapper class source** - - Drag `ZTSDK.cs` into your `Assets` folder. - - Add a file `Assets/smcs.rsp` containing the flag `-unsafe`. This is needed to execute the native library. - -**Step 4: Create and use a `ZTSDK` object** - - See examples below for how to use it! - -*** - -## Listening for a connection -``` -public class Example -{ - public ZTSDK zt; - - public void example_server() - { - zt = new ZTSDK (); // Start interface - zt.Join("8056c2e21c000001"); // Join your network - - Thread connectThread = new Thread(() => { - // Create ZeroTier-administered socket - int sock = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Stream, (int)ProtocolType.Unspecified); - zt.Bind(sock, "0.0.0.0", 8000); - zt.Listen(sock, 1); - - // Accept client connection - int accept_sock = -1; - while(accept_res < 0) { - accept_sock = zt.Accept(sock); - } - - // Read data from client - char[] msg = new char[1024]; - int bytes_read = 0; - while(bytes_read >= 0) { - bytes_read = zt.Read(accept_sock, ref msg, 80); - string msgstr = new string(msg); - Debug.Log("MSG (" + bytes_read + "):" + msgstr); - } - }); - connectThread.IsBackground = true; - connectThread.Start(); - } -} -``` - -## Establishing a connection -``` -public class Example -{ - public ZTSDK zt; - - public void example_client() - { - zt = new ZTSDK (); - zt.Join("8056c2e21c000001"); - - Thread connectThread = new Thread(() => { - // Create ZeroTier-administered socket - int sock = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Stream, (int)ProtocolType.Unspecified); - zt.Connect (sock, "0.0.0.0",8000); - zt.Write(sock, "Welcome to the machine!", 24); - }); - connectThread.IsBackground = true; - connectThread.Start(); - } -} -``` \ No newline at end of file diff --git a/integrations/Unity3D/Unity3D.sln b/integrations/Unity3D/Unity3D.sln deleted file mode 100644 index 5a2d770..0000000 --- a/integrations/Unity3D/Unity3D.sln +++ /dev/null @@ -1,23 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2008 - -Project("{0BF2C6BC-4121-AE75-A3F9-F3A441421429}") = "Unity3D", "Assembly-CSharp.csproj", "{7214E491-EE9D-B906-A42D-2F3EA3DCD8FE}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7214E491-EE9D-B906-A42D-2F3EA3DCD8FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7214E491-EE9D-B906-A42D-2F3EA3DCD8FE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7214E491-EE9D-B906-A42D-2F3EA3DCD8FE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7214E491-EE9D-B906-A42D-2F3EA3DCD8FE}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = Assembly-CSharp.csproj - EndGlobalSection -EndGlobal diff --git a/integrations/Unity3D/Unity3D.userprefs b/integrations/Unity3D/Unity3D.userprefs deleted file mode 100644 index b995740..0000000 --- a/integrations/Unity3D/Unity3D.userprefs +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/integrations/Unity3D/ZeroTier-Unity3D-Test.sln b/integrations/Unity3D/ZeroTier-Unity3D-Test.sln deleted file mode 100644 index 44dad97..0000000 --- a/integrations/Unity3D/ZeroTier-Unity3D-Test.sln +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2008 - -Project("{9AF94C27-9A63-1F6F-49AF-DCF505B8257A}") = "ZeroTier-Unity3D-Test", "Assembly-CSharp.csproj", "{5AB900A8-5B14-044A-A52D-10417305A5D2}" -EndProject -Project("{9AF94C27-9A63-1F6F-49AF-DCF505B8257A}") = "ZeroTier-Unity3D-Test", "Assembly-CSharp-Editor.csproj", "{24F9E71C-1810-2FEA-B9CC-4258EB20D4CD}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5AB900A8-5B14-044A-A52D-10417305A5D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5AB900A8-5B14-044A-A52D-10417305A5D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5AB900A8-5B14-044A-A52D-10417305A5D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5AB900A8-5B14-044A-A52D-10417305A5D2}.Release|Any CPU.Build.0 = Release|Any CPU - {24F9E71C-1810-2FEA-B9CC-4258EB20D4CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {24F9E71C-1810-2FEA-B9CC-4258EB20D4CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {24F9E71C-1810-2FEA-B9CC-4258EB20D4CD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {24F9E71C-1810-2FEA-B9CC-4258EB20D4CD}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = Assembly-CSharp.csproj - EndGlobalSection -EndGlobal diff --git a/integrations/Unity3D/ZeroTier-Unity3D-Test.userprefs b/integrations/Unity3D/ZeroTier-Unity3D-Test.userprefs deleted file mode 100644 index 45e7d23..0000000 --- a/integrations/Unity3D/ZeroTier-Unity3D-Test.userprefs +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/integrations/android/README.md b/integrations/android/README.md deleted file mode 100644 index 229e587..0000000 --- a/integrations/android/README.md +++ /dev/null @@ -1,65 +0,0 @@ -Android + ZeroTier SDK -==== - -Welcome! - -Imagine a flat, encrypted, no-configuration LAN for all of the instances of your Android app. This short tutorial will show you how to enable ZeroTier functionality for your Android app with little to no code modification. Check out our [ZeroTier SDK](https://www.zerotier.com/blog) page for more info on how the integration works. In this example we aim to set up a minimal [Android Studio](https://developer.android.com/studio/index.html) project which contains all of the components necessary to enable ZeroTier for your app. - -*NOTE: For Android JNI libraries to build you'll need to install [Android Studio](https://developer.android.com/studio/index.html) the [Android NDK](https://developer.android.com/ndk/index.html). Currently only Android NDK r10e is supported and can be found [here for OSX](http://dl.google.com/android/repository/android-ndk-r10e-darwin-x86_64.zip) and [here for Linux](http://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip). You'll need to tell our project where you put it by putting the path in [this file](android_jni_lib/proj/local.properties), you'll need to install the Android Build-Tools (this can typically be done through the editor the first time you start it up), and finally you should probably upgrade your Gradle plugin if it asks you to. If you don't have these things installed and configured we will detect that and just skip those builds automatically.* - -If you want to skip the following steps and just take a look at the project, go [here](example_app). - -*** - -**Step 1: App Code Modifications** - - In your project, create a new package called `ZeroTier` and class file within called `ZTSDK.java` and copy contents from `src/wrappers/java/JavaWrapper.java` - - - Start the service - - ``` - String nwid = "8056c2e21c000001"; - // Set up service - final ZTSDK zt = new ZTSDK(); - final String homeDir = getApplicationContext().getFilesDir() + "/zerotier"; - new Thread(new Runnable() { - public void run() { - // Calls to JNI code - zt.start_service(homeDir); - } - }).start(); - while(!zt.running()) { } - ``` - - - Join network and start doing network stuff! - - ``` - zt.join_network(nwid); - int sock = zt.socket(zt.AF_INET, zt.SOCK_STREAM, 0); - int err = zt.connect(sock, "10.9.9.203", 8080, nwid); - // zt.recvfrom(), zt.write(), etc... - ``` - -**Step 2: App permissions** - - - In order for your application to write the auth keys and network files to the internal storage you'll need to set a few permissions in your `AndroidManifest.xml` file at the same scope level as ``: - - ``` - - - ``` - -**Step 3: Set NDK/SDK paths** - - Specify your SDK/NDK path in `android_jni_lib/proj/local.properties`. For example: - - ``` - sdk.dir=/Users/Name/Library/Android/sdk - ndk.dir=/Users/Name/Library/Android/ndk-r10e - ``` - -**Step 4: Select build targets** - - Specify the target architectures you want to build in [Application.mk](android_jni_lib/java/jni/Application.mk). By default it will build `arm64-v8a`, `armeabi`, `armeabi-v7a`, `mips`, `mips64`, `x86`, and `x86_64`. For each architecture you wish to support a different shared library will need to be built. This is all taken care of automatically by the build script. - -**Step 4: Build Shared Library** - - `make android_jni_lib` - - The resultant `build/android_jni_lib/ARCH/libZeroTierOneJNI.so` is what you want to import into your own project to provide our API implementation to your app. Select your architecture and copy the shared library `libZeroTierOneJNI.so` into your project's JNI directory, possibly `/src/main/jniLibs/ARCH/libZeroTierOneJNI.so`. - - Selecting only the architectures you need will *significantly* reduce overall build time. diff --git a/integrations/android/android_jni_lib/java/build.xml b/integrations/android/android_jni_lib/java/build.xml deleted file mode 100644 index 4604ad6..0000000 --- a/integrations/android/android_jni_lib/java/build.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/integrations/android/android_jni_lib/java/jni/Android.mk b/integrations/android/android_jni_lib/java/jni/Android.mk deleted file mode 100644 index 93a4fb4..0000000 --- a/integrations/android/android_jni_lib/java/jni/Android.mk +++ /dev/null @@ -1,118 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -ZTSDK := $(ZT1)/.. -ZT := $(ZTSDK)/zerotierone -LWIP := $(ZTSDK)/ext/lwip/src - -LOCAL_MODULE := ZeroTierOneJNI - -LOCAL_C_INCLUDES := $(LWIP)/include -LOCAL_C_INCLUDES += $(LWIP)/include/lwip -LOCAL_C_INCLUDES += $(LWIP)/include/lwip/priv - -LOCAL_C_INCLUDES += $(ZTSDK) -LOCAL_C_INCLUDES += $(ZTSDK)/src -LOCAL_C_INCLUDES += $(ZTSDK)/src/stack_drivers/lwip -LOCAL_C_INCLUDES += $(ZTSDK)/src/stack_drivers - -LOCAL_C_INCLUDES += $(ZT1)/include -LOCAL_C_INCLUDES += $(ZT1)/node -LOCAL_C_INCLUDES += $(ZT1)/ -LOCAL_C_INCLUDES += $(ZT1)/service -LOCAL_C_INCLUDES += $(ZT1)/osdep - -LOCAL_LDLIBS := -llog -# LOCAL_CFLAGS := -g - -# ZeroTierOne ext files -LOCAL_SRC_FILES := \ - $(ZT1)/ext/lz4/lz4.c \ - $(ZT1)/ext/json-parser/json.c \ - $(ZT1)/ext/http-parser/http_parser.c \ - -# ZeroTierOne files -LOCAL_SRC_FILES += \ - $(ZT1)/service/OneService.cpp \ - $(ZT1)/service/ControlPlane.cpp \ - $(ZT1)/node/C25519.cpp \ - $(ZT1)/node/CertificateOfMembership.cpp \ - $(ZT1)/node/DeferredPackets.cpp \ - $(ZT1)/node/Identity.cpp \ - $(ZT1)/node/IncomingPacket.cpp \ - $(ZT1)/node/InetAddress.cpp \ - $(ZT1)/node/Multicaster.cpp \ - $(ZT)/node/Network.cpp \ - $(ZT)/node/NetworkConfig.cpp \ - $(ZT)/node/Node.cpp \ - $(ZT)/node/OutboundMulticast.cpp \ - $(ZT)/node/Packet.cpp \ - $(ZT)/node/Path.cpp \ - $(ZT)/node/Peer.cpp \ - $(ZT)/node/Poly1305.cpp \ - $(ZT)/node/Salsa20.cpp \ - $(ZT)/node/SelfAwareness.cpp \ - $(ZT)/node/SHA512.cpp \ - $(ZT)/node/Switch.cpp \ - $(ZT)/node/Topology.cpp \ - $(ZT)/node/Utils.cpp \ - $(ZT)/osdep/Http.cpp \ - $(ZT)/osdep/OSUtils.cpp \ - $(ZT)/osdep/ManagedRoute.cpp \ - $(ZT)/osdep/BackgroundResolver.cpp - - -#lwip -LOCAL_SRC_FILES += $(LWIP)/core/init.c \ - $(LWIP)/core/def.c \ - $(LWIP)/core/dns.c \ - $(LWIP)/core/inet_chksum.c \ - $(LWIP)/core/ip.c \ - $(LWIP)/core/mem.c \ - $(LWIP)/core/memp.c \ - $(LWIP)/core/netif.c \ - $(LWIP)/core/pbuf.c \ - $(LWIP)/core/raw.c \ - $(LWIP)/core/stats.c \ - $(LWIP)/core/sys.c \ - $(LWIP)/core/tcp.c \ - $(LWIP)/core/tcp_in.c \ - $(LWIP)/core/tcp_out.c \ - $(LWIP)/core/timeouts.c \ - $(LWIP)/core/udp.c - -LOCAL_SRC_FILES += $(LWIP)/core/ipv4/autoip.c \ - $(LWIP)/core/ipv4/dhcp.c \ - $(LWIP)/core/ipv4/etharp.c \ - $(LWIP)/core/ipv4/icmp.c \ - $(LWIP)/core/ipv4/igmp.c \ - $(LWIP)/core/ipv4/ip4_frag.c \ - $(LWIP)/core/ipv4/ip4.c \ - $(LWIP)/core/ipv4/ip4_addr.c - -#LOCAL_SRC_FILES += $(LWIP)/core/ipv6/dhcp6.c \ -# $(LWIP)/core/ipv6/ethip6.c \ -# $(LWIP)/core/ipv6/icmp6.c \ -# $(LWIP)/core/ipv6/inet6.c \ -# $(LWIP)/core/ipv6/ip6.c \ -# $(LWIP)/core/ipv6/ip6_addr.c \ -# $(LWIP)/core/ipv6/ip6_frag.c \ -# $(LWIP)/core/ipv6/mld6.c \ -# $(LWIP)/core/ipv6/nd6.c - -# lwIP netif files -LOCAL_SRC_FILES += \ - $(LWIP)/netif/ethernetif.c \ - $(LWIP)/netif/ethernet.c - -# Netcon files -LOCAL_SRC_FILES += \ - $(ZTSDK)/src/rpc.c \ - $(ZTSDK)/src/proxy.cpp \ - $(ZTSDK)/src/sockets.c \ - $(ZTSDK)/src/service.cpp \ - $(ZTSDK)/src/tap.cpp \ - $(ZTSDK)/src/stack_drivers/lwip/lwip.cpp - -include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/integrations/android/android_jni_lib/java/jni/Android.pico.mk b/integrations/android/android_jni_lib/java/jni/Android.pico.mk deleted file mode 100644 index 4d259c8..0000000 --- a/integrations/android/android_jni_lib/java/jni/Android.pico.mk +++ /dev/null @@ -1,121 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -ZTSDK := $(ZT1)/.. -ZT := $(ZTSDK)/zerotierone -PICO := $(ZTSDK)/ext/picotcp - -LOCAL_MODULE := ZeroTierOneJNI - -LOCAL_C_INCLUDES := $(PICO)/modules -LOCAL_C_INCLUDES += $(PICO)/include -LOCAL_C_INCLUDES += $(PICO)/build/include -LOCAL_C_INCLUDES += $(PICO)/build/include/arch - -LOCAL_C_INCLUDES += $(ZTSDK)/src -LOCAL_C_INCLUDES += $(ZTSDK)/src/stack_drivers/picotcp -LOCAL_C_INCLUDES += $(ZTSDK)/src/stack_drivers - -LOCAL_C_INCLUDES += $(ZT1)/include -LOCAL_C_INCLUDES += $(ZT1)/node -LOCAL_C_INCLUDES += $(ZT1)/ -LOCAL_C_INCLUDES += $(ZT1)/service -LOCAL_C_INCLUDES += $(ZT1)/osdep - -LOCAL_LDLIBS := -llog -# LOCAL_CFLAGS := -g - -# ZeroTierOne ext files -LOCAL_SRC_FILES := \ - $(ZT1)/ext/lz4/lz4.c \ - $(ZT1)/ext/json-parser/json.c \ - $(ZT1)/ext/http-parser/http_parser.c \ - -# ZeroTierOne files -LOCAL_SRC_FILES += \ - $(ZT1)/service/OneService.cpp \ - $(ZT1)/service/ControlPlane.cpp \ - $(ZT1)/node/C25519.cpp \ - $(ZT1)/node/CertificateOfMembership.cpp \ - $(ZT1)/node/DeferredPackets.cpp \ - $(ZT1)/node/Identity.cpp \ - $(ZT1)/node/IncomingPacket.cpp \ - $(ZT1)/node/InetAddress.cpp \ - $(ZT1)/node/Multicaster.cpp \ - $(ZT)/node/Network.cpp \ - $(ZT)/node/NetworkConfig.cpp \ - $(ZT)/node/Node.cpp \ - $(ZT)/node/OutboundMulticast.cpp \ - $(ZT)/node/Packet.cpp \ - $(ZT)/node/Path.cpp \ - $(ZT)/node/Peer.cpp \ - $(ZT)/node/Poly1305.cpp \ - $(ZT)/node/Salsa20.cpp \ - $(ZT)/node/SelfAwareness.cpp \ - $(ZT)/node/SHA512.cpp \ - $(ZT)/node/Switch.cpp \ - $(ZT)/node/Topology.cpp \ - $(ZT)/node/Utils.cpp \ - $(ZT)/osdep/Http.cpp \ - $(ZT)/osdep/OSUtils.cpp \ - $(ZT)/osdep/ManagedRoute.cpp \ - $(ZT)/osdep/BackgroundResolver.cpp - -# picoTCP files -LOCAL_SRC_FILES += \ - $(PICO)/stack/pico_device.c \ - $(PICO)/stack/pico_frame.c \ - $(PICO)/stack/pico_md5.c \ - $(PICO)/stack/pico_protocol.c \ - $(PICO)/stack/pico_socket_multicast.c \ - $(PICO)/stack/pico_socket.c \ - $(PICO)/stack/pico_stack.c \ - $(PICO)/stack/pico_tree.c \ - -# picoTCP files -LOCAL_SRC_FILES += \ - $(PICO)/modules/pico_aodv.c \ - $(PICO)/modules/pico_arp.c \ - $(PICO)/modules/pico_dev_loop.c \ - $(PICO)/modules/pico_dev_mock.c \ - $(PICO)/modules/pico_dev_null.c \ - $(PICO)/modules/pico_dev_tun.c \ - $(PICO)/modules/pico_dns_client.c \ - $(PICO)/modules/pico_dns_common.c \ - $(PICO)/modules/pico_dns_sd.c \ - $(PICO)/modules/pico_fragments.c \ - $(PICO)/modules/pico_hotplug_detection.c \ - $(PICO)/modules/pico_icmp4.c \ - $(PICO)/modules/pico_icmp6.c \ - $(PICO)/modules/pico_igmp.c \ - $(PICO)/modules/pico_ipfilter.c \ - $(PICO)/modules/pico_ipv4.c \ - $(PICO)/modules/pico_ipv6_nd.c \ - $(PICO)/modules/pico_ipv6.c \ - $(PICO)/modules/pico_mdns.c \ - $(PICO)/modules/pico_mld.c \ - $(PICO)/modules/pico_mm.c \ - $(PICO)/modules/pico_nat.c \ - $(PICO)/modules/pico_olsr.c \ - $(PICO)/modules/pico_posix.c \ - $(PICO)/modules/pico_slaacv4.c \ - $(PICO)/modules/pico_sntp_client.c \ - $(PICO)/modules/pico_socket_tcp.c \ - $(PICO)/modules/pico_socket_udp.c \ - $(PICO)/modules/pico_strings.c \ - $(PICO)/modules/pico_tcp.c \ - $(PICO)/modules/pico_tftp.c \ - $(PICO)/modules/pico_udp.c - -# Netcon files -LOCAL_SRC_FILES += \ - $(ZTSDK)/src/rpc.c \ - $(ZTSDK)/src/proxy.cpp \ - $(ZTSDK)/src/sockets.c \ - $(ZTSDK)/src/service.cpp \ - $(ZTSDK)/src/tap.cpp \ - $(ZTSDK)/src/stack_drivers/picotcp/picotcp.cpp - - -include $(BUILD_SHARED_LIBRARY) diff --git a/integrations/android/android_jni_lib/java/jni/Application.mk b/integrations/android/android_jni_lib/java/jni/Application.mk deleted file mode 100644 index 32c4f20..0000000 --- a/integrations/android/android_jni_lib/java/jni/Application.mk +++ /dev/null @@ -1,16 +0,0 @@ -NDK_TOOLCHAIN_VERSION := clang -APP_STL := c++_static -APP_CPPFLAGS := -D__ANDROID__ -v -g -O3 -DSDK_BUNDLED -DSDK_DEBUG -DSDK_LWIP=1 -DSDK_IPV4=1 -DSDK -fPIC -fPIE -fvectorize -Wall -fstack-protector -fexceptions -fno-strict-aliasing -Wno-deprecated-register -DZT_NO_TYPE_PUNNING=1 -APP_CFLAGS := -v -g -DSDK_BUNDLED -APP_PLATFORM := android-14 - -# Architectures -# APP_ABI := all - -#APP_ABI += arm64-v8a -#APP_ABI += armeabi -APP_ABI += armeabi-v7a -#APP_ABI += mips -#APP_ABI += mips64 -#APP_ABI += x86 -#APP_ABI += x86_64 \ No newline at end of file diff --git a/integrations/android/android_jni_lib/java/jni/Application.pico.mk b/integrations/android/android_jni_lib/java/jni/Application.pico.mk deleted file mode 100644 index 72f06c8..0000000 --- a/integrations/android/android_jni_lib/java/jni/Application.pico.mk +++ /dev/null @@ -1,16 +0,0 @@ -NDK_TOOLCHAIN_VERSION := clang -APP_STL := c++_static -APP_CPPFLAGS := -v -g -O3 -DSDK_BUNDLED -DSDK_DEBUG -PICO_SUPPORT_IPV4=1 -DPICO_SUPPORT_TCP=1 -DSDK_PICOTCP=1 -DSDK_IPV4=1 -DIPV4=1 -DIPV6=1 -DSDK -fPIC -fPIE -fvectorize -Wall -fstack-protector -fexceptions -fno-strict-aliasing -Wno-deprecated-register -DZT_NO_TYPE_PUNNING=1 -APP_CFLAGS := -g -DSDK_BUNDLED -APP_PLATFORM := android-14 - -# Architectures -# APP_ABI := all - -#APP_ABI += arm64-v8a -#APP_ABI += armeabi -APP_ABI += armeabi-v7a -#APP_ABI += mips -#APP_ABI += mips64 -#APP_ABI += x86 -#APP_ABI += x86_64 diff --git a/integrations/android/android_jni_lib/proj/app/app.iml b/integrations/android/android_jni_lib/proj/app/app.iml deleted file mode 100644 index a42d8fd..0000000 --- a/integrations/android/android_jni_lib/proj/app/app.iml +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/integrations/android/android_jni_lib/proj/app/build.gradle b/integrations/android/android_jni_lib/proj/app/build.gradle deleted file mode 100644 index fb6eac1..0000000 --- a/integrations/android/android_jni_lib/proj/app/build.gradle +++ /dev/null @@ -1,55 +0,0 @@ -import org.apache.tools.ant.taskdefs.condition.Os - -apply plugin: 'com.android.application' -apply plugin: 'com.google.gms.google-services' - -android { - compileSdkVersion 23 - buildToolsVersion "23.0.2" - defaultConfig { - applicationId "com.zerotier.one" - minSdkVersion 15 - targetSdkVersion 23 - versionCode 112 - versionName "1.1.2" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - debug { - jniDebuggable true - } - } - sourceSets.main { - jniLibs.srcDir '../../java/libs' //set jniLibs directory to ./libs - jni.srcDirs = [] //disable automatic ndk-build call - java.srcDirs = ['src/main/java', '../../java/src'] - } - task ndkBuild(type: Exec) { - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - commandLine "${android.getNdkDirectory().getAbsolutePath()}/ndk-build.cmd", '-j8', '-C', file('../../java').absolutePath, "ZT1=${System.getProperty('user.dir')}/../../../../zerotierone" - } else { - commandLine "${android.getNdkDirectory().getAbsolutePath()}/ndk-build", '-j8', '-C', file('../../java').absolutePath, "ZT1=${System.getProperty('user.dir')}/../../../../zerotierone" - } - } - tasks.withType(JavaCompile) { - compileTask -> compileTask.dependsOn ndkBuild - } -} - -repositories { - maven { - url "http://teleal.org/m2" - } -} - -dependencies { - compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:appcompat-v7:23.1.1' - compile 'de.greenrobot:eventbus:2.4.0' - compile 'com.android.support:support-v4:23.1.1' - compile 'org.fourthline.cling:cling-core:2.0.1' - compile 'com.google.android.gms:play-services-analytics:8.4.0' -} \ No newline at end of file diff --git a/integrations/android/android_jni_lib/proj/app/google-services.json b/integrations/android/android_jni_lib/proj/app/google-services.json deleted file mode 100644 index a583e97..0000000 --- a/integrations/android/android_jni_lib/proj/app/google-services.json +++ /dev/null @@ -1 +0,0 @@ -{"project_info":{"project_id":"zerotier-one","project_number":"877961003667","name":"ZeroTier One"},"client":[{"client_info":{"client_id":"android:com.zerotier.one","client_type":1,"android_client_info":{"package_name":"com.zerotier.one"}},"oauth_client":[],"api_key":[],"services":{"analytics_service":{"status":2,"analytics_property":{"tracking_id":"UA-40176068-3"}},"cloud_messaging_service":{"status":1,"apns_config":[]},"appinvite_service":{"status":1,"other_platform_oauth_client":[]},"google_signin_service":{"status":1},"ads_service":{"status":1}}}],"ARTIFACT_VERSION":"1"} \ No newline at end of file diff --git a/integrations/android/android_jni_lib/proj/app/proguard-rules.pro b/integrations/android/android_jni_lib/proj/app/proguard-rules.pro deleted file mode 100644 index db02937..0000000 --- a/integrations/android/android_jni_lib/proj/app/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in C:\Users\Grant\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - --keepclassmembers class ** { - public void onEvent*(**); -} diff --git a/integrations/android/android_jni_lib/proj/app/src/androidTest/java/com/zerotier/one/ApplicationTest.java b/integrations/android/android_jni_lib/proj/app/src/androidTest/java/com/zerotier/one/ApplicationTest.java deleted file mode 100644 index ffdf3ba..0000000 --- a/integrations/android/android_jni_lib/proj/app/src/androidTest/java/com/zerotier/one/ApplicationTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.zerotier.one; - -import android.app.Application; -import android.test.ApplicationTestCase; - -/** - *
Testing Fundamentals - */ -public class ApplicationTest extends ApplicationTestCase { - public ApplicationTest() { - super(Application.class); - } -} \ No newline at end of file diff --git a/integrations/android/android_jni_lib/proj/app/src/main/AndroidManifest.xml b/integrations/android/android_jni_lib/proj/app/src/main/AndroidManifest.xml deleted file mode 100644 index ef9c004..0000000 --- a/integrations/android/android_jni_lib/proj/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/integrations/android/android_jni_lib/proj/app/src/main/ic_launcher-web.png b/integrations/android/android_jni_lib/proj/app/src/main/ic_launcher-web.png deleted file mode 100644 index a9f5fe0e8e2c0a4e6de3c0daf64352a8e8ba685b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10882 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 diff --git a/integrations/android/android_jni_lib/proj/app/src/main/java/Netcon/ZT_SDK_Wrapper.java b/integrations/android/android_jni_lib/proj/app/src/main/java/Netcon/ZT_SDK_Wrapper.java deleted file mode 100644 index ca46db0..0000000 --- a/integrations/android/android_jni_lib/proj/app/src/main/java/Netcon/ZT_SDK_Wrapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package Netcon; - -/** - * Created by Joseph Henry on 3/14/16. - */ -public class ZT_SDK_Wrapper { - public native int loadsymbols(); - - // From SDK_ServiceSetup.cpp - public native void startOneService(); - - static { - System.loadLibrary("ZeroTierOneJNI"); - } -} diff --git a/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/button_style.xml b/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/button_style.xml deleted file mode 100644 index 0583073..0000000 --- a/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/button_style.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/hex.png b/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/hex.png deleted file mode 100644 index 86659344ba75e83b3f9980773c6c8c4b980cad16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 689 zcmV;i0#5yjP)<{)JW8ABzEEa_qjYe6X-|wgQ_jl&q-Q7_j5McQTK$uJ>mWTHpo`-RG&U88@ zr_;Iql1(NPIyyQMJ_bN!vsuf(Y&Jy>Ab4IV6cTH)RzQK+xgH^O$i zEr1%0hUD&V1gKJ}h{9aWyS%(4hr=Q9N~IFZeS3Qo%T_29HVcFr;c;_wLnkLEluoCG zcY1ot@~*C~gomd9HUO_D6#T}3Ak@NVf!&1u7_Oi6!HGxC6Kba=Bc>$C1H(er74J9}18H^nU{#92}6r zV2}+4bAv$uX|-BrfKm=&ZZL45uWGgW=R%~>Xk-!Q1_M}B%Rh;}EwsPTcbT-mWZ3xy XJ|+k#o;KDa00000NkvXXu0mjfXemKl diff --git a/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/ic_launcher.png b/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/ic_launcher.png deleted file mode 100644 index 19ffd51b00b8cbdaacd78cf95b3e0fb69d57b471..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1119 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 az|hdH^28YmzYXE|1r9dO)_GQ|H~a_P2iW8Q diff --git a/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_allright.png b/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_allright.png deleted file mode 100644 index cb876ad6375dc90fb9fe248a1d482f7657124c94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21492 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 diff --git a/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_delete.png b/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_delete.png deleted file mode 100644 index 2235e6e709c0976c832151626a8fc19a56c84dfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20711 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 F`WJz|GTs0H diff --git a/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_return.png b/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/sym_keyboard_return.png deleted file mode 100644 index 9d97e1efd4e71081af462243be27abf511d03098..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1719 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 diff --git a/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/txt.png b/integrations/android/android_jni_lib/proj/app/src/main/res/drawable/txt.png deleted file mode 100644 index 92ae3dcaa04dc245be11ba824ed523f7e56711fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 624 zcmV-$0+0QPP)fPqgQ}!alW z$z+m65gQC(0nj@h&N4fAddhA0s-P88OUrllgHx`3sx!>vfJ&`l><w^?IGzQCY24OZZi*)tkcLQYaLj)2X-HEn9HCUej3DaW>cOb_<}zVnO5am}OQHP_0(Gc`ZmiFX!oWDw-p@GH(U2^CsACw{Pa-2T49$ zk$N;fTrCz0J7}R_b!t8azw7fboldi+s(cSAKnjoobPuG{>Bwj_$_9hjU=ToBt(F-; zDTg997&y>(wOak_tfbLsWKqNh16Wj-KZ$;v_4BMhWzx?J!`p8+*5c=o+2Cpb0000< KMNUMnLSTZJG$jN8 diff --git a/integrations/android/android_jni_lib/proj/app/src/main/res/layout/activity_fragment.xml b/integrations/android/android_jni_lib/proj/app/src/main/res/layout/activity_fragment.xml deleted file mode 100644 index c23482d..0000000 --- a/integrations/android/android_jni_lib/proj/app/src/main/res/layout/activity_fragment.xml +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/integrations/android/android_jni_lib/proj/app/src/main/res/layout/fragment_join_network.xml b/integrations/android/android_jni_lib/proj/app/src/main/res/layout/fragment_join_network.xml deleted file mode 100644 index 3ab9638..0000000 --- a/integrations/android/android_jni_lib/proj/app/src/main/res/layout/fragment_join_network.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/integrations/apple/example_app/OSX/Example_OSX_App/Info.plist b/integrations/apple/example_app/OSX/Example_OSX_App/Info.plist deleted file mode 100644 index 5717660..0000000 --- a/integrations/apple/example_app/OSX/Example_OSX_App/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2016 ZeroTier Inc. All rights reserved. - NSMainStoryboardFile - Main - NSPrincipalClass - NSApplication - - diff --git a/integrations/apple/example_app/OSX/Example_OSX_App/ViewController.swift b/integrations/apple/example_app/OSX/Example_OSX_App/ViewController.swift deleted file mode 100644 index c677611..0000000 --- a/integrations/apple/example_app/OSX/Example_OSX_App/ViewController.swift +++ /dev/null @@ -1,275 +0,0 @@ -// -// ViewController.swift -// Example_OSX_App -// -// Created by Joseph Henry on 6/22/16. -// Copyright © 2016 ZeroTier Inc. All rights reserved. -// - -import Cocoa - -class ViewController: NSViewController { - - let zt = ZTSDK(); - - @IBOutlet weak var btnJoinNetwork: NSButton! - @IBOutlet weak var btnLeaveNetwork: NSButton! - @IBOutlet weak var txtNWID: NSTextField! - @IBOutlet weak var segmentAPISelector: NSSegmentedCell! - @IBOutlet weak var segmentProtocolSelector: NSSegmentedCell! - @IBOutlet weak var txtAddr: NSTextField! - @IBOutlet weak var txtPort: NSTextField! - @IBOutlet weak var btnConnect: NSButton! - @IBOutlet weak var btnBind: NSButton! - - @IBOutlet weak var txtTX: NSTextField! - @IBOutlet weak var txtRX: NSTextField! - - var serverPort:Int32 = 8080 - var serverAddr:String = "0.0.0.0" - var sock:Int32 = -1 - var accepted_sock:Int32 = -1 - - @IBAction func txtAddrChanged(sender: AnyObject) { - if(sender.stringValue != nil) { - serverAddr = sender.stringValue - } - } - @IBAction func txtPortChanged(sender: AnyObject) { - serverPort = sender.intValue - } - // Join a ZeroTier network - @IBAction func UI_JoinNetwork(sender: AnyObject) { - zt.join_network(txtNWID.stringValue); - } - // Leave a ZeroTier network - @IBAction func UI_LeaveNetwork(sender: AnyObject) { - zt.leave_network(txtNWID.stringValue); - } - // Select an API - var selectedShim:Int32 = 0 - @IBAction func UI_SelectAPI(sender: AnyObject) { - selectedShim = sender.intValue // 0 = BSD-style, 1 = SOCKS5 Proxy, etc - } - // Select a protocol - // Protocol { TCP / UDP } - var selectedProtocol:Int32 = 0 - @IBAction func UI_SelectProtocol(sender: AnyObject) { - switch sender.intValue - { - case 0: - selectedProtocol = SOCK_STREAM - case 1: - selectedProtocol = SOCK_DGRAM - default: - break; - } - } - - // CONNECT - var connect_thread : NSThread! - func attempt_connect() - { - // TCP - if(selectedProtocol == SOCK_STREAM) - { - sock = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort)) - let connect_err = zt.connect(sock, ztaddr) - - print("connect_err = \(connect_err),\(errno)") - if connect_err < 0 { - let err = errno - print("Error connecting IPv4 socket \(err)") - return - } - } - - // UDP - if(selectedProtocol == SOCK_DGRAM) - { - - } - } - - // Connect to remote host on ZeroTier virtual network - @IBAction func UI_Connect(sender: AnyObject) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { - self.connect_thread = NSThread(target:self, selector:#selector(ViewController.attempt_connect), object:nil) - self.connect_thread.start() - }); - } - - // BIND - var bind_thread : NSThread! - func attempt_bind() - { - sock = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort)) - let bind_err = zt.bind(sock, ztaddr) - - print("bind_err = \(bind_err),\(errno)") - if bind_err < 0 { - let err = errno - print("Error binding IPv4 socket \(err)") - return - } - - // Put socket into listening state - zt.listen(sock, 1); - - // TCP - if(selectedProtocol == SOCK_STREAM) { - while(accepted_sock < 0) { - accepted_sock = zt.accept(sock, ztaddr) - } - print("accepted connection") - } - // UDP - if(selectedProtocol == SOCK_DGRAM) { - // nothing - } - } - - // Bind a ZeroTier socket - @IBAction func UI_Bind(sender: AnyObject) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { - self.bind_thread = NSThread(target:self, selector:#selector(ViewController.attempt_bind), object:nil) - self.bind_thread.start() - }); - } - - // TX - @IBOutlet weak var btnSend: NSButton! - @IBAction func UI_SendData(sender: AnyObject) { - // Use ordinary read/write calls on ZeroTier socket - // TCP - if(selectedProtocol == SOCK_STREAM) - { - write(sock, txtTX.description, txtTX.description.characters.count); - } - // UDP - if(selectedProtocol == SOCK_DGRAM) - { - // zt_sendto - } - } - - // RX - @IBOutlet weak var btnReadData: NSButton! - @IBAction func UI_ReadData(sender: AnyObject) { - // Use ordinary read/write calls on ZeroTier socket - // TCP - if(selectedProtocol == SOCK_STREAM) - { - var buffer = [UInt8](count: 100, repeatedValue: 0) - read(accepted_sock, &buffer, 1024); - print(buffer) - - } - // UDP - if(selectedProtocol == SOCK_DGRAM) - { - // zt_recvfrom - } - } - - // Watch for incoming data - var rx_thread : NSThread! - func update_rx() { - while(true) - { - sleep(1) - dispatch_async(dispatch_get_main_queue()) { - let str_buf = [Int8](count: 16, repeatedValue: 0) - print("addr = ", String.fromCString(str_buf)) - } - - // TCP - if(selectedProtocol == SOCK_STREAM) - { - let len = 32 - var buffer = [UInt8](count: len, repeatedValue: 0) - let n = read(accepted_sock, &buffer, len); - if(n > 0) - { - if let str = String(data: NSData(bytes: &buffer, length: len), encoding: NSUTF8StringEncoding) { - dispatch_async(dispatch_get_main_queue()) { - self.txtRX.stringValue = str - } - } else { - print("not a valid UTF-8 sequence") - } - } - } - // UDP - if(selectedProtocol == SOCK_DGRAM) - { - // zt_recvfrom - } - } - } - - - // Built-in SOCKS5 Proxy Server Test - func test_client_proxy_nsstream() - { - // For HTTP request - var buffer = [UInt8](count: 100, repeatedValue: 0) - let str = "GET / HTTP/1.0\r\n\r\n" - //let str = "Welcome to the machine" - print("strlen = %d\n", str.characters.count) - let encodedDataArray = [UInt8](str.utf8) - - var inputStream:NSInputStream? - var outputStream:NSOutputStream? - - // As usual, get our streams to our desired "local" address - NSStream.getStreamsToHostWithName(serverAddr, port: Int(serverPort), inputStream: &inputStream, outputStream: &outputStream) - - // SOCKS Proxy config dictionary - let myDict:NSDictionary = [NSStreamSOCKSProxyHostKey : "0.0.0.0", - NSStreamSOCKSProxyPortKey : 1337, - NSStreamSOCKSProxyVersionKey : NSStreamSOCKSProxyVersion5] - - // Give configuration to NSStreams - inputStream!.setProperty(myDict, forKey: NSStreamSOCKSProxyConfigurationKey) - outputStream!.setProperty(myDict, forKey: NSStreamSOCKSProxyConfigurationKey) - - inputStream!.open() - outputStream!.open() - - // TX - outputStream?.write(encodedDataArray, maxLength: encodedDataArray.count) - - // RX - sleep(5) - inputStream?.read(&buffer, maxLength: 100) - print("buffer = \(buffer)\n") - } - - override func viewDidLoad() { - super.viewDidLoad() - // Set initial UI values for demo - txtAddr.stringValue = serverAddr - txtPort.intValue = serverPort - txtNWID.stringValue = "8056c2e21c000001" - selectedProtocol = SOCK_STREAM // Just for selecting test mode. Not necessary for zt API - - zt.start_service("."); - zt.join_network(txtNWID.stringValue); - - // Update UI on RX of data - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { - self.rx_thread = NSThread(target:self, selector:#selector(ViewController.update_rx), object:nil) - self.rx_thread.start() - }); - } - - override var representedObject: AnyObject? { - didSet { - // Update the view, if already loaded. - } - } -} - diff --git a/integrations/apple/example_app/OSX/README.md b/integrations/apple/example_app/OSX/README.md deleted file mode 100644 index 742afba..0000000 --- a/integrations/apple/example_app/OSX/README.md +++ /dev/null @@ -1,78 +0,0 @@ -OSX + ZeroTier SDK -==== - -Welcome! - -Imagine a flat, encrypted, no-configuration LAN for all of the instances of your OSX app. - -*** - -## Via Traditional Linking (Service and Intercept) - - - This will allow the interception of traditional socket API calls such as `socket()`, `connect()`, `bind()`, etc. - -Build against our library: - - gcc app.c -o app libztintercept.so - export ZT_NC_NETWORK=/tmp/sdk-test-home/nc_8056c2e21c000001 - -Start service - - ./zerotier-sdk-service -d -p8000 /tmp/sdk-test-home & - -Run application - - ./app - -## Via `DYLD_LIBRARY_PATH` (Injecting code dynamically at runtime) - -As of the release of El Capitan, Apple requires one to turn off System Integrity Protection for code injection from external libraries. This method of intercepting network calls is now deprecated and we are investigating new methods for future releases of the SDK. If you still wish to use this method just `export DYLD_LIBRARY_PATH=./path/to/libztintercept.so:$DYLD_LIBRARY_PATH`. Also set `ZT_NC_NETWORK` appropriately. - - -## Via App Framework in XCode - -*** -**Step 1: Build OSX framework** - -- `make osx_app_framework` -- This will output to `build/osx_app_framework/Release/ZeroTierSDK_OSX.framework` - -**Step 2: Integrate SDK into project** - -- Add the resultant framework package to your project -- Add `src` directory to *Build Settings -> Header Search Paths* -- Add `build/osx_app_framework/Release/` to *Build Settings -> Framework Search Paths* -- Add `ZeroTierSDK.frameworkOSX` to *General->Embedded Binaries* -- Add `src/wrappers/swift/ZTSDK.swift`, `src/wrappers/swift/XcodeWrapper.cpp`, and `src/wrappers/swift/XcodeWrapper.hpp` to your project: -- Set `src/wrappers/swift/Apple-Bridging-Header.h` as your bridging-header in *Build Settings -> Objective-C Bridging-header* - -**Step 3: Start the ZeroTier service** - -Start the service: - -``` - zt.start_service("."); // Where the ZeroTier config files for this app will be stored - zt.join_network(nwid); -``` - -Listen for incoming connections: - -``` - let sock: Int32 = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort)) - let bind_err: Int32 = zt.bind(sock, ztaddr) - zt_listen(sock, 1); - let accepted_sock: Int32 = zt.accept(sock, ztaddr) -``` - -Or, establish a connection: - -``` - let sock: Int32 = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort)) - let connect_err: Int32 = zt.connect(sock, ztaddr) -``` - -**Alternative APIs** - -Click [here](../../../../docs/api_discussion.md) to learn more about alternative APIs such as the Intercept and SOCKS5 Proxy. \ No newline at end of file diff --git a/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/project.pbxproj b/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/project.pbxproj deleted file mode 100644 index fe23ba8..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/project.pbxproj +++ /dev/null @@ -1,346 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 7C7F16901DBEB94700C7AFFD /* XcodeWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C7F168B1DBEB92600C7AFFD /* XcodeWrapper.cpp */; }; - 7C7F16911DBEB94700C7AFFD /* ztsdk.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C7F168D1DBEB92600C7AFFD /* ztsdk.swift */; }; - 7C7F16921DBEBDF000C7AFFD /* Apple-Bridging-Header.h in Sources */ = {isa = PBXBuildFile; fileRef = 7C7F168A1DBEB92600C7AFFD /* Apple-Bridging-Header.h */; }; - 7C7F16931DBEBDF000C7AFFD /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C8BC03D1D3348A6001E1B6F /* ViewController.swift */; }; - 7C7F16941DBEBE0600C7AFFD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C8BC03B1D3348A6001E1B6F /* AppDelegate.swift */; }; - 7C8BC0411D3348A6001E1B6F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7C8BC03F1D3348A6001E1B6F /* Main.storyboard */; }; - 7C8BC0431D3348A6001E1B6F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7C8BC0421D3348A6001E1B6F /* Assets.xcassets */; }; - 7C8BC0461D3348A6001E1B6F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7C8BC0441D3348A6001E1B6F /* LaunchScreen.storyboard */; }; - 7C9B10DA1D36C81F005BA825 /* ZeroTierSDK_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C9B10D81D36C615005BA825 /* ZeroTierSDK_iOS.framework */; }; - 7C9B10DB1D36C81F005BA825 /* ZeroTierSDK_iOS.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7C9B10D81D36C615005BA825 /* ZeroTierSDK_iOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 7C9B10DC1D36C81F005BA825 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 7C9B10DB1D36C81F005BA825 /* ZeroTierSDK_iOS.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 7C7F168A1DBEB92600C7AFFD /* Apple-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Apple-Bridging-Header.h"; path = "../../../../../src/wrappers/swift/Apple-Bridging-Header.h"; sourceTree = ""; }; - 7C7F168B1DBEB92600C7AFFD /* XcodeWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = XcodeWrapper.cpp; path = ../../../../../src/wrappers/swift/XcodeWrapper.cpp; sourceTree = ""; }; - 7C7F168C1DBEB92600C7AFFD /* XcodeWrapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = XcodeWrapper.hpp; path = ../../../../../src/wrappers/swift/XcodeWrapper.hpp; sourceTree = ""; }; - 7C7F168D1DBEB92600C7AFFD /* ztsdk.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ztsdk.swift; path = ../../../../../src/wrappers/swift/ztsdk.swift; sourceTree = ""; }; - 7C8BC0381D3348A6001E1B6F /* Example_iOS_App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example_iOS_App.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7C8BC03B1D3348A6001E1B6F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7C8BC03D1D3348A6001E1B6F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - 7C8BC0401D3348A6001E1B6F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 7C8BC0421D3348A6001E1B6F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 7C8BC0451D3348A6001E1B6F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 7C8BC0471D3348A6001E1B6F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7C9B10D81D36C615005BA825 /* ZeroTierSDK_iOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ZeroTierSDK_iOS.framework; path = "../../../../build/ios_app_framework/Debug-iphoneos/ZeroTierSDK_iOS.framework"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7C8BC0351D3348A6001E1B6F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 7C9B10DA1D36C81F005BA825 /* ZeroTierSDK_iOS.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 7C8BC02F1D3348A6001E1B6F = { - isa = PBXGroup; - children = ( - 7C9B10D81D36C615005BA825 /* ZeroTierSDK_iOS.framework */, - 7C8BC03A1D3348A6001E1B6F /* Example_iOS_App */, - 7C8BC0391D3348A6001E1B6F /* Products */, - ); - sourceTree = ""; - }; - 7C8BC0391D3348A6001E1B6F /* Products */ = { - isa = PBXGroup; - children = ( - 7C8BC0381D3348A6001E1B6F /* Example_iOS_App.app */, - ); - name = Products; - sourceTree = ""; - }; - 7C8BC03A1D3348A6001E1B6F /* Example_iOS_App */ = { - isa = PBXGroup; - children = ( - 7C7F168A1DBEB92600C7AFFD /* Apple-Bridging-Header.h */, - 7C7F168B1DBEB92600C7AFFD /* XcodeWrapper.cpp */, - 7C7F168C1DBEB92600C7AFFD /* XcodeWrapper.hpp */, - 7C7F168D1DBEB92600C7AFFD /* ztsdk.swift */, - 7C8BC03B1D3348A6001E1B6F /* AppDelegate.swift */, - 7C8BC03D1D3348A6001E1B6F /* ViewController.swift */, - 7C8BC03F1D3348A6001E1B6F /* Main.storyboard */, - 7C8BC0421D3348A6001E1B6F /* Assets.xcassets */, - 7C8BC0441D3348A6001E1B6F /* LaunchScreen.storyboard */, - 7C8BC0471D3348A6001E1B6F /* Info.plist */, - ); - path = Example_iOS_App; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7C8BC0371D3348A6001E1B6F /* Example_iOS_App */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7C8BC04A1D3348A6001E1B6F /* Build configuration list for PBXNativeTarget "Example_iOS_App" */; - buildPhases = ( - 7C8BC0341D3348A6001E1B6F /* Sources */, - 7C8BC0351D3348A6001E1B6F /* Frameworks */, - 7C8BC0361D3348A6001E1B6F /* Resources */, - 7C9B10DC1D36C81F005BA825 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Example_iOS_App; - productName = Example_iOS_App; - productReference = 7C8BC0381D3348A6001E1B6F /* Example_iOS_App.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7C8BC0301D3348A6001E1B6F /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; - ORGANIZATIONNAME = "ZeroTier Inc."; - TargetAttributes = { - 7C8BC0371D3348A6001E1B6F = { - CreatedOnToolsVersion = 7.3; - DevelopmentTeam = 57AG88JR8A; - LastSwiftMigration = 0810; - }; - }; - }; - buildConfigurationList = 7C8BC0331D3348A6001E1B6F /* Build configuration list for PBXProject "Example_iOS_App" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 7C8BC02F1D3348A6001E1B6F; - productRefGroup = 7C8BC0391D3348A6001E1B6F /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7C8BC0371D3348A6001E1B6F /* Example_iOS_App */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7C8BC0361D3348A6001E1B6F /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7C8BC0461D3348A6001E1B6F /* LaunchScreen.storyboard in Resources */, - 7C8BC0431D3348A6001E1B6F /* Assets.xcassets in Resources */, - 7C8BC0411D3348A6001E1B6F /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7C8BC0341D3348A6001E1B6F /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7C7F16941DBEBE0600C7AFFD /* AppDelegate.swift in Sources */, - 7C7F16921DBEBDF000C7AFFD /* Apple-Bridging-Header.h in Sources */, - 7C7F16931DBEBDF000C7AFFD /* ViewController.swift in Sources */, - 7C7F16901DBEB94700C7AFFD /* XcodeWrapper.cpp in Sources */, - 7C7F16911DBEB94700C7AFFD /* ztsdk.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 7C8BC03F1D3348A6001E1B6F /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 7C8BC0401D3348A6001E1B6F /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 7C8BC0441D3348A6001E1B6F /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 7C8BC0451D3348A6001E1B6F /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7C8BC0481D3348A6001E1B6F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.3; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 7C8BC0491D3348A6001E1B6F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.3; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 7C8BC04B1D3348A6001E1B6F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../../../../build/iOS_app_framework/debug-iphoneos"; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../../../../src"; - INFOPLIST_FILE = Example_iOS_App/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks $(SRC_ROOT)/../../"; - PRODUCT_BUNDLE_IDENTIFIER = "zerotier.Example-iOS-App"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/../../../../src/wrappers/swift/Apple-Bridging-Header.h"; - SWIFT_VERSION = 2.3; - }; - name = Debug; - }; - 7C8BC04C1D3348A6001E1B6F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../../../../build/iOS_app_framework/debug-iphoneos"; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../../../../src"; - INFOPLIST_FILE = Example_iOS_App/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks $(SRC_ROOT)/../../"; - PRODUCT_BUNDLE_IDENTIFIER = "zerotier.Example-iOS-App"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/../../../../src/wrappers/swift/Apple-Bridging-Header.h"; - SWIFT_VERSION = 2.3; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7C8BC0331D3348A6001E1B6F /* Build configuration list for PBXProject "Example_iOS_App" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7C8BC0481D3348A6001E1B6F /* Debug */, - 7C8BC0491D3348A6001E1B6F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7C8BC04A1D3348A6001E1B6F /* Build configuration list for PBXNativeTarget "Example_iOS_App" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7C8BC04B1D3348A6001E1B6F /* Debug */, - 7C8BC04C1D3348A6001E1B6F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7C8BC0301D3348A6001E1B6F /* Project object */; -} diff --git a/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 92c673d..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index 20ff1bb..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/Example_iOS_App.xcscheme b/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/Example_iOS_App.xcscheme deleted file mode 100644 index f7c9333..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/Example_iOS_App.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/xcschememanagement.plist b/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index ce178c4..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App.xcodeproj/xcuserdata/Joseph.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - Example_iOS_App.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - 7C8BC0371D3348A6001E1B6F - - primary - - - - - diff --git a/integrations/apple/example_app/iOS/Example_iOS_App/AppDelegate.swift b/integrations/apple/example_app/iOS/Example_iOS_App/AppDelegate.swift deleted file mode 100644 index ef6f9cd..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App/AppDelegate.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// AppDelegate.swift -// Example_iOS_App -// -// Created by Joseph Henry on 7/10/16. -// Copyright © 2016 ZeroTier Inc. All rights reserved. -// - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { - // Override point for customization after application launch. - return true - } - - func applicationWillResignActive(application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - -} - diff --git a/integrations/apple/example_app/iOS/Example_iOS_App/Assets.xcassets/AppIcon.appiconset/Contents.json b/integrations/apple/example_app/iOS/Example_iOS_App/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index eeea76c..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/integrations/apple/example_app/iOS/Example_iOS_App/Base.lproj/LaunchScreen.storyboard b/integrations/apple/example_app/iOS/Example_iOS_App/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index ebf48f6..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/integrations/apple/example_app/iOS/Example_iOS_App/Base.lproj/Main.storyboard b/integrations/apple/example_app/iOS/Example_iOS_App/Base.lproj/Main.storyboard deleted file mode 100644 index 6bc9fee..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App/Base.lproj/Main.storyboard +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/integrations/apple/example_app/iOS/Example_iOS_App/Info.plist b/integrations/apple/example_app/iOS/Example_iOS_App/Info.plist deleted file mode 100644 index 40c6215..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App/Info.plist +++ /dev/null @@ -1,47 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/integrations/apple/example_app/iOS/Example_iOS_App/ViewController.swift b/integrations/apple/example_app/iOS/Example_iOS_App/ViewController.swift deleted file mode 100644 index bfd4d71..0000000 --- a/integrations/apple/example_app/iOS/Example_iOS_App/ViewController.swift +++ /dev/null @@ -1,295 +0,0 @@ -// -// ViewController.swift -// Example_iOS_App -// -// Created by Joseph Henry on 7/10/16. -// Copyright © 2016 ZeroTier Inc. All rights reserved. -// - -import UIKit - -class ViewController: UIViewController { - - let zt = ZTSDK(); - - var serverPort:Int16 = 8080 - var serverAddr:String = "10.9.9.100" - var selectedProtocol:Int32 = 0 - var sock:Int32 = -1 - var accepted_sock:Int32 = -1 - - @IBOutlet weak var txtAddr: UITextField! - @IBOutlet weak var txtPort: UITextField! - @IBOutlet weak var txtTX: UITextField! - @IBOutlet weak var txtRX: UITextField! - @IBOutlet weak var btnTX: UIButton! - @IBOutlet weak var btnConnect: UIButton! - @IBOutlet weak var btnBind: UIButton! - - @IBOutlet weak var btnRX: UIButton! - @IBAction func UI_RX(sender: AnyObject) { - // Use ordinary read/write calls on ZeroTier socket - - // TCP - if(selectedProtocol == SOCK_STREAM) { - var buffer = [UInt8](count: 100, repeatedValue: 0) - read(accepted_sock, &buffer, 100); - print(buffer) - - } - // UDP - if(selectedProtocol == SOCK_DGRAM) { - var buffer = [UInt8](count: 100, repeatedValue: 0) - read(Int32(sock), &buffer, 100); - print(buffer) - } - } - - - @IBAction func UI_TX(sender: AnyObject) { - // Use ordinary read/write calls on ZeroTier socket - // TCP - if(selectedProtocol == SOCK_STREAM) { - write(Int32(sock), txtTX.description, txtTX.description.characters.count); - } - // UDP - if(selectedProtocol == SOCK_DGRAM) { - sendto(Int32(sock), txtTX.description, txtTX.description.characters.count, 0, UnsafePointer([udp_addr]), UInt32(udp_addr.sin_len)) - } - } - - - @IBOutlet weak var txtNWID: UITextField! - - @IBOutlet weak var btnJoinNetwork: UIButton! - @IBAction func UI_JoinNetwork(sender: AnyObject) { - zt.join_network(txtNWID.text!) - } - - @IBOutlet weak var btnLeaveNetwork: UIButton! - @IBAction func UI_LeaveNetwork(sender: AnyObject) { - zt.leave_network(txtNWID.text!) - } - - @IBOutlet weak var segmentProtocol: UISegmentedControl! - @IBAction func protocolSelected(sender: AnyObject) { - switch sender.selectedSegmentIndex - { - case 0: - selectedProtocol = SOCK_STREAM - case 1: - selectedProtocol = SOCK_DGRAM - default: - break; - } - } - - - // CONNECT - var connect_thread : NSThread! - func attempt_connect() - { - // TCP - if(selectedProtocol == SOCK_STREAM) - { - sock = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, serverPort) - let connect_err = zt.connect(sock, ztaddr) - - print("connect_err = \(connect_err),\(errno)") - if connect_err < 0 { - let err = errno - print("Error connecting IPv4 socket \(err)") - return - } - } - - // UDP - if(selectedProtocol == SOCK_DGRAM) - { - - } - } - - // Connect to remote host on ZeroTier virtual network - @IBAction func UI_Connect(sender: AnyObject) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { - self.connect_thread = NSThread(target:self, selector:#selector(ViewController.attempt_connect), object:nil) - self.connect_thread.start() - }); - } - - // BIND - var bind_thread : NSThread! - func attempt_bind() - { - var err:Int32 - - // TCP - if(selectedProtocol == SOCK_STREAM) - { - sock = zt_socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, serverPort) - let bind_err = zt.bind(sock, ztaddr) - - print("bind_err = \(bind_err),\(errno)") - - if bind_err < 0 { - let err = errno - print("Error binding IPv4 socket \(err)") - return - } - - // Put socket into listening state - zt_listen(Int32(sock), 1); - - while(accepted_sock < 0) { - accepted_sock = zt.accept(sock, ztaddr) - } - print("accepted connection") - } - - // UDP - if(selectedProtocol == SOCK_DGRAM) - { - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, serverPort) - - sock = zt_socket(AF_INET, SOCK_DGRAM, 0) - err = zt.bind(sock, ztaddr) - print("bind_err = ", err) - - err = zt.listen(sock, 0) - print("listen_err = ", err) - } - } - - @IBOutlet weak var txtAddress: UITextField! - // Bind a ZeroTier socket - @IBAction func UI_Bind(sender: AnyObject) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { - self.bind_thread = NSThread(target:self, selector:#selector(ViewController.attempt_bind), object:nil) - self.bind_thread.start() - }); - } - - @IBOutlet weak var lblAddress: UILabel! - - - var udp_addr:sockaddr_in! - - // Watch for incoming data - var rx_thread : NSThread! - func update_rx() { - while(true) - { - sleep(1) - dispatch_async(dispatch_get_main_queue()) { - var str_buf = [Int8](count: 16, repeatedValue: 0) - self.zt.get_ipv4_address(self.txtNWID.text!, &str_buf) - self.lblAddress.text = String.fromCString(str_buf) - print("addr = ", String.fromCString(str_buf)) - } - - - // TCP - if(selectedProtocol == SOCK_STREAM) - { - let len = 32 - var buffer = [UInt8](count: len, repeatedValue: 0) - let n = read(accepted_sock, &buffer, len); - if(n > 0) - { - if let str = String(data: NSData(bytes: &buffer, length: len), encoding: NSUTF8StringEncoding) { - dispatch_async(dispatch_get_main_queue()) { - self.txtRX.text = str - } - } else { - print("not a valid UTF-8 sequence") - } - } - } - // UDP - /* - if(selectedProtocol == SOCK_DGRAM) - { - let len = 32 - var buffer = [UInt8](count: len, repeatedValue: 0) - - //udp_addr = sockaddr_in(sin_len: UInt8(sizeof(sockaddr_in)), - // sin_family: UInt8(AF_INET), - // sin_port: UInt16(0).bigEndian, - // sin_addr: in_addr(s_addr: 0), - // sin_zero: (0,0,0,0,0,0,0,0)) - - //var addrlen:socklen_t = 0; - //var legIntPtr = withUnsafeMutablePointer(&addrlen, { $0 }) - //let n = recvfrom(sock, &buffer, len, 0, UnsafeMutablePointer([udp_addr]), legIntPtr) - - - var socketAddress = sockaddr_storage() - var socketAddressLength = socklen_t(sizeof(sockaddr_storage.self)) - - let bytesRead = withUnsafeMutablePointers(&socketAddress, &socketAddressLength) { - recvfrom(sock, UnsafeMutablePointer(buffer), len, 0, UnsafeMutablePointer($0), UnsafeMutablePointer($1)) - //recvfrom(<#T##Int32#>, <#T##UnsafeMutablePointer#>, <#T##Int#>, <#T##Int32#>, <#T##UnsafeMutablePointer#>, <#T##UnsafeMutablePointer#>) - } - - if(bytesRead > 0) - { - print("socketAddressLength = ", socketAddressLength); - let bytesWritten = withUnsafePointer(&socketAddress) { - print("TXing...\n"); - sendto(sock, UnsafePointer(buffer), bytesRead, 0, UnsafePointer($0), socketAddressLength) - } - - print("bytesWritten = ", bytesWritten); - - //let bytesWritten = withUnsafePointer(&socketAddress.sin) { - // sendto(sock, buffer, len, 0, UnsafePointer($0), socklen_t(socketAddress.sin.sin_len)) - //} - - if let str = String(data: NSData(bytes: &buffer, length: len), encoding: NSUTF8StringEncoding) { - dispatch_async(dispatch_get_main_queue()) { - self.txtRX.text = str - } - } else { - print("not a valid UTF-8 sequence") - } - } - } - */ - } - } - - override func viewDidLoad() { - super.viewDidLoad() - - txtNWID.text = "8056c2e21c000001" - txtTX.text = "welcome to the machine" - txtAddr.text = "0.0.0.0" - serverAddr = "0.0.0.0" - txtPort.text = "8080" - serverPort = 8080 - - selectedProtocol = SOCK_STREAM - print("Starting ZeroTier...\n"); - zt.start_service(nil); - print("Joining network...\n"); - zt.join_network(txtNWID.text!); - print("Complete\n"); - - // UI RX update - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { - self.rx_thread = NSThread(target:self, selector:#selector(ViewController.update_rx), object:nil) - self.rx_thread.start() - }); - - // Do any additional setup after loading the view, typically from a nib. - } - - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. - } -} - diff --git a/integrations/apple/example_app/iOS/README.md b/integrations/apple/example_app/iOS/README.md deleted file mode 100644 index 968008f..0000000 --- a/integrations/apple/example_app/iOS/README.md +++ /dev/null @@ -1,54 +0,0 @@ -iOS + ZeroTier SDK -==== - -Welcome! - -Imagine a flat, encrypted, no-configuration LAN for all of the instances of your iOS app. - -This short tutorial will show you how to enable ZeroTier functionality for your iOS app with little to no code modification. Check out our [ZeroTier SDK](https://www.zerotier.com/blog) page for more info on how the integration works. - -*** -**Step 1: Build iOS framework** - -- `make ios_app_framework` -- This will output to `build/ios_app_framework/Release-iphoneos/ZeroTierSDK_iOS.framework` - -**Step 2: Integrate SDK into project** - -- Add the resultant framework package to your project -- Add `src` directory to *Build Settings -> Header Search Paths* -- Add `build/ios_app_framework/Release-iphoneos/` to *Build Settings -> Framework Search Paths* -- Add `ZeroTierSDK.frameworkiOS` to *General->Embedded Binaries* -- Add `src/wrappers/swift/ZTSDK.swift`, `src/wrappers/swift/XcodeWrapper.cpp` and `src/wrappers/swift/XcodeWrapper.hpp` to your project: -- Set `src/wrappers/swift/Apple-Bridging-Header.h` as your bridging-header in *Build Settings -> Objective-C Bridging-header* - -**Step 3: Start the ZeroTier service** - -Start the service: - -``` - zt.start_service(nil); - zt.join_network(nwid); -``` - -Listen for incoming connections: - -``` - let sock: Int32 = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort)) - let bind_err = zt.bind(sock, ztaddr) - zt_listen(sock, 1); - let accepted_sock: Int32 = zt.accept(sock, ztaddr) -``` - -Or, establish a connection: - -``` - let sock: Int32 = zt.socket(AF_INET, SOCK_STREAM, 0) - let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort)) - let connect_err: Int32 = zt.connect(sock, ztaddr) -``` - -**Alternative APIs** - -CLick [here](../../../../docs/api_discussion.md) to learn more about alternative APIs such as the Intercept and SOCKS5 Proxy. \ No newline at end of file diff --git a/integrations/docker/README.md b/integrations/docker/README.md deleted file mode 100644 index 27b6f80..0000000 --- a/integrations/docker/README.md +++ /dev/null @@ -1,94 +0,0 @@ -Docker + ZeroTier SDK -==== - -Welcome! - -Imagine a flat, encrypted, no-configuration LAN for all of your Docker containers. - -This short tutorial will show you how to enable ZeroTier functionality for your Docker container. In this example we aim to build a Docker container with ZeroTier’s Network Container service bundled right in so that it’s effortless to hook any number of your services in the container up to your virtual network. Alternatively, you can check out a docker project directory [here](docker_demo). - - -**Step 1: Build ZeroTier shared library** - -`make linux_service_and_intercept` - - For debug output from the SDK, use `SDK_DEBUG=1`, or `ZT_DEBUG=1` to see debug output from the ZeroTier service. - -**Step 2: Build your Docker image** - -`docker build --tag=redis_test .` - -The example dockerfile below incorperates a few important elements: - -1) The ZeroTier service binaries -2) Whatever ZeroTier identity keys you plan on using (if you don't already have keys you wish to use, fret not! A new identity will be generated automatically). -3) The service we've chosen to use. In this case, redis. -``` -FROM fedora:23 -# Install apps -RUN yum -y update -RUN yum -y install redis-3.0.4-1.fc23.x86_64 -RUN yum clean all -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / -EXPOSE 9993/udp 6379/udp -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libztintercept -ADD zerotier-cli / -Add zerotier-sdk-service / -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] -``` - -**Step 3: Start container** - -`docker run -d -it redis_test /bin/bash` - -**Step 4: From container, set up environment variables** - -Set our application pre-load with `export LD_PRELOAD=./libztintercept.so`. This dynamically loads our intercept library into your application which allows us to re-direct its network calls to our virtual network. - -Tell the ZeroTier Network Containers service which network to connect to with `export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_XXXXXXXXXXXXXXXX`. - -**Step 5: Run your new ZeroTier-enabled service** - -At this point, simply run your application as you normally would. It will be automatically intercepted and linked to the ZeroTier service (and hence your virtual networks!) - -`/usr/bin/redis-server --port 6379` - -*** -**Additional info** -If you'd like to know the IP address your service can be reached at on this particular virtual network, use the following: -`zerotier-cli -D/var/lib/zerotier-one/nc_XXXXXXXXXXXXXXXX listnetworks` - -## Installing in a Docker container (or any other container engine) - -If it's not immediately obvious, installation into a Docker container is easy. Just install `zerotier-sdk-service`, `libztintercept.so`, and `liblwip.so` into the container at an appropriate locations. We suggest putting it all in `/var/lib/zerotier-one` since this is the default ZeroTier home and will eliminate the need to supply a path to any of ZeroTier's services or utilities. Then, in your Docker container entry point script launch the service with *-d* to run it in the background, set the appropriate environment variables as described above, and launch your container's main application. - -The only bit of complexity is configuring which virtual network to join. ZeroTier's service automatically joins networks that have `.conf` files in `ZTHOME/networks.d` even if the `.conf` file is empty. So one way of doing this very easily is to add the following commands to your Dockerfile or container entry point script: - - mkdir -p /var/lib/zerotier-one/networks.d - touch /var/lib/zerotier-one/networks.d/8056c2e21c000001.conf - -Replace 8056c2e21c000001 with the network ID of the network you want your container to automatically join. It's also a good idea in your container's entry point script to add a small loop to wait until the container's instance of ZeroTier generates an identity and comes online. This could be something like: - - /var/lib/zerotier-one/zerotier-sdk-service -d - while [ ! -f /var/lib/zerotier-one/identity.secret ]; do - sleep 0.1 - done - # zerotier-sdk-service is now running and has generated an identity - -(Be sure you don't bundle the identity into the container, otherwise every container will try to be the same device and they will "fight" over the device's address.) - -Now each new instance of your container will automatically join the specified network on startup. Authorizing the container on a private network still requires a manual authorization step either via the ZeroTier Central web UI or the API. We're working on some ideas to automate this via bearer token auth or similar since doing this manually or with scripts for large deployments is tedious. diff --git a/integrations/docker/_remove_all.sh b/integrations/docker/_remove_all.sh deleted file mode 100755 index c6090a9..0000000 --- a/integrations/docker/_remove_all.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# Delete all containers -docker rm $(docker ps -a -q) -# Delete all images -docker rmi $(docker images -q) diff --git a/integrations/docker/docker_demo/README.md b/integrations/docker/docker_demo/README.md deleted file mode 100644 index 10b25f8..0000000 --- a/integrations/docker/docker_demo/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Simple Docker Demo -==== - -- Type `make docker_demo` to build an image with the SDK pre-installed and a test image to serve as a monitor -- From this local directory, start both containers with `./start.sh` - -Results of the test can be found in `_results` \ No newline at end of file diff --git a/integrations/docker/docker_demo/docker_demo.name b/integrations/docker/docker_demo/docker_demo.name deleted file mode 100644 index e69de29..0000000 diff --git a/integrations/docker/docker_demo/hello.lua b/integrations/docker/docker_demo/hello.lua deleted file mode 100644 index 59a2dea..0000000 --- a/integrations/docker/docker_demo/hello.lua +++ /dev/null @@ -1,3 +0,0 @@ -local msg = "welcome to the machine!" -redis.call("SET", "msg", msg) -return redis.call("GET", "msg") diff --git a/integrations/docker/docker_demo/monitor_dockerfile b/integrations/docker/docker_demo/monitor_dockerfile deleted file mode 100644 index 3c89941..0000000 --- a/integrations/docker/docker_demo/monitor_dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -RUN yum -y install redis-3.0.4-1.fc23.x86_64 - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD hello.lua / - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/integrations/docker/docker_demo/monitor_entrypoint.sh b/integrations/docker/docker_demo/monitor_entrypoint.sh deleted file mode 100644 index 384a226..0000000 --- a/integrations/docker/docker_demo/monitor_entrypoint.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=60 # wait for test container to come online -app_timeout_time=15 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - -# --- Test section --- -echo '*** Running lua script against redis host at' $ncvirtip -redis-cli -h $ncvirtip EVAL "$(cat hello.lua)" 0 > redis_response.txt -response_string=$(> "$file_path$ok$test_name.txt" -else - echo 'REDIS RESPONSE FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: redis server did NOT respond!\n' >> "$file_path$fail$test_name.txt" -fi \ No newline at end of file diff --git a/integrations/docker/docker_demo/sdk_dockerfile b/integrations/docker/docker_demo/sdk_dockerfile deleted file mode 100644 index f307991..0000000 --- a/integrations/docker/docker_demo/sdk_dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install redis-3.0.4-1.fc23.x86_64 -RUN yum clean all - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -EXPOSE 9993/udp 6379/udp - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -Add zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/integrations/docker/docker_demo/sdk_entrypoint.sh b/integrations/docker/docker_demo/sdk_entrypoint.sh deleted file mode 100644 index 2045743..0000000 --- a/integrations/docker/docker_demo/sdk_entrypoint.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -echo '*** Starting application...' -sleep 0.5 - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -/usr/bin/redis-server --port 6379 diff --git a/integrations/docker/docker_demo/start.sh b/integrations/docker/docker_demo/start.sh deleted file mode 100755 index 72a77e8..0000000 --- a/integrations/docker/docker_demo/start.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Runs test image and monitor image as daemons -test_name="docker_demo" -echo 'Starting containers for: ' "$test_name" -touch "$test_name".name -test_container=$(docker run -d -it -v $PWD/_results:/opt/results --privileged --device=/dev/net/tun "$test_name":latest) -monitor_container=$(docker run -d -it -v $PWD/_results:/opt/results --privileged --device=/dev/net/tun "$test_name"_monitor:latest) \ No newline at end of file diff --git a/integrations/docker/docker_demo/stop.sh b/integrations/docker/docker_demo/stop.sh deleted file mode 100755 index ec572ed..0000000 --- a/integrations/docker/docker_demo/stop.sh +++ /dev/null @@ -1,3 +0,0 @@ -docker stop $(docker ps -a -q) -docker rm $test_container -docker rm $monitor_container diff --git a/integrations/simple_app/app.cpp b/integrations/simple_app/app.cpp deleted file mode 100644 index 4120cf2..0000000 --- a/integrations/simple_app/app.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include -#include -#include - -#include "SDK.h" - - -int tcp_client(struct sockaddr_in *remote) -{ - printf("\t\t\tperforming TCP CLIENT test\n"); - - if(argc < 3) { - printf("usage: client \n"); - return 1; - } - - int sock, port = atoi(argv[2]); - struct sockaddr_in server; - char message[1000] , server_reply[2000]; - - sock = socket(AF_INET , SOCK_STREAM , 0); - if (sock == -1) { - printf("could not create socket"); - } - server.sin_addr.s_addr = inet_addr(argv[1]); - server.sin_family = AF_INET; - server.sin_port = htons( port ); - - printf("connecting...\n"); - if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) { - perror("connect failed. Error"); - return 1; - } - printf("connected\n"); - - char *msg = "welcome to the machine!"; - // TX - if(send(sock, msg, strlen(msg), 0) < 0) { - printf("send failed"); - return 1; - } - else { - printf("sent message: %s\n", msg); - printf("len = %ld\n", strlen(msg)); - } - close(sock); -} - -int tcp_server(struct sockaddr_in *local) -{ - printf("\t\t\tperforming TCP SERVER test\n"); -if(argc < 2) { - printf("usage: tcp_server \n"); - return 0; - } - - int socket_desc, client_sock, c, read_size, port = atoi(argv[1]); - struct sockaddr_in server , client; - char client_message[2000]; - - socket_desc = socket(AF_INET , SOCK_STREAM , 0); - if (socket_desc == -1) { - printf("could not create socket"); - return 0; - } - - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - server.sin_port = htons(port); - - printf("binding on port %d\n", port); - if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) { - perror("bind failed. Error"); - return 0; - } - printf("listening\n"); - listen(socket_desc , 3); - printf("waiting to accept\n"); - c = sizeof(struct sockaddr_in); - - client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c); - if (client_sock < 0) { - perror("accept failed"); - return 0; - } - printf("connection accepted\n reading...\n"); - - // RX - - int msglen = 1024; - unsigned long count = 0; - while(1) - { - count++; - int bytes_read = read(client_sock, client_message, msglen); - printf("[%lu] RX = (%d): ", count, bytes_read); - for(int i=0; i \n", argv[0]); - exit(0); - } - hostname = argv[1]; - portno = atoi(argv[2]); - - /* socket: create the socket */ - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) - error("ERROR opening socket"); - - /* gethostbyname: get the server's DNS entry */ - server = gethostbyname(hostname); - if (server == NULL) { - fprintf(stderr,"ERROR, no such host as %s\n", hostname); - exit(0); - } - - /* build the server's Internet address */ - bzero((char *) &serveraddr, sizeof(serveraddr)); - serveraddr.sin_family = AF_INET; - bcopy((char *)server->h_addr, - (char *)&serveraddr.sin_addr.s_addr, server->h_length); - serveraddr.sin_port = htons(portno); - - /* get a message from the user */ - char *msg = "A message to the server!\0"; - fcntl(sockfd, F_SETFL, O_NONBLOCK); - long count = 0; - while(1) - { - count++; - printf("\nTX(%lu)...\n", count); - usleep(10000); - //bzero(buf, BUFSIZE); - //printf("\nPlease enter msg: "); - //fgets(buf, BUFSIZE, stdin); - - /* send the message to the server */ - serverlen = sizeof(serveraddr); - printf("A\n"); - n = sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr *)&serveraddr, serverlen); - printf("B\n"); - //if (n < 0) - // error("ERROR in sendto"); - - /* print the server's reply */ - printf("C\n"); - memset(buf, 0, sizeof(buf)); - printf("D\n"); - n = recvfrom(sockfd, buf, BUFSIZE, 0, (struct sockaddr *)&serveraddr, (socklen_t *)&serverlen); - printf("E\n"); - //if (n < 0) - // printf("ERROR in recvfrom: %d", n); - printf("Echo from server: %s", buf); - } - return 0; -} - -int udp_server(struct sockaddr_in *local) -{ - printf("\t\t\tperforming UDP SERVER test\n"); - -} - - -int udp_tests(struct sockaddr_in *local, struct sockaddr_in *local) { - printf("\t\tperforming UDP tests\n"); - udp_client(remote); - udp_server(local); -} -int tcp_tests(struct sockaddr_in *local, struct sockaddr_in *local) { - printf("\t\tperforming TCP tests\n"); - tcp_client(remote); - tcp_server(local) -} -int test(struct sockaddr_in *local, struct sockaddr_in *local) { - printf("\tperforming tests\n"); - udp_tests(local, remote); - tcp_tests(local, remote); -} - -int main() -{ - printf("Starting ZeroTier...\n"); - // where you want the zerotier identity/config files for this app to reside - char *path = "/Users/Joseph/code/ZeroTierSDK/build/simple_app/zerotier"; - char *nwid = "565799d8f612388c"; - - // start ZeroTier in separate thread - pid_t pid = fork(); - if(pid) - zt_start_service(path, nwid); - - printf("started!"); - - //zt_join_network(nwid); - //zt_leave_network(nwid); - test(); // run unit tests - - return 0; -} \ No newline at end of file diff --git a/make-liblwip.mk b/make-liblwip.mk deleted file mode 100644 index ca52b9c..0000000 --- a/make-liblwip.mk +++ /dev/null @@ -1,143 +0,0 @@ -# -# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# 3. The name of the author may not be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -# OF SUCH DAMAGE. -# -# This file is part of the lwIP TCP/IP stack. -# -# Author: Adam Dunkels -# - -CONTRIBDIR=ext/contrib -LWIPARCH=$(CONTRIBDIR)/ports/unix - -#Set this to where you have the lwip core module checked out from CVS -#default assumes it's a dir named lwip at the same level as the contrib module -LWIPDIR=ext/lwip/src - - -CCDEP=gcc -CC=gcc -CFLAGS=-O3 -g -Wall -DIPv4 -fPIC - -# Debug output for lwIP -ifeq ($(SDK_LWIP_DEBUG),1) - CFLAGS+=-DLWIP_DEBUG -endif - -CFLAGS:=$(CFLAGS) \ - -I$(LWIPDIR)/include -I$(LWIPARCH)/include -I$(LWIPDIR)/include/ipv4 \ - -I$(LWIPDIR) -I. -Iext -Isrc/stack_drivers/lwip - -# COREFILES, CORE4FILES: The minimum set of files needed for lwIP. -COREFILES=$(LWIPDIR)/core/init.c \ - $(LWIPDIR)/core/def.c \ - $(LWIPDIR)/core/dns.c \ - $(LWIPDIR)/core/inet_chksum.c \ - $(LWIPDIR)/core/ip.c \ - $(LWIPDIR)/core/mem.c \ - $(LWIPDIR)/core/memp.c \ - $(LWIPDIR)/core/netif.c \ - $(LWIPDIR)/core/pbuf.c \ - $(LWIPDIR)/core/raw.c \ - $(LWIPDIR)/core/stats.c \ - $(LWIPDIR)/core/sys.c \ - $(LWIPDIR)/core/tcp.c \ - $(LWIPDIR)/core/tcp_in.c \ - $(LWIPDIR)/core/tcp_out.c \ - $(LWIPDIR)/core/timeouts.c \ - $(LWIPDIR)/core/udp.c - -CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c \ - $(LWIPDIR)/core/ipv4/dhcp.c \ - $(LWIPDIR)/core/ipv4/etharp.c \ - $(LWIPDIR)/core/ipv4/icmp.c \ - $(LWIPDIR)/core/ipv4/igmp.c \ - $(LWIPDIR)/core/ipv4/ip4_frag.c \ - $(LWIPDIR)/core/ipv4/ip4.c \ - $(LWIPDIR)/core/ipv4/ip4_addr.c - -CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c \ - $(LWIPDIR)/core/ipv6/ethip6.c \ - $(LWIPDIR)/core/ipv6/icmp6.c \ - $(LWIPDIR)/core/ipv6/inet6.c \ - $(LWIPDIR)/core/ipv6/ip6.c \ - $(LWIPDIR)/core/ipv6/ip6_addr.c \ - $(LWIPDIR)/core/ipv6/ip6_frag.c \ - $(LWIPDIR)/core/ipv6/mld6.c \ - $(LWIPDIR)/core/ipv6/nd6.c - - # APIFILES: The files which implement the sequential and socket APIs. -APIFILES=$(LWIPDIR)/api/api_lib.c \ - $(LWIPDIR)/api/api_msg.c \ - $(LWIPDIR)/api/err.c \ - $(LWIPDIR)/api/netbuf.c \ - $(LWIPDIR)/api/netdb.c \ - $(LWIPDIR)/api/netifapi.c \ - $(LWIPDIR)/api/sockets.c \ - $(LWIPDIR)/api/tcpip.c - -# NETIFFILES: Files implementing various generic network interface functions -NETIFFILES=$(LWIPDIR)/netif/ethernet.c -#\ -# $(LWIPDIR)/netif/slipif.c - -# SIXLOWPAN: 6LoWPAN -SIXLOWPAN=$(LWIPDIR)/netif/lowpan6.c \ - -# ARCHFILES: Architecture specific files. -ARCHFILES=$(wildcard $(LWIPARCH)/*.c $(LWIPARCH)tapif.c $(LWIPARCH)/netif/list.c $(LWIPARCH)/netif/tcpdump.c) - -# LWIPFILES: All the above. -LWIPFILES=$(COREFILES) $(CORE4FILES) $(APIFILES) $(NETIFFILES) $(ARCHFILES) - -# ipv6 support -ifeq ($(SDK_IPV6),1) - LWIPFILES+=$(CORE6FILES) - CFLAGS+=-DSDK_IPV6=1 -endif -LWIPFILESW=$(wildcard $(LWIPFILES)) -LWIPOBJS=$(notdir $(LWIPFILESW:.c=.o)) - -LWIPLIB=liblwip.so - -%.o: - $(CC) $(CFLAGS) -Isrc/stack_drivers/lwip -c $(<:.o=.c) - -all: $(LWIPLIB) -.PHONY: all - -clean: - rm -f *.o $(LWIPLIB4) $(LWIPLIB6) *.s .depend* *.core core - -depend dep: .depend - -include .depend - -$(LWIPLIB): $(LWIPOBJS) - mkdir -p build - $(CC) -Isrc/stack_drivers/lwip -g -nostartfiles -shared -o build/$@ $^ - -.depend: $(LWIPFILES) - $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend \ No newline at end of file diff --git a/make-linux.mk b/make-linux.mk deleted file mode 100644 index a5427f4..0000000 --- a/make-linux.mk +++ /dev/null @@ -1,358 +0,0 @@ -# -# Makefile for ZeroTier SDK on Linux -# -# Targets -# all: build every target possible on host system, plus tests -# check: reports OK/FAIL of built targets -# tests: build only test applications for host system -# clean: removes all built files, objects, other trash - -# Build everything -all: one linux android lwip pico check - -# ------------------------------------------------------------------------------ -# ----------------------------------- Config ----------------------------------- -# ------------------------------------------------------------------------------ - -# Automagically pick clang or gcc, with preference for clang -# This is only done if we have not overridden these with an environment or CLI variable -ifeq ($(origin CC),default) - CC=$(shell if [ -e /usr/bin/clang ]; then echo clang; else echo gcc; fi) -endif -ifeq ($(origin CXX),default) - CXX=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) -endif - -INCLUDES= -DEFS= -ARCH_FLAGS=-arch x86_64 -CFLAGS= -CXXFLAGS=$(CFLAGS) -Wno-format -fno-rtti -std=c++11 -DZT_SDK - -include objects.mk - -# Target output filenames -STATIC_LIB_NAME = libzt.a -SDK_INTERCEPT_NAME = libztintercept.so -SDK_SERVICE_NAME = zerotier-sdk-service -ONE_SERVICE_NAME = zerotier-one -ONE_CLI_NAME = zerotier-cli -ONE_ID_TOOL_NAME = zerotier-idtool -LWIP_LIB_NAME = liblwip.so -PICO_LIB_NAME = libpicotcp.so -# -STATIC_LIB = $(BUILD)/$(STATIC_LIB_NAME) -SDK_INTERCEPT = $(BUILD)/$(SDK_INTERCEPT_NAME) -SDK_SERVICE = $(BUILD)/$(SDK_SERVICE_NAME) -ONE_SERVICE = $(BUILD)/$(ONE_SERVICE_NAME) -ONE_CLI = $(BUILD)/$(ONE_CLI_NAME) -ONE_IDTOOL = $(BUILD)/$(ONE_IDTOOL_NAME) -LWIP_LIB = $(BUILD)/$(LWIP_LIB_NAME) -PICO_LIB = $(BUILD)/$(PICO_LIB_NAME) -# -LWIP_DIR = ext/lwip -PICOTCP_DIR = ext/picotcp -# -LWIP_DRIVER_FILES = src/stack_drivers/lwip/lwip.cpp -PICO_DRIVER_FILES = src/stack_drivers/picotcp/picotcp.cpp -SDK_SERVICE_CPP_FILES:=src/tap.cpp \ - src/proxy.cpp \ - $(ZT1)/service/OneService.cpp \ - $(ZT1)/one.cpp - -SDK_SERVICE_C_FILES = src/rpc.c -SDK_INTERCEPT_C_FILES:=src/sockets.c \ - src/intercept.c \ - src/rpc.c - -INCLUDES+= -Iext \ - -I$(ZT1)/osdep \ - -I$(ZT1)/node \ - -I$(ZT1)/service \ - -I$(ZT1)/include \ - -I../$(ZT1)/osdep \ - -I../$(ZT1)/node \ - -I../$(ZT1)/service \ - -I. \ - -Isrc \ - -Isrc/stack_drivers - -# ------------------------------------------------------------------------------ -# --------------------------------- ZT Config ---------------------------------- -# ------------------------------------------------------------------------------ - -ZTFLAGS:=-DSDK -DZT_ONE_NO_ROOT_CHECK - -# Disable codesign since open source users will not have ZeroTier's certs -CODESIGN=echo -PRODUCTSIGN=echo -CODESIGN_APP_CERT= -CODESIGN_INSTALLER_CERT= - -# Debug output for ZeroTier service -ifeq ($(ZT_DEBUG),1) - DEFS+=-DZT_TRACE - CFLAGS+=-Wall -Werror -g -pthread $(INCLUDES) $(DEFS) - CXXFLAGS+=-Wall -Werror -g -pthread $(INCLUDES) $(DEFS) - LDFLAGS=-ldl - STRIP?=echo - # The following line enables optimization for the crypto code, since - # C25519 in particular is almost UNUSABLE in -O0 even on a 3ghz box! -ext/lz4/lz4.o node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS) -else - CFLAGS?=-O3 -fstack-protector - CFLAGS+=-Wall -Werror -fPIE -fvisibility=hidden -pthread $(INCLUDES) -DNDEBUG $(DEFS) - CXXFLAGS?= -fstack-protector - CXXFLAGS+=-Wall -Werror -Wreorder -fPIE -fvisibility=hidden -fno-rtti -pthread $(INCLUDES) -DNDEBUG $(DEFS) -std=c++11 - LDFLAGS=-ldl -pie -Wl,-z,relro,-z,now - STRIP?=strip - STRIP+=--strip-all -endif - -# ------------------------------------------------------------------------------ -# -------------------------------- SDK Config ---------------------------------- -# ------------------------------------------------------------------------------ - -# Debug output for the SDK -# Specific levels can be controlled in src/debug.h -ifeq ($(SDK_DEBUG),1) - DEFS+=-DSDK_DEBUG -g -endif - -# ------------------------------------------------------------------------------ -# ------------------------ Network Stack Configuration ------------------------- -# ------------------------------------------------------------------------------ - -# lwIP -ifeq ($(SDK_LWIP),1) - STACK_FLAGS+=-DSDK_LWIP - INCLUDES+= -I$(LWIP_DIR)/src/include \ - -I$(LWIP_DIR)/src/include/ipv4 \ - -I$(LWIP_DIR)/src/include/ipv6 \ - -Isrc/stack_drivers/lwip - - ifeq ($(SDK_LWIP_DEBUG),1) - LWIP_FLAGS+=SDK_LWIP_DEBUG=1 - endif -endif - -# picoTCP -ifeq ($(SDK_PICOTCP),1) - STACK_FLAGS+=-DSDK_PICOTCP - INCLUDES+= -I$(PICOTCP_DIR)/include \ - -I$(PICOTCP_DIR)/build/include \ - -Isrc/stack_drivers/picotcp -endif - -# jip -ifeq ($(SDK_JIP),1) - STACK_FLAGS+=-DSDK_JIP - INCLUDES+= -Isrc/stack_drivers/jip -endif - - -# TCP protocol version -ifeq ($(SDK_IPV4),1) - LWIP_FLAGS+=SDK_IPV4=1 - STACK_FLAGS+=-DSDK_IPV4 -endif - -ifeq ($(SDK_IPV6),1) - LWIP_FLAGS+=SDK_IPV6=1 - STACK_FLAGS+=-DSDK_IPV6 -endif - -lwip: - -make -f make-liblwip.mk $(LWIP_FLAGS) - -pico: - mkdir -p build - cd ext/picotcp; make lib ARCH=shared IPV4=1 IPV6=1 - $(CC) -g -nostartfiles -shared -o ext/picotcp/build/lib/libpicotcp.so ext/picotcp/build/lib/*.o ext/picotcp/build/modules/*.o - cp ext/picotcp/build/lib/libpicotcp.so build/libpicotcp.so - -jip: - -make -f make-jip.mk $(JIP_FLAGS) - -# ------------------------------------------------------------------------------ -# ---------------------------------- Linux ------------------------------------- -# ------------------------------------------------------------------------------ - -# Build everything -linux: one linux_service_and_intercept linux_static_lib - -# Build vanilla ZeroTier One binary -one: $(OBJS) $(ZT1)/service/OneService.o $(ZT1)/one.o $(ZT1)/osdep/LinuxEthernetTap.o - mkdir -p $(BUILD) - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(BUILD)/zerotier-one $(OBJS) $(ZT1)/service/OneService.o $(ZT1)/one.o $(ZT1)/osdep/LinuxEthernetTap.o - $(STRIP) $(ONE_SERVICE) - cp $(ONE_SERVICE) $(INT)/docker/docker_demo/$(ONE_SERVICE_NAME) - -# --------------------------------------- -# --------------- Intercept ------------- -# --------------------------------------- - -# Build only the intercept library -linux_intercept: - # Use gcc not clang to build standalone intercept library since gcc is typically used for libc and we want to ensure maximal ABI compatibility - gcc $(DEFS) $(INCLUDES) -g -O2 -Wall -std=c99 -fPIC -DVERBOSE -D_GNU_SOURCE -DSDK_INTERCEPT -nostdlib -nostdlib -shared -o $(SDK_INTERCEPT) $(SDK_INTERCEPT_C_FILES) -ldl - -# --------------------------------------- -# ----- Service Library Combinations ---- -# --------------------------------------- - -# Build only the SDK service -ifeq ($(SDK_LWIP),1) -linux_sdk_service: lwip $(OBJS) - mkdir -p build - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(STACK_FLAGS) $(DEFS) $(INCLUDES) $(ZTFLAGS) -DSDK_SERVICE -o $(SDK_SERVICE) $(OBJS) $(LWIP_DRIVER_FILES) $(SDK_SERVICE_CPP_FILES) $(SDK_SERVICE_C_FILES) -ldl -else -linux_sdk_service: pico $(OBJS) - mkdir -p build - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(STACK_FLAGS) $(DEFS) $(INCLUDES) $(ZTFLAGS) -DSDK_SERVICE -o $(SDK_SERVICE) $(OBJS) $(PICO_DRIVER_FILES) $(SDK_SERVICE_CPP_FILES) $(SDK_SERVICE_C_FILES) -ldl -endif - ln -sf $(SDK_SERVICE_NAME) $(BUILD)/zerotier-cli - ln -sf $(SDK_SERVICE_NAME) $(BUILD)/zerotier-idtool - -# Build both intercept library and SDK service (separate) -linux_service_and_intercept: linux_intercept linux_sdk_service - -# Builds a single static library which contains everything -linux_static_lib: pico $(OBJS) - $(CC) $(CFLAGS) $(STACK_FLAGS) $(DEFS) $(INCLUDES) $(ZTFLAGS) -DSDK_SERVICE -DSDK -DSDK_BUNDLED $(SDK_INTERCEPT_C_FILES) -c - $(CXX) $(CXXFLAGS) $(STACK_FLAGS) $(DEFS) $(INCLUDES) $(ZTFLAGS) -DSDK_SERVICE -DSDK -DSDK_BUNDLED $(PICO_DRIVER_FILES) $(SDK_SERVICE_CPP_FILES) src/service.cpp -c - ar -rcs build/libzt.a picotcp.o proxy.o tap.o one.o OneService.o service.o sockets.o rpc.o intercept.o $(OBJS) - -# Builds zts_* library tests -linux_static_lib_tests_6: - mkdir -p $(TEST_OBJDIR) - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(INCLUDES) $(STACK_FLAGS) $(DEFS) -DSDK_SERVICE -DSDK -DSDK_BUNDLED -Isrc tests/zts/zts.udpserver6.c -o $(TEST_OBJDIR)/$(OSTYPE).zts.udpserver6.out -Lbuild -lzt -ldl - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(INCLUDES) $(STACK_FLAGS) $(DEFS) -DSDK_SERVICE -DSDK -DSDK_BUNDLED -Isrc tests/zts/zts.udpclient6.c -o $(TEST_OBJDIR)/$(OSTYPE).zts.udpclient6.out -Lbuild -lzt -ldl - -# ------------------------------------------------------------------------------ -# --------------------------------- Android ------------------------------------ -# ------------------------------------------------------------------------------ - -# Build all Android targets -# Chip architectures can be specified in integrations/android/android_jni_lib/java/jni/Application.mk -android: android_jni_lib - -# TODO: CHECK if ANDROID/GRADLE TOOLS are installed -# Build library for Android Unity integrations -# Build JNI library for Android app integration -android_jni_lib: - cd $(INT)/android/android_jni_lib/proj; ./gradlew assembleDebug - mkdir -p $(BUILD)/android_jni_lib - cp docs/android_zt_sdk.md $(BUILD)/android_jni_lib/README.md - mv -f $(INT)/android/android_jni_lib/java/libs/* $(BUILD)/android_jni_lib - cp -R $(BUILD)/android_jni_lib/* $(INT)/android/example_app/app/src/main/jniLibs - -# ------------------------------------------------------------------------------ -# ---------------------------------- Testing ----------------------------------- -# ------------------------------------------------------------------------------ - -unit_test: one linux_service_and_intercept - mkdir -p $(BUILD) - cp $(SDK_INTERCEPT) tests/unit/docker/$(SDK_INTERCEPT_NAME) - cp $(SDK_SERVICE) tests/unit/docker/$(SDK_SERVICE_NAME) - cp $(LWIP_LIB) tests/unit/docker/$(LWIP_LIB_NAME) - cp $(ONE_CLI) tests/unit/docker/$(ONE_CLI_NAME) - cp $(ONE_SERVICE) tests/unit/docker/$(ONE_SERVICE_NAME) - touch tests/unit/docker/docker_demo.name - # Server image - # This image will contain the server application and everything required to - # run the ZeroTier SDK service - cd tests/unit/docker; docker build --tag="docker_demo" -f sdk_dockerfile . - # Client image - # This image is merely a test image designed to interact with the server image - # in order to verify it's working properly - cd tests/unit/docker; docker build --tag="docker_demo_monitor" -f monitor_dockerfile . - -# Build the docker demo images -docker_demo: one linux_service_and_intercept - mkdir -p $(BUILD) - cp $(SDK_INTERCEPT) $(INT)/docker/docker_demo/$(SDK_INTERCEPT_NAME) - cp $(SDK_SERVICE) $(INT)/docker/docker_demo/$(SDK_SERVICE_NAME) - cp $(LWIP_LIB) $(INT)/docker/docker_demo/$(LWIP_LIB_NAME) - cp $(ONE_CLI) $(INT)/docker/docker_demo/$(ONE_CLI_NAME) - touch $(INT)/docker/docker_demo/docker_demo.name - # Server image - # This image will contain the server application and everything required to - # run the ZeroTier SDK service - cd $(INT)/docker/docker_demo; docker build --tag="docker_demo" -f sdk_dockerfile . - # Client image - # This image is merely a test image designed to interact with the server image - # in order to verify it's working properly - cd $(INT)/docker/docker_demo; docker build --tag="docker_demo_monitor" -f monitor_dockerfile . - -# Builds all docker test images -docker_images: one linux_service_and_intercept - ./tests/docker/build_images.sh - -# Runs docker container tests -docker_test: - ./tests/docker/test.sh - -# Checks the results of the docker tests -docker_check_test: - ./tests/docker/check.sh - -# Check for the presence of built frameworks/bundles/libaries -check: - -./check.sh $(LWIP_LIB) - -./check.sh $(PICO_LIB) - -./check.sh $(SDK_INTERCEPT) - -./check.sh $(ONE_SERVICE) - -./check.sh $(SDK_SERVICE) - -./check.sh $(STATIC_LIB) - -./check.sh $(BUILD)/android_jni_lib/arm64-v8a/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/armeabi/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/armeabi-v7a/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/mips/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/mips64/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/x86/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/x86_64/libZeroTierOneJNI.so - -# Tests -OSTYPE=$(shell uname -s | tr '[A-Z]' '[a-z]') -TEST_OBJDIR := $(BUILD)/tests -TEST_SOURCES := $(wildcard tests/api_test/*.c) -TEST_TARGETS := $(addprefix $(BUILD)/tests/$(OSTYPE).,$(notdir $(TEST_SOURCES:.c=.out))) - -$(BUILD)/tests/$(OSTYPE).%.out: tests/api_test/%.c - -$(CC) $(CC_FLAGS) -o $@ $< - -$(TEST_OBJDIR): - mkdir -p $(TEST_OBJDIR) - -tests: $(TEST_OBJDIR) $(TEST_TARGETS) - mkdir -p $(BUILD)/tests; - -test_suite: tests lwip linux_service_and_intercept - -# ------------------------------------------------------------------------------ -# ------------------------------ Administrative -------------------------------- -# ------------------------------------------------------------------------------ - -clean_android: - # android JNI lib project - -test -s /usr/bin/javac || { echo "Javac not found"; exit 1; } - -cd $(INT)/android/android_jni_lib/proj; ./gradlew clean - -rm -rf $(INT)/android/android_jni_lib/proj/build - # example android app project - -cd $(INT)/android/example_app; ./gradlew clean - -clean_basic: - -rm -rf $(BUILD)/* - -rm -rf $(INT)/Unity3D/Assets/Plugins/* - -rm -rf zerotier-cli zerotier-idtool - -find . -type f \( -name $(ONE_SERVICE_NAME) -o -name $(SDK_SERVICE_NAME) -o -name $(ONE_CLI_NAME) \) -delete - -find . -type f \( -name '*.a' -o -name '*.o' -o -name '*.so' -o -name '*.o.d' -o -name '*.out' -o -name '*.log' -o -name '*.dSYM' \) -delete - -clean_thorough: clean_basic - -rm -rf .depend - -clean: clean_basic - -clean_for_production: - -find . -type f \( -name '*.identity'\) -delete \ No newline at end of file diff --git a/make-mac.mk b/make-mac.mk deleted file mode 100644 index 7cd0c01..0000000 --- a/make-mac.mk +++ /dev/null @@ -1,373 +0,0 @@ -# -# Makefile for ZeroTier SDK on macOS -# -# Targets -# all: build every target possible on host system, plus tests -# check: reports OK/FAIL of built targets -# tests: build only test applications for host system -# clean: removes all built files, objects, other trash - -# Build everything -all: one osx ios android lwip pico check - -# ------------------------------------------------------------------------------ -# ----------------------------------- Config ----------------------------------- -# ------------------------------------------------------------------------------ - -# Automagically pick clang or gcc, with preference for clang -# This is only done if we have not overridden these with an environment or CLI variable -ifeq ($(origin CC),default) - CC=$(shell if [ -e /usr/bin/clang ]; then echo clang; else echo gcc; fi) -endif -ifeq ($(origin CXX),default) - CXX=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) -endif - -INCLUDES= -DEFS= -ARCH_FLAGS=-arch x86_64 -CFLAGS= -CXXFLAGS=$(CFLAGS) -Wno-format -fno-rtti -std=c++11 -DZT_SDK - -include objects.mk - -# Target output filenames -STATIC_LIB_NAME = libzt.a -INTERCEPT_NAME = libztintercept.so -SDK_SERVICE_NAME = zerotier-sdk-service -ONE_SERVICE_NAME = zerotier-one -ONE_CLI_NAME = zerotier-cli -ONE_ID_TOOL_NAME = zerotier-idtool -LWIP_LIB_NAME = liblwip.so -PICO_LIB_NAME = libpicotcp.so -# -STATIC_LIB = $(BUILD)/$(STATIC_LIB_NAME) -SDK_INTERCEPT = $(BUILD)/$(INTERCEPT_NAME) -SDK_SERVICE = $(BUILD)/$(SDK_SERVICE_NAME) -ONE_SERVICE = $(BUILD)/$(ONE_SERVICE_NAME) -ONE_CLI = $(BUILD)/$(ONE_CLI_NAME) -ONE_IDTOOL = $(BUILD)/$(ONE_IDTOOL_NAME) -LWIP_LIB = $(BUILD)/$(LWIP_LIB_NAME) -PICO_LIB = $(BUILD)/$(PICO_LIB_NAME) -# -LWIP_DIR = ext/lwip -PICOTCP_DIR = ext/picotcp -# -LWIP_DRIVER_FILES = src/stack_drivers/lwip/lwip.cpp -PICO_DRIVER_FILES = src/stack_drivers/picotcp/picotcp.cpp -SDK_SERVICE_CPP_FILES:=src/tap.cpp \ - src/proxy.cpp \ - $(ZT1)/service/OneService.cpp \ - $(ZT1)/one.cpp - -SDK_SERVICE_C_FILES = src/rpc.c -SDK_INTERCEPT_C_FILES:=src/sockets.c \ - src/intercept.c \ - src/rpc.c - -INCLUDES+= -Iext \ - -I$(ZT1)/osdep \ - -I$(ZT1)/node \ - -I$(ZT1)/service \ - -I$(ZT1)/include \ - -I../$(ZT1)/osdep \ - -I../$(ZT1)/node \ - -I../$(ZT1)/service \ - -I. \ - -Isrc \ - -Isrc/stack_drivers - -# ------------------------------------------------------------------------------ -# --------------------------------- ZT Config ---------------------------------- -# ------------------------------------------------------------------------------ - -ZTFLAGS:=-DZT_SDK -DZT_ONE_NO_ROOT_CHECK - -# Disable codesign since open source users will not have ZeroTier's certs -CODESIGN=echo -PRODUCTSIGN=echo -CODESIGN_APP_CERT= -CODESIGN_INSTALLER_CERT= - -# Debug output for ZeroTier service -ifeq ($(ZT_DEBUG),1) - DEFS+=-DZT_TRACE - #CFLAGS+=-Wall -fPIE -fvisibility=hidden -pthread $(INCLUDES) $(DEFS) - CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS) - STRIP=echo - # The following line enables optimization for the crypto code, since - # C25519 in particular is almost UNUSABLE in heavy testing without it. -#ext/lz4/lz4.o node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS) -else - CFLAGS?=-Ofast -fstack-protector - CFLAGS+=-Wall -fPIE -fvisibility=hidden -pthread $(INCLUDES) $(DEFS) - #CFLAGS+=$(ARCH_FLAGS) -Wall -flto -fPIC -pthread -mmacosx-version-min=10.7 -DNDEBUG -Wno-unused-private-field $(INCLUDES) $(DEFS) - STRIP=strip -endif - -# ------------------------------------------------------------------------------ -# -------------------------------- SDK Config ---------------------------------- -# ------------------------------------------------------------------------------ - -# Debug output for the SDK -# Specific levels can be controlled in src/debug.h -ifeq ($(SDK_DEBUG),1) - DEFS+=-DSDK_DEBUG -g -endif - -# ------------------------------------------------------------------------------ -# ------------------------ Network Stack Configuration ------------------------- -# ------------------------------------------------------------------------------ - -# lwIP -ifeq ($(SDK_LWIP),1) - STACK_FLAGS+=-DSDK_LWIP - INCLUDES+= -I$(LWIP_DIR)/src/include \ - -I$(LWIP_DIR)/src/include/ipv4 \ - -I$(LWIP_DIR)/src/include/ipv6 \ - -Isrc/stack_drivers/lwip - - ifeq ($(SDK_LWIP_DEBUG),1) - LWIP_FLAGS+=SDK_LWIP_DEBUG=1 - endif -endif - -# picoTCP -ifeq ($(SDK_PICOTCP),1) - STACK_FLAGS+=-DSDK_PICOTCP - INCLUDES+= -I$(PICOTCP_DIR)/include \ - -I$(PICOTCP_DIR)/build/include \ - -Isrc/stack_drivers/picotcp -endif - -# jip -ifeq ($(SDK_JIP),1) - STACK_FLAGS+=-DSDK_JIP - INCLUDES+= -Isrc/stack_drivers/jip -endif - - -# TCP protocol version -ifeq ($(SDK_IPV4),1) - LWIP_FLAGS+=SDK_IPV4=1 - STACK_FLAGS+=-DSDK_IPV4 -endif - -ifeq ($(SDK_IPV6),1) - LWIP_FLAGS+=SDK_IPV6=1 - STACK_FLAGS+=-DSDK_IPV6 -endif - -lwip: - -make -f make-liblwip.mk $(LWIP_FLAGS) - -pico: - mkdir -p build - cd ext/picotcp; make lib ARCH=shared IPV4=1 IPV6=1 - $(CC) -g -nostartfiles -shared -o ext/picotcp/build/lib/libpicotcp.so ext/picotcp/build/lib/*.o ext/picotcp/build/modules/*.o - cp ext/picotcp/build/lib/libpicotcp.so build/libpicotcp.so - -jip: - -make -f make-jip.mk $(JIP_FLAGS) - -# ------------------------------------------------------------------------------ -# -------------------------------- IOS / macOS --------------------------------- -# ------------------------------------------------------------------------------ -# Build all Apple targets -apple: one osx ios - -# Build vanilla ZeroTier One binary -one: $(OBJS) $(ZT1)/service/OneService.o $(ZT1)/one.o $(ZT1)/osdep/OSXEthernetTap.o - mkdir -p $(BUILD) - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(BUILD)/zerotier-one $(OBJS) $(ZT1)/service/OneService.o $(ZT1)/one.o $(ZT1)/osdep/OSXEthernetTap.o - $(STRIP) $(ONE_SERVICE) - cp $(ONE_SERVICE) $(INT)/docker/docker_demo/$(ONE_SERVICE_NAME) - -# Build all iOS targets -ios: ios_app_framework ios_unity3d_bundle - -# Build all OSX targets -osx: osx_app_framework osx_unity3d_bundle osx_sdk_service osx_intercept osx_static_lib - -# --------------------------------------- -# ----------- App Frameworks ------------ -# --------------------------------------- - -# TODO: CHECK if XCODE TOOLS are installed -# Build frameworks for application development -osx_app_framework: - cd $(INT)/apple/ZeroTierSDK_Apple; xcodebuild -configuration Release -scheme ZeroTierSDK_OSX build SYMROOT="../../../$(BUILD)/osx_app_framework" - cd $(INT)/apple/ZeroTierSDK_Apple; xcodebuild -configuration Debug -scheme ZeroTierSDK_OSX build SYMROOT="../../../$(BUILD)/osx_app_framework" - cp docs/osx.md $(BUILD)/osx_app_framework/README.md - -ios_app_framework: - cd $(INT)/apple/ZeroTierSDK_Apple; xcodebuild -configuration Release -scheme ZeroTierSDK_iOS build SYMROOT="../../../$(BUILD)/ios_app_framework" - cd $(INT)/apple/ZeroTierSDK_Apple; xcodebuild -configuration Debug -scheme ZeroTierSDK_iOS build SYMROOT="../../../$(BUILD)/ios_app_framework" - cp docs/ios.md $(BUILD)/ios_app_framework/README.md - -# --------------------------------------- -# ------------ Unity Bundles ------------ -# --------------------------------------- - -# Build bundles for Unity integrations -osx_unity3d_bundle: - cd $(INT)/apple/ZeroTierSDK_Apple; xcodebuild -configuration Release -scheme ZeroTierSDK_Unity3D_OSX build SYMROOT="../../../$(BUILD)/osx_unity3d_bundle" - cd $(INT)/apple/ZeroTierSDK_Apple; xcodebuild -configuration Debug -scheme ZeroTierSDK_Unity3D_OSX build SYMROOT="../../../$(BUILD)/osx_unity3d_bundle" - cp docs/osx_unity3d.md $(BUILD)/osx_unity3d_bundle/README.md - chmod 755 $(BUILD)/osx_unity3d_bundle/Debug/ZeroTierSDK_Unity3D_OSX.bundle - cp -p -R $(BUILD)/osx_unity3d_bundle/Debug/ZeroTierSDK_Unity3D_OSX.bundle $(INT)/Unity3D/Assets/Plugins - -ios_unity3d_bundle: - cd $(INT)/apple/ZeroTierSDK_Apple; xcodebuild -configuration Release -scheme ZeroTierSDK_Unity3D_iOS build SYMROOT="../../../$(BUILD)/ios_unity3d_bundle" - cd $(INT)/apple/ZeroTierSDK_Apple; xcodebuild -configuration Debug -scheme ZeroTierSDK_Unity3D_iOS build SYMROOT="../../../$(BUILD)/ios_unity3d_bundle" - cp docs/ios_unity3d.md $(BUILD)/ios_unity3d_bundle/README.md - -# --------------------------------------- -# --------------- Intercept ------------- -# --------------------------------------- - -osx_intercept: - # Use gcc not clang to build standalone intercept library since gcc is typically used for libc and we want to ensure maximal ABI compatibility - gcc $(DEFS) $(INCLUDES) -g -O2 -Wall -std=c99 -fPIC -DVERBOSE -D_GNU_SOURCE -DSDK_INTERCEPT -nostdlib -nostdlib -shared -o $(SDK_INTERCEPT) $(SDK_INTERCEPT_C_FILES) -ldl - -# --------------------------------------- -# ----- Service Library Combinations ---- -# --------------------------------------- - -# Build only the SDK service -ifeq ($(SDK_LWIP),1) -osx_sdk_service: lwip $(OBJS) - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(STACK_FLAGS) $(DEFS) $(INCLUDES) $(ZTFLAGS) -DSDK_SERVICE -o $(SDK_SERVICE) $(OBJS) $(LWIP_DRIVER_FILES) $(SDK_SERVICE_CPP_FILES) $(SDK_SERVICE_C_FILES) -ldl -else -osx_sdk_service: pico $(OBJS) - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(STACK_FLAGS) $(DEFS) $(INCLUDES) $(ZTFLAGS) -DSDK_SERVICE -o $(SDK_SERVICE) $(OBJS) $(PICO_DRIVER_FILES) $(SDK_SERVICE_CPP_FILES) $(SDK_SERVICE_C_FILES) -ldl -endif - ln -sf $(SDK_SERVICE_NAME) $(BUILD)/zerotier-cli - ln -sf $(SDK_SERVICE_NAME) $(BUILD)/zerotier-idtool - -# Build both intercept library and SDK service (separate) -osx_service_and_intercept: osx_intercept osx_sdk_service - -ifeq ($(SDK_LWIP),1) -osx_static_lib: lwip $(OBJS) - $(CXX) $(CXXFLAGS) $(STACK_FLAGS) $(DEFS) $(INCLUDES) $(ZTFLAGS) -DSDK_SERVICE -DSDK -DSDK_BUNDLED $(LWIP_DRIVER_FILES) $(SDK_INTERCEPT_C_FILES) $(SDK_SERVICE_CPP_FILES) src/service.cpp -c - ar -rcs build/libzt.a lwip.o proxy.o tap.o one.o OneService.o service.o sockets.o rpc.o intercept.o $(OBJS) -else -osx_static_lib: pico $(OBJS) - $(CXX) $(CXXFLAGS) $(STACK_FLAGS) $(DEFS) $(INCLUDES) $(ZTFLAGS) -DSDK_SERVICE -DSDK -DSDK_BUNDLED $(PICO_DRIVER_FILES) $(SDK_INTERCEPT_C_FILES) $(SDK_SERVICE_CPP_FILES) src/service.cpp -c - libtool -static -o build/libzt.a picotcp.o proxy.o tap.o one.o OneService.o service.o sockets.o rpc.o intercept.o $(OBJS) -endif - -# Builds zts_* library tests -osx_static_lib_tests: - mkdir -p $(TEST_OBJDIR) - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(INCLUDES) $(STACK_FLAGS) $(DEFS) -DSDK_SERVICE -DSDK -DSDK_BUNDLED -Isrc tests/shared_test/zts.udpserver4.c -o $(TEST_OBJDIR)/$(OSTYPE).zts.udpserver4.out -Lbuild -lzt -ldl - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(INCLUDES) $(STACK_FLAGS) $(DEFS) -DSDK_SERVICE -DSDK -DSDK_BUNDLED -Isrc tests/shared_test/zts.udpclient4.c -o $(TEST_OBJDIR)/$(OSTYPE).zts.udpclient4.out -Lbuild -lzt -ldl - -# ------------------------------------------------------------------------------ -# ---------------------------------- Android ----------------------------------- -# ------------------------------------------------------------------------------ - -# Build all Android targets -# Chip architectures can be specified in integrations/android/android_jni_lib/java/jni/Application.mk -android: android_jni_lib - -# TODO: CHECK if ANDROID/GRADLE TOOLS are installed -# Build library for Android Unity integrations -# Build JNI library for Android app integration -android_jni_lib: - cd $(INT)/android/android_jni_lib/proj; ./gradlew assembleDebug - mkdir -p $(BUILD)/android_jni_lib - cp docs/android.md $(BUILD)/android_jni_lib/README.md - mv -f $(INT)/android/android_jni_lib/java/libs/* $(BUILD)/android_jni_lib - cp -R $(BUILD)/android_jni_lib/* $(INT)/android/example_app/app/src/main/jniLibs - -# ------------------------------------------------------------------------------ -# ---------------------------------- Testing ----------------------------------- -# ------------------------------------------------------------------------------ - -# Check for the presence of built frameworks/bundles/libaries -check: - -./check.sh $(LWIP_LIB) - -./check.sh $(PICO_LIB) - -./check.sh $(SDK_INTERCEPT) - -./check.sh $(ONE_SERVICE) - -./check.sh $(SDK_SERVICE) - -./check.sh $(STATIC_LIB) - -./check.sh $(BUILD)/osx_unity3d_bundle/Debug/ZeroTierSDK_Unity3D_OSX.bundle - -./check.sh $(BUILD)/osx_app_framework/Debug/ZeroTierSDK_OSX.framework - -./check.sh $(BUILD)/ios_app_framework/Debug-iphoneos/ZeroTierSDK_iOS.framework - -./check.sh $(BUILD)/ios_unity3d_bundle/Debug-iphoneos/ZeroTierSDK_Unity3D_iOS.bundle - -./check.sh $(BUILD)/android_jni_lib/arm64-v8a/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/armeabi/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/armeabi-v7a/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/mips/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/mips64/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/x86/libZeroTierOneJNI.so - -./check.sh $(BUILD)/android_jni_lib/x86_64/libZeroTierOneJNI.so - -# Tests -OSTYPE=$(shell uname -s | tr '[A-Z]' '[a-z]') -TEST_OBJDIR := $(BUILD)/tests -TEST_SOURCES := $(wildcard tests/api_test/*.c) -TEST_TARGETS := $(addprefix $(BUILD)/tests/$(OSTYPE).,$(notdir $(TEST_SOURCES:.c=.out))) - -$(BUILD)/tests/$(OSTYPE).%.out: tests/api_test/%.c - -$(CC) $(CC_FLAGS) -o $@ $< - -$(TEST_OBJDIR): - mkdir -p $(TEST_OBJDIR) - -tests: $(TEST_OBJDIR) $(TEST_TARGETS) - mkdir -p $(BUILD)/tests; - mkdir -p build/tests/zerotier - -test_suite: tests lwip osx_service_and_intercept - -# ------------------------------------------------------------------------------ -# ------------------------------ Administrative -------------------------------- -# ------------------------------------------------------------------------------ - -JAVAC := $(shell which javac) - -clean_android: - # android JNI lib project - -test -s /usr/bin/javac || { echo "Javac not found"; exit 1; } - -cd $(INT)/android/android_jni_lib/proj; ./gradlew clean - -rm -rf $(INT)/android/android_jni_lib/proj/build - # example android app project - -cd $(INT)/android/example_app; ./gradlew clean - -clean_basic: - #-rm -rf .depend - -rm -rf $(BUILD)/* - -rm -rf $(INT)/Unity3D/Assets/Plugins/* - -rm -rf zerotier-cli zerotier-idtool - -find . -type f \( -name $(ONE_SERVICE_NAME) -o -name $(SDK_SERVICE_NAME) \) -delete - -find . -type f \( -name '*.o' -o -name '*.so' -o -name '*.o.d' -o -name '*.out' -o -name '*.log' -o -name '*.dSYM' \) -delete - -clean: clean_basic - -clean_for_production: - -find . -type f \( -name '*.identity'\) -delete - -prep: - cp $(INT)/android/android_jni_lib/java/libs/* build - -# Copy and rename source files into example projects to follow local ordinances -update_examples: - cp src/wrappers/dotnet/DotNetWrapper.cs integrations/Unity3D/Assets/ZTSDK.cs - cp src/wrappers/java/JavaWrapper.java integrations/android/example_app/app/src/main/java/ZeroTier/ZTSDK.java - -# For authors -# Copies documentation to all of the relevant directories to make viewing in the repo a little easier -update_docs: - cp docs/intro.md README.md - cp docs/network_stacks.md src/stack_drivers/README.md - cp docs/integrations.md integrations/README.md - cp docs/osx.md integrations/apple/example_app/OSX/README.md - cp docs/ios.md integrations/apple/example_app/iOS/README.md - cp docs/docker.md integrations/docker/README.md - cp docs/android.md integrations/android/README.md - cp docs/osx_unity3d.md integrations/Unity3D/README.md - cp docs/tests.md tests/README.md diff --git a/objects.mk b/objects.mk deleted file mode 100644 index 7b44c5a..0000000 --- a/objects.mk +++ /dev/null @@ -1,36 +0,0 @@ -OBJS=\ - zto/controller/EmbeddedNetworkController.o \ - zto/controller/JSONDB.o \ - zto/node/C25519.o \ - zto/node/Capability.o \ - zto/node/CertificateOfMembership.o \ - zto/node/CertificateOfOwnership.o \ - zto/node/Cluster.o \ - zto/node/Identity.o \ - zto/node/IncomingPacket.o \ - zto/node/InetAddress.o \ - zto/node/Membership.o \ - zto/node/Multicaster.o \ - zto/node/Network.o \ - zto/node/NetworkConfig.o \ - zto/node/Node.o \ - zto/node/OutboundMulticast.o \ - zto/node/Packet.o \ - zto/node/Path.o \ - zto/node/Peer.o \ - zto/node/Poly1305.o \ - zto/node/Revocation.o \ - zto/node/Salsa20.o \ - zto/node/SelfAwareness.o \ - zto/node/SHA512.o \ - zto/node/Switch.o \ - zto/node/Tag.o \ - zto/node/Topology.o \ - zto/node/Utils.o \ - zto/osdep/ManagedRoute.o \ - zto/osdep/Http.o \ - zto/osdep/OSUtils.o \ - zto/service/ClusterGeoIpService.o \ - zto/service/SoftwareUpdater.o \ - zto/ext/http-parser/http_parser.o - diff --git a/src/README.md b/src/README.md deleted file mode 100644 index 210bb17..0000000 --- a/src/README.md +++ /dev/null @@ -1,8 +0,0 @@ -Source Directory Structure -==== - -`wrappers` - Example bindings of the ZeroTierSDK Sockets API to your favorite native languages - -`stack_drivers` - Drivers to mate various network stacks to the ZeroTier tap interface - -See [here](../docs/technical.md) for a technical discussion on this all works. \ No newline at end of file diff --git a/src/debug.h b/src/debug.h deleted file mode 100644 index b9b472d..0000000 --- a/src/debug.h +++ /dev/null @@ -1,159 +0,0 @@ - -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include -#include -#include - -#ifndef _SDK_DEBUG_H_ -#define _SDK_DEBUG_H_ - -#define DEBUG_LEVEL 0 // Set this to adjust what you'd like to see in the debug traces - -#define MSG_ERROR 1 // Errors -#define MSG_TRANSFER 2 // RX/TX specific statements -#define MSG_INFO 3 // Information which is generally useful to any developer -#define MSG_EXTRA 4 // If nothing in your world makes sense -#define MSG_FLOW 5 // High-level flow messages - -#define __SHOW_FILENAMES__ true -#define __SHOW_COLOR__ true - -// Colors -#if defined(__APPLE__) - #include "TargetConditionals.h" -#endif -#if defined(__SHOW_COLOR__) && !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(__APP_FRAMEWORK__) - #define RED "\x1B[31m" - #define GRN "\x1B[32m" - #define YEL "\x1B[33m" - #define BLU "\x1B[34m" - #define MAG "\x1B[35m" - #define CYN "\x1B[36m" - #define WHT "\x1B[37m" - #define RESET "\x1B[0m" -#else - #define RED - #define GRN - #define YEL - #define BLU - #define MAG - #define CYN - #define WHT - #define RESET -#endif - -// filenames -#if __SHOW_FILENAMES__ - #if __SHOW_FULL_FILENAME_PATH__ - #define __FILENAME__ __FILE__ // show the entire mess - #else - #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // shorten - #endif -#else - #define __FILENAME__ // omit filename -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __linux__ - #define THREAD_ID (long)getpid() -#elif __APPLE__ - #define THREAD_ID (long)syscall(SYS_thread_selfid) -#endif - -#if defined(__ANDROID__) - #include - #include - #define LOG_TAG "ZTSDK" -#endif - -//#if defined(SDK_DEBUG) - #if DEBUG_LEVEL >= MSG_ERROR - #define DEBUG_ERROR(fmt, args...) fprintf(stderr, RED "ZT_ERROR[%ld] : %14s:%4d:%25s: " fmt "\n" RESET, THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args) - #else - #define DEBUG_ERROR(fmt, args...) - #endif - - #if DEBUG_LEVEL >= MSG_INFO - #if defined(__ANDROID__) - #define DEBUG_INFO(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_INFO : %14s:%4d:%20s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args)) - #define DEBUG_BLANK(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_INFO : %14s:%4d:" fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args)) - #define DEBUG_ATTN(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_INFO : %14s:%4d:%25s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args)) - #define DEBUG_STACK(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_STACK: %14s:%4d:%25s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args)) - #else - #define DEBUG_INFO(fmt, args...) fprintf(stderr, "ZT_INFO [%ld] : %14s:%4d:%25s: " fmt "\n", THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args) - #define DEBUG_ATTN(fmt, args...) fprintf(stderr, CYN "ZT_ATTN [%ld] : %14s:%4d:%25s: " fmt "\n" RESET, THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args) - #define DEBUG_STACK(fmt, args...) fprintf(stderr, YEL "ZT_STACK[%ld] : %14s:%4d:%25s: " fmt "\n" RESET, THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args) - #define DEBUG_BLANK(fmt, args...) fprintf(stderr, "ZT_INFO [%ld] : %14s:%4d:" fmt "\n", THREAD_ID, __FILENAME__, __LINE__, ##args) - #endif - #else - #define DEBUG_INFO(fmt, args...) - #define DEBUG_BLANK(fmt, args...) - #define DEBUG_ATTN(fmt, args...) - #define DEBUG_STACK(fmt, args...) - #endif - - #if DEBUG_LEVEL >= MSG_TRANSFER - #if defined(__ANDROID__) - #define DEBUG_TRANS(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_TRANS : %14s:%4d:%25s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args)) - #else - #define DEBUG_TRANS(fmt, args...) fprintf(stderr, GRN "ZT_TRANS[%ld] : %14s:%4d:%25s: " fmt "\n" RESET, THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args) - #endif - #else - #define DEBUG_TRANS(fmt, args...) - #endif - - #if DEBUG_LEVEL >= MSG_EXTRA - #if defined(__ANDROID__) - #define DEBUG_EXTRA(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_EXTRA : %14s:%4d:%25s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args)) - #else - #define DEBUG_EXTRA(fmt, args...) fprintf(stderr, "ZT_EXTRA[%ld] : %14s:%4d:%25s: " fmt "\n", THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args) - #endif - #else - #define DEBUG_EXTRA(fmt, args...) - #endif - -#if DEBUG_LEVEL >= MSG_FLOW - #if defined(__ANDROID__) - #define DEBUG_FLOW(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_FLOW : %14s:%4d:%25s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args)) - #else - #define DEBUG_FLOW(fmt, args...) fprintf(stderr, "ZT_FLOW [%ld] : %14s:%4d:%25s: " fmt "\n", THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args) - #endif - #else - #define DEBUG_FLOW(fmt, args...) - #endif -//#endif - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // _SDK_DEBUG_H_ \ No newline at end of file diff --git a/src/defs.h b/src/defs.h deleted file mode 100644 index e252097..0000000 --- a/src/defs.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#define SDK_MTU 1200//ZT_MAX_MTU // 2800, usually - -#define UNIX_SOCK_BUF_SIZE 1024*1024 -#define ZT_PHY_POLL_INTERVAL 50 // in ms - -// picoTCP -#define MAX_PICO_FRAME_RX_BUF_SZ ZT_MAX_MTU * 128 - -// General -// TCP Buffer sizes -#define DEFAULT_TCP_TX_BUF_SZ 1024 * 1024 -#define DEFAULT_TCP_RX_BUF_SZ 1024 * 1024 - -// TCP RX/TX buffer soft boundaries -#define DEFAULT_TCP_TX_BUF_SOFTMAX DEFAULT_TCP_TX_BUF_SZ * 0.80 -#define DEFAULT_TCP_TX_BUF_SOFTMIN DEFAULT_TCP_TX_BUF_SZ * 0.20 -#define DEFAULT_TCP_RX_BUF_SOFTMAX DEFAULT_TCP_RX_BUF_SZ * 0.80 -#define DEFAULT_TCP_RX_BUF_SOFTMIN DEFAULT_TCP_RX_BUF_SZ * 0.20 - -// UDP Buffer sizes (should be about the size of your MTU) -#define DEFAULT_UDP_TX_BUF_SZ ZT_MAX_MTU -#define DEFAULT_UDP_RX_BUF_SZ ZT_MAX_MTU * 10 - -// lwIP -#define APPLICATION_POLL_FREQ 2 -#define ZT_LWIP_TCP_TIMER_INTERVAL 50 -#define STATUS_TMR_INTERVAL 500 // How often we check connection statuses (in ms) \ No newline at end of file diff --git a/src/intercept.c b/src/intercept.c deleted file mode 100644 index f10f083..0000000 --- a/src/intercept.c +++ /dev/null @@ -1,587 +0,0 @@ - /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#if defined(SDK_INTERCEPT) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__linux__) - #include - #include - #include -#endif - -#include "sdk.h" -#include "debug.h" -#include "rpc.h" - -pthread_key_t thr_id_key; - -// externs common between SDK_Intercept and SDK_Socket from SDK.h -#if defined(__linux__) - int (*realaccept4)(ACCEPT4_SIG) = 0; - #if !defined(__ANDROID__) - int (*realsyscall)(SYSCALL_SIG) = 0; - #endif -#endif - -#if !defined(__ANDROID__) - int (*realbind)(BIND_SIG) = 0; - int (*realsendmsg)(SENDMSG_SIG) = 0; - ssize_t (*realsendto)(SENDTO_SIG) = 0; - int (*realrecvmsg)(RECVMSG_SIG) = 0; - int (*realrecvfrom)(RECVFROM_SIG) = 0; -#endif - int (*realconnect)(CONNECT_SIG) = 0; - int (*realaccept)(ACCEPT_SIG) = 0; - int (*reallisten)(LISTEN_SIG) = 0; - int (*realsocket)(SOCKET_SIG) = 0; - int (*realsetsockopt)(SETSOCKOPT_SIG) = 0; - int (*realgetsockopt)(GETSOCKOPT_SIG) = 0; - int (*realclose)(CLOSE_SIG); - int (*realgetsockname)(GETSOCKNAME_SIG) = 0; - - // ------------------------------------------------------------------------------ - // --------------------- Get Original socket API pointers ----------------------- - // ------------------------------------------------------------------------------ - - extern void load_symbols() - { - DEBUG_EXTRA(""); - -#if defined(__linux__) - realaccept4 = dlsym(RTLD_NEXT, "accept4"); - #if !defined(__ANDROID__) - realsyscall = dlsym(RTLD_NEXT, "syscall"); - #endif -#endif - - realsetsockopt = (int(*)(SETSOCKOPT_SIG))dlsym(RTLD_NEXT, "setsockopt"); - realgetsockopt = (int(*)(GETSOCKOPT_SIG))dlsym(RTLD_NEXT, "getsockopt"); - realsocket = (int(*)(SOCKET_SIG))dlsym(RTLD_NEXT, "socket"); - realconnect = (int(*)(CONNECT_SIG))dlsym(RTLD_NEXT, "connect"); - realaccept = (int(*)(ACCEPT_SIG))dlsym(RTLD_NEXT, "accept"); - reallisten = (int(*)(LISTEN_SIG))dlsym(RTLD_NEXT, "listen"); - realclose = (int(*)(CLOSE_SIG))dlsym(RTLD_NEXT, "close"); - realgetsockname = (int(*)(GETSOCKNAME_SIG))dlsym(RTLD_NEXT, "getsockname"); - #if !defined(__ANDROID__) - realbind = (int(*)(BIND_SIG))dlsym(RTLD_NEXT, "bind"); - realsendto = (ssize_t(*)(int, const void *, size_t, int, const struct sockaddr *, socklen_t))dlsym(RTLD_NEXT, "sendto"); - realrecvfrom = (int(*)(RECVFROM_SIG))dlsym(RTLD_NEXT, "recvfrom"); - realrecvmsg = (int(*)(RECVMSG_SIG))dlsym(RTLD_NEXT, "recvmsg"); - #endif - } - - // ------------------------------------------------------------------------------ - // ------------------------------- Intercept Setup ------------------------------ - // ------------------------------------------------------------------------------ - // Return whether 'intercept' API is enabled for this thread - - bool check_intercept_enabled() { - if(!realconnect){ - load_symbols(); - } - #if defined(SDK_BUNDLED) - // The reasoning for this check is that if you've built the SDK with SDK_BUNDLE=1, then - // you've included a full ZeroTier service in the same binary as your intercept, and we - // don't want to run ZeroTier network API calls through the intercept, so we must specify - // which threads should be intercepted manually - void *spec = pthread_getspecific(thr_id_key); - int thr_id = spec != NULL ? *((int*)spec) : -1; - return thr_id == INTERCEPT_ENABLED; - #else - return 1; - #endif - } - - // ------------------------------------------------------------------------------ - // ------------------------- connected_to_service() ----------------------------- - // ------------------------------------------------------------------------------ - // Check whether or not the socket is mapped to the service. We - // need to know if this is a regular AF_LOCAL socket or an end of a socketpair - // that the service uses. We don't want to keep state in the intercept, so - // we simply ask the service via an RPC - - int connected_to_service(int sockfd) - { - struct sockaddr_storage addr; - socklen_t len = sizeof addr; - struct sockaddr_un * addr_un; - getpeername(sockfd, (struct sockaddr*)&addr, &len); - if (addr.ss_family == AF_LOCAL || addr.ss_family == AF_LOCAL) { - addr_un = (struct sockaddr_un*)&addr; - return strcmp(addr_un->sun_path, api_netpath) == 0; - } - DEBUG_ERROR("not connected to service"); - return 0; - } - - // ------------------------------------------------------------------------------ - // ------------------------------------ sendto() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd, const void *buf, size_t len, int flags, - // const struct sockaddr *addr, socklen_t addrlen - -#if !defined(__ANDROID__) - ssize_t sendto(SENDTO_SIG) - { - DEBUG_INFO("fd=%d, len=%d", fd, (int)len); - if (!check_intercept_enabled()) - return realsendto(fd, buf, len, flags, addr, addrlen); - return zts_sendto(fd, buf, len, flags, addr, addrlen); - } -#endif - - // ------------------------------------------------------------------------------ - // ----------------------------------- sendmsg() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd, const struct msghdr *msg, int flags - -#if !defined(__ANDROID__) - ssize_t sendmsg(SENDMSG_SIG) - { - DEBUG_INFO("fd=%d", fd); - //if(!check_intercept_enabled()) - return realsendmsg(fd, msg, flags); - zts_sendmsg(fd, msg, flags); - } -#endif - - // ------------------------------------------------------------------------------ - // ---------------------------------- recvfrom() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd, void *restrict buf, size_t len, int flags, struct sockaddr - // *restrict addr, socklen_t *restrict addrlen - -#if !defined(__ANDROID__) - ssize_t recvfrom(RECVFROM_SIG) - { - DEBUG_INFO("fd=%d", fd); - //if(!check_intercept_enabled()) - // return realrecvfrom(fd, buf, len, flags, addr, addrlen); - return zts_recvfrom(fd, buf, len, flags, addr, addrlen); - } -#endif - - // ------------------------------------------------------------------------------ - // ----------------------------------- recvmsg() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd, struct msghdr *msg, int flags - -#if !defined(__ANDROID__) - ssize_t recvmsg(RECVMSG_SIG) - { - DEBUG_INFO("fd=%d", fd); - //if(!check_intercept_enabled()) - return realrecvmsg(fd, msg, flags); - return zts_recvmsg(fd, msg, flags); - } -#endif - - // ------------------------------------------------------------------------------ - // --------------------------------- setsockopt() ------------------------------- - // ------------------------------------------------------------------------------ - // int fd, int level, int optname, const void *optval, socklen_t optlen - - int setsockopt(SETSOCKOPT_SIG) - { - DEBUG_INFO("fd=%d", fd); - if (!check_intercept_enabled()) - return realsetsockopt(fd, level, optname, optval, optlen); - #if defined(__linux__) - if(level == SOL_IPV6 && optname == IPV6_V6ONLY) - return 0; - if(level == SOL_IP && (optname == IP_TTL || optname == IP_TOS)) - return 0; - #endif - if(level == IPPROTO_TCP || (level == SOL_SOCKET && optname == SO_KEEPALIVE)) - return 0; - if(realsetsockopt(fd, level, optname, optval, optlen) < 0) - perror("setsockopt():\n"); - return zts_setsockopt(fd, level, optname, optval, optlen); - } - - // ------------------------------------------------------------------------------ - // --------------------------------- getsockopt() ------------------------------- - // ------------------------------------------------------------------------------ - // int fd, int level, int optname, void *optval, socklen_t *optlen - - int getsockopt(GETSOCKOPT_SIG) - { - DEBUG_INFO("fd=%d", fd); - if (!check_intercept_enabled() || !connected_to_service(fd)) - return realgetsockopt(fd, level, optname, optval, optlen); - return zts_getsockopt(fd, level, optname, optval, optlen); - } - - // ------------------------------------------------------------------------------ - // ----------------------------------- socket() --------------------------------- - // ------------------------------------------------------------------------------ - // int socket_family, int socket_type, int protocol - - int socket(SOCKET_SIG) - { - DEBUG_ATTN(); - int err; - if (!check_intercept_enabled() && socket_type) { - if((err = realsocket(socket_family, socket_type, protocol)) < 0) { - perror("socket:\n"); - } - else { - DEBUG_BLANK("realsocket(): fd=%d", err); - return err; - } - } - // If the socket type is LOCAL, we don't want to handle it, pass to system - if(socket_family == AF_LOCAL - #if defined(__linux__) - || socket_family == AF_NETLINK - #endif - || socket_family == AF_UNIX) { - err = realsocket(socket_family, socket_type, protocol); - DEBUG_BLANK("realsocket(): fd=%d", err); - return err; - } - return zts_socket(socket_family, socket_type, protocol); - } - - // ------------------------------------------------------------------------------ - // ---------------------------------- connect() --------------------------------- - // ------------------------------------------------------------------------------ - // int fd, const struct sockaddr *addr, socklen_t addrlen - - int connect(CONNECT_SIG) - { - DEBUG_ATTN("fd=%d", fd); - struct sockaddr_in *connaddr; - connaddr = (struct sockaddr_in *)addr; - if(addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) { - struct sockaddr_storage storage; - memcpy(&storage, addr, addrlen); - struct sockaddr_un *s_un = (struct sockaddr_un*)&storage; - DEBUG_INFO("addr=%s", s_un->sun_path); - } - - char addrstr[INET6_ADDRSTRLEN]; - if(addr->sa_family == AF_INET) { - struct sockaddr_in *connaddr = (struct sockaddr_in *)addr; - inet_ntop(AF_INET, &(connaddr->sin_addr), addrstr, INET_ADDRSTRLEN); - sprintf(addrstr, "%s:%d", addrstr, ntohs(connaddr->sin_port)); - } - if(addr->sa_family == AF_INET6) { - struct sockaddr_in6 *connaddr6 = (struct sockaddr_in6 *)addr; - inet_ntop(AF_INET6, &(connaddr6->sin6_addr), addrstr, INET6_ADDRSTRLEN); - sprintf(addrstr, "%s:%d", addrstr, ntohs(connaddr6->sin6_port)); - } - DEBUG_INFO("addr=%s", addrstr); - - if(!check_intercept_enabled()) - return realconnect(fd, addr, addrlen); - - // Check that this is a valid fd - /* - if(fcntl(fd, F_GETFD) < 0) { - errno = EBADF; - return -1; - } - */ - // Check that it is a socket - int sock_type; - socklen_t sock_type_len = sizeof(sock_type); - if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *) &sock_type, &sock_type_len) < 0) { - errno = ENOTSOCK; - return -1; - } - #if defined(__linux__) - // Check family - if (connaddr->sin_family < 0 || connaddr->sin_family >= NPROTO){ - errno = EAFNOSUPPORT; - return -1; - } - #endif - // make sure we don't touch any standard outputs - if(fd == 0 || fd == 1 || fd == 2) - return(realconnect(fd, addr, addrlen)); - - if(addr != NULL && (connaddr->sin_family == AF_LOCAL - #if defined(__linux__) - || connaddr->sin_family == PF_NETLINK - || connaddr->sin_family == AF_NETLINK - #endif - || connaddr->sin_family == AF_UNIX)) { - return realconnect(fd, addr, addrlen); - } - return zts_connect(fd, addr, addrlen); - } - - // ------------------------------------------------------------------------------ - // ------------------------------------ bind() ---------------------------------- - // ------------------------------------------------------------------------------ - // int fd, const struct sockaddr *addr, socklen_t addrlen - - int bind(BIND_SIG) - { - DEBUG_ATTN("fd=%d", fd); - // make sure we don't touch any standard outputs - if(fd == 0 || fd == 1 || fd == 2) - return(realbind(fd, addr, addrlen)); - - // TODO: Revisit - char addrstr[INET6_ADDRSTRLEN]; - if(addr->sa_family == AF_INET) { - struct sockaddr_in *connaddr = (struct sockaddr_in *)addr; - inet_ntop(AF_INET, &(connaddr->sin_addr), addrstr, INET_ADDRSTRLEN); - sprintf(addrstr, "%s:%d", addrstr, ntohs(connaddr->sin_port)); - } - if(addr->sa_family == AF_INET6) { - struct sockaddr_in6 *connaddr6 = (struct sockaddr_in6 *)addr; - inet_ntop(AF_INET6, &(connaddr6->sin6_addr), addrstr, INET6_ADDRSTRLEN); - sprintf(addrstr, "%s:%d", addrstr, ntohs(connaddr6->sin6_port)); - } - DEBUG_INFO("addr=%s", addrstr); - - if(addr->sa_family == AF_LOCAL - #if defined(__linux__) - || addr->sa_family == AF_NETLINK - #endif - || addr->sa_family == AF_UNIX) { - int err = realbind(fd, addr, addrlen); - DEBUG_BLANK("realbind(): err=%d", err); - return err; - } - - int sock_type; - socklen_t sock_type_len = sizeof(sock_type); - if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *) &sock_type, &sock_type_len) < 0) { - errno = ENOTSOCK; - return -1; - } - - // Otherwise, perform usual intercept logic - if (!check_intercept_enabled()) - return realbind(fd, addr, addrlen); - - // Check that this is a valid fd - /* - if(fcntl(fd, F_GETFD) < 0) { - errno = EBADF; - return -1; - } - */ - // Check that it is a socket - int opt = -1; - socklen_t opt_len; - if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *) &opt, &opt_len) < 0) { - errno = ENOTSOCK; - return -1; - } - return zts_bind(fd, addr, addrlen); - } - - // ------------------------------------------------------------------------------ - // ----------------------------------- accept4() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd, struct sockaddr *addr, socklen_t *addrlen, int flags - -#if defined(__linux__) - int accept4(ACCEPT4_SIG) { - DEBUG_ATTN("fd=%d", fd); - return zts_accept4(fd, addr, addrlen, flags); - } -#endif - - // ------------------------------------------------------------------------------ - // ----------------------------------- accept() --------------------------------- - // ------------------------------------------------------------------------------ - // int fd struct sockaddr *addr, socklen_t *addrlen - - int accept(ACCEPT_SIG) { - DEBUG_ATTN("fd=%d", fd); - if (!check_intercept_enabled()) - return realaccept(fd, addr, addrlen); - - // Check that this is a valid fd - if(fcntl(fd, F_GETFD) < 0) { - return -1; - errno = EBADF; - DEBUG_ERROR("EBADF"); - return -1; - } - /* - int opt; - socklen_t opt_len; - if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *) &opt, &opt_len) < 0) { - errno = ENOTSOCK; - return -1; - } - // Check that this socket supports accept() - if((opt != SOCK_STREAM) && (opt != SOCK_SEQPACKET)) { - errno = EOPNOTSUPP; - return -1; - } - */ - // Check that we haven't hit the soft-limit file descriptors allowed - struct rlimit rl; - getrlimit(RLIMIT_NOFILE, &rl); - if(fd >= rl.rlim_cur){ - errno = EMFILE; - DEBUG_ERROR("EMFILE"); - return -1; - } - // Check address length - if(addrlen < 0) { - errno = EINVAL; - DEBUG_ERROR("EINVAL"); - return -1; - } - // redirect calls for standard I/O descriptors to kernel - if(fd == 0 || fd == 1 || fd == 2){ - DEBUG_BLANK("realaccept(): "); - return(realaccept(fd, addr, addrlen)); - } - - return zts_accept(fd, addr, addrlen); - } - - // ------------------------------------------------------------------------------ - // ------------------------------------- listen()-------------------------------- - // ------------------------------------------------------------------------------ - // int fd, int backlog - - int listen(LISTEN_SIG) - { - DEBUG_ATTN("fd=%d", fd); - if (!check_intercept_enabled() || !connected_to_service(fd)) - return reallisten(fd, backlog); - // make sure we don't touch any standard outputs - if(fd == 0 || fd == 1 || fd == 2) - return reallisten(fd, backlog); - return zts_listen(fd, backlog); - } - - // ------------------------------------------------------------------------------ - // ------------------------------------- close() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd - - int close(CLOSE_SIG) { - DEBUG_EXTRA("fd=%d", fd); - if(!check_intercept_enabled()) - return realclose(fd); - return zts_close(fd); - } - - // ------------------------------------------------------------------------------ - // -------------------------------- getsockname() ------------------------------- - // ------------------------------------------------------------------------------ - // int fd, struct sockaddr *addr, socklen_t *addrlen - - int getsockname(GETSOCKNAME_SIG) - { - DEBUG_INFO("fd=%d", fd); - #if !defined(__IOS__) - if (!check_intercept_enabled()) - return realgetsockname(fd, addr, addrlen); - #endif - DEBUG_INFO("fd=%d", fd); - if(!connected_to_service(fd)) { - DEBUG_ERROR("fd=%d not used by service", fd); - return realgetsockname(fd, addr, addrlen); - } - return zts_getsockname(fd, addr, addrlen); - } - - // ------------------------------------------------------------------------------ - // ------------------------------------ syscall() ------------------------------- - // ------------------------------------------------------------------------------ - // long number, ... - -#if !defined(__ANDROID__) -#if defined(__linux__) - long syscall(SYSCALL_SIG) - { - va_list ap; - uintptr_t a,b,c,d,e,f; - va_start(ap, number); - a=va_arg(ap, uintptr_t); - b=va_arg(ap, uintptr_t); - c=va_arg(ap, uintptr_t); - d=va_arg(ap, uintptr_t); - e=va_arg(ap, uintptr_t); - f=va_arg(ap, uintptr_t); - va_end(ap); - - if (!check_intercept_enabled()) - return realsyscall(number,a,b,c,d,e,f); - DEBUG_INFO("number=%ld", number); - -#if defined(__i386__) - // TODO: Implement for 32-bit systems: syscall(__NR_socketcall, 18, args); - // args[0] = (unsigned long) fd; - // args[1] = (unsigned long) addr; - // args[2] = (unsigned long) addrlen; - // args[3] = (unsigned long) flags; -#else - if(number == __NR_accept4) { - int sockfd = a; - struct sockaddr * addr = (struct sockaddr*)b; - socklen_t * addrlen = (socklen_t*)c; - int flags = d; - int old_errno = errno; - int err = accept4(sockfd, addr, addrlen, flags); - errno = old_errno; - err = err == -EBADF ? -EAGAIN : err; - return err; - } -#endif - return realsyscall(number,a,b,c,d,e,f); - } - -#endif -#endif - -#endif // _SDK_INTERCEPT_ - diff --git a/src/proxy.cpp b/src/proxy.cpp deleted file mode 100644 index f9be604..0000000 --- a/src/proxy.cpp +++ /dev/null @@ -1,458 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include "debug.h" -#include "tap.hpp" - -#include "Phy.hpp" -#include "Utils.hpp" -#include "OSUtils.hpp" - -#include -#include -#include -#include - - -#define SOCKS_OPEN 0 -#define SOCKS_CONNECT_INIT 1 -#define SOCKS_CONNECT_IPV4 2 -#define SOCKS_UDP 3 // ? -#define SOCKS_COMPLETE 4 - -#define CONNECTION_TIMEOUT 8 - -#define IDX_VERSION 0 -#define IDX_COMMAND 1 -#define IDX_METHOD 1 -#define IDX_FRAG 1 -#define IDX_ERROR_CODE 1 -#define IDX_NMETHODS 1 -#define IDX_METHODS 2 // Supported methods -#define IDX_ATYP 3 -#define IDX_DST_ADDR 4 // L:D where L = addrlen, D = addr -#define IDX_ - -#define THIS_PROXY_VERSION 5 -#define MAX_ADDR_LEN 32 -#define PORT_LEN 2 - -void dwr(int level, const char *fmt, ... ); - -namespace ZeroTier -{ - int NetconEthernetTap::getProxyServerAddress(struct sockaddr_storage *addr) { - if(sockstate >= 0) { - addr = &proxyServerAddress; - return 0; - } - return -1; - } - - int NetconEthernetTap::getProxyServerPort() { - struct sockaddr_in *in4; - in4 = (struct sockaddr_in *)&proxyServerAddress; - return in4->sin_port; - } - - int NetconEthernetTap::stopProxyServer() - { - DEBUG_INFO(); - if(proxyListenPhySocket) { - _phy.close(proxyListenPhySocket); - return 0; - } - DEBUG_ERROR("invalid proxyListenPhySocket"); - return -1; - } - - int NetconEthernetTap::startProxyServer(const char *homepath, uint64_t nwid, struct sockaddr_storage *addr) - { - // Address of proxy server is determined in the following order: - // - Provided address in param: addr - // - If no address, assume 127.0.0.1: - // - If no port assignment file, 127.0.0.1:RANDOM_PORT - - DEBUG_INFO(); - int portno = -1; - if(addr) { - DEBUG_INFO("using provided address"); - // This address pointer may come from a different memory space and might be de-allocated, so we keep a copy - memcpy(&proxyServerAddress, addr, sizeof(struct sockaddr_storage)); - struct sockaddr_in *in4 = (struct sockaddr_in *)&addr; - proxyListenPhySocket = _phy.tcpListen((const struct sockaddr*)&in4,(void *)this); - sockstate = SOCKS_OPEN; - // DEBUG_INFO("SOCKS5 proxy server address for <%.16llx> is: <%s> (sock=%p)", nwid, inet_ntoa(in4->sin_addr), /*ntohs(in4->sin_port), */(void*)&proxyListenPhySocket); - return 0; - } - else { - DEBUG_INFO("no address provided. Checking port file."); - // Look for a port file for this network's proxy server instance - char portFile[4096]; - Utils::snprintf(portFile,sizeof(portFile),"%s/networks.d/%.16llx.port",homepath,nwid); - std::string portStr; - DEBUG_INFO("reading port from: %s\n", portFile); - if(ZeroTier::OSUtils::fileExists(portFile,true)) - { - if(ZeroTier::OSUtils::readFile(portFile, portStr)) { - portno = atoi(portStr.c_str()); - } - } - else { - unsigned int randp = 0; - Utils::getSecureRandom(&randp,sizeof(randp)); - portno = 1000 + (randp % 1000); - // DEBUG_INFO("no port specified in networks.d/%.16llx.port, randomly picking port", nwid); - std::stringstream ss; - ss << portno; - portStr = ss.str(); - if(!ZeroTier::OSUtils::writeFile(portFile, portStr)) { - DEBUG_ERROR("unable to write proxy port file: %s", portFile); - } - } - struct sockaddr_in in4; - memset(&in4,0,sizeof(in4)); - in4.sin_family = AF_INET; - in4.sin_addr.s_addr = Utils::hton((uint32_t)0x00000000); // right now we just listen for TCP @0.0.0.0 - in4.sin_port = Utils::hton((uint16_t)portno); - proxyListenPhySocket = _phy.tcpListen((const struct sockaddr*)&in4,(void *)this); - sockstate = SOCKS_OPEN; - //DEBUG_INFO("SOCKS5 proxy server address for <%.16llx> is: <%s:%d> (sock=%p)\n", nwid, , portno, (void*)&proxyListenPhySocket); - } - return 0; - } - - void ExtractAddress(int addr_type, unsigned char *buf, struct sockaddr_in * addr) - { - // TODO: Generalize extraction logic - if(addr_type == 144) - { - // Extract address from buffer - int domain_len = buf[IDX_DST_ADDR]; // (L):D - char addr_[MAX_ADDR_LEN]; - int port_ = 0; - memset(addr_, 0, MAX_ADDR_LEN); - memcpy(addr_, &buf[IDX_DST_ADDR+1], domain_len); // L:(D) - memcpy(&port_, &buf[IDX_DST_ADDR+1]+(domain_len), PORT_LEN); - port_ = Utils::hton((uint16_t)port_); - std::string addr_str(addr_); - // Format address for Netcon/lwIP - addr->sin_family = AF_INET; - addr->sin_port = port_; - addr->sin_addr.s_addr = inet_addr(addr_str.c_str()); - } - } - - void NetconEthernetTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) - { - DEBUG_INFO("sock=%p, len=%lu", (void*)&sock, len); - unsigned char *buf; - buf = (unsigned char *)data; - - // Get connection for this PhySocket - Connection *conn = getConnection(sock); - if(!conn) { - DEBUG_INFO("unable to locate Connection for sock=%p", (void*)&sock); - return; - } - - // Write data to lwIP PCB (outgoing) - if(conn->proxy_conn_state == SOCKS_COMPLETE) - { - if(len) { - DEBUG_INFO("len=%lu\n", len); - memcpy((&conn->txbuf)+(conn->txsz), buf, len); - conn->txsz += len; - handleWrite(conn); - } - } - - if(conn->proxy_conn_state==SOCKS_UDP) - { - DEBUG_INFO("SOCKS_UDP from client\n"); - // +----+------+------+----------+----------+----------+ - // |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | - // +----+------+------+----------+----------+----------+ - // | 2 | 1 | 1 | Variable | 2 | Variable | - // +----+------+------+----------+----------+----------+ - - //int fragment_num = buf[2]; - //int addr_type = buf[3]; - } - - // SOCKS_OPEN - // +----+----------+----------+ - // |VER | NMETHODS | METHODS | - // +----+----------+----------+ - // | 1 | 1 | 1 to 255 | - // +----+----------+----------+ - if(conn->proxy_conn_state==SOCKS_OPEN) - { - if(len >= 3) - { - //int version = buf[IDX_VERSION]; - //int methodsLength = buf[IDX_NMETHODS]; - int firstSupportedMethod = buf[IDX_METHODS]; - int supportedMethod = 0; - - // Password auth - if(firstSupportedMethod == 2) { - supportedMethod = firstSupportedMethod; - } - //DEBUG_INFO(" INFO ", version, methodsLength, supportedMethod); - - // Send METHOD selection msg - // +----+--------+ - // |VER | METHOD | - // +----+--------+ - // | 1 | 1 | - // +----+--------+ - char reply[2]; - reply[IDX_VERSION] = THIS_PROXY_VERSION; // version - reply[IDX_METHOD] = supportedMethod; - _phy.streamSend(sock, reply, sizeof(reply)); - - // Set state for next message - conn->proxy_conn_state = SOCKS_CONNECT_INIT; - } - } - - // SOCKS_CONNECT - // +----+-----+-------+------+----------+----------+ - // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | - // +----+-----+-------+------+----------+----------+ - // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +----+-----+-------+------+----------+----------+ - if(conn->proxy_conn_state==SOCKS_CONNECT_INIT) - { - // Ex. 4(meta) + 4(ipv4) + 2(port) = 10 - if(len >= 10) - { - //int version = buf[IDX_VERSION]; - int cmd = buf[IDX_COMMAND]; - int addr_type = buf[IDX_ATYP]; - - //DEBUG_INFO("SOCKS REQUEST = ", version, cmd, addr_type); - - // CONNECT request - if(cmd == 1) { - DEBUG_INFO("CONNECT request"); - // Ipv4 - /* - if(addr_type == 144) - { - //DEBUG_INFO("IPv4\n"); - int raw_addr; - memcpy(&raw_addr, &buf[4], 4); - char newaddr[16]; - inet_ntop(AF_INET, &raw_addr, (char*)newaddr, INET_ADDRSTRLEN); - DEBUG_INFO("new addr = %s\n", newaddr); - - int rawport, port; - memcpy(&rawport, &buf[5], 2); - port = Utils::ntoh(rawport); - DEBUG_INFO("new port = %d\n", port); - - // Assemble new address - struct sockaddr_in addr; - addr.sin_addr.s_addr = IPADDR_ANY; - addr.sin_family = AF_INET; - addr.sin_port = Utils::hton(8080); - - int fd = socket(AF_INET, SOCK_STREAM, 0); - DEBUG_INFO("fd = %d\n", fd); - - if(fd < 0) - perror("socket"); - - int err = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); - DEBUG_INFO("connect_err = %d\n", err); - if(err < 0) - perror("connect"); - } - */ - // Fully-qualified domain name - if(addr_type == 144) - { - int domain_len = buf[IDX_DST_ADDR]; // (L):D - struct sockaddr_in addr; - ExtractAddress(addr_type,buf,&addr); - PhySocket * new_sock = handleSocketProxy(sock, SOCK_STREAM); - if(!new_sock) - DEBUG_ERROR("error while creating proxied-socket"); - handleConnectProxy(sock, &addr); - - // Convert connection err code into SOCKS-err-code - // X'00' succeeded - // X'01' general SOCKS server failure - // X'02' connection not allowed by ruleset - // X'03' Network unreachable - // X'04' Host unreachable - // X'05' Connection refused - // X'06' TTL expired - // X'07' Command not supported - // X'08' Address type not supported - // X'09' to X'FF' unassigned - - // SOCKS_CONNECT_REPLY - // +----+-----+-------+------+----------+----------+ - // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - // +----+-----+-------+------+----------+----------+ - // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +----+-----+-------+------+----------+----------+ - - DEBUG_INFO("REPLY = %d", addr.sin_port); - char reply[len]; // TODO: determine proper length - int addr_len = domain_len; - memset(reply, 0, len); // Create reply buffer at least as big as incoming SOCKS request data - memcpy(&reply[IDX_DST_ADDR],&buf[IDX_DST_ADDR],domain_len); - reply[IDX_VERSION] = THIS_PROXY_VERSION; // version - reply[IDX_ERROR_CODE] = 0; // success/err code - reply[2] = 0; // RSV - reply[IDX_ATYP] = addr_type; // ATYP (1, 3, 4) - reply[IDX_DST_ADDR] = addr_len; - memcpy(&reply[IDX_DST_ADDR+domain_len], &addr.sin_port, PORT_LEN); // PORT - _phy.streamSend(sock, reply, sizeof(reply)); - - // Any further data activity on this PhySocket will be considered data to send - conn->proxy_conn_state = SOCKS_COMPLETE; - } - // END CONNECT - } - - // BIND Request - if(cmd == 2) - { - DEBUG_INFO("BIND request"); - //char raw_addr[15]; - //int bind_port; - } - - // UDP ASSOCIATION Request - if(cmd == 3) - { - // PORT supplied should be port assigned by server in previous msg - DEBUG_INFO("UDP association request"); - - // SOCKS_CONNECT (Cont.) - // +----+-----+-------+------+----------+----------+ - // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | - // +----+-----+-------+------+----------+----------+ - // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +----+-----+-------+------+----------+----------+ - - // NOTE: Similar to cmd==1, should consolidate logic - - // NOTE: Can't separate out port with method used in IPv4 block - int domain_len = buf[4]; - // Grab Addr:Port - char raw_addr[domain_len]; - memset(raw_addr, 0, domain_len); - memcpy(raw_addr, &buf[5], domain_len); - - std::string ip, port, addrstr(raw_addr); - ssize_t del = addrstr.find(":"); - ip = addrstr.substr(0, del); - port = addrstr.substr(del+1, domain_len); - - // Create new lwIP PCB - PhySocket * new_sock = handleSocketProxy(sock, SOCK_DGRAM); - - DEBUG_INFO("sock = %p", (void*)&sock); - DEBUG_INFO("new_sock = %p", (void*)&new_sock); - if(!new_sock) - DEBUG_ERROR("error while creating proxied-socket"); - - // Form address - struct sockaddr_in addr; - memset(&addr, '0', sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = Utils::hton((uint16_t)atoi(port.c_str())); - addr.sin_addr.s_addr = inet_addr(ip.c_str()); - //addr.sin_addr.s_addr = inet_addr("10.5.5.2"); - handleConnectProxy(sock, &addr); - conn->proxy_conn_state = SOCKS_UDP; - } - - //if(addr_type == 1337) - //{ - // // IPv6 - //} - } - } - } - - void NetconEthernetTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) - { - DEBUG_INFO("sock=%p", (void*)&sockN); - Connection *newConn = new Connection(); - newConn->sock = sockN; - _phy.setNotifyWritable(sockN, false); - _Connections.push_back(newConn); - } - - void NetconEthernetTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) - { - DEBUG_INFO("sock=%p", (void*)&sock); - } - - // Unused -- no UDP or TCP from this thread/Phy<> - void NetconEthernetTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address, const struct sockaddr *from,void *data,unsigned long len) - { - DEBUG_INFO("len = %lu", len); - if(len) { - Connection *conn = getConnection(sock); - if(!conn){ - DEBUG_ERROR("unable to locate Connection: sock=%p", (void*)sock); - return; - } - unsigned char *buf = (unsigned char*)data; - memcpy((&conn->txbuf)+(conn->txsz), buf, len); - conn->txsz += len; - handleWrite(conn); - } - } - - void NetconEthernetTap::phyOnTcpClose(PhySocket *sock,void **uptr) - { - DEBUG_INFO("sock=%p", (void*)&sock); - Mutex::Lock _l(_tcpconns_m); - closeConnection(sock); - } - - void NetconEthernetTap::phyOnTcpWritable(PhySocket *sock,void **uptr, bool lwip_invoked) - { - DEBUG_INFO("sock=%p", (void*)&sock); - handleRead(sock,uptr,true); - } - - // RX data on stream socks and send back over client sock's underlying fd - void NetconEthernetTap::phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) - { - DEBUG_INFO("sock=%p", (void*&)sock); - } -} \ No newline at end of file diff --git a/src/rpc.c b/src/rpc.c deleted file mode 100644 index 84a1037..0000000 --- a/src/rpc.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifdef USE_GNU_SOURCE -#define _GNU_SOURCE -#endif - -#if defined(__linux__) - #include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sdk.h" -#include "rpc.h" -#include "debug.h" - - -// externs common between SDK_Intercept and SDK_Socket from SDK.h -int (*realsocket)(SOCKET_SIG); -int (*realconnect)(CONNECT_SIG); - -#ifdef __cplusplus -extern "C" { -#endif - -#define SERVICE_CONNECT_ATTEMPTS 30 - -ssize_t sock_fd_write(int sock, int fd); -ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd); - -static int rpc_count; - -static pthread_mutex_t lock; -void rpc_mutex_init() { - if(pthread_mutex_init(&lock, NULL) != 0) { - } -} -void rpc_mutex_destroy() { - pthread_mutex_destroy(&lock); -} - -/* - * Reads a new file descriptor from the service - */ -int get_new_fd(int sock) -{ - char buf[BUF_SZ]; - int newfd; - ssize_t size = sock_fd_read(sock, buf, sizeof(buf), &newfd); - if(size > 0) - return newfd; - return -1; -} - -/* - * Reads a return value from the service and sets errno (if applicable) - */ -int get_retval(int rpc_sock) -{ - if(rpc_sock >= 0) { - int retval; - int sz = sizeof(char) + sizeof(retval) + sizeof(errno); - char retbuf[BUF_SZ]; - memset(&retbuf, 0, sz); - long n_read = read(rpc_sock, &retbuf, sz); - if(n_read > 0) { - memcpy(&retval, &retbuf[1], sizeof(retval)); - memcpy(&errno, &retbuf[1+sizeof(retval)], sizeof(errno)); - return retval; - } - } - return -1; -} - -int load_symbols_rpc() -{ -#if defined(__IOS__) || defined(__UNITY_3D__) - realsocket = dlsym(RTLD_NEXT, "socket"); - realconnect = dlsym(RTLD_NOW, "connect"); - if(!realconnect || !realsocket) - return -1; -#endif - return 1; -} - -int rpc_join(char * sockname) -{ - if(sockname == NULL) { - DEBUG_ERROR("warning, rpc netpath is NULL"); - } - if(!load_symbols_rpc()) - return -1; - struct sockaddr_un addr; - int conn_err = -1, attempts = 0; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, sockname, sizeof(addr.sun_path)-1); - int sock; - -#if defined(SDK_INTERCEPT) - if((sock = realsocket(AF_UNIX, SOCK_STREAM, 0)) < 0){ -#else - if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){ -#endif - DEBUG_ERROR("error creating RPC socket"); - return -1; - } - while((conn_err != 0) /* && (attempts < SERVICE_CONNECT_ATTEMPTS) */){ - #if defined(SDK_INTERCEPT) - if((conn_err = realconnect(sock, (struct sockaddr*)&addr, sizeof(addr))) != 0) { - #else - if((conn_err = connect(sock, (struct sockaddr*)&addr, sizeof(addr))) != 0) { - #endif - DEBUG_ERROR("error connecting to RPC socket (%s). Re-attempting...", sockname); - usleep(100000); - } - else - return sock; - attempts++; - } - return -1; -} - -/* - * Send a command to the service - */ -int rpc_send_command(char *path, int cmd, int forfd, void *data, int len) -{ - pthread_mutex_lock(&lock); - char c, padding[] = {PADDING}; - char cmdbuf[BUF_SZ], CANARY[CANARY_SZ+PADDING_SZ], metabuf[BUF_SZ]; - - memcpy(CANARY+CANARY_SZ, padding, sizeof(padding)); - uint64_t canary_num; - // ephemeral RPC socket used only for this command - int rpc_sock = rpc_join(path); - - // Generate token - int fdrand = open("/dev/urandom", O_RDONLY); - if(read(fdrand, &CANARY, CANARY_SZ) < 0) { - DEBUG_ERROR("unable to read from /dev/urandom for RPC canary data"); - return -1; - } - - close(fdrand); - memcpy(&canary_num, CANARY, CANARY_SZ); - cmdbuf[CMD_ID_IDX] = cmd; - memcpy(&cmdbuf[CANARY_IDX], &canary_num, CANARY_SZ); - memcpy(&cmdbuf[STRUCT_IDX], data, len); - - rpc_count++; - memset(metabuf, 0, BUF_SZ); -#if defined(__linux__) - #if !defined(__ANDROID__) - pid_t pid = 5; //syscall(SYS_getpid); - pid_t tid = 4;//syscall(SYS_gettid); - #else - // Dummy values - pid_t pid = 5; - pid_t tid = gettid(); - #endif -#endif - char timestring[20]; - time_t timestamp; - timestamp = time(NULL); - strftime(timestring, sizeof(timestring), "%H:%M:%S", localtime(×tamp)); -#if defined(__linux__) - memcpy(&metabuf[IDX_PID], &pid, sizeof(pid_t) ); /* pid */ - memcpy(&metabuf[IDX_TID], &tid, sizeof(pid_t) ); /* tid */ -#endif - memcpy(&metabuf[IDX_TIME], ×tring, 20 ); /* timestamp */ - - /* Combine command flag+payload with RPC metadata */ - memcpy(metabuf, RPC_PHRASE, RPC_PHRASE_SZ); // Write signal phrase - memcpy(&metabuf[IDX_PAYLOAD], cmdbuf, len + 1 + CANARY_SZ); - - // Write RPC - long n_write = write(rpc_sock, &metabuf, BUF_SZ); - if(n_write < 0) { - DEBUG_ERROR("error writing command to service (CMD = %d)", cmdbuf[CMD_ID_IDX]); - errno = 0; - } - // Write token to corresponding data stream - if(read(rpc_sock, &c, 1) < 0) { - DEBUG_ERROR("unable to read RPC ACK byte from service."); - close(rpc_sock); - return -1; - } - if(c == 'z' && n_write > 0 && forfd > -1){ - if(send(forfd, &CANARY, CANARY_SZ+PADDING_SZ, 0) < 0) { - perror("send: \n"); - DEBUG_ERROR("unable to write canary to stream (fd=%d)", forfd); - close(rpc_sock); - return -1; - } - } - // Process response from service - int ret = ERR_OK; - if(n_write > 0) { - if(cmdbuf[CMD_ID_IDX]==RPC_SOCKET) { - pthread_mutex_unlock(&lock); - return rpc_sock; // Used as new socket - } - if(cmdbuf[CMD_ID_IDX]==RPC_CONNECT - || cmdbuf[CMD_ID_IDX]==RPC_BIND - || cmdbuf[CMD_ID_IDX]==RPC_LISTEN) { - ret = get_retval(rpc_sock); - } - if(cmdbuf[CMD_ID_IDX]==RPC_GETSOCKNAME || cmdbuf[CMD_ID_IDX]==RPC_GETPEERNAME) { - pthread_mutex_unlock(&lock); - return rpc_sock; // Don't close rpc here, we'll use it to read getsockopt_st - } - } - else - ret = -1; - close(rpc_sock); // We're done with this RPC socket, close it (if type-R) - pthread_mutex_unlock(&lock); - return ret; -} - -/* - * Send file descriptor - */ -ssize_t sock_fd_write(int sock, int fd) -{ - ssize_t size; - struct msghdr msg; - struct iovec iov; - char buf = '\0'; - int buflen = 1; - union { - struct cmsghdr cmsghdr; - char control[CMSG_SPACE(sizeof (int))]; - } cmsgu; - struct cmsghdr *cmsg; - iov.iov_base = &buf; - iov.iov_len = buflen; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - if (fd != -1) { - msg.msg_control = cmsgu.control; - msg.msg_controllen = sizeof(cmsgu.control); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof (int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - *((int *) CMSG_DATA(cmsg)) = fd; - } else { - msg.msg_control = NULL; - msg.msg_controllen = 0; - } - size = sendmsg(sock, &msg, 0); - if (size < 0) - perror ("sendmsg"); - return size; -} -/* - * Read a file descriptor - */ -ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd) -{ - ssize_t size; - if (fd) { - struct msghdr msg; - struct iovec iov; - union { - struct cmsghdr cmsghdr; - char control[CMSG_SPACE(sizeof (int))]; - } cmsgu; - - struct cmsghdr *cmsg; - iov.iov_base = buf; - iov.iov_len = bufsize; - msg.msg_name = NULL; - msg.msg_namelen = 0; - - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = cmsgu.control; - msg.msg_controllen = sizeof(cmsgu.control); - size = recvmsg (sock, &msg, 0); - - if (size < 0) - return -1; - cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { - if (cmsg->cmsg_level != SOL_SOCKET) { - DEBUG_ERROR("invalid cmsg_level %d",cmsg->cmsg_level); - return -1; - } - if (cmsg->cmsg_type != SCM_RIGHTS) { - DEBUG_ERROR("invalid cmsg_type %d",cmsg->cmsg_type); - return -1; - } - *fd = *((int *) CMSG_DATA(cmsg)); - } else { -*fd = -1;} - } else { - size = read (sock, buf, bufsize); - if (size < 0) { - DEBUG_ERROR("sock_fd_read(): read: Error"); - return -1; - } - } - return size; -} - -#ifdef __cplusplus -} -#endif diff --git a/src/rpc.h b/src/rpc.h deleted file mode 100644 index 1385577..0000000 --- a/src/rpc.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef __RPCLIB_H_ -#define __RPCLIB_H_ - -#include - -#define CANARY_SZ sizeof(uint64_t) -#define PADDING_SZ 12 -#define PADDING 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 - -#define RPC_PHRASE "zerotier\0" -#define RPC_PHRASE_SZ 9 -#define RPC_TIMESTAMP_SZ 20 -// 1st RPC section (metdata) -#define IDX_SIGNAL_PHRASE 0 -#define IDX_PID IDX_SIGNAL_PHRASE + RPC_PHRASE_SZ -#define IDX_TID sizeof(pid_t) + IDX_PID -#define IDX_TIME IDX_TID + sizeof(int) -#define IDX_PAYLOAD IDX_TIME + RPC_TIMESTAMP_SZ -// 2nd RPC section (payload and canary) -#define CMD_ID_IDX 0 -#define CANARY_IDX 1 -#define STRUCT_IDX CANARY_IDX+CANARY_SZ - -#define BUF_SZ 512 - -#define ERR_OK 0 - -/* RPC codes */ -#define RPC_UNDEFINED 0 -#define RPC_CONNECT 1 -#define RPC_CONNECT_SOCKARG 2 -#define RPC_CLOSE 3 -#define RPC_READ 4 -#define RPC_WRITE 5 -#define RPC_BIND 6 -#define RPC_ACCEPT 7 -#define RPC_LISTEN 8 -#define RPC_SOCKET 9 -#define RPC_SHUTDOWN 10 -#define RPC_GETSOCKNAME 11 -#define RPC_GETPEERNAME 12 -#define RPC_RETVAL 13 -#define RPC_IS_CONNECTED 14 - - -#ifdef __cplusplus -extern "C" { -#endif - -int get_retval(int); -int rpc_join( char * sockname); -int rpc_send_command(char *path, int cmd, int forfd, void *data, int len); - -int get_new_fd(int sock); -ssize_t sock_fd_write(int sock, int fd); -ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd); - -void rpc_mutex_destroy(); -void rpc_mutex_init(); - - -/* Structures used for sending commands via RPC mechanism */ - -struct bind_st { - int fd; - struct sockaddr_storage addr; - socklen_t addrlen; - int tid; -}; - -struct connect_st { - int fd; - struct sockaddr_storage addr; - socklen_t addrlen; - int tid; -}; - -struct close_st { - int fd; -}; - -struct listen_st { - int fd; - int backlog; - int tid; -}; - -struct socket_st { - int socket_family; - int socket_type; - int protocol; - int tid; -}; - -struct accept_st { - int fd; - struct sockaddr_storage addr; - socklen_t addrlen; - int tid; -}; - -struct shutdown_st { - int socket; - int how; -}; - -struct getsockname_st { - int fd; - struct sockaddr_storage addr; - socklen_t addrlen; -}; - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/src/sdk.h b/src/sdk.h deleted file mode 100644 index 7322ff5..0000000 --- a/src/sdk.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef _ZT_SDK_H -#define _ZT_SDK_H 1 - -#include -#include - - // ------------------------------------------------------------------------------ - // ---------------------------- Compilation flag checks ------------------------- - // ------------------------------------------------------------------------------ - -#define INTERCEPT_ENABLED 111 -#define INTERCEPT_DISABLED 222 -#define MAX_DIR_SZ 256 // Max path length used for home dir - -#if defined(SDK_SERVICE) - // Sanity checks for compilation - #if !defined(SDK_LWIP) && !defined(SDK_PICOTCP) - #error "No network stack specified, use SDK_LWIP=1, SDK_PICOTCP=1, or similar" - #endif - #if defined(SDK_LWIP) && defined(SDK_PICOTCP) - #error "Dual stacks is not currently supported, try one or the other" - #endif - #if !defined(SDK_IPV4) && !defined(SDK_IPV6) - #error "No IP protocol version specified, use SDK_IPV4=1, or SDK_IPV6=1" - #endif - #if !defined(SDK_IPV4) && !defined(SDK_IPV6) - #error "Dual protocol versions is not currently supported. try one or the other" - #endif -#endif - - // ------------------------------------------------------------------------------ - // -------------- Socket API function signatures for convenience ---------------- - // ------------------------------------------------------------------------------ - -#define SETSOCKOPT_SIG int fd, int level, int optname, const void *optval, socklen_t optlen -#define GETSOCKOPT_SIG int fd, int level, int optname, void *optval, socklen_t *optlen -#define SENDMSG_SIG int fd, const struct msghdr *msg, int flags -#define SENDTO_SIG int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen -#define RECV_SIG int fd, void *buf, size_t len, int flags -#define RECVFROM_SIG int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen -#define RECVMSG_SIG int fd, struct msghdr *msg,int flags -#define SEND_SIG int fd, const void *buf, size_t len, int flags -#define WRITE_SIG int fd, const void *buf, size_t len -#define READ_SIG int fd, void *buf, size_t len -#define SOCKET_SIG int socket_family, int socket_type, int protocol -#define CONNECT_SIG int fd, const struct sockaddr *addr, socklen_t addrlen -#define BIND_SIG int fd, const struct sockaddr *addr, socklen_t addrlen -#define LISTEN_SIG int fd, int backlog -#define ACCEPT4_SIG int fd, struct sockaddr *addr, socklen_t *addrlen, int flags -#define ACCEPT_SIG int fd, struct sockaddr *addr, socklen_t *addrlen -#define CLOSE_SIG int fd -#define GETSOCKNAME_SIG int fd, struct sockaddr *addr, socklen_t *addrlen -#define GETPEERNAME_SIG int fd, struct sockaddr *addr, socklen_t *addrlen -#define FCNTL_SIG int fd, int cmd, int flags -#define SYSCALL_SIG long number, ... - -#if defined(__ANDROID__) - #include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -extern void load_symbols(); -extern void zts_init_rpc(const char *path, const char *nwid); -extern char *api_netpath; -extern char *debug_logfile; - - // ------------------------------------------------------------------------------ - // ------------------------- Ancient INTERCEPT-related cruft -------------------- - // ------------------------------------------------------------------------------ - -// Function pointers to original system calls -// - These are used when we detect that either the intercept is not -// available or that ZeroTier hasn't administered the given socket -#if defined(__linux__) - extern int (*realaccept4)(ACCEPT4_SIG); - #if !defined(__ANDROID__) - extern int (*realsyscall)(SYSCALL_SIG); - #endif -#endif - -#if !defined(__ANDROID__) - bool check_intercept_enabled(); - extern int (*realbind)(BIND_SIG); - extern int (*realsendmsg)(SENDMSG_SIG); - extern ssize_t (*realsendto)(SENDTO_SIG); - extern int (*realrecvmsg)(RECVMSG_SIG); - extern int (*realrecvfrom)(RECVFROM_SIG); -#endif - extern int (*realconnect)(CONNECT_SIG); - extern int (*realaccept)(ACCEPT_SIG); - extern int (*reallisten)(LISTEN_SIG); - extern int (*realsocket)(SOCKET_SIG); - extern int (*realsetsockopt)(SETSOCKOPT_SIG); - extern int (*realgetsockopt)(GETSOCKOPT_SIG); - extern int (*realclose)(CLOSE_SIG); - extern int (*realgetsockname)(GETSOCKNAME_SIG); - - // ------------------------------------------------------------------------------ - // ---------------------------- Direct API call section ------------------------- - // ------------------------------------------------------------------------------ - -// SOCKS5 Proxy Controls -int zts_start_proxy_server(const char *homepath, const char * nwid, struct sockaddr_storage * addr); -int zts_stop_proxy_server(const char *nwid); -int zts_get_proxy_server_address(const char * nwid, struct sockaddr_storage *addr); -bool zts_proxy_is_running(const char *nwid); -// ZT Service Controls -void zts_start_service(const char *path); -void *zts_start_core_service(void *thread_id); -void zts_stop_service(); -void zts_stop(); -bool zts_service_is_running(); -void zts_join_network(const char * nwid); -void zts_join_network_soft(const char * filepath, const char * nwid); -void zts_leave_network_soft(const char * filepath, const char * nwid); -void zts_leave_network(const char * nwid); -void zts_get_ipv4_address(const char *nwid, char *addrstr); -void zts_get_ipv6_address(const char *nwid, char *addrstr); -bool zts_has_address(const char *nwid); -int zts_get_device_id(char *devID); -int zts_get_device_id_from_file(const char *filepath, char *devID); -int zts_get_peer_address(char *peer, const char *devID); -unsigned long zts_get_peer_count(); -//int zts_get_peer_list(); -char *zts_get_homepath(); -void zts_get_6plane_addr(char *addr, const char *nwid, const char *devID); -void zts_get_rfc4193_addr(char *addr, const char *nwid, const char *devID); -// BSD-like socket API -int zts_socket(SOCKET_SIG); -int zts_connect(CONNECT_SIG); -int zts_bind(BIND_SIG); -#if defined(__linux__) - int zts_accept4(ACCEPT4_SIG); -#endif -int zts_accept(ACCEPT_SIG); -int zts_listen(LISTEN_SIG); -int zts_setsockopt(SETSOCKOPT_SIG); -int zts_getsockopt(GETSOCKOPT_SIG); -int zts_getsockname(GETSOCKNAME_SIG); -int zts_getpeername(GETPEERNAME_SIG); -int zts_close(CLOSE_SIG); -int zts_fcntl(FCNTL_SIG); -ssize_t zts_sendto(SENDTO_SIG); -ssize_t zts_sendmsg(SENDMSG_SIG); -ssize_t zts_recvfrom(RECVFROM_SIG); -ssize_t zts_recvmsg(RECVMSG_SIG); -#if defined(__UNITY_3D__) - ssize_t zts_recv(int fd, void *buf, int len); - ssize_t zts_send(int fd, void *buf, int len); - int zts_set_nonblock(int fd); // TODO combine with fcntl() -#endif - -#if !defined(__IOS__) - void zt_start_service(const char * path, const char *nwid); - void zt_join_network(const char * nwid); - void zt_leave_network(const char * nwid); -#endif - - // ------------------------------------------------------------------------------ - // --------------------- Direct API call section (for Android) ------------------ - // ------------------------------------------------------------------------------ - -// JNI naming convention: Java_PACKAGENAME_CLASSNAME_METHODNAME -#if defined(__ANDROID__) - // ZT SERVICE CONTROLS - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1start_1service(JNIEnv *env, jobject thisObj, jstring path); - JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1stop_service(); - JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1service_1is_1running(JNIEnv *env, jobject thisObj); - JNIEXPORT jstring JNICALL Java_ZeroTier_ZTSDK_zt_1get_1homepath(JNIEnv *env, jobject thisObj); - JNIEXPORT void JNICALL Java_ZeroTier_ZTSDK_zt_1join_1network(JNIEnv *env, jobject thisObj, jstring nwid); - JNIEXPORT void JNICALL Java_ZeroTier_ZTSDK_zt_1leave_1network(JNIEnv *env, jobject thisObj, jstring nwid); - JNIEXPORT jobject JNICALL Java_ZeroTier_ZTSDK_zt_1get_1ipv4_1address(JNIEnv *env, jobject thisObj, jstring nwid); - JNIEXPORT jobject JNICALL Java_ZeroTier_ZTSDK_zt_1get_1ipv6_1address(JNIEnv *env, jobject thisObj, jstring nwid); - JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1is_1relayed(); - // SOCKS5 PROXY SERVER CONTROLS - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1start_1proxy_1server(JNIEnv *env, jobject thisObj, jstring nwid, jobject zaddr); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1stop_1proxy_1server(JNIEnv *env, jobject thisObj, jstring nwid); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1get_1proxy_1server_1address(JNIEnv *env, jobject thisObj, jstring nwid, jobject zaddr); - JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1proxy_1is_1running(JNIEnv *env, jobject thisObj, jstring nwid); - // SOCKET API - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1socket(JNIEnv *env, jobject thisObj, jint family, jint type, jint protocol); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1connect(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1bind(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1accept4(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port, jint flags); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1accept(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1listen(JNIEnv *env, jobject thisObj, jint fd, int backlog); - // TCP - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1write(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1read(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1send(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, int flags); - // UDP - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1sendto(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1recvfrom(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr); - // GENERAL UTILITY - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1close(JNIEnv *env, jobject thisObj, jint fd); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1fcntl(JNIEnv *env, jobject thisObj, jint socket, jint cmd, jint flags); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1setsockopt(JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getsockopt(JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getsockname(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr); - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getpeername(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr); -#endif - - -// Prototypes for redefinition of syscalls -// - Implemented in intercept.c -#if defined(SDK_INTERCEPT) - int socket(SOCKET_SIG); - int connect(CONNECT_SIG); - int bind(BIND_SIG); - #if defined(__linux__) - int accept4(ACCEPT4_SIG); - #endif - int accept(ACCEPT_SIG); - int listen(LISTEN_SIG); - int setsockopt(SETSOCKOPT_SIG); - int getsockopt(GETSOCKOPT_SIG); - int getsockname(GETSOCKNAME_SIG); - int close(CLOSE_SIG); -#endif - -#ifdef __cplusplus -} -#endif - -#endif // _ZT_SDK_H diff --git a/src/sdkutils.hpp b/src/sdkutils.hpp deleted file mode 100644 index 0c8f4a2..0000000 --- a/src/sdkutils.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef _SDK_UTILS_HPP_ -#define _SDK_UTILS_HPP_ - -#if defined(SDK_LWIP) && defined(SDK_IPV6) - #define IP6_ADDR2(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = ZeroTier::Utils::hton((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \ - (ipaddr)->addr[1] = ZeroTier::Utils::hton(((c & 0xffff) << 16) | (d & 0xffff)); \ - (ipaddr)->addr[2] = ZeroTier::Utils::hton(((e & 0xffff) << 16) | (f & 0xffff)); \ - (ipaddr)->addr[3] = ZeroTier::Utils::hton(((g & 0xffff) << 16) | (h & 0xffff)); } while(0) - - // Convert from standard IPV6 address structure to an lwIP native structure - inline void in6_to_ip6(ip6_addr_t *ba, struct sockaddr_in6 *in6) - { - uint8_t *ip = &(in6->sin6_addr).s6_addr[0]; - IP6_ADDR2(ba, - (((ip[ 0] & 0xffff) << 8) | ((ip[ 1]) & 0xffff)), - (((ip[ 2] & 0xffff) << 8) | ((ip[ 3]) & 0xffff)), - (((ip[ 4] & 0xffff) << 8) | ((ip[ 5]) & 0xffff)), - (((ip[ 6] & 0xffff) << 8) | ((ip[ 7]) & 0xffff)), - (((ip[ 8] & 0xffff) << 8) | ((ip[ 9]) & 0xffff)), - (((ip[10] & 0xffff) << 8) | ((ip[11]) & 0xffff)), - (((ip[12] & 0xffff) << 8) | ((ip[13]) & 0xffff)), - (((ip[14] & 0xffff) << 8) | ((ip[15]) & 0xffff)) - ); - } -#endif - -#if defined(SDK_LWIP) && defined(SDK_IPV4) - #define ip4_addr1b(ipaddr) (((u8_t*)(ipaddr))[0]) - #define ip4_addr2b(ipaddr) (((u8_t*)(ipaddr))[1]) - #define ip4_addr3b(ipaddr) (((u8_t*)(ipaddr))[2]) - #define ip4_addr4b(ipaddr) (((u8_t*)(ipaddr))[3]) - - inline ip_addr_t convert_ip(struct sockaddr_in * addr) - { - ip_addr_t conn_addr; - struct sockaddr_in *ipv4 = addr; - short a = ip4_addr1b(&(ipv4->sin_addr)); - short b = ip4_addr2b(&(ipv4->sin_addr)); - short c = ip4_addr3b(&(ipv4->sin_addr)); - short d = ip4_addr4b(&(ipv4->sin_addr)); - IP4_ADDR(&conn_addr, a,b,c,d); - return conn_addr; - } -#endif - -#endif // _SDK_UTILS_HPP_ \ No newline at end of file diff --git a/src/service.cpp b/src/service.cpp deleted file mode 100644 index 524681e..0000000 --- a/src/service.cpp +++ /dev/null @@ -1,611 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#if defined(__ANDROID__) - #include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "OneService.hpp" -#include "Utils.hpp" -#include "OSUtils.hpp" -#include "InetAddress.hpp" -#include "ZeroTierOne.h" - -#include "tap.hpp" -#include "sdk.h" -#include "debug.h" - -#ifdef __cplusplus -extern "C" { -#endif - -static ZeroTier::OneService *zt1Service; - -std::string service_path; -std::string localHomeDir; // Local shortened path -std::string givenHomeDir; // What the user/application provides as a suggestion -std::string homeDir; // The resultant platform-specific dir we *must* use internally -std::string netDir; // Where network .conf files are to be written - -pthread_t intercept_thread; -pthread_key_t thr_id_key; - -int * intercept_thread_id; - - // ------------------------------------------------------------------------------ - // --------------------------------- Base zts_* API ----------------------------- - // ------------------------------------------------------------------------------ - -// Prototypes -void *zts_start_core_service(void *thread_id); -void zts_init_rpc(const char * path, const char * nwid); - -// -int zts_start_proxy_server(const char *homepath, const char * nwid, struct sockaddr_storage * addr) { - DEBUG_INFO(); - uint64_t nwid_int = strtoull(nwid, NULL, 16); - ZeroTier::NetconEthernetTap * tap = zt1Service->getTap(nwid_int); - if(tap) { - if(tap->startProxyServer(homepath, nwid_int, addr) < 0) { - DEBUG_ERROR("zts_start_proxy_server(%s): Problem while starting server.", nwid); - return -1; - } - } - DEBUG_ERROR("zts_start_proxy_server(%s): Invalid tap. Possibly incorrect NWID", nwid); - return 0; -} -// -int zts_stop_proxy_server(const char *nwid) { - DEBUG_INFO(); - uint64_t nwid_int = strtoull(nwid, NULL, 16); - ZeroTier::NetconEthernetTap * tap = zt1Service->getTap(nwid_int); - if(tap) { - if(tap->stopProxyServer() < 0) { - DEBUG_ERROR("zts_stop_proxy_server(%s): Problem while stopping server.", nwid); - return -1; - } - } - DEBUG_ERROR("zts_stop_proxy_server(%s): Invalid tap. Possibly incorrect NWID", nwid); - return 0; -} -// -bool zts_proxy_is_running(const char *nwid) -{ - return false; // TODO -} -// -int zts_get_proxy_server_address(const char * nwid, struct sockaddr_storage * addr) { - uint64_t nwid_int = strtoull(nwid, NULL, 16); - ZeroTier::NetconEthernetTap * tap = zt1Service->getTap(nwid_int); - if(tap) { - tap->getProxyServerAddress(addr); - return 0; - } - return -1; -} - -// Basic ZT service controls -// Will also spin up a SOCKS5 proxy server if USE_SOCKS_PROXY is set -void zts_join_network(const char * nwid) { - DEBUG_ERROR(); - std::string confFile = zt1Service->givenHomePath() + "/networks.d/" + nwid + ".conf"; - if(!ZeroTier::OSUtils::mkdir(netDir)) { - DEBUG_ERROR("unable to create: %s", netDir.c_str()); - } - if(!ZeroTier::OSUtils::writeFile(confFile.c_str(), "")) { - DEBUG_ERROR("unable to write network conf file: %s", confFile.c_str()); - } - zt1Service->join(nwid); - // Provide the API with the RPC information - zts_init_rpc(homeDir.c_str(), nwid); - // SOCKS5 Proxy server - // Default is 127.0.0.1:RANDOM_PORT - #if defined(USE_SOCKS_PROXY) - zts_start_proxy_server(homeDir.c_str(), nwid, NULL); // NULL addr for default - #endif -} -// Just create the dir and conf file required, don't instruct the core to do anything -void zts_join_network_soft(const char * filepath, const char * nwid) { - std::string net_dir = std::string(filepath) + "/networks.d/"; - std::string confFile = net_dir + std::string(nwid) + ".conf"; - if(!ZeroTier::OSUtils::mkdir(net_dir)) { - DEBUG_ERROR("unable to create: %s", net_dir.c_str()); - } - if(!ZeroTier::OSUtils::fileExists(confFile.c_str(),false)) { - if(!ZeroTier::OSUtils::writeFile(confFile.c_str(), "")) { - DEBUG_ERROR("unable to write network conf file: %s", confFile.c_str()); - } - } -} -// Prevent service from joining network upon startup -void zts_leave_network_soft(const char * filepath, const char * nwid) { - std::string net_dir = std::string(filepath) + "/networks.d/"; - ZeroTier::OSUtils::rm((net_dir + nwid + ".conf").c_str()); -} -// Instruct the service to leave the network -void zts_leave_network(const char * nwid) { - if(zt1Service) - zt1Service->leave(nwid); -} -// Check whether the service is running -bool zts_service_is_running() { - return !zt1Service ? false : zt1Service->isRunning(); -} -// Stop the service -void zts_stop_service() { - if(zt1Service) - zt1Service->terminate(); -} -// Stop the service, proxy server, stack, etc -void zts_stop() { - DEBUG_INFO("Stopping STSDK"); - zts_stop_service(); - /* TODO: kill each proxy server as well - zts_stop_proxy_server(...); */ -} - -// FIXME: Re-implemented to make it play nicer with the C-linkage required for Xcode integrations -// Now only returns first assigned address per network. Shouldn't normally be a problem. - -// Get IPV4 Address for this device on given network -bool zts_has_address(const char *nwid) -{ - char ipv4_addr[64], ipv6_addr[64]; - memset(ipv4_addr, 0, 64); - memset(ipv6_addr, 0, 64); - zts_get_ipv4_address(nwid, ipv4_addr); - zts_get_ipv6_address(nwid, ipv6_addr); - if(!strcmp(ipv4_addr, "-1.-1.-1.-1/-1") && !strcmp(ipv4_addr, "-1.-1.-1.-1/-1")) { - return false; - } - return true; -} -void zts_get_ipv4_address(const char *nwid, char *addrstr) -{ - uint64_t nwid_int = strtoull(nwid, NULL, 16); - ZeroTier::NetconEthernetTap *tap = zt1Service->getTap(nwid_int); - if(tap && tap->_ips.size()){ - for(int i=0; i_ips.size(); i++) { - if(tap->_ips[i].isV4()) { - std::string addr = tap->_ips[i].toString(); - // DEBUG_EXTRA("addr=%s, addrlen=%d", addr.c_str(), addr.length()); - memcpy(addrstr, addr.c_str(), addr.length()); // first address found that matches protocol version 4 - return; - } - } - } - else { - memcpy(addrstr, "-1.-1.-1.-1/-1", 14); - } -} -// Get IPV6 Address for this device on given network -void zts_get_ipv6_address(const char *nwid, char *addrstr) -{ - uint64_t nwid_int = strtoull(nwid, NULL, 16); - ZeroTier::NetconEthernetTap *tap = zt1Service->getTap(nwid_int); - if(tap && tap->_ips.size()){ - for(int i=0; i_ips.size(); i++) { - if(tap->_ips[i].isV6()) { - std::string addr = tap->_ips[i].toString(); - // DEBUG_EXTRA("addr=%s, addrlen=%d", addr.c_str(), addr.length()); - memcpy(addrstr, addr.c_str(), addr.length()); // first address found that matches protocol version 4 - return; - } - } - } - else { - memcpy(addrstr, "-1.-1.-1.-1/-1", 14); - } -} -// Get device ID (from running service) -int zts_get_device_id(char *devID) { - if(zt1Service) { - char id[10]; - sprintf(id, "%lx",zt1Service->getNode()->address()); - memcpy(devID, id, 10); - return 0; - } - else - return -1; -} -// Get device ID (from file) -int zts_get_device_id_from_file(const char *filepath, char *devID) { - std::string fname("identity.public"); - std::string fpath(filepath); - - if(ZeroTier::OSUtils::fileExists((fpath + ZT_PATH_SEPARATOR_S + fname).c_str(),false)) { - std::string oldid; - ZeroTier::OSUtils::readFile((fpath + ZT_PATH_SEPARATOR_S + fname).c_str(),oldid); - memcpy(devID, oldid.c_str(), 10); // first 10 bytes of file - return 0; - } - return -1; -} -// Get the IP address of a peer if a direct path is available -int zts_get_peer_address(char *peer, const char *devID) { - if(zt1Service) { - ZT_PeerList *pl = zt1Service->getNode()->peers(); - // uint64_t addr; - for(int i=0; ipeerCount; i++) { - // ZT_Peer *p = &(pl->peers[i]); - // DEBUG_INFO("peer[%d] = %lx", i, p->address); - } - return pl->peerCount; - } - else - return -1; -} -// Return the number of peers on this network -unsigned long zts_get_peer_count() { - if(zt1Service) - return zt1Service->getNode()->peers()->peerCount; - else - return 0; -} -// Return the home path for this instance of ZeroTier -char *zts_get_homepath() { - return (char*)givenHomeDir.c_str(); -} -// Returns a 6PLANE IPv6 address given a network ID and zerotier ID -void zts_get_6plane_addr(char *addr, const char *nwid, const char *devID) -{ - ZeroTier::InetAddress _6planeAddr = ZeroTier::InetAddress::makeIpv66plane(ZeroTier::Utils::hexStrToU64(nwid),ZeroTier::Utils::hexStrToU64(devID)); - memcpy(addr, _6planeAddr.toIpString().c_str(), 40); -} -// Returns a RFC 4193 IPv6 address given a network ID and zerotier ID -void zts_get_rfc4193_addr(char *addr, const char *nwid, const char *devID) -{ - ZeroTier::InetAddress _6planeAddr = ZeroTier::InetAddress::makeIpv6rfc4193(ZeroTier::Utils::hexStrToU64(nwid),ZeroTier::Utils::hexStrToU64(devID)); - memcpy(addr, _6planeAddr.toIpString().c_str(), 40); -} - - // ------------------------------------------------------------------------------ - // ----------------------------- .NET Interop functions ------------------------- - // ------------------------------------------------------------------------------ - - -#if defined(__UNITY_3D__) - // .NET Interop-friendly debug mechanism - typedef void (*FuncPtr)( const char * ); - FuncPtr Debug; - void SetDebugFunction( FuncPtr fp ) { Debug = fp; } - - /* - // Starts a ZeroTier service at the given path - void unity_start_service(char * path, int len) { - zts_start_service(path); - - //std::string dstr = std::string(path); - //dstr = "unity_start_service(): path = " + dstr; - //Debug(dstr.c_str()); - //init_service(INTERCEPT_DISABLED, path); - } - // Starts a ZeroTier service and RPC - void unity_start_service_and_rpc(char * path, char *nwid, int len) { - std::string dstr = std::string(path); - dstr = "unity_start_service_and_rpc(): path = " + dstr; - Debug(dstr.c_str()); - init_service_and_rpc(INTERCEPT_DISABLED, path, nwid); - } - */ -#endif - - - // ------------------------------------------------------------------------------ - // ----------------------------------- Other ------------------------------------ - // ------------------------------------------------------------------------------ - // For use when symbols are used in Swift - - -void zts_start_service(const char *path) -{ - DEBUG_INFO("path=%s", path); - if(path) - homeDir = path; - zts_start_core_service(NULL); -} - -// Typically used on iOS/OSX -#if !defined(__ANDROID__) -/* - // Starts a service thread and performs basic setup tasks - void init_service(int key, const char * path) { - givenHomeDir = path; - pthread_key_create(&thr_id_key, NULL); - intercept_thread_id = (int*)malloc(sizeof(int)); - *intercept_thread_id = key; - pthread_create(&intercept_thread, NULL, zts_start_core_service, (void *)(intercept_thread_id)); - } - - //void init_service_and_rpc(int key, const char * path, const char * nwid) { - // rpcNWID = nwid; - // init_service(key, path); - //} - - // Enables or disables intercept for current thread using key in thread-local storage - void set_intercept_status(int mode) { - #if defined(__APPLE__) - DEBUG_INFO("mode=%d, tid=%d", mode, pthread_mach_thread_np(pthread_self())); - #else - // fprintf(stderr, "set_intercept_status(mode=%d): tid = %d\n", mode, gettid()); - #endif - pthread_key_create(&thr_id_key, NULL); - intercept_thread_id = (int*)malloc(sizeof(int)); - *intercept_thread_id = mode; - pthread_setspecific(thr_id_key, intercept_thread_id); - } - */ -#endif - - - // ------------------------------------------------------------------------------ - // ------------------------------ EXPORTED JNI METHODS -------------------------- - // ------------------------------------------------------------------------------ - // JNI naming convention: Java_PACKAGENAME_CLASSNAME_METHODNAME - - -#if defined(__ANDROID__) - // Starts a new service instance - /* NOTE: Since on Android devices the sdcard is formatted as fat32, we can't use just any - location to set up the RPC unix domain socket. Rather we must use the application's specific - data directory given by getApplicationContext().getFilesDir() */ - JNIEXPORT int JNICALL Java_ZeroTier_ZTSDK_zt_1start_1service(JNIEnv *env, jobject thisObj, jstring path) { - if(path) - homeDir = env->GetStringUTFChars(path, NULL); - zts_start_core_service(NULL); - } - // Shuts down ZeroTier service and SOCKS5 Proxy server - JNIEXPORT void JNICALL Java_ZeroTier_ZTSDK_zt_1stop_1service(JNIEnv *env, jobject thisObj) { - if(zt1Service) - zts_stop_service(); - // TODO: Also terminate SOCKS5 Proxy - // zts_stop_proxy_server(); - } - // Returns whether the ZeroTier service is running - JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1service_1is_1running(JNIEnv *env, jobject thisObj) { - if(zt1Service) - return zts_service_is_running(); - return false; - } - // Returns path for ZT config/data files - JNIEXPORT jstring JNICALL Java_ZeroTier_ZTSDK_zt_1get_1homepath(JNIEnv *env, jobject thisObj) { - return (*env).NewStringUTF(zts_get_homepath()); - } - // Join a network - JNIEXPORT void JNICALL Java_ZeroTier_ZTSDK_zt_1join_1network(JNIEnv *env, jobject thisObj, jstring nwid) { - const char *nwidstr; - if(nwid) { - nwidstr = env->GetStringUTFChars(nwid, NULL); - zts_join_network(nwidstr); - } - } - // Leave a network - JNIEXPORT void JNICALL Java_ZeroTier_ZTSDK_zt_1leave_1network(JNIEnv *env, jobject thisObj, jstring nwid) { - const char *nwidstr; - if(nwid) { - nwidstr = env->GetStringUTFChars(nwid, NULL); - zts_leave_network(nwidstr); - } - } - // FIXME: Re-implemented to make it play nicer with the C-linkage required for Xcode integrations - // Now only returns first assigned address per network. Shouldn't normally be a problem - JNIEXPORT jobject JNICALL Java_ZeroTier_ZTSDK_zt_1get_1ipv4_1address(JNIEnv *env, jobject thisObj, jstring nwid) { - const char *nwid_str = env->GetStringUTFChars(nwid, NULL); - char address_string[32]; - memset(address_string, 0, 32); - zts_get_ipv4_address(nwid_str, address_string); - jclass clazz = (*env).FindClass("java/util/ArrayList"); - jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "", "()V")); - jstring _str = (*env).NewStringUTF(address_string); - env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str); - return addresses; - } - - JNIEXPORT jobject JNICALL Java_ZeroTier_ZTSDK_zt_1get_1ipv6_1address(JNIEnv *env, jobject thisObj, jstring nwid) { - const char *nwid_str = env->GetStringUTFChars(nwid, NULL); - char address_string[32]; - memset(address_string, 0, 32); - zts_get_ipv6_address(nwid_str, address_string); - jclass clazz = (*env).FindClass("java/util/ArrayList"); - jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "", "()V")); - jstring _str = (*env).NewStringUTF(address_string); - env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str); - return addresses; - } - - // Returns the device is in integer form - JNIEXPORT jint Java_ZeroTier_ZTSDK_zt_1get_1device_1id() { - return zts_get_device_id(); - } - // Returns whether the path to an endpoint is currently relayed by a root server - JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1is_1relayed() { - return zts_is_relayed(); - } - // Starts a SOCKS5 proxy server for a given ZeroTier network - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1start_1proxy_1server(JNIEnv *env, jobject thisObj, jstring nwid, jobject ztaddr) { - const char *nwidstr = env->GetStringUTFChars(nwid, NULL); - struct sockaddr_in addr; - // GET ZTAddress fields - jclass cls = env->GetObjectClass(ztaddr); - jfieldID fid = env->GetFieldID(cls, "port", "I"); - addr.sin_port = htons(env->GetIntField(ztaddr, fid)); - fid = env->GetFieldID(cls, "_rawAddr", "J"); - addr.sin_addr.s_addr = env->GetLongField(ztaddr, fid); - return zts_start_proxy_server((char *)zts_get_homepath, nwidstr, (struct sockaddr_storage *)&addr); - } - // - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1stop_1proxy_1server(JNIEnv *env, jobject thisObj, jstring nwid) { - return zts_stop_proxy_server((char*)env->GetStringUTFChars(nwid, NULL)); - } - // Returns the local address of the SOCKS5 Proxy server - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1get_1proxy_1server_1address(JNIEnv *env, jobject thisObj, jstring nwid, jobject ztaddr) { - struct sockaddr_in addr; - int err = zts_get_proxy_server_address(env->GetStringUTFChars(nwid, NULL), (struct sockaddr_storage*)&addr); - // SET ZTAddress fields - jfieldID fid; - jclass cls = env->GetObjectClass(ztaddr); - fid = env->GetFieldID(cls, "port", "I"); - env->SetIntField(ztaddr, fid, addr.sin_port); - fid = env->GetFieldID(cls,"_rawAddr", "J"); - env->SetLongField(ztaddr, fid,addr.sin_addr.s_addr); - return err; - } - // - JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1proxy_1is_1running(JNIEnv *env, jobject thisObj, jstring nwid) { - // TODO: implement - } -#endif - - - // ------------------------------------------------------------------------------ - // --------------------------- zts_start_core_service --------------------------- - // ------------------------------------------------------------------------------ - - -// Starts a ZeroTier service in the background -void *zts_start_core_service(void *thread_id) { - - #if defined(SDK_BUNDLED) - if(thread_id) - homeDir = std::string((char*)thread_id); - #endif - - //#if defined(SDK_BUNDLED) && !defined(__ANDROID__) - // set_intercept_status(INTERCEPT_DISABLED); // Ignore network calls from ZT service - //#endif - - #if defined(__IOS__) - char current_dir[MAX_DIR_SZ]; - // Go to the app's data directory so we can shorten the sun_path we bind to - getcwd(current_dir, MAX_DIR_SZ); - std::string targetDir = homeDir; // + "/../../"; - chdir(targetDir.c_str()); - homeDir = localHomeDir; - #endif - - #if defined(__UNITY_3D__) - char current_dir[MAX_DIR_SZ]; - getcwd(current_dir, MAX_DIR_SZ); - chdir(service_path.c_str()); - homeDir = current_dir; // homeDir shall be current_dir - #endif - - #if defined(__APPLE__) - #include "TargetConditionals.h" - #if TARGET_IPHONE_SIMULATOR - // homeDir = "dont/run/this/in/the/simulator/it/wont/work"; - #elif TARGET_OS_IPHONE - localHomeDir = "ZeroTier/One"; - std::string del = givenHomeDir.length() && givenHomeDir[givenHomeDir.length()-1]!='/' ? "/" : ""; - homeDir = givenHomeDir + del + localHomeDir; - #endif - #endif - - #if defined(__APPLE__) && !defined(__IOS__) - localHomeDir = homeDir; // Used for RPC and *can* differ from homeDir on some platforms - #endif - - DEBUG_INFO("homeDir=%s", homeDir.c_str()); - // Where network .conf files will be stored - netDir = homeDir + "/networks.d"; - zt1Service = (ZeroTier::OneService *)0; - - // Construct path for network config and supporting service files - if (homeDir.length()) { - std::vector hpsp(ZeroTier::OSUtils::split(homeDir.c_str(),ZT_PATH_SEPARATOR_S,"","")); - std::string ptmp; - if (homeDir[0] == ZT_PATH_SEPARATOR) - ptmp.push_back(ZT_PATH_SEPARATOR); - for(std::vector::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) { - if (ptmp.length() > 0) - ptmp.push_back(ZT_PATH_SEPARATOR); - ptmp.append(*pi); - if ((*pi != ".")&&(*pi != "..")) { - if (!ZeroTier::OSUtils::mkdir(ptmp)) { - DEBUG_ERROR("home path does not exist, and could not create"); - perror("error\n"); - } - } - } - } - else { - DEBUG_ERROR("homeDir is empty, could not construct path"); - return NULL; - } - - DEBUG_INFO("starting service..."); - - // Generate random port for new service instance - unsigned int randp = 0; - ZeroTier::Utils::getSecureRandom(&randp,sizeof(randp)); - int servicePort = 9000 + (randp % 1000); - - for(;;) { - zt1Service = ZeroTier::OneService::newInstance(homeDir.c_str(),servicePort); - switch(zt1Service->run()) { - case ZeroTier::OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done - case ZeroTier::OneService::ONE_NORMAL_TERMINATION: - break; - case ZeroTier::OneService::ONE_UNRECOVERABLE_ERROR: - DEBUG_ERROR("fatal error: %s",zt1Service->fatalErrorMessage().c_str()); - break; - case ZeroTier::OneService::ONE_IDENTITY_COLLISION: { - delete zt1Service; - zt1Service = (ZeroTier::OneService *)0; - std::string oldid; - ZeroTier::OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid); - if (oldid.length()) { - ZeroTier::OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid); - ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); - ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); - } - } - continue; // restart! - } - break; // terminate loop -- normally we don't keep restarting - } - delete zt1Service; - zt1Service = (ZeroTier::OneService *)0; - return NULL; -} - -#ifdef __cplusplus -} -#endif diff --git a/src/sockets.c b/src/sockets.c deleted file mode 100644 index 6b43e46..0000000 --- a/src/sockets.c +++ /dev/null @@ -1,887 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifdef USE_GNU_SOURCE - #define _GNU_SOURCE -#endif - -// For defining the Android direct-call API -#if defined(__ANDROID__) - #include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include - -#include - -#if defined(__linux__) - #include - #include - #include -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -#if defined(__linux__) - #define SOCK_MAX (SOCK_PACKET + 1) -#endif -#define SOCK_TYPE_MASK 0xf - -#include "sdk.h" -#include "debug.h" -#include "rpc.h" -#include "defs.h" - -#include "Constants.hpp" // For Tap's MTU - -// Prototypes -char *api_netpath = (char *)0; -void load_symbols(); -void load_symbols_rpc(); -int (*realclose)(CLOSE_SIG); - - // ------------------------------------------------------------------------------ - // ---------------------------------- zt_init_rpc ------------------------------- - // ------------------------------------------------------------------------------ - - int service_initialized = 0; - - // Assembles (and/or) sets the RPC path for communication with the ZeroTier service - void zts_init_rpc(const char *path, const char *nwid) - { - #if !defined(__IOS__) - // Since we don't use function interposition in iOS - if(!realconnect) { - load_symbols_rpc(); - } - #endif - // If no path, construct one or get it fron system env vars - if(!api_netpath) { - rpc_mutex_init(); - // Provided by user - #if defined(SDK_BUNDLED) - // Get the path/nwid from the user application - // netpath = [path + "/nc_" + nwid] - char *fullpath = (char *)malloc(strlen(path)+strlen(nwid)+1+4); - if(fullpath) { - zts_join_network_soft(path, nwid); - strcpy(fullpath, path); - strcat(fullpath, "/nc_"); - strcat(fullpath, nwid); - api_netpath = fullpath; - } - // Provided by Env - #else - // Get path/nwid from environment variables - if (!api_netpath) { - api_netpath = getenv("ZT_NC_NETWORK"); - DEBUG_INFO("$ZT_NC_NETWORK=%s", api_netpath); - } - #endif - } - - // start the SDK service if this is bundled - #if defined(SDK_BUNDLED) - if(!service_initialized) { - DEBUG_ATTN("api_netpath = %s", api_netpath); - pthread_t intercept_thread; - pthread_create(&intercept_thread, NULL, zts_start_core_service, (void *)(path)); - service_initialized = 1; - DEBUG_ATTN("waiting for service to assign address to network stack"); - // wait for zt service to assign the network stack an address - sleep(1); - while(!zts_has_address(nwid)) { usleep(1000); } - } - #endif - } - - void get_api_netpath() { zts_init_rpc("",""); } - - // ------------------------------------------------------------------------------ - // ------------------------------------ send() ---------------------------------- - // ------------------------------------------------------------------------------ - // int fd, const void *buf, size_t len - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1send(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, int flags) - { - jbyte *body = (*env)->GetByteArrayElements(env, buf, 0); - char * bufp = (char *)malloc(sizeof(char)*len); - memcpy(bufp, body, len); - (*env)->ReleaseByteArrayElements(env, buf, body, 0); - int written_bytes = write(fd, body, len); - return written_bytes; - } -#endif - - // ------------------------------------------------------------------------------ - // ------------------------------------ sendto() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd, const void *buf, size_t len, int flags, - // const struct sockaddr *addr, socklen_t addrlen - -#if defined(__ANDROID__) - // TODO: Check result of each JNI call - // UDP TX - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1sendto( - JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr) - { - struct sockaddr_in addr; - jclass cls = (*env)->GetObjectClass(env, ztaddr); - jfieldID f = (*env)->GetFieldID(env, cls, "port", "I"); - addr.sin_port = htons((*env)->GetIntField(env, ztaddr, f)); - f = (*env)->GetFieldID(env, cls, "_rawAddr", "J"); - addr.sin_addr.s_addr = (*env)->GetLongField(env, ztaddr, f); - addr.sin_family = AF_INET; - //LOGV("zt_sendto(): fd = %d\naddr = %s\nport=%d", fd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - // TODO: Optimize this - jbyte *body = (*env)->GetByteArrayElements(env, buf, 0); - char * bufp = (char *)malloc(sizeof(char)*len); - memcpy(bufp, body, len); - (*env)->ReleaseByteArrayElements(env, buf, body, 0); - // "connect" and send buffer contents - int sent_bytes = zts_sendto(fd, body, len, flags, (struct sockaddr *)&addr, sizeof(addr)); - return sent_bytes; - } -#endif - -//#if !defined(__ANDROID__) - #ifdef DYNAMIC_LIB - ssize_t zt_sendto(SENDTO_SIG) // Exposed as API - #else - ssize_t zts_sendto(SENDTO_SIG) // Used as internal implementation - #endif - { - if(len > ZT_UDP_DEFAULT_PAYLOAD_MTU) { - errno = EMSGSIZE; // Msg is too large - return -1; - } - int socktype = 0; - socklen_t socktype_len; - getsockopt(fd,SOL_SOCKET, SO_TYPE, (void*)&socktype, &socktype_len); - - if((socktype & SOCK_STREAM) || (socktype & SOCK_SEQPACKET)) { - if(addr == NULL || flags != 0) { - errno = EISCONN; - return -1; - } - } - // EMSGSIZE should be returned if the message is too long to be passed atomically through - // the underlying protocol, in our case MTU? - // TODO: More efficient solution - // This connect call is used to get the address info to the stack for sending the packet - int err; - if((err = zts_connect(fd, addr, addrlen)) < 0) { - DEBUG_ERROR("unknown problem passing address info to stack"); - errno = EISCONN; // double-check this is correct - return -1; - } - return write(fd, buf, len); - } -//#endif - - // ------------------------------------------------------------------------------ - // ----------------------------------- sendmsg() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd, const struct msghdr *msg, int flags - -#if !defined(__ANDROID__) - #ifdef DYNAMIC_LIB - ssize_t zt_sendmsg(SENDMSG_SIG) - #else - ssize_t zts_sendmsg(SENDMSG_SIG) - #endif - { - //DEBUG_EXTRA("fd=%d",fd); - char * p, * buf; - size_t tot_len = 0; - size_t err; - struct iovec * iov = msg->msg_iov; - for(int i=0; imsg_iovlen; ++i) - tot_len += iov[i].iov_len; - if(tot_len > ZT_UDP_DEFAULT_PAYLOAD_MTU) { - errno = EMSGSIZE; // Message too large to send atomically via underlying protocol, don't send - return -1; - } - buf = (char *)malloc(tot_len); - if(tot_len != 0 && buf == NULL) { - errno = ENOMEM; // Unable to allocate space for message - return -1; - } - p = buf; - for(int i=0; i < msg->msg_iovlen; ++i) { - memcpy(p, iov[i].iov_base, iov[i].iov_len); - p += iov[i].iov_len; - } - #if defined(__cplusplus) - #if defined(__APPLE__) - err = sendto(fd, buf, tot_len, flags, (const struct sockaddr *)(msg->msg_name), msg->msg_namelen); - #elif defined (__linux__) - err = sendto(fd, buf, tot_len, flags, (__CONST_SOCKADDR_ARG)(msg->msg_name), msg->msg_namelen); - #endif - #else - err = sendto(fd, buf, tot_len, flags, msg->msg_name, msg->msg_namelen); - #endif - free(buf); - return err; - } -#endif - - // ------------------------------------------------------------------------------ - // ---------------------------------- recvfrom() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd, void *restrict buf, size_t len, int flags, struct sockaddr - // *restrict addr, socklen_t *restrict addrlen - -#if defined(__ANDROID__) - // UDP RX - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1recvfrom( - JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint len, jint flags, jobject ztaddr) - { - struct sockaddr_in addr; - jbyte *body = (*env)->GetByteArrayElements(env, buf, 0); - unsigned char buffer[SDK_MTU]; - int payload_offset = sizeof(int) + sizeof(struct sockaddr_storage); - int rxbytes = zts_recvfrom(fd, &buffer, len, flags, &addr, sizeof(struct sockaddr_storage)); - if(rxbytes > 0) - memcpy(body, (jbyte*)buffer + payload_offset, rxbytes); - (*env)->ReleaseByteArrayElements(env, buf, body, 0); - // Update fields of Java ZTAddress object - jfieldID fid; - jclass cls = (*env)->GetObjectClass(env, ztaddr); - fid = (*env)->GetFieldID(env, cls, "port", "I"); - (*env)->SetIntField(env, ztaddr, fid, addr.sin_port); - fid = (*env)->GetFieldID(env, cls,"_rawAddr", "J"); - (*env)->SetLongField(env, ztaddr, fid,addr.sin_addr.s_addr); - return rxbytes; - } -#endif - -//#if !defined(__ANDROID__) - #ifdef DYNAMIC_LIB - ssize_t zt_recvfrom(RECVFROM_SIG) - #else - ssize_t zts_recvfrom(RECVFROM_SIG) - #endif - { - int read_chunk_sz = 0, payload_offset, tmpsz=0, pnum=0; // payload size - char tmpbuf[SDK_MTU]; - memset(tmpbuf, 0, SDK_MTU); - - // Attempt to read SDK_MTU sized chunk - int total_read = 0, n=0; - - // Read the entire SDK_MTU-sized chunk from the service socket - while(total_read < SDK_MTU) { - n = read(fd, tmpbuf+total_read, SDK_MTU); - - if(n>0) { - total_read += n; - } - else if (n < 0) - return n; - } - - if(n > 0) { - // For cases where *addrlen is an unreasonable value - // FIXME: This should probably have some more thought put into it - *addrlen = *addrlen > SDK_MTU ? 0 : *addrlen; - - memcpy(addr, tmpbuf, *addrlen); - memcpy(&tmpsz, tmpbuf + sizeof(struct sockaddr_storage), sizeof(tmpsz)); - memcpy(&pnum, tmpbuf + sizeof(struct sockaddr_storage) + sizeof(int), sizeof(int)); - if(tmpsz > SDK_MTU || tmpsz < 0) { - DEBUG_ERROR("An error occured somewhere in the SDK, read=%d", n); - return -1; - } - payload_offset = sizeof(int) + sizeof(struct sockaddr_storage); - - // No matter how much we read from the service, only copy 'read_chunk_sz' - // into the app's buffer - read_chunk_sz = len < SDK_MTU ? len : SDK_MTU; - read_chunk_sz = tmpsz < read_chunk_sz ? tmpsz : read_chunk_sz; // FIXME - memcpy(buf, tmpbuf + payload_offset, read_chunk_sz); - } - else { - return -1; - } - return read_chunk_sz; - } -//#endif - - // ------------------------------------------------------------------------------ - // ----------------------------------- recvmsg() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd, struct msghdr *msg, int flags - -#if !defined(__ANDROID__) - #ifdef DYNAMIC_LIB - ssize_t zt_recvmsg(RECVMSG_SIG) - #else - ssize_t zts_recvmsg(RECVMSG_SIG) - #endif - { - //DEBUG_EXTRA("fd=%d", fd); - ssize_t err, n, tot_len = 0; - char *buf, *p; - struct iovec *iov = msg->msg_iov; - - for(int i = 0; i < msg->msg_iovlen; ++i) - tot_len += iov[i].iov_len; - buf = (char *)malloc(tot_len); - if(tot_len != 0 && buf == NULL) { - errno = ENOMEM; - return -1; - } - #if defined(__cplusplus) - #if defined(__APPLE__) - n = err = recvfrom(fd, buf, tot_len, flags, (struct sockaddr * __restrict)(msg->msg_name), &msg->msg_namelen); - #elif defined(__linux__) - n = err = recvfrom(fd, buf, tot_len, flags, (__SOCKADDR_ARG)(msg->msg_name), &msg->msg_namelen); - #endif - #else - n = err = recvfrom(fd, buf, tot_len, flags, msg->msg_name, &msg->msg_namelen); - #endif - p = buf; - - // According to: http://pubs.opengroup.org/onlinepubs/009695399/functions/recvmsg.html - if(err > msg->msg_controllen && !( msg->msg_flags & MSG_PEEK)) { - // excess data should be disgarded - msg->msg_flags |= MSG_TRUNC; // Indicate that the buffer has been truncated - } - - while (n > 0) { - ssize_t count = n < iov->iov_len ? n : iov->iov_len; - memcpy (iov->iov_base, p, count); - p += count; - n -= count; - ++iov; - } - free(buf); - return err; - } -#endif - - // ------------------------------------------------------------------------------ - // --------------------- Exposed RX/TX API for .NET Wrapper --------------------- - // ------------------------------------------------------------------------------ - -#if defined(__UNITY_3D__) - // Just expose some basic calls for configuring and RX/TXing through ZT sockets - ssize_t zt_send(int fd, void *buf, int len) { - return write(fd, buf, len); - } - - ssize_t zt_recv(int fd, void *buf, int len) { - return read(fd, buf, len); - } - - int zt_set_nonblock(int fd) { - return fcntl(fd, F_SETFL, O_NONBLOCK); - } -#endif - - // ------------------------------------------------------------------------------ - // ----------------------- Exposed RX/TX API for Java JNI ----------------------- - // ------------------------------------------------------------------------------ - -#if defined(__ANDROID__) - // TCP TX - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1write(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len) - { - jbyte *body = (*env)->GetByteArrayElements(env, buf, 0); - char * bufp = (char *)malloc(sizeof(char)*len); - memcpy(bufp, body, len); - (*env)->ReleaseByteArrayElements(env, buf, body, 0); - int written_bytes = write(fd, body, len); - return written_bytes; - } - // TCP RX - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1read(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len) - { - jbyte *body = (*env)->GetByteArrayElements(env, buf, 0); - int read_bytes = read(fd, body, len); - (*env)->ReleaseByteArrayElements(env, buf, body, 0); - return read_bytes; - } -#endif - - // ------------------------------------------------------------------------------ - // --------------------------------- setsockopt() ------------------------------- - // ------------------------------------------------------------------------------ - // int fd, int level, int optname, const void *optval, socklen_t optlen - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1setsockopt( - JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen) { - return zts_setsockopt(fd, level, optname, optval, optlen); - } -#endif - - #ifdef DYNAMIC_LIB - int zt_setsockopt(SETSOCKOPT_SIG) - #else - int zts_setsockopt(SETSOCKOPT_SIG) - #endif - { - DEBUG_INFO("fd=%d", fd); - return 0; - } - - // ------------------------------------------------------------------------------ - // --------------------------------- getsockopt() ------------------------------- - // ------------------------------------------------------------------------------ - // int fd, int level, int optname, void *optval, socklen_t *optlen - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getsockopt( - JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen) { - return zts_getsockopt(fd, level, optname, optval, optlen); - } -#endif - -#ifdef DYNAMIC_LIB - int zt_getsockopt(GETSOCKOPT_SIG) -#else - int zts_getsockopt(GETSOCKOPT_SIG) -#endif - { - DEBUG_INFO("fd=%d", fd); - if(optname == SO_TYPE) { - int* val = (int*)optval; - *val = 2; - optval = (void*)val; - } - return 0; - } - - // ------------------------------------------------------------------------------ - // ----------------------------------- socket() --------------------------------- - // ------------------------------------------------------------------------------ - // int socket_family, int socket_type, int protocol - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1socket(JNIEnv *env, jobject thisObj, jint family, jint type, jint protocol) { - return zts_socket(family, type, protocol); - } -#endif - -#ifdef DYNAMIC_LIB - int zt_socket(SOCKET_SIG) -#else - int zts_socket(SOCKET_SIG) -#endif - { - get_api_netpath(); - DEBUG_INFO(""); - // Check that type makes sense -#if defined(__linux__) && !defined(__ANDROID__) - int flags = socket_type & ~SOCK_TYPE_MASK; - if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) { - errno = EINVAL; - return -1; - } -#endif - socket_type &= SOCK_TYPE_MASK; - // Check protocol is in range -#if defined(__linux__) - if (socket_family < 0 || socket_family >= NPROTO){ - errno = EAFNOSUPPORT; - return -1; - } - if (socket_type < 0 || socket_type >= SOCK_MAX) { - errno = EINVAL; - return -1; - } -#endif - // Assemble and send RPC - struct socket_st rpc_st; - rpc_st.socket_family = socket_family; - rpc_st.socket_type = socket_type; - rpc_st.protocol = protocol; - // -1 is passed since we we're generating the new socket in this call - int err = rpc_send_command(api_netpath, RPC_SOCKET, -1, &rpc_st, sizeof(struct socket_st)); - DEBUG_INFO("err=%d", err); - return err; - } - - // ------------------------------------------------------------------------------ - // ---------------------------------- connect() --------------------------------- - // ------------------------------------------------------------------------------ - // int fd, const struct sockaddr *addr, socklen_t addrlen - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1connect(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) { - struct sockaddr_in addr; - const char *str = (*env)->GetStringUTFChars(env, addrstr, 0); - addr.sin_addr.s_addr = inet_addr(str); - addr.sin_family = AF_INET; - addr.sin_port = htons( port ); - (*env)->ReleaseStringUTFChars(env, addrstr, str); - return zts_connect(fd, (struct sockaddr *)&addr, sizeof(addr)); - } -#endif - -#ifdef DYNAMIC_LIB - int zt_connect(CONNECT_SIG) -#else - int zts_connect(CONNECT_SIG) -#endif - { - get_api_netpath(); - struct connect_st rpc_st; - rpc_st.fd = fd; - memcpy(&rpc_st.addr, addr, sizeof(struct sockaddr_storage)); - memcpy(&rpc_st.addrlen, &addrlen, sizeof(socklen_t)); - return rpc_send_command(api_netpath, RPC_CONNECT, fd, &rpc_st, sizeof(struct connect_st)); - } - - // ------------------------------------------------------------------------------ - // ------------------------------------ bind() ---------------------------------- - // ------------------------------------------------------------------------------ - // int fd, const struct sockaddr *addr, socklen_t addrlen - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1bind(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) { - struct sockaddr_in addr; - const char *str = (*env)->GetStringUTFChars(env, addrstr, 0); - DEBUG_INFO("fd=%d, addr=%s, port=%d", fd, str, port); - addr.sin_addr.s_addr = inet_addr(str); - addr.sin_family = AF_INET; - addr.sin_port = htons( port ); - (*env)->ReleaseStringUTFChars(env, addrstr, str); - return zts_bind(fd, (struct sockaddr *)&addr, sizeof(addr)); - } -#endif - -#ifdef DYNAMIC_LIB - int zt_bind(BIND_SIG) -#else - int zts_bind(BIND_SIG) -#endif - { - get_api_netpath(); - DEBUG_INFO("fd=%d", fd); - struct bind_st rpc_st; - rpc_st.fd = fd; - memcpy(&rpc_st.addr, addr, sizeof(struct sockaddr_storage)); - memcpy(&rpc_st.addrlen, &addrlen, sizeof(socklen_t)); - return rpc_send_command(api_netpath, RPC_BIND, fd, &rpc_st, sizeof(struct bind_st)); - } - - // ------------------------------------------------------------------------------ - // ----------------------------------- accept4() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd, struct sockaddr *addr, socklen_t *addrlen, int flags - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1accept4(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port, jint flags) { - struct sockaddr_in addr; - char *str; - // = env->GetStringUTFChars(addrstr, NULL); - (*env)->ReleaseStringUTFChars(env, addrstr, str); - addr.sin_addr.s_addr = inet_addr(str); - addr.sin_family = AF_INET; - addr.sin_port = htons( port ); - return zts_accept4(fd, (struct sockaddr *)&addr, sizeof(addr), flags); - } -#endif - -#if defined(__linux__) - #ifdef DYNAMIC_LIB - int zt_accept4(ACCEPT4_SIG) - #else - int zts_accept4(ACCEPT4_SIG) - #endif - { - get_api_netpath(); - DEBUG_INFO("fd=%d", fd); - #if !defined(__ANDROID__) - if ((flags & SOCK_CLOEXEC)) - fcntl(fd, F_SETFL, FD_CLOEXEC); - if ((flags & SOCK_NONBLOCK)) - fcntl(fd, F_SETFL, O_NONBLOCK); - #endif - addrlen = !addr ? 0 : addrlen; - return accept(fd, addr, addrlen); - } -#endif - - // ------------------------------------------------------------------------------ - // ----------------------------------- accept() --------------------------------- - // ------------------------------------------------------------------------------ - // int fd struct sockaddr *addr, socklen_t *addrlen - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1accept(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) { - struct sockaddr_in addr; - // TODO: Send addr info back to Javaland - addr.sin_addr.s_addr = inet_addr(""); - addr.sin_family = AF_INET; - addr.sin_port = htons( port ); - return zts_accept(fd, (struct sockaddr *)&addr, sizeof(addr)); - } -#endif - -#ifdef DYNAMIC_LIB - int zt_accept(ACCEPT_SIG) -#else - int zts_accept(ACCEPT_SIG) -#endif - { - get_api_netpath(); - DEBUG_INFO("fd=%d", fd); - #if !defined(__UNITY_3D__) - if(addr) - addr->sa_family = AF_INET; - #endif - int new_fd = get_new_fd(fd); - DEBUG_INFO("newfd=%d", new_fd); - - if(new_fd > 0) { - errno = ERR_OK; - return new_fd; - } - errno = EAGAIN; - return -EAGAIN; - } - - // ------------------------------------------------------------------------------ - // ------------------------------------- listen()-------------------------------- - // ------------------------------------------------------------------------------ - // int fd, int backlog - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1listen(JNIEnv *env, jobject thisObj, jint fd, int backlog) { - return zts_listen(fd, backlog); - } -#endif - -#ifdef DYNAMIC_LIB - int zt_listen(LISTEN_SIG) -#else - int zts_listen(LISTEN_SIG) -#endif - { - get_api_netpath(); - DEBUG_INFO("fd=%d", fd); - struct listen_st rpc_st; - rpc_st.fd = fd; - rpc_st.backlog = backlog; - return rpc_send_command(api_netpath, RPC_LISTEN, fd, &rpc_st, sizeof(struct listen_st)); - } - - // ------------------------------------------------------------------------------ - // ------------------------------------- close() -------------------------------- - // ------------------------------------------------------------------------------ - // int fd - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1close(JNIEnv *env, jobject thisObj, jint fd) { - return zts_close(fd); - } -#endif - -#ifdef DYNAMIC_LIB - int zt_close(CLOSE_SIG) -#else - int zts_close(CLOSE_SIG) -#endif - { - get_api_netpath(); - DEBUG_INFO("fd=%d", fd); - return realclose(fd); - } - - // ------------------------------------------------------------------------------ - // -------------------------------- getsockname() ------------------------------- - // ------------------------------------------------------------------------------ - // int fd, struct sockaddr *addr, socklen_t *addrlen - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getsockname(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr) { - struct sockaddr_in addr; - int err = zts_getsockname(fd, &addr, sizeof(struct sockaddr)); - jfieldID fid; - jclass cls = (*env)->GetObjectClass(env, ztaddr); - fid = (*env)->GetFieldID(env, cls, "port", "I"); - (*env)->SetIntField(env, ztaddr, fid, addr.sin_port); - fid = (*env)->GetFieldID(env, cls,"_rawAddr", "J"); - (*env)->SetLongField(env, ztaddr, fid,addr.sin_addr.s_addr); - return err; - } -#endif - -#ifdef DYNAMIC_LIB - int zt_getsockname(GETSOCKNAME_SIG) -#else - int zts_getsockname(GETSOCKNAME_SIG) -#endif - { - get_api_netpath(); - DEBUG_EXTRA("fd=%d", fd); - struct getsockname_st rpc_st; - rpc_st.fd = fd; - memcpy(&rpc_st.addrlen, &addrlen, sizeof(socklen_t)); - int rpcfd = rpc_send_command(api_netpath, RPC_GETSOCKNAME, fd, &rpc_st, sizeof(struct getsockname_st)); - // read address info from service - char addrbuf[sizeof(struct sockaddr_storage)]; - memset(&addrbuf, 0, sizeof(struct sockaddr_storage)); - if(rpcfd > -1) { - int err = read(rpcfd, &addrbuf, sizeof(struct sockaddr)); - close(rpcfd); - if(err > 0) { - int sum=0; - for(int i=0;isa_family = AF_INET; - return 0; - } - - // ------------------------------------------------------------------------------ - // -------------------------------- getpeername() ------------------------------- - // ------------------------------------------------------------------------------ - // int fd, struct sockaddr *addr, socklen_t *addrlen - -#if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getpeername(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr) { - struct sockaddr_in addr; - int err = zts_getpeername(fd, &addr, sizeof(struct sockaddr)); - jfieldID fid; - jclass cls = (*env)->GetObjectClass(env, ztaddr); - fid = (*env)->GetFieldID(env, cls, "port", "I"); - (*env)->SetIntField(env, ztaddr, fid, addr.sin_port); - fid = (*env)->GetFieldID(env, cls,"_rawAddr", "J"); - (*env)->SetLongField(env, ztaddr, fid,addr.sin_addr.s_addr); - return err; - } -#endif - -#ifdef DYNAMIC_LIB - int zt_getpeername(GETSOCKNAME_SIG) -#else - int zts_getpeername(GETSOCKNAME_SIG) -#endif - { - get_api_netpath(); - DEBUG_EXTRA("fd=%d", fd); - struct getsockname_st rpc_st; - rpc_st.fd = fd; - memcpy(&rpc_st.addrlen, &addrlen, sizeof(socklen_t)); - int rpcfd = rpc_send_command(api_netpath, RPC_GETPEERNAME, fd, &rpc_st, sizeof(struct getsockname_st)); - // read address info from service - char addrbuf[sizeof(struct sockaddr_storage)]; - memset(&addrbuf, 0, sizeof(struct sockaddr_storage)); - - if(rpcfd > -1) { - int err = read(rpcfd, &addrbuf, sizeof(struct sockaddr)); - close(rpcfd); - if(err > 0) { - int sum=0; - for(int i=0;isa_family = AF_INET; - return 0; - } - - // ------------------------------------------------------------------------------ - // ------------------------------------ fcntl() --------------------------------- - // ------------------------------------------------------------------------------ - // int fd, int cmd, int flags - - #if defined(__ANDROID__) - JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1fcntl(JNIEnv *env, jobject thisObj, jint fd, jint cmd, jint flags) { - return zts_fcntl(fd,cmd,flags); - } -#endif - -#ifdef DYNAMIC_LIB - int zt_fcntl(FCNTL_SIG) -#else - int zts_fcntl(FCNTL_SIG) -#endif - { - DEBUG_EXTRA("fd=%d, cmd=%d, flags=%d", fd, cmd, flags); - return fcntl(fd,cmd,flags); - } - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/src/stack_drivers/README.md b/src/stack_drivers/README.md deleted file mode 100644 index 1933e87..0000000 --- a/src/stack_drivers/README.md +++ /dev/null @@ -1,25 +0,0 @@ -Hot-Swappable Network Stacks! -==== - -We've now enabled the ability for users to build the ZeroTier SDK with different network stacks with the mere flip of a compiler flag as well as running different stacks concurrently! This is perfect for embedded developers which may need a smaller code footprint and would like to use their own smaller or more specialized network stacks. - -`SDK_LWIP=1` and `SDK_PICOTCP=1` will enable the lwIP and picoTCP network stacks respectively. - -Currently our *lwIP* stack driver supports IPV4 and limited IPV6, whereas our *picoTCP* stack driver supports both IPV4 and IPV6 with no known issues. - -To enable specific protocol versions use `SDK_IPV4=1` and `SDK_IPV6=1` in conjunction with the above stack selection flags. - -Also, to enable debug for the SDK use `SDK_DEBUG=1`, to enable debug for the *lwIP* stack use `SDK_LWIP_DEBUG=1`. - -## Integrating Your Own Custom Stack - -If you don't know why this section exists, then I suggest turning back now. This is not for you. Otherwise, let's get on with things, here's how you can integrate your own custom network stack if for some reason lwIP or picoTCP aren't cutting it for you: - -Investigate the structure of `src/tap.cpp`, this file contains calls to functions implemented in the stack driver code (located in `src/stack_drivers`). - -Each stack is different but generally you'll need to provide: - - An initialization function to configure and bring up the stack's `interface` (or similar). - - An I/O polling loop section where you'll execute your timer calls, and check for inbound and outbound frames. - - A low-level input and output function to handle feeding ethernet frames into and out of the stack in its own unique way. - - Calls to your stack's API which roughly correspond with `handleRead()`, `handleWrite()`, `handleSocket()`, `handleConnect()`, etc - - In those calls you'll need to handle the creation, management, and destruction of your stack's "connection" objects, whatever that may be. \ No newline at end of file diff --git a/src/stack_drivers/jip/README.md b/src/stack_drivers/jip/README.md deleted file mode 100644 index 479a48b..0000000 --- a/src/stack_drivers/jip/README.md +++ /dev/null @@ -1,4 +0,0 @@ -jIP Network Stack Driver -==== - -This section only exists as minimal example of how a network stack would interact with the ZeroTier ethernet tap service. See the `lwIP` and `picoTCP` driver sections for full implementations of a stack driver. \ No newline at end of file diff --git a/src/stack_drivers/jip/jip.cpp b/src/stack_drivers/jip/jip.cpp deleted file mode 100644 index d8145ab..0000000 --- a/src/stack_drivers/jip/jip.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#if defined(SDK_JIP) - -namespace ZeroTier { - - void jip_init_interface(NetconEthernetTap *tap, const InetAddress &ip) - { - // initialize your stack here - } - - void jip_loop(NetconEthernetTap *tap) - { - while(_run) - { - // Tick stack timers here - // Perhaps do some polling? - } - } - - void jip_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) - { - // RX packets here - } -} - -#endif // SDK_JIP \ No newline at end of file diff --git a/src/stack_drivers/jip/jip.hpp b/src/stack_drivers/jip/jip.hpp deleted file mode 100644 index bf18dba..0000000 --- a/src/stack_drivers/jip/jip.hpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef SDK_JIPSTACK_H -#define SDK_JIPSTACK_H - -#if defined(SDK_JIP) - -#include "Mutex.hpp" -#include "OSUtils.hpp" -#include "debug.h" - -#include -#include - -#ifdef D_GNU_SOURCE -#define _GNU_SOURCE -#endif - -namespace ZeroTier { - - void jip_init_interface(NetconEthernetTap *tap, const InetAddress &ip); - void jip_loop(NetconEthernetTap *tap); - void jip_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - - /** - * Loads an instance of picoTCP stack library in a private memory arena - * - * This uses dlmopen() to load an instance of the LWIP stack into its - * own private memory space. This is done to get around the stack's - * lack of thread-safety or multi-instance support. The alternative - * would be to massively refactor the stack so everything lives in a - * state object instead of static memory space. - */ - class jip_stack - { - public: - - void *_libref; - - void close() { -#if defined(__STATIC_STACK__) - return; -#elif defined(__DYNAMIC_STACK__) - dlclose(_libref); -#endif - } - - //void (*_netif_init)(void); - - Mutex _lock; - Mutex _lock_mem; - - jip_stack(const char* path) : - _libref(NULL) - { -#if defined(__ANDROID__) || defined(__UNITY_3D__) - #define __STATIC_STACK__ -#elif defined(__linux__) - #define __DYNAMIC_STACK__ - // Dynamically load liblwip.so - _libref = dlmopen(LM_ID_NEWLM, path, RTLD_NOW); -#elif defined(__APPLE__) - #include "TargetConditionals.h" - #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE - #include "node/Mutex.hpp" - #define __STATIC_STACK__ - // iOS Simulator or iOS device - // Do nothing, symbols are statically-linked - #elif TARGET_OS_MAC && !defined(SDK_BUNDLED) - #define __DYNAMIC_STACK__ - // Dynamically load liblwip.so - _libref = dlopen(path, RTLD_NOW); - #else - #define __STATIC_STACK__ - #endif -#endif - -#ifdef __STATIC_STACK__ // Set static references (for use in iOS) - - //_netif_init = (void(*)(void))&netif_init; - -#endif - -#ifdef __DYNAMIC_STACK__ // Use dynamically-loaded symbols (for use in normal desktop applications) - - if(_libref == NULL) - DEBUG_ERROR("dlerror(): %s", dlerror()); - - //_netif_init = (void(*)(void))dlsym(_libref, "netif_init"); - -#endif - } - - ~jip_stack() - { - if (_libref) - dlclose(_libref); - } - - //inline void __netif_init(void) throw() { Mutex::Lock _l(_lock); _netif_init(); } -}; - -} // namespace ZeroTier - -#endif // SDK_JIP - -#endif diff --git a/src/stack_drivers/lwip/README.md b/src/stack_drivers/lwip/README.md deleted file mode 100644 index 6116363..0000000 --- a/src/stack_drivers/lwip/README.md +++ /dev/null @@ -1,2 +0,0 @@ -lwIP Network Stack Driver -==== diff --git a/src/stack_drivers/lwip/lwip.cpp b/src/stack_drivers/lwip/lwip.cpp deleted file mode 100644 index 0f2f703..0000000 --- a/src/stack_drivers/lwip/lwip.cpp +++ /dev/null @@ -1,1137 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#if defined(__ANDROID__) - #include "src/debug.h" -#endif - -#include "tap.hpp" -#include "sdkutils.hpp" - -namespace ZeroTier -{ - void lwip_init_interface(NetconEthernetTap *tap, const InetAddress &ip) - { - DEBUG_INFO(); - lwIP_stack *stack = tap->lwipstack; - Mutex::Lock _l(tap->_ips_m); - - if (std::find(tap->_ips.begin(),tap->_ips.end(),ip) == tap->_ips.end()) { - tap->_ips.push_back(ip); - std::sort(tap->_ips.begin(),tap->_ips.end()); - - #if defined(SDK_IPV4) - if (ip.isV4()) { - // Set IP - static ip_addr_t ipaddr, netmask, gw; - IP4_ADDR(&gw,127,0,0,1); - ipaddr.addr = *((u32_t *)ip.rawIpData()); - netmask.addr = *((u32_t *)ip.netmask().rawIpData()); - stack->__netif_add(&(tap->interface),&ipaddr, &netmask, &gw, NULL, tapif_init, stack->_ethernet_input); - tap->interface.state = tap; - tap->interface.output = stack->_etharp_output; - tap->_mac.copyTo(tap->interface.hwaddr, 6); - tap->interface.mtu = tap->_mtu; - tap->interface.name[0] = 'l'; - tap->interface.name[1] = '4'; - tap->interface.linkoutput = low_level_output; - tap->interface.hwaddr_len = 6; - tap->interface.flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP; - stack->__netif_set_default(&(tap->interface)); - stack->__netif_set_up(&(tap->interface)); - DEBUG_INFO("addr=%s, netmask=%s", ip.toString().c_str(), ip.netmask().toString().c_str()); - } - #endif - #if defined(SDK_IPV6) - if(ip.isV6()) { - DEBUG_INFO("local_addr=%s", ip.toString().c_str()); - static ip6_addr_t addr6; - struct sockaddr_in6 in6; - memcpy(in6.sin6_addr.s6_addr,ip.rawIpData(),16); - in6_to_ip6((ip6_addr *)&addr6, &in6); - tap->interface6.mtu = tap->_mtu; - tap->interface6.name[0] = 'l'; - tap->interface6.name[1] = '6'; - tap->interface6.hwaddr_len = 6; - tap->interface6.linkoutput = low_level_output; - tap->interface6.ip6_autoconfig_enabled = 1; - tap->_mac.copyTo(tap->interface6.hwaddr, tap->interface6.hwaddr_len); - stack->__netif_create_ip6_linklocal_address(&(tap->interface6), 1); - stack->__netif_add(&(tap->interface6), NULL, tapif_init, stack->_ethernet_input); - stack->__netif_set_default(&(tap->interface6)); - stack->__netif_set_up(&(tap->interface6)); - netif_ip6_addr_set_state(&(tap->interface6), 1, IP6_ADDR_TENTATIVE); - ip6_addr_copy(ip_2_ip6(tap->interface6.ip6_addr[1]), addr6); - tap->interface6.output_ip6 = stack->_ethip6_output; - tap->interface6.state = tap; - tap->interface6.flags = NETIF_FLAG_LINK_UP | NETIF_FLAG_UP; - DEBUG_INFO("addr=%s, netmask=%s", ip.toString().c_str(), ip.netmask().toString().c_str()); - } - #endif - } - } - - void lwip_loop(NetconEthernetTap *tap) - { - DEBUG_INFO(); - lwIP_stack *stack = tap->lwipstack; - uint64_t prev_tcp_time = 0, prev_status_time = 0, prev_discovery_time = 0; - // Main timer loop - while (tap->_run) { - uint64_t now = OSUtils::now(); - uint64_t since_tcp = now - prev_tcp_time; - uint64_t since_discovery = now - prev_discovery_time; - uint64_t since_status = now - prev_status_time; - uint64_t tcp_remaining = ZT_LWIP_TCP_TIMER_INTERVAL; - uint64_t discovery_remaining = 5000; - - #if defined(LWIP_IPV6) - #define DISCOVERY_INTERVAL 1000 - #elif defined(LWIP_IPV4) - #define DISCOVERY_INTERVAL ARP_TMR_INTERVAL - #endif - - // Connection prunning - if (since_status >= STATUS_TMR_INTERVAL) { - prev_status_time = now; - for(size_t i=0;i_Connections.size();++i) { - if(!tap->_Connections[i]->sock || tap->_Connections[i]->type != SOCK_STREAM) - continue; - int fd = tap->_phy.getDescriptor(tap->_Connections[i]->sock); - // DEBUG_INFO(" tap_thread(): tcp\\jobs = {%d, %d}\n", _Connection.size(), jobmap.size()); - // If there's anything on the RX buf, set to notify in case we stalled - if(tap->_Connections[i]->rxsz > 0) - tap->_phy.setNotifyWritable(tap->_Connections[i]->sock, true); - fcntl(fd, F_SETFL, O_NONBLOCK); - unsigned char tmpbuf[BUF_SZ]; - - ssize_t n = read(fd,&tmpbuf,BUF_SZ); - if(tap->_Connections[i]->TCP_pcb->state == SYN_SENT) { - DEBUG_EXTRA(" should finish or be removed soon, sock=%p, state=SYN_SENT", - (void*)&(tap->_Connections[i]->sock)); - } - if((n < 0 && errno != EAGAIN) || (n == 0 && errno == EAGAIN)) { - //DEBUG_INFO(" closing sock (%x)", (void*)_Connections[i]->sock); - tap->closeConnection(tap->_Connections[i]->sock); - } else if (n > 0) { - DEBUG_INFO(" data read during connection check (%ld bytes)", n); - tap->phyOnUnixData(tap->_Connections[i]->sock,tap->_phy.getuptr(tap->_Connections[i]->sock),&tmpbuf,n); - } - } - } - // Main TCP/ETHARP timer section - if (since_tcp >= ZT_LWIP_TCP_TIMER_INTERVAL) { - prev_tcp_time = now; - stack->__tcp_tmr(); - // FIXME: could be removed or refactored? - // Makeshift poll - for(size_t i=0;i_Connections.size();++i) { - if(tap->_Connections[i]->txsz > 0){ - lwip_handleWrite(tap, tap->_Connections[i]); - } - } - } else { - tcp_remaining = ZT_LWIP_TCP_TIMER_INTERVAL - since_tcp; - } - if (since_discovery >= DISCOVERY_INTERVAL) { - prev_discovery_time = now; - #if defined(SDK_IPV4) - stack->__etharp_tmr(); - #endif - #if defined(SDK_IPV6) - stack->__nd6_tmr(); - #endif - } else { - discovery_remaining = DISCOVERY_INTERVAL - since_discovery; - } - tap->_phy.poll((unsigned long)std::min(tcp_remaining,discovery_remaining)); - } - stack->close(); - } - - void lwip_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) - { - // DEBUG_EXTRA(); - lwIP_stack *stack = tap->lwipstack; - struct pbuf *p,*q; - if (!tap->_enabled) - return; - struct eth_hdr ethhdr; - from.copyTo(ethhdr.src.addr, 6); - to.copyTo(ethhdr.dest.addr, 6); - ethhdr.type = Utils::hton((uint16_t)etherType); - - p = stack->__pbuf_alloc(PBUF_RAW, len+sizeof(struct eth_hdr), PBUF_POOL); - if (p != NULL) { - const char *dataptr = reinterpret_cast(data); - // First pbuf gets ethernet header at start - q = p; - if (q->len < sizeof(ethhdr)) { - DEBUG_ERROR("dropped packet: first pbuf smaller than ethernet header"); - return; - } - memcpy(q->payload,ðhdr,sizeof(ethhdr)); - memcpy((char*)q->payload + sizeof(ethhdr),dataptr,q->len - sizeof(ethhdr)); - dataptr += q->len - sizeof(ethhdr); - - // Remaining pbufs (if any) get rest of data - while ((q = q->next)) { - memcpy(q->payload,dataptr,q->len); - dataptr += q->len; - } - } - else { - DEBUG_ERROR("dropped packet: no pbufs available"); - return; - } - { - #if defined(SDK_IPV6) - if(tap->interface6.input(p, &(tap->interface6)) != ERR_OK) { - DEBUG_ERROR("error while feeding frame into stack interface6"); - } - #endif - #if defined(SDK_IPV4) - if(tap->interface.input(p, &(tap->interface)) != ERR_OK) { - DEBUG_ERROR("error while feeding frame into stack interface"); - } - #endif - } - } - - // Create and set up a lwIP socket PCB and Connection object - Connection *lwip_handleSocket(NetconEthernetTap *tap, PhySocket *sock, void **uptr, struct socket_st* socket_rpc) - { - lwIP_stack *stack = tap->lwipstack; - struct udp_pcb *new_udp_PCB = NULL; - struct tcp_pcb *new_tcp_PCB = NULL; - - if(socket_rpc->socket_type == SOCK_DGRAM) { - DEBUG_EXTRA("SOCK_DGRAM"); - Mutex::Lock _l(tap->_tcpconns_m); - new_udp_PCB = stack->__udp_new(); - } - else if(socket_rpc->socket_type == SOCK_STREAM) { - DEBUG_EXTRA("SOCK_STREAM"); - Mutex::Lock _l(tap->_tcpconns_m); - new_tcp_PCB = stack->__tcp_new(); - } - else if(socket_rpc->socket_type == SOCK_RAW) { - DEBUG_ERROR("SOCK_RAW, not currently supported."); - } - if(new_udp_PCB || new_tcp_PCB) { - Connection * newConn = new Connection(); - *uptr = newConn; - newConn->type = socket_rpc->socket_type; - newConn->sock = sock; - newConn->local_addr = NULL; - newConn->peer_addr = NULL; - if(newConn->type == SOCK_DGRAM) newConn->UDP_pcb = new_udp_PCB; - if(newConn->type == SOCK_STREAM) newConn->TCP_pcb = new_tcp_PCB; - tap->_Connections.push_back(newConn); - return newConn; - } - DEBUG_ERROR(" memory not available for new PCB"); - tap->sendReturnValue(tap->_phy.getDescriptor(sock), -1, ENOMEM); - return NULL; - } - - // - Connection * lwip_handleSocketProxy(NetconEthernetTap *tap, PhySocket *sock, int socket_type) - { - /* - Connection *conn = getConnection(sock); - if(!conn){ - DEBUG_ERROR("unable to locate Connection object for this PhySocket sock=%p", (void*)&sock); - return NULL; - } - DEBUG_ATTN("sock=%p", (void*)&sock); - struct udp_pcb *new_udp_PCB = NULL; - struct tcp_pcb *new_tcp_PCB = NULL; - if(socket_type == SOCK_DGRAM) { - DEBUG_EXTRA("SOCK_DGRAM"); - Mutex::Lock _l(_tcpconns_m); - new_udp_PCB = lwipstack->__udp_new(); - } - else if(socket_type == SOCK_STREAM) { - DEBUG_EXTRA("SOCK_STREAM"); - Mutex::Lock _l(_tcpconns_m); - new_tcp_PCB = lwipstack->__tcp_new(); - } - if(new_udp_PCB || new_tcp_PCB) { - conn->sock = sock; - conn->type = socket_type; - conn->local_addr = NULL; - conn->peer_addr = NULL; - if(conn->type == SOCK_DGRAM) conn->UDP_pcb = new_udp_PCB; - if(conn->type == SOCK_STREAM) conn->TCP_pcb = new_tcp_PCB; - DEBUG_INFO(" updated sock=%p", (void*)&sock); - return conn; - } - DEBUG_ERROR(" memory not available for new PCB"); - */ - return NULL; - } - - // Connects an lwIP socket PCB to a remote host - void lwip_handleConnect(NetconEthernetTap *tap, PhySocket *sock, PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc) - { - lwIP_stack *stack = tap->lwipstack; - ip_addr_t ba; - char addrstr[INET6_ADDRSTRLEN]; - struct sockaddr_in6 *rawAddr = (struct sockaddr_in6 *) &connect_rpc->addr; - struct sockaddr *addr = (struct sockaddr*)rawAddr; - int err, port = stack->__lwip_ntohs(rawAddr->sin6_port); - - // ipv4 - #if defined(SDK_IPV4) - if(addr->sa_family == AF_INET) { - struct sockaddr_in *connaddr = (struct sockaddr_in *)addr; - inet_ntop(AF_INET, &(connaddr->sin_addr), addrstr, INET_ADDRSTRLEN); - sprintf(addrstr, "%s:%d", addrstr, stack->__lwip_ntohs(connaddr->sin_port)); - } - struct sockaddr_in *rawAddr4 = (struct sockaddr_in *) &connect_rpc->addr; - ba = convert_ip(rawAddr4); - port = stack->__lwip_ntohs(rawAddr4->sin_port); - #endif - - // ipv6 - #if defined(SDK_IPV6) - struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&connect_rpc->addr; - in6_to_ip6((ip6_addr *)&ba, in6); - - if(addr->sa_family == AF_INET6) { - struct sockaddr_in6 *connaddr6 = (struct sockaddr_in6 *)addr; - inet_ntop(AF_INET6, &(connaddr6->sin6_addr), addrstr, INET6_ADDRSTRLEN); - sprintf(addrstr, "%s:%d", addrstr, stack->__lwip_ntohs(connaddr6->sin6_port)); - } - #endif - DEBUG_INFO("addr=%s", addrstr); - - if(conn->type == SOCK_DGRAM) { - // Generates no network traffic - if((err = stack->__udp_connect(conn->UDP_pcb,(ip_addr_t *)&ba,port)) < 0) - DEBUG_ERROR("error while connecting to with UDP"); - stack->__udp_recv(conn->UDP_pcb, nc_udp_recved, new Larg(tap, conn)); - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), 0, ERR_OK); - return; - } - if(conn != NULL) { - stack->__tcp_sent(conn->TCP_pcb, nc_sent); - stack->__tcp_recv(conn->TCP_pcb, nc_recved); - stack->__tcp_err(conn->TCP_pcb, nc_err); - stack->__tcp_poll(conn->TCP_pcb, nc_poll, APPLICATION_POLL_FREQ); - stack->__tcp_arg(conn->TCP_pcb, new Larg(tap, conn)); - - DEBUG_EXTRA(" pcb->state=%x", conn->TCP_pcb->state); - if(conn->TCP_pcb->state != CLOSED) { - DEBUG_INFO(" cannot connect using this PCB, PCB!=CLOSED"); - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EAGAIN); - return; - } - if((err = stack->__tcp_connect(conn->TCP_pcb,&ba,port,nc_connected)) < 0) - { - if(err == ERR_ISCONN) { - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EISCONN); // Already in connected state - return; - } if(err == ERR_USE) { - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EADDRINUSE); // Already in use - return; - } if(err == ERR_VAL) { - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EINVAL); // Invalid ipaddress parameter - return; - } if(err == ERR_RTE) { - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, ENETUNREACH); // No route to host - return; - } if(err == ERR_BUF) { - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EAGAIN); // No more ports available - return; - } - if(err == ERR_MEM) { - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EAGAIN); // TODO: Doesn't describe the problem well, but closest match - return; - } - // We should only return a value if failure happens immediately - // Otherwise, we still need to wait for a callback from lwIP. - // - This is because an ERR_OK from tcp_connect() only verifies - // that the SYN packet was enqueued onto the stack properly, - // that's it! - // - Most instances of a retval for a connect() should happen - // in the nc_connect() and nc_err() callbacks! - DEBUG_ERROR(" unable to connect"); - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EAGAIN); - } - // Everything seems to be ok, but we don't have enough info to retval - conn->listening=true; - conn->rpcSock=rpcSock; // used for return value from lwip CB - } - else { - DEBUG_ERROR(" could not locate PCB based on application-provided fd"); - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EBADF); - } - } - - // Connect to a remote hose via the built-in SOCKS5 proxy server - int lwip_handleConnectProxy(NetconEthernetTap *tap, PhySocket *sock, struct sockaddr_in *rawAddr) - { - /* - DEBUG_ATTN("sock=%p", (void*)&sock); - Mutex::Lock _l(_tcpconns_m); - int port = rawAddr->sin_port; - ip_addr_t connAddr = convert_ip(rawAddr); - int err = 0; - - Connection *conn = getConnection(sock); - if(!conn) { - DEBUG_INFO(" unable to locate Connection object for sock=%p", (void*)&sock); - return -1; - } - if(conn->type == SOCK_DGRAM) { - // Generates no network traffic - if((err = lwipstack->__udp_connect(conn->UDP_pcb,&connAddr,port)) < 0) - DEBUG_INFO("error while connecting to with UDP (sock=%p)", (void*)&sock); - lwipstack->__udp_recv(conn->UDP_pcb, nc_udp_recved, new Larg(this, conn)); - errno = ERR_OK; - return 0; - } - if(conn != NULL) { - lwipstack->__tcp_sent(conn->TCP_pcb, nc_sent); - lwipstack->__tcp_recv(conn->TCP_pcb, nc_recved); - lwipstack->__tcp_err(conn->TCP_pcb, nc_err); - lwipstack->__tcp_poll(conn->TCP_pcb, nc_poll, APPLICATION_POLL_FREQ); - lwipstack->__tcp_arg(conn->TCP_pcb, new Larg(this, conn)); - - int ip = rawAddr->sin_addr.s_addr; - unsigned char d[4]; - d[0] = ip & 0xFF; - d[1] = (ip >> 8) & 0xFF; - d[2] = (ip >> 16) & 0xFF; - d[3] = (ip >> 24) & 0xFF; - DEBUG_INFO(" addr=%d.%d.%d.%d:%d", d[0],d[1],d[2],d[3], port); - DEBUG_INFO(" pcb->state=%x", conn->TCP_pcb->state); - if(conn->TCP_pcb->state != CLOSED) { - DEBUG_INFO(" cannot connect using this PCB, PCB!=CLOSED"); - errno = EAGAIN; - return -1; - } - if((err = lwipstack->__tcp_connect(conn->TCP_pcb,&connAddr,port,nc_connected_proxy)) < 0) - { - if(err == ERR_ISCONN) { - errno = EISCONN; // Already in connected state - return -1; - } if(err == ERR_USE) { - errno = EADDRINUSE; // Already in use - return -1; - } if(err == ERR_VAL) { - errno = EINVAL; // Invalid ipaddress parameter - return -1; - } if(err == ERR_RTE) { - errno = ENETUNREACH; // No route to host - return -1; - } if(err == ERR_BUF) { - errno = EAGAIN; // No more ports available - return -1; - } - if(err == ERR_MEM) { - // Can occur for the following reasons: tcp_enqueue_flags() - - // 1) tcp_enqueue_flags is always called with either SYN or FIN in flags. - // We need one available snd_buf byte to do that. - // This means we can't send FIN while snd_buf==0. A better fix would be to - // not include SYN and FIN sequence numbers in the snd_buf count. - - // 2) Cannot allocate new pbuf - // 3) Cannot allocate new TCP segment - - errno = EAGAIN; // TODO: Doesn't describe the problem well, but closest match - return -1; - } - // We should only return a value if failure happens immediately - // Otherwise, we still need to wait for a callback from lwIP. - // - This is because an ERR_OK from tcp_connect() only verifies - // that the SYN packet was enqueued onto the stack properly, - // that's it! - // - Most instances of a retval for a connect() should happen - // in the nc_connect() and nc_err() callbacks! - DEBUG_ERROR(" unable to connect"); - errno = EAGAIN; - return -1; - } - // Everything seems to be ok, but we don't have enough info to retval - conn->listening=true; - return 0; - } else { - DEBUG_ERROR(" could not locate PCB based on application-provided fd"); - errno = EBADF; - return -1; - } - */ - return -1; - } - - void lwip_handleBind(NetconEthernetTap *tap, PhySocket *sock, PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc) - { - lwIP_stack *stack = tap->lwipstack; - ip_addr_t ba; - char addrstr[INET6_ADDRSTRLEN]; - struct sockaddr_in6 *rawAddr = (struct sockaddr_in6 *) &bind_rpc->addr; - struct sockaddr *addr = (struct sockaddr*)rawAddr; - int err, port = stack->__lwip_ntohs(rawAddr->sin6_port); - - // ipv4 - #if defined(SDK_IPV4) - if(addr->sa_family == AF_INET) { - struct sockaddr_in *connaddr = (struct sockaddr_in *)addr; - inet_ntop(AF_INET, &(connaddr->sin_addr), addrstr, INET_ADDRSTRLEN); - sprintf(addrstr, "%s:%d", addrstr, stack->__lwip_ntohs(connaddr->sin_port)); - } - struct sockaddr_in *rawAddr4 = (struct sockaddr_in *) &bind_rpc->addr; - ba = convert_ip(rawAddr4); - port = stack->__lwip_ntohs(rawAddr4->sin_port); - #endif - - // ipv6 - #if defined(SDK_IPV6) - struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&bind_rpc->addr; - in6_to_ip6((ip6_addr *)&ba, in6); - if(addr->sa_family == AF_INET6) { - struct sockaddr_in6 *connaddr6 = (struct sockaddr_in6 *)addr; - inet_ntop(AF_INET6, &(connaddr6->sin6_addr), addrstr, INET6_ADDRSTRLEN); - sprintf(addrstr, "%s:%d", addrstr, stack->__lwip_ntohs(connaddr6->sin6_port)); - } - #endif - - Connection *conn = tap->getConnection(sock); - DEBUG_ATTN(" addr=%s, sock=%p, fd=%d", addrstr, (void*)&sock, bind_rpc->fd); - if(conn) { - if(conn->type == SOCK_DGRAM) { - #if defined(__ANDROID__) - err = stack->__udp_bind(conn->UDP_pcb, NULL, port); - #else - err = stack->__udp_bind(conn->UDP_pcb, (const ip_addr_t *)&ba, port); - #endif - if(err == ERR_USE) // port in use - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EADDRINUSE); - else { - stack->__udp_recv(conn->UDP_pcb, nc_udp_recved, new Larg(tap, conn)); - struct sockaddr_in addr_in; - memcpy(&addr_in, &bind_rpc->addr, sizeof(addr_in)); - addr_in.sin_port = Utils::ntoh(conn->UDP_pcb->local_port); // Newly assigned port - memcpy(&conn->local_addr, &addr_in, sizeof(addr_in)); - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); // Success - } - return; - } - else if (conn->type == SOCK_STREAM) { - if(conn->TCP_pcb->state == CLOSED){ - err = stack->__tcp_bind(conn->TCP_pcb, (const ip_addr_t *)&ba, port); - if(err != ERR_OK) { - DEBUG_ERROR("err=%d", err); - if(err == ERR_USE) - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EADDRINUSE); - if(err == ERR_MEM) - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, ENOMEM); - if(err == ERR_BUF) - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, ENOMEM); - } else { - conn->local_addr = (struct sockaddr_storage *) &bind_rpc->addr; - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); // Success - } - } else { - DEBUG_ERROR(" ignoring BIND request, PCB (conn=%p, pcb=%p) not in CLOSED state. ", - (void*)&conn, (void*)&conn->TCP_pcb); - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EINVAL); - } - } - } - else { - DEBUG_ERROR(" unable to locate Connection"); - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EBADF); - } - } - - void lwip_handleListen(NetconEthernetTap *tap, PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc) - { - DEBUG_ATTN("sock=%p", (void*)&sock); - lwIP_stack *stack = tap->lwipstack; - - Connection *conn = tap->getConnection(sock); - if(conn->type==SOCK_DGRAM) { - // FIX: Added sendReturnValue() call to fix listen() return bug on Android - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); - return; - } - if(!conn) { - DEBUG_ERROR(" unable to locate Connection"); - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, EBADF); - return; - } - if(conn->TCP_pcb->state == LISTEN) { - DEBUG_ERROR(" PCB is already in listening state"); - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); - return; - } - struct tcp_pcb* listeningPCB; - - #ifdef TCP_LISTEN_BACKLOG - listeningPCB = stack->__tcp_listen_with_backlog(conn->TCP_pcb, listen_rpc->backlog); - #else - listeningPCB = stack->__tcp_listen(conn->pcb); - #endif - if(listeningPCB != NULL) { - conn->TCP_pcb = listeningPCB; - stack->__tcp_accept(listeningPCB, nc_accept); - stack->__tcp_arg(listeningPCB, new Larg(tap, conn)); - fcntl(tap->_phy.getDescriptor(conn->sock), F_SETFL, O_NONBLOCK); - conn->listening = true; - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); - return; - } - tap->sendReturnValue(tap->_phy.getDescriptor(rpcSock), -1, -1); - } - - // (RX packet) Read data from the RX buffer that lwIP just wrote to - void lwip_handleRead(NetconEthernetTap *tap, PhySocket *sock, void **uptr, bool lwip_invoked) - { - DEBUG_EXTRA(); - lwIP_stack *stack = tap->lwipstack; - if(!lwip_invoked) { - tap->_tcpconns_m.lock(); - tap->_rx_buf_m.lock(); - } - Connection *conn = tap->getConnection(sock); - if(conn && conn->rxsz) { - float max = conn->type == SOCK_STREAM ? (float)DEFAULT_TCP_RX_BUF_SZ : (float)DEFAULT_UDP_RX_BUF_SZ; - long n = tap->_phy.streamSend(conn->sock, conn->rxbuf, ZT_MAX_MTU); - int payload_sz, addr_sz_offset = sizeof(struct sockaddr_storage); - memcpy(&payload_sz, conn->rxbuf + addr_sz_offset, sizeof(int)); // OPT: - // extract address - struct sockaddr_storage addr; - memcpy(&addr, conn->rxbuf, addr_sz_offset); - - if(n == ZT_MAX_MTU) { - if(conn->rxsz-n > 0) // If more remains on buffer - memcpy(conn->rxbuf, conn->rxbuf+ZT_MAX_MTU, conn->rxsz - ZT_MAX_MTU); - conn->rxsz -= ZT_MAX_MTU; - // DGRAM - if(conn->type==SOCK_DGRAM){ - tap->_phy.setNotifyWritable(conn->sock, false); - - #if DEBUG_LEVEL >= MSG_TRANSFER - struct sockaddr_in * addr_in2 = (struct sockaddr_in *)&addr; - int port = stack->__lwip_ntohs(addr_in2->sin_port); - int ip = addr_in2->sin_addr.s_addr; - unsigned char d[4]; - d[0] = ip & 0xFF; - d[1] = (ip >> 8) & 0xFF; - d[2] = (ip >> 16) & 0xFF; - d[3] = (ip >> 24) & 0xFF; - DEBUG_TRANS("UDP RX <--- :: {TX: %.3f%%, RX: %d, sock=%p} :: payload = %d bytes (src_addr=%d.%d.%d.%d:%d)", - (float)conn->txsz / max, conn->rxsz/* / max*/, (void*)conn->sock, payload_sz, d[0],d[1],d[2],d[3], port); - #endif - } - // STREAM - //DEBUG_INFO("phyOnUnixWritable(): tid = %d\n", pthread_mach_thread_np(pthread_self())); - if(conn->type==SOCK_STREAM) { // Only acknolwedge receipt of TCP packets - stack->__tcp_recved(conn->TCP_pcb, n); - DEBUG_TRANS("TCP RX <--- :: {TX: %.3f%%, RX: %.3f%%, sock=%p} :: %ld bytes", - (float)conn->txsz / max, (float)conn->rxsz / max, (void*)conn->sock, n); - } - } else { - DEBUG_EXTRA(" errno = %d, rxsz = %d", errno, conn->rxsz); - tap->_phy.setNotifyWritable(conn->sock, false); - } - } - // If everything on the buffer has been written - if(conn->rxsz == 0) { - tap->_phy.setNotifyWritable(conn->sock, false); - } - if(!lwip_invoked) { - tap->_tcpconns_m.unlock(); - tap->_rx_buf_m.unlock(); - } - } - - // (TX packet) Write data from user app to network stack - void lwip_handleWrite(NetconEthernetTap *tap, Connection *conn) - { - DEBUG_EXTRA("conn=%p", (void*)&conn); - lwIP_stack *stack = tap->lwipstack; - if(!conn || (!conn->TCP_pcb && !conn->UDP_pcb)) { - DEBUG_ERROR(" invalid connection"); - return; - } - if(conn->type == SOCK_DGRAM) { - if(!conn->UDP_pcb) { - DEBUG_ERROR(" invalid UDP_pcb, type=SOCK_DGRAM"); - return; - } - // TODO: Packet re-assembly hasn't yet been tested with lwIP so UDP packets are limited to MTU-sized chunks - int udp_trans_len = conn->txsz < ZT_UDP_DEFAULT_PAYLOAD_MTU ? conn->txsz : ZT_UDP_DEFAULT_PAYLOAD_MTU; - - DEBUG_EXTRA(" allocating pbuf chain of size=%d for UDP packet, txsz=%d", udp_trans_len, conn->txsz); - struct pbuf * pb = stack->__pbuf_alloc(PBUF_TRANSPORT, udp_trans_len, PBUF_POOL); - if(!pb){ - DEBUG_ERROR(" unable to allocate new pbuf of size=%d", conn->txsz); - return; - } - memcpy(pb->payload, conn->txbuf, udp_trans_len); - int err = stack->__udp_send(conn->UDP_pcb, pb); - - if(err == ERR_MEM) { - DEBUG_ERROR(" error sending packet. out of memory"); - } else if(err == ERR_RTE) { - DEBUG_ERROR(" could not find route to destinations address"); - } else if(err != ERR_OK) { - DEBUG_ERROR(" error sending packet - %d", err); - } else { - // Success - int buf_remaining = (conn->txsz)-udp_trans_len; - if(buf_remaining) - memmove(&conn->txbuf, (conn->txbuf+udp_trans_len), buf_remaining); - conn->txsz -= udp_trans_len; - - #if DEBUG_LEVEL >= MSG_TRANSFER - struct sockaddr_in * addr_in2 = (struct sockaddr_in *)conn->peer_addr; - int port = stack->__lwip_ntohs(addr_in2->sin_port); - int ip = addr_in2->sin_addr.s_addr; - unsigned char d[4]; - d[0] = ip & 0xFF; - d[1] = (ip >> 8) & 0xFF; - d[2] = (ip >> 16) & 0xFF; - d[3] = (ip >> 24) & 0xFF; - DEBUG_TRANS("[UDP TX] ---> :: {TX: ------, RX: ------, sock=%p} :: %d bytes (dest_addr=%d.%d.%d.%d:%d)", - (void*)conn->sock, udp_trans_len, d[0], d[1], d[2], d[3], port); - #endif - } - stack->__pbuf_free(pb); - return; - } - else if(conn->type == SOCK_STREAM) { - if(!conn->TCP_pcb) { - DEBUG_ERROR(" invalid TCP_pcb, type=SOCK_STREAM"); - return; - } - // How much we are currently allowed to write to the connection - int sndbuf = conn->TCP_pcb->snd_buf; - int err, sz, r; - - if(!sndbuf) { - // PCB send buffer is full, turn off readability notifications for the - // corresponding PhySocket until nc_sent() is called and confirms that there is - // now space on the buffer - if(!conn->probation) { - DEBUG_ERROR(" LWIP stack is full, sndbuf == 0"); - tap->_phy.setNotifyReadable(conn->sock, false); - conn->probation = true; - } - return; - } - if(conn->txsz <= 0) - return; // Nothing to write - if(!conn->listening) - stack->__tcp_output(conn->TCP_pcb); - - if(conn->sock) { - r = conn->txsz < sndbuf ? conn->txsz : sndbuf; - // Writes data pulled from the client's socket buffer to LWIP. This merely sends the - // data to LWIP to be enqueued and eventually sent to the network. - if(r > 0) { - err = stack->__tcp_write(conn->TCP_pcb, &conn->txbuf, r, TCP_WRITE_FLAG_COPY); - stack->__tcp_output(conn->TCP_pcb); - if(err != ERR_OK) { - DEBUG_ERROR(" error while writing to PCB, err=%d", err); - if(err == -1) - DEBUG_ERROR("out of memory"); - return; - } else { - // adjust buffer - sz = (conn->txsz)-r; - if(sz) - memmove(&conn->txbuf, (conn->txbuf+r), sz); - conn->txsz -= r; - int max = conn->type == SOCK_STREAM ? DEFAULT_TCP_TX_BUF_SZ : DEFAULT_UDP_TX_BUF_SZ; - DEBUG_TRANS("[TCP TX] ---> :: {TX: %.3f%%, RX: %.3f%%, sock=%p} :: %d bytes", - (float)conn->txsz / (float)max, (float)conn->rxsz / max, (void*)&conn->sock, r); - return; - } - } - } - } - } - - void lwip_handleClose(NetconEthernetTap *tap, PhySocket *sock, Connection *conn) - { - DEBUG_ATTN(); - lwIP_stack *stack = tap->lwipstack; - - if(conn->type==SOCK_DGRAM) { - stack->__udp_remove(conn->UDP_pcb); - } - if(conn->TCP_pcb && conn->TCP_pcb->state != CLOSED) { - DEBUG_EXTRA("conn=%p, sock=%p, PCB->state = %d", - (void*)&conn, (void*)&sock, conn->TCP_pcb->state); - if(conn->TCP_pcb->state == SYN_SENT /*|| conn->TCP_pcb->state == CLOSE_WAIT*/) { - DEBUG_EXTRA("ignoring close request. invalid PCB state for this operation. sock=%p", (void*)&sock); - return; - } - // DEBUG_BLANK("__tcp_close(...)"); - if(stack->__tcp_close(conn->TCP_pcb) == ERR_OK) { - // Unregister callbacks for this PCB - stack->__tcp_arg(conn->TCP_pcb, NULL); - stack->__tcp_recv(conn->TCP_pcb, NULL); - stack->__tcp_err(conn->TCP_pcb, NULL); - stack->__tcp_sent(conn->TCP_pcb, NULL); - stack->__tcp_poll(conn->TCP_pcb, NULL, 1); - } - else { - DEBUG_EXTRA("error while calling tcp_close() sock=%p", (void*)&sock); - } - } - } - - /*------------------------------------------------------------------------------ - -------------------------------- lwIP Callbacks -------------------------------- - ------------------------------------------------------------------------------*/ - - err_t tapif_init(struct netif *netif) - { - // Actual init functionality is in addIp() of tap - return ERR_OK; - } - - /* - * Outputs data from the pbuf queue to the interface - */ - err_t low_level_output(struct netif *netif, struct pbuf *p) - { - struct pbuf *q; - char buf[ZT_MAX_MTU+32]; - char *bufptr; - int totalLength = 0; - - ZeroTier::NetconEthernetTap *tap = (ZeroTier::NetconEthernetTap*)netif->state; - bufptr = buf; - // Copy data from each pbuf, one at a time - for(q = p; q != NULL; q = q->next) { - memcpy(bufptr, q->payload, q->len); - bufptr += q->len; - totalLength += q->len; - } - // [Send packet to network] - // Split ethernet header and feed into handler - struct eth_hdr *ethhdr; - ethhdr = (struct eth_hdr *)buf; - - ZeroTier::MAC src_mac; - ZeroTier::MAC dest_mac; - src_mac.setTo(ethhdr->src.addr, 6); - dest_mac.setTo(ethhdr->dest.addr, 6); - - tap->_handler(tap->_arg,tap->_nwid,src_mac,dest_mac, - Utils::ntoh((uint16_t)ethhdr->type),0,buf + sizeof(struct eth_hdr),totalLength - sizeof(struct eth_hdr)); - return ERR_OK; - } - - // - err_t nc_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err) - { - Larg *l = (Larg*)arg; - DEBUG_EXTRA("conn=%p, pcb=%p", (void*)&(l->conn), (void*)&PCB); - int tot = 0; - struct pbuf* q = p; - Mutex::Lock _l(l->tap->_tcpconns_m); - - if(!l->conn) { - DEBUG_ERROR("no connection"); - return ERR_OK; - } - if(p == NULL) { - if(l->conn->TCP_pcb->state == CLOSE_WAIT){ - l->tap->closeConnection(l->conn->sock); - return ERR_ABRT; - } - return err; - } - Mutex::Lock _l2(l->tap->_rx_buf_m); - // Cycle through pbufs and write them to the RX buffer - // The RX buffer will be emptied via phyOnUnixWritable() - while(p != NULL) { - if(p->len <= 0) - break; - int avail = DEFAULT_TCP_RX_BUF_SZ - l->conn->rxsz; - int len = p->len; - if(avail < len) - DEBUG_ERROR("not enough room (%d bytes) on RX buffer", avail); - memcpy(l->conn->rxbuf + (l->conn->rxsz), p->payload, len); - l->conn->rxsz += len; - p = p->next; - tot += len; - } - if(tot) { - //#if defined(USE_SOCKS_PROXY) - // l->tap->phyOnTcpWritable(l->conn->sock, NULL, true); - //#else - l->tap->phyOnUnixWritable(l->conn->sock, NULL, true); - //#endif - } - l->tap->lwipstack->__pbuf_free(q); - return ERR_OK; - } - - // - err_t nc_accept(void *arg, struct tcp_pcb *newPCB, err_t err) - { - DEBUG_ATTN("pcb=%p", (void*)&newPCB); - Larg *l = (Larg*)arg; - Mutex::Lock _l(l->tap->_tcpconns_m); - Connection *conn = l->conn; - NetconEthernetTap *tap = l->tap; - - if(!conn) - return -1; - if(conn->type==SOCK_DGRAM) - return -1; - if(!conn->sock) - return -1; - int fd = tap->_phy.getDescriptor(conn->sock); - - if(conn) { - // create new socketpair - ZT_PHY_SOCKFD_TYPE fds[2]; - if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) { - if(errno < 0) { - // sendReturnValue(conn, -1, errno); - DEBUG_ERROR("unable to create socketpair"); - return ERR_MEM; - } - } - // create and populate new Connection - Connection *newTcpConn = new Connection(); - l->tap->_Connections.push_back(newTcpConn); - newTcpConn->TCP_pcb = newPCB; - newTcpConn->type = SOCK_STREAM; - newTcpConn->sock = tap->_phy.wrapSocket(fds[0], newTcpConn); - - if(sock_fd_write(fd, fds[1]) < 0) - return -1; - tap->lwipstack->__tcp_arg(newPCB, new Larg(tap, newTcpConn)); - tap->lwipstack->__tcp_recv(newPCB, nc_recved); - tap->lwipstack->__tcp_err(newPCB, nc_err); - tap->lwipstack->__tcp_sent(newPCB, nc_sent); - tap->lwipstack->__tcp_poll(newPCB, nc_poll, 1); - if(conn->TCP_pcb->state == LISTEN) - return ERR_OK; - tcp_accepted(conn->TCP_pcb); // Let lwIP know that it can queue additional incoming connections - return ERR_OK; - } else - DEBUG_ERROR("can't locate Connection object for PCB"); - return -1; - } - - // - void nc_udp_recved(void * arg, struct udp_pcb * upcb, struct pbuf * p, ip_addr_t * addr, u16_t port) - { - Larg *l = (Larg*)arg; - DEBUG_EXTRA("nc_udp_recved(conn=%p,pcb=%p,port=%d)\n", (void*)&(l->conn), (void*)&upcb, port); - /* - int tot = 0; - unsigned char *addr_pos, *sz_pos, *payload_pos; - struct pbuf* q = p; - struct sockaddr_storage sockaddr_big; - - #if defined(LWIP_IPV6) - struct sockaddr_in6 addr_in; - addr_in.sin6_addr.s6_addr = addr->u_addr.ip6.addr; - addr_in.sin6_port = port; - #else // ipv4 - struct sockaddr_in *addr_in = (struct sockaddr_in *)&sockaddr_big; - addr_in->sin_addr.s_addr = addr->addr; - addr_in->sin_port = port; - #endif - - // TODO: Finish address treatment - - Mutex::Lock _l2(l->tap->_rx_buf_m); - // Cycle through pbufs and write them to the RX buffer - // The RX "buffer" will be emptied via phyOnUnixWritable() - if(p) { - // Intra-API "packetization" scheme: [addr_len|addr|payload_len|payload] - if(l->conn->rxsz == DEFAULT_UDP_RX_BUF_SZ) { // if UDP buffer full - DEBUG_INFO("UDP RX buffer full. Discarding oldest payload segment"); - memmove(l->conn->rxbuf, l->conn->rxbuf + ZT_MAX_MTU, DEFAULT_UDP_RX_BUF_SZ - ZT_MAX_MTU); - addr_pos = l->conn->rxbuf + (DEFAULT_UDP_RX_BUF_SZ - ZT_MAX_MTU); // TODO: - sz_pos = addr_pos + sizeof(struct sockaddr_storage); - l->conn->rxsz -= ZT_MAX_MTU; - } - else { - addr_pos = l->conn->rxbuf + l->conn->rxsz; // where we'll prepend the size of the address - sz_pos = addr_pos + sizeof(struct sockaddr_storage); - } - payload_pos = addr_pos + sizeof(struct sockaddr_storage) + sizeof(tot); // where we'll write the payload - // write remote host address - memcpy(addr_pos, &addr_in, sizeof(struct sockaddr_storage)); - } - while(p != NULL) { - if(p->len <= 0) - break; - int len = p->len; - memcpy(payload_pos, p->payload, len); - payload_pos = payload_pos + len; - p = p->next; - tot += len; - } - if(tot) { - l->conn->rxsz += ZT_MAX_MTU; - memcpy(sz_pos, &tot, sizeof(tot)); - //DEBUG_EXTRA(" nc_udp_recved(): data_len = %d, rxsz = %d, addr_info_len = %d\n", - // tot, l->conn->rxsz, sizeof(u32_t) + sizeof(u16_t)); - l->tap->phyOnUnixWritable(l->conn->sock, NULL, true); - l->tap->_phy.setNotifyWritable(l->conn->sock, true); - } - l->tap->lwipstack->__pbuf_free(q); - */ - } - - // - err_t nc_sent(void* arg, struct tcp_pcb *PCB, u16_t len) - { - DEBUG_EXTRA("pcb=%p", (void*)&PCB); - Larg *l = (Larg*)arg; - Mutex::Lock _l(l->tap->_tcpconns_m); - if(l->conn->probation && l->conn->txsz == 0){ - l->conn->probation = false; // TX buffer now empty, removing from probation - } - if(l && l->conn && len && !l->conn->probation) { - int softmax = l->conn->type == SOCK_STREAM ? DEFAULT_TCP_TX_BUF_SZ : DEFAULT_UDP_TX_BUF_SZ; - if(l->conn->txsz < softmax) { - l->tap->_phy.setNotifyReadable(l->conn->sock, true); - l->tap->_phy.whack(); - } - } - return ERR_OK; - } - - // - err_t nc_connected_proxy(void *arg, struct tcp_pcb *PCB, err_t err) - { - DEBUG_INFO("pcb=%p", (void*)&PCB); - return ERR_OK; - } - - // - err_t nc_connected(void *arg, struct tcp_pcb *PCB, err_t err) - { - DEBUG_ATTN("pcb=%p", (void*)&PCB); - Larg *l = (Larg*)arg; - if(l && l->conn) - l->tap->sendReturnValue(l->tap->_phy.getDescriptor(l->conn->rpcSock), ERR_OK, 0); - return ERR_OK; - } - - // - err_t nc_poll(void* arg, struct tcp_pcb *PCB) - { - return ERR_OK; - } - - // - void nc_err(void *arg, err_t err) - { - DEBUG_ERROR("err=%d", err); - Larg *l = (Larg*)arg; - Mutex::Lock _l(l->tap->_tcpconns_m); - - if(!l->conn) - DEBUG_ERROR("conn==NULL"); - int fd = l->tap->_phy.getDescriptor(l->conn->sock); - switch(err) - { - case ERR_MEM: - DEBUG_ERROR("ERR_MEM->ENOMEM"); - l->tap->sendReturnValue(fd, -1, ENOMEM); - break; - case ERR_BUF: - DEBUG_ERROR("ERR_BUF->ENOBUFS"); - l->tap->sendReturnValue(fd, -1, ENOBUFS); - break; - case ERR_TIMEOUT: - DEBUG_ERROR("ERR_TIMEOUT->ETIMEDOUT"); - l->tap->sendReturnValue(fd, -1, ETIMEDOUT); - break; - case ERR_RTE: - DEBUG_ERROR("ERR_RTE->ENETUNREACH"); - l->tap->sendReturnValue(fd, -1, ENETUNREACH); - break; - case ERR_INPROGRESS: - DEBUG_ERROR("ERR_INPROGRESS->EINPROGRESS"); - l->tap->sendReturnValue(fd, -1, EINPROGRESS); - break; - case ERR_VAL: - DEBUG_ERROR("ERR_VAL->EINVAL"); - l->tap->sendReturnValue(fd, -1, EINVAL); - break; - case ERR_WOULDBLOCK: - DEBUG_ERROR("ERR_WOULDBLOCK->EWOULDBLOCK"); - l->tap->sendReturnValue(fd, -1, EWOULDBLOCK); - break; - case ERR_USE: - DEBUG_ERROR("ERR_USE->EADDRINUSE"); - l->tap->sendReturnValue(fd, -1, EADDRINUSE); - break; - case ERR_ISCONN: - DEBUG_ERROR("ERR_ISCONN->EISCONN"); - l->tap->sendReturnValue(fd, -1, EISCONN); - break; - case ERR_ABRT: - DEBUG_ERROR("ERR_ABRT->ECONNREFUSED"); - l->tap->sendReturnValue(fd, -1, ECONNREFUSED); - break; - - // TODO: Below are errors which don't have a standard errno correlate - - case ERR_RST: - l->tap->sendReturnValue(fd, -1, -1); - break; - case ERR_CLSD: - l->tap->sendReturnValue(fd, -1, -1); - break; - case ERR_CONN: - l->tap->sendReturnValue(fd, -1, -1); - break; - case ERR_ARG: - l->tap->sendReturnValue(fd, -1, -1); - break; - case ERR_IF: - l->tap->sendReturnValue(fd, -1, -1); - break; - default: - break; - } - DEBUG_ERROR(" closing connection"); - l->tap->closeConnection(l->conn->sock); - } -} diff --git a/src/stack_drivers/lwip/lwip.hpp b/src/stack_drivers/lwip/lwip.hpp deleted file mode 100644 index 4d6b1ab..0000000 --- a/src/stack_drivers/lwip/lwip.hpp +++ /dev/null @@ -1,534 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef SDK_LWIPSTACK_H -#define SDK_LWIPSTACK_H - -#if defined (SDK_LWIP) - -#include "lwip/mem.h" -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/init.h" -#include "lwip/udp.h" -#include "lwip/tcp.h" -#include "lwip/priv/tcp_priv.h" - -#include "Mutex.hpp" -#include "OSUtils.hpp" -#include "debug.h" - -#include -#include - -#include "tap.hpp" - -namespace ZeroTier { - class NetconEthernetTap; - struct Connection; - - void lwip_init_interface(NetconEthernetTap *tap, const InetAddress &ip); - void lwip_loop(NetconEthernetTap *tap); - void lwip_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - Connection *lwip_handleSocket(NetconEthernetTap *tap, PhySocket *sock, void **uptr, struct socket_st* socket_rpc); - Connection * lwip_handleSocketProxy(NetconEthernetTap *tap, PhySocket *sock, int socket_type); - void lwip_handleConnect(NetconEthernetTap *tap, PhySocket *sock, PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc); - int lwip_handleConnectProxy(NetconEthernetTap *tap, PhySocket *sock, struct sockaddr_in *rawAddr); - void lwip_handleBind(NetconEthernetTap *tap, PhySocket *sock, PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc); - void lwip_handleListen(NetconEthernetTap *tap, PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc); - void lwip_handleRead(NetconEthernetTap *tap, PhySocket *sock, void **uptr, bool lwip_invoked); - void lwip_handleWrite(NetconEthernetTap *tap, Connection *conn); - void lwip_handleClose(NetconEthernetTap *tap, PhySocket *sock, Connection *conn); - - - - err_t tapif_init(struct netif *netif); - err_t low_level_output(struct netif *netif, struct pbuf *p); - - /* - * Callback from LWIP for when data is available to be read from the network. - * - * Data is in the form of a linked list of struct pbufs, it is then recombined and - * send to the client over the associated unix socket. - * - * @param associated service state object - * @param allocated PCB - * @param chain of pbufs - * @param error code - * @return ERR_OK if everything is ok, -1 otherwise - * - */ - err_t nc_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err); - - /* - * Callback from LWIP for when a connection has been accepted and the PCB has been - * put into an ACCEPT state. - * - * A socketpair is created, one end is kept and wrapped into a PhySocket object - * for use in the main ZT I/O loop, and one end is sent to the client. The client - * is then required to tell the service what new file descriptor it has allocated - * for this connection. After the mapping is complete, the accepted socket can be - * used. - * - * @param associated service state object - * @param newly allocated PCB - * @param error code - * @return ERR_OK if everything is ok, -1 otherwise - * - * i := should be implemented in intercept lib - * I := is implemented in intercept lib - * X := is implemented in service - * ? := required treatment Unknown - * - := Not needed - * - * [ ] EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and no connections are present - * to be accepted. POSIX.1-2001 allows either error to be returned for - * this case, and does not require these constants to have the same value, - * so a portable application should check for both possibilities. - * [I] EBADF - The descriptor is invalid. - * [I] ECONNABORTED - A connection has been aborted. - * [i] EFAULT - The addr argument is not in a writable part of the user address space. - * [-] EINTR - The system call was interrupted by a signal that was caught before a valid connection arrived; see signal(7). - * [I] EINVAL - Socket is not listening for connections, or addrlen is invalid (e.g., is negative). - * [I] EINVAL - (accept4()) invalid value in flags. - * [I] EMFILE - The per-process limit of open file descriptors has been reached. - * [ ] ENFILE - The system limit on the total number of open files has been reached. - * [ ] ENOBUFS, ENOMEM - Not enough free memory. This often means that the memory allocation is - * limited by the socket buffer limits, not by the system memory. - * [I] ENOTSOCK - The descriptor references a file, not a socket. - * [I] EOPNOTSUPP - The referenced socket is not of type SOCK_STREAM. - * [ ] EPROTO - Protocol error. - * - */ - err_t nc_accept(void *arg, struct tcp_pcb *newPCB, err_t err); - - - err_t nc_recved_proxy(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err); - void nc_udp_recved(void * arg, struct udp_pcb * upcb, struct pbuf * p, ip_addr_t * addr, u16_t port); - - - /* - * Callback from LWIP when an internal error is associtated with the given (arg) - * - * Since the PCB related to this error might no longer exist, only its perviously - * associated (arg) is provided to us. - * - * @param associated service state object - * @param error code - * - */ - void nc_err(void *arg, err_t err); - - /* - * Callback from LWIP to do whatever work we might need to do. - * - * @param associated service state object - * @param PCB we're polling on - * @return ERR_OK if everything is ok, -1 otherwise - * - */ - err_t nc_poll(void* arg, struct tcp_pcb *PCB); - - /* - * Callback from LWIP to signal that 'len' bytes have successfully been sent. - * As a result, we should put our socket back into a notify-on-readability state - * since there is now room on the PCB buffer to write to. - * - * NOTE: This could be used to track the amount of data sent by a connection. - * - * @param associated service state object - * @param relevant PCB - * @param length of data sent - * @return ERR_OK if everything is ok, -1 otherwise - * - */ - err_t nc_sent(void *arg, struct tcp_pcb *PCB, u16_t len); - - /* - * Callback from LWIP which sends a return value to the client to signal that - * a connection was established for this PCB - * - * @param associated service state object - * @param relevant PCB - * @param error code - * @return ERR_OK if everything is ok, -1 otherwise - * - */ - err_t nc_connected(void *arg, struct tcp_pcb *PCB, err_t err); - err_t nc_connected_proxy(void *arg, struct tcp_pcb *PCB, err_t err); -} - -#ifdef D_GNU_SOURCE -#define _GNU_SOURCE -#endif - -struct tcp_pcb; - -#if defined(SDK_IPV4) - #define NETIF_ADD_SIG struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input - #define ETHARP_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr -#endif - -#if defined(SDK_IPV6) - #define NETIF_ADD_SIG struct netif *netif, void *state, netif_init_fn init, netif_input_fn input - #define ETHIP6_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr - #define ETHARP_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip6_addr_t *ipaddr - #define NETIF_IP6_ADDR_SET_STATE_SIG struct netif* netif, s8_t addr_idx, u8_t state - #define NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG struct netif *netif, u8_t from_mac_48bit -#endif - -// lwip General Stack API -#define PBUF_FREE_SIG struct pbuf *p -#define PBUF_ALLOC_SIG pbuf_layer layer, u16_t length, pbuf_type type -#define LWIP_HTONS_SIG u16_t x -#define LWIP_NTOHS_SIG u16_t x - -// lwIP UDP API -#define UDP_NEW_SIG void -#define UDP_CONNECT_SIG struct udp_pcb * pcb, ip_addr_t * ipaddr, u16_t port -#define UDP_SEND_SIG struct udp_pcb * pcb, struct pbuf * p -#define UDP_SENDTO_SIG struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port -#define UDP_RECV_SIG struct udp_pcb * pcb, void (* recv)(void * arg, struct udp_pcb * upcb, struct pbuf * p, ip_addr_t * addr, u16_t port), void * recv_arg -#define UDP_RECVED_SIG struct udp_pcb * pcb, u16_t len -#define UDP_BIND_SIG struct udp_pcb * pcb, const ip_addr_t * ipaddr, u16_t port -#define UDP_REMOVE_SIG struct udp_pcb *pcb - -// lwIP TCP API -#define TCP_WRITE_SIG struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags -#define TCP_SENT_SIG struct tcp_pcb * pcb, err_t (* sent)(void * arg, struct tcp_pcb * tpcb, u16_t len) -#define TCP_NEW_SIG void -#define TCP_RECV_SIG struct tcp_pcb * pcb, err_t (* recv)(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err) -#define TCP_RECVED_SIG struct tcp_pcb * pcb, u16_t len -#define TCP_SNDBUF_SIG struct tcp_pcb * pcb -#define TCP_CONNECT_SIG struct tcp_pcb * pcb, ip_addr_t * ipaddr, u16_t port, err_t (* connected)(void * arg, struct tcp_pcb * tpcb, err_t err) -#define TCP_RECV_SIG struct tcp_pcb * pcb, err_t (* recv)(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err) -#define TCP_ERR_SIG struct tcp_pcb * pcb, void (* err)(void * arg, err_t err) -#define TCP_POLL_SIG struct tcp_pcb * pcb, err_t (* poll)(void * arg, struct tcp_pcb * tpcb), u8_t interval -#define TCP_ARG_SIG struct tcp_pcb * pcb, void * arg -#define TCP_CLOSE_SIG struct tcp_pcb * pcb -#define TCP_ABORT_SIG struct tcp_pcb * pcb -#define TCP_OUTPUT_SIG struct tcp_pcb * pcb -#define TCP_ACCEPT_SIG struct tcp_pcb * pcb, err_t (* accept)(void * arg, struct tcp_pcb * newpcb, err_t err) -#define TCP_LISTEN_SIG struct tcp_pcb * pcb -#define TCP_LISTEN_WITH_BACKLOG_SIG struct tcp_pcb * pcb, u8_t backlog -#define TCP_BIND_SIG struct tcp_pcb * pcb, const ip_addr_t * ipaddr, u16_t port -#define TCP_INPUT_SIG struct pbuf *p, struct netif *inp - -// lwIP network stack interfaces -#define ETHERNET_INPUT_SIG struct pbuf *p, struct netif *netif -#define IP_INPUT_SIG struct pbuf *p, struct netif *inp -#define NETIF_SET_DEFAULT_SIG struct netif *netif -#define NETIF_SET_UP_SIG struct netif *netif -#define NETIF_POLL_SIG struct netif *netif - -//#define NETIF_SET_ADDR_SIG struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw - -namespace ZeroTier { - - /** - * Loads an instance of liblwip.so in a private memory arena - * - * This uses dlmopen() to load an instance of the LWIP stack into its - * own private memory space. This is done to get around the stack's - * lack of thread-safety or multi-instance support. The alternative - * would be to massively refactor the stack so everything lives in a - * state object instead of static memory space. - */ - class lwIP_stack - { - public: - - void *_libref; - - void close() { -#if defined(__STATIC_STACK__) - return; -#elif defined(__DYNAMIC_STACK__) - dlclose(_libref); -#endif - } - - #if defined(SDK_IPV4) - err_t (*_etharp_output)(ETHARP_OUTPUT_SIG); - #endif - - #if defined(SDK_IPV6) - err_t (*_ethip6_output)(ETHIP6_OUTPUT_SIG); - void (*_nd6_tmr)(void); - void (*_netif_ip6_addr_set_state)(NETIF_IP6_ADDR_SET_STATE_SIG); - void (*_netif_create_ip6_linklocal_address)(NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG); - #endif - - void (*_netif_init)(void); - // void (*_netif_set_addr)(NETIF_SET_ADDR_SIG); - - void (*_lwip_init)(); - err_t (*_tcp_write)(TCP_WRITE_SIG); - void (*_tcp_sent)(TCP_SENT_SIG); - struct tcp_pcb * (*_tcp_new)(TCP_NEW_SIG); - u16_t (*_tcp_sndbuf)(TCP_SNDBUF_SIG); - err_t (*_tcp_connect)(TCP_CONNECT_SIG); - struct udp_pcb * (*_udp_new)(UDP_NEW_SIG); - err_t (*_udp_connect)(UDP_CONNECT_SIG); - err_t (*_udp_send)(UDP_SEND_SIG); - err_t (*_udp_sendto)(UDP_SENDTO_SIG); - void (*_udp_recv)(UDP_RECV_SIG); - void (*_udp_recved)(UDP_RECVED_SIG); - err_t (*_udp_bind)(UDP_BIND_SIG); - void (*_udp_remove)(UDP_REMOVE_SIG); - void (*_tcp_recv)(TCP_RECV_SIG); - void (*_tcp_recved)(TCP_RECVED_SIG); - void (*_tcp_err)(TCP_ERR_SIG); - void (*_tcp_poll)(TCP_POLL_SIG); - void (*_tcp_arg)(TCP_ARG_SIG); - err_t (*_tcp_close)(TCP_CLOSE_SIG); - void (*_tcp_abort)(TCP_ABORT_SIG); - err_t (*_tcp_output)(TCP_OUTPUT_SIG); - void (*_tcp_accept)(TCP_ACCEPT_SIG); - struct tcp_pcb * (*_tcp_listen)(TCP_LISTEN_SIG); - struct tcp_pcb * (*_tcp_listen_with_backlog)(TCP_LISTEN_WITH_BACKLOG_SIG); - err_t (*_tcp_bind)(TCP_BIND_SIG); - void (*_etharp_tmr)(void); - void (*_tcp_tmr)(void); - u8_t (*_pbuf_free)(PBUF_FREE_SIG); - struct pbuf * (*_pbuf_alloc)(PBUF_ALLOC_SIG); - u16_t (*_lwip_htons)(LWIP_HTONS_SIG); - u16_t (*_lwip_ntohs)(LWIP_NTOHS_SIG); - err_t (*_ethernet_input)(ETHERNET_INPUT_SIG); - void (*_tcp_input)(TCP_INPUT_SIG); - err_t (*_ip_input)(IP_INPUT_SIG); - void (*_netif_set_default)(NETIF_SET_DEFAULT_SIG); - struct netif * (*_netif_add)(NETIF_ADD_SIG); - void (*_netif_set_up)(NETIF_SET_UP_SIG); - void (*_netif_poll)(NETIF_POLL_SIG); - - Mutex _lock; - Mutex _lock_mem; - - lwIP_stack(const char* path) : - _libref(NULL) - { -#if defined(__ANDROID__) || defined(__UNITY_3D__) - #define __STATIC_STACK__ -#elif defined(__linux__) - #define __DYNAMIC_STACK__ - // Dynamically load liblwip.so - _libref = dlmopen(LM_ID_NEWLM, path, RTLD_NOW); -#elif defined(__APPLE__) - #include "TargetConditionals.h" - #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE - #include "node/Mutex.hpp" - #define __STATIC_STACK__ - // iOS Simulator or iOS device - // Do nothing, symbols are statically-linked - #elif TARGET_OS_MAC && !defined(SDK_BUNDLED) - #define __DYNAMIC_STACK__ - // Dynamically load liblwip.so - _libref = dlopen(path, RTLD_NOW); - #elif TARGET_OS_MAC && defined(SDK_BUNDLED) - #define __DYNAMIC_STACK__ // TODO: Implement static version - // Dynamically load liblwip.so - _libref = dlopen(path, RTLD_NOW); - #endif -#endif - -#ifdef __STATIC_STACK__ // Set static references (for use in iOS) - - #if defined(SDK_IPV4) - _etharp_output = (err_t(*)(ETHARP_OUTPUT_SIG))ðarp_output; - #endif - - #if defined(SDK_IPV6) - _nd6_tmr = (void(*)(void))&nd6_tmr; - _netif_ip6_addr_set_state = (void(*)(NETIF_IP6_ADDR_SET_STATE_SIG))&netif_ip6_addr_set_state; - _netif_create_ip6_linklocal_address = (void(*)(NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG))&netif_create_ip6_linklocal_address; - _ethip6_output = (err_t(*)(ETHIP6_OUTPUT_SIG))ðip6_output; - #endif - - _netif_init = (void(*)(void))&netif_init; - _ethernet_input = (err_t(*)(ETHERNET_INPUT_SIG))ðernet_input; - _lwip_init = (void(*)(void))&lwip_init; - _tcp_write = (err_t(*)(TCP_WRITE_SIG))&tcp_write; - _tcp_sent = (void(*)(TCP_SENT_SIG))&tcp_sent; - _tcp_new = (struct tcp_pcb*(*)(TCP_NEW_SIG))&tcp_new; - _udp_new = (struct udp_pcb*(*)(UDP_NEW_SIG))&udp_new; - _udp_connect = (err_t(*)(UDP_CONNECT_SIG))&udp_connect; - _udp_send = (err_t(*)(UDP_SEND_SIG))&udp_send; - _udp_sendto = (err_t(*)(UDP_SENDTO_SIG))&udp_sendto; - _udp_recv = (void(*)(UDP_RECV_SIG))&udp_recv; - _udp_bind = (err_t(*)(UDP_BIND_SIG))&udp_bind; - _udp_remove = (void(*)(UDP_REMOVE_SIG))&udp_remove; - _tcp_connect = (err_t(*)(TCP_CONNECT_SIG))&tcp_connect; - _tcp_recv = (void(*)(TCP_RECV_SIG))&tcp_recv; - _tcp_recved = (void(*)(TCP_RECVED_SIG))&tcp_recved; - _tcp_err = (void(*)(TCP_ERR_SIG))&tcp_err; - _tcp_poll = (void(*)(TCP_POLL_SIG))&tcp_poll; - _tcp_arg = (void(*)(TCP_ARG_SIG))&tcp_arg; - _tcp_close = (err_t(*)(TCP_CLOSE_SIG))&tcp_close; - _tcp_abort = (void(*)(TCP_ABORT_SIG))&tcp_abort; - _tcp_output = (err_t(*)(TCP_OUTPUT_SIG))&tcp_output; - _tcp_accept = (void(*)(TCP_ACCEPT_SIG))&tcp_accept; - _tcp_listen_with_backlog = (struct tcp_pcb*(*)(TCP_LISTEN_WITH_BACKLOG_SIG))&tcp_listen_with_backlog; - _tcp_bind = (err_t(*)(TCP_BIND_SIG))&tcp_bind; - _etharp_tmr = (void(*)(void))ðarp_tmr; - _tcp_tmr = (void(*)(void))&tcp_tmr; - _pbuf_free = (u8_t(*)(PBUF_FREE_SIG))&pbuf_free; - _pbuf_alloc = (struct pbuf*(*)(PBUF_ALLOC_SIG))&pbuf_alloc; - _lwip_htons = (u16_t(*)(LWIP_HTONS_SIG))&lwip_htons; - _lwip_ntohs = (u16_t(*)(LWIP_NTOHS_SIG))&lwip_ntohs; - _tcp_input = (void(*)(TCP_INPUT_SIG))&tcp_input; - _ip_input = (err_t(*)(IP_INPUT_SIG))&ip_input; - _netif_set_default = (void(*)(NETIF_SET_DEFAULT_SIG))&netif_set_default; - _netif_add = (struct netif*(*)(NETIF_ADD_SIG))&netif_add; - _netif_set_up = (void(*)(NETIF_SET_UP_SIG))&netif_set_up; - -#endif - -#ifdef __DYNAMIC_STACK__ // Use dynamically-loaded symbols (for use in normal desktop applications) - - if(_libref == NULL) - DEBUG_ERROR("dlerror(): %s", dlerror()); - - #if defined(SDK_IPV4) - _etharp_output = (err_t(*)(ETHARP_OUTPUT_SIG))dlsym(_libref, "etharp_output"); - #endif - - #if defined(SDK_IPV6) - _nd6_tmr = (void(*)(void))dlsym(_libref, "nd6_tmr"); - _netif_ip6_addr_set_state = (void(*)(NETIF_IP6_ADDR_SET_STATE_SIG))dlsym(_libref, "netif_ip6_addr_set_state"); - _netif_create_ip6_linklocal_address = (void(*)(NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG))dlsym(_libref, "netif_create_ip6_linklocal_address"); - _ethip6_output = (err_t(*)(ETHIP6_OUTPUT_SIG))dlsym(_libref, "ethip6_output"); - #endif - - _netif_init = (void(*)(void))dlsym(_libref, "netif_init"); - // _netif_set_addr = (void(*))(NETIF_SET_ADDR_SIG))dlsym(_libref, "netif_set_addr"); - - _ethernet_input = (err_t(*)(ETHERNET_INPUT_SIG))dlsym(_libref, "ethernet_input"); - _lwip_init = (void(*)(void))dlsym(_libref, "lwip_init"); - _tcp_write = (err_t(*)(TCP_WRITE_SIG))dlsym(_libref, "tcp_write"); - _tcp_sent = (void(*)(TCP_SENT_SIG))dlsym(_libref, "tcp_sent"); - _tcp_new = (struct tcp_pcb*(*)(TCP_NEW_SIG))dlsym(_libref, "tcp_new"); - _udp_new = (struct udp_pcb*(*)(UDP_NEW_SIG))dlsym(_libref, "udp_new"); - _udp_connect = (err_t(*)(UDP_CONNECT_SIG))dlsym(_libref, "udp_connect"); - _udp_send = (err_t(*)(UDP_SEND_SIG))dlsym(_libref, "udp_send"); - _udp_sendto = (err_t(*)(UDP_SENDTO_SIG))dlsym(_libref, "udp_sendto"); - _udp_recv = (void(*)(UDP_RECV_SIG))dlsym(_libref, "udp_recv"); - _udp_bind = (err_t(*)(UDP_BIND_SIG))dlsym(_libref, "udp_bind"); - _udp_remove = (void(*)(UDP_REMOVE_SIG))dlsym(_libref, "udp_remove"); - _tcp_sndbuf = (u16_t(*)(TCP_SNDBUF_SIG))dlsym(_libref, "tcp_sndbuf"); - _tcp_connect = (err_t(*)(TCP_CONNECT_SIG))dlsym(_libref, "tcp_connect"); - _tcp_recv = (void(*)(TCP_RECV_SIG))dlsym(_libref, "tcp_recv"); - _tcp_recved = (void(*)(TCP_RECVED_SIG))dlsym(_libref, "tcp_recved"); - _tcp_err = (void(*)(TCP_ERR_SIG))dlsym(_libref, "tcp_err"); - _tcp_poll = (void(*)(TCP_POLL_SIG))dlsym(_libref, "tcp_poll"); - _tcp_arg = (void(*)(TCP_ARG_SIG))dlsym(_libref, "tcp_arg"); - _tcp_close = (err_t(*)(TCP_CLOSE_SIG))dlsym(_libref, "tcp_close"); - _tcp_abort = (void(*)(TCP_ABORT_SIG))dlsym(_libref, "tcp_abort"); - _tcp_output = (err_t(*)(TCP_OUTPUT_SIG))dlsym(_libref, "tcp_output"); - _tcp_accept = (void(*)(TCP_ACCEPT_SIG))dlsym(_libref, "tcp_accept"); - _tcp_listen = (struct tcp_pcb*(*)(TCP_LISTEN_SIG))dlsym(_libref, "tcp_listen"); - _tcp_listen_with_backlog = (struct tcp_pcb*(*)(TCP_LISTEN_WITH_BACKLOG_SIG))dlsym(_libref, "tcp_listen_with_backlog"); - _tcp_bind = (err_t(*)(TCP_BIND_SIG))dlsym(_libref, "tcp_bind"); - _etharp_tmr = (void(*)(void))dlsym(_libref, "etharp_tmr"); - _tcp_tmr = (void(*)(void))dlsym(_libref, "tcp_tmr"); - _pbuf_free = (u8_t(*)(PBUF_FREE_SIG))dlsym(_libref, "pbuf_free"); - _pbuf_alloc = (struct pbuf*(*)(PBUF_ALLOC_SIG))dlsym(_libref, "pbuf_alloc"); - _lwip_htons = (u16_t(*)(LWIP_HTONS_SIG))dlsym(_libref, "lwip_htons"); - _lwip_ntohs = (u16_t(*)(LWIP_NTOHS_SIG))dlsym(_libref, "lwip_ntohs"); - _tcp_input = (void(*)(TCP_INPUT_SIG))dlsym(_libref, "tcp_input"); - _ip_input = (err_t(*)(IP_INPUT_SIG))dlsym(_libref, "ip_input"); - _netif_set_default = (void(*)(NETIF_SET_DEFAULT_SIG))dlsym(_libref, "netif_set_default"); - _netif_add = (struct netif*(*)(NETIF_ADD_SIG))dlsym(_libref, "netif_add"); - _netif_set_up = (void(*)(NETIF_SET_UP_SIG))dlsym(_libref, "netif_set_up"); -#endif - } - - ~lwIP_stack() - { - if (_libref) - dlclose(_libref); - } - - #if defined(SDK_IPV4) - inline struct netif * __netif_add(NETIF_ADD_SIG) throw() { Mutex::Lock _l(_lock); return _netif_add(netif,ipaddr,netmask,gw,state,init,input); } - #endif - - #if defined(SDK_IPV6) - inline struct netif * __netif_add(NETIF_ADD_SIG) throw() { Mutex::Lock _l(_lock); return _netif_add(netif,state,init,input); } - inline void __nd6_tmr(void) throw() { /**/ Mutex::Lock _l(_lock); _nd6_tmr(); } - inline void __netif_ip6_addr_set_state(NETIF_IP6_ADDR_SET_STATE_SIG) throw() { Mutex::Lock _l(_lock); _netif_ip6_addr_set_state(netif, addr_idx, state); } - inline void __netif_create_ip6_linklocal_address(NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG) throw() { Mutex::Lock _l(_lock); _netif_create_ip6_linklocal_address(netif, from_mac_48bit); } - inline err_t __ethip6_output(ETHIP6_OUTPUT_SIG) throw() { Mutex::Lock _l(_lock); return _ethip6_output(netif,q,ip6addr); } - #endif - - inline void __netif_init(void) throw() { Mutex::Lock _l(_lock); _netif_init(); } - // inline void __netif_set_addr(NETIF_SET_ADDR_SIG) throw() { Mutex::Lock _l(_lock); _netif_set_addr(netif, ipaddr, netmask, gw); } - inline void __lwip_init() throw() { Mutex::Lock _l(_lock); return _lwip_init(); } - inline err_t __tcp_write(TCP_WRITE_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_write(pcb,arg,len,apiflags); } - inline void __tcp_sent(TCP_SENT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_sent(pcb,sent); } - inline struct tcp_pcb * __tcp_new(TCP_NEW_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_new(); } - inline struct udp_pcb * __udp_new(UDP_NEW_SIG) throw() { Mutex::Lock _l(_lock); return _udp_new(); } - inline err_t __udp_connect(UDP_CONNECT_SIG) throw() { Mutex::Lock _l(_lock); return _udp_connect(pcb,ipaddr,port); } - inline err_t __udp_send(UDP_SEND_SIG) throw() { Mutex::Lock _l(_lock); return _udp_send(pcb,p); } - inline err_t __udp_sendto(UDP_SENDTO_SIG) throw() { Mutex::Lock _l(_lock); return _udp_sendto(pcb,p,dst_ip,dst_port); } - inline void __udp_recv(UDP_RECV_SIG) throw() { Mutex::Lock _l(_lock); return _udp_recv(pcb,recv,recv_arg); } - inline err_t __udp_bind(UDP_BIND_SIG) throw() { Mutex::Lock _l(_lock); return _udp_bind(pcb,ipaddr,port); } - inline void __udp_remove(UDP_REMOVE_SIG) throw() { Mutex::Lock _l(_lock); return _udp_remove(pcb); } - inline u16_t __tcp_sndbuf(TCP_SNDBUF_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_sndbuf(pcb); } - inline err_t __tcp_connect(TCP_CONNECT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_connect(pcb,ipaddr,port,connected); } - inline void __tcp_recv(TCP_RECV_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_recv(pcb,recv); } - inline void __tcp_recved(TCP_RECVED_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_recved(pcb,len); } - inline void __tcp_err(TCP_ERR_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_err(pcb,err); } - inline void __tcp_poll(TCP_POLL_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_poll(pcb,poll,interval); } - inline void __tcp_arg(TCP_ARG_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_arg(pcb,arg); } - inline err_t __tcp_close(TCP_CLOSE_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_close(pcb); } - inline void __tcp_abort(TCP_ABORT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_abort(pcb); } - inline err_t __tcp_output(TCP_OUTPUT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_output(pcb); } - inline void __tcp_accept(TCP_ACCEPT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_accept(pcb,accept); } - inline struct tcp_pcb * __tcp_listen(TCP_LISTEN_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_listen(pcb); } - inline struct tcp_pcb * __tcp_listen_with_backlog(TCP_LISTEN_WITH_BACKLOG_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_listen_with_backlog(pcb,backlog); } - inline err_t __tcp_bind(TCP_BIND_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_bind(pcb,ipaddr,port); } - inline void __etharp_tmr(void) throw() { Mutex::Lock _l(_lock); return _etharp_tmr(); } - inline void __tcp_tmr(void) throw() { Mutex::Lock _l(_lock); return _tcp_tmr(); } - inline u8_t __pbuf_free(PBUF_FREE_SIG) throw() { Mutex::Lock _l(_lock); return _pbuf_free(p); } - inline struct pbuf * __pbuf_alloc(PBUF_ALLOC_SIG) throw() { Mutex::Lock _l(_lock_mem); return _pbuf_alloc(layer,length,type); } - inline u16_t __lwip_htons(LWIP_HTONS_SIG) throw() { Mutex::Lock _l(_lock); return _lwip_htons(x); } - inline u16_t __lwip_ntohs(LWIP_NTOHS_SIG) throw() { Mutex::Lock _l(_lock); return _lwip_ntohs(x); } - //inline err_t __etharp_output(ETHARP_OUTPUT_SIG) throw() { Mutex::Lock _l(_lock); return _etharp_output(netif,q,ipaddr); } - inline err_t __ethernet_input(ETHERNET_INPUT_SIG) throw() { Mutex::Lock _l(_lock); return _ethernet_input(p,netif); } - inline void __tcp_input(TCP_INPUT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_input(p,inp); } - inline err_t __ip_input(IP_INPUT_SIG) throw() { Mutex::Lock _l(_lock); return _ip_input(p,inp); } - inline void __netif_set_default(NETIF_SET_DEFAULT_SIG) throw() { Mutex::Lock _l(_lock); return _netif_set_default(netif); } - inline void __netif_set_up(NETIF_SET_UP_SIG) throw() { Mutex::Lock _l(_lock); return _netif_set_up(netif); } -}; - -} // namespace ZeroTier - -#endif - -#endif // SDK_LWIP diff --git a/src/stack_drivers/lwip/lwipopts.h b/src/stack_drivers/lwip/lwipopts.h deleted file mode 100644 index cf4a1d3..0000000 --- a/src/stack_drivers/lwip/lwipopts.h +++ /dev/null @@ -1,496 +0,0 @@ -/** - * @file - * - * lwIP Options Configuration - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIPOPTS_H__ -#define __LWIPOPTS_H__ - -/* - * Include user defined options first. Anything not defined in these files - * will be set to standard values. Override anything you dont like! - */ -#include "lwip/debug.h" - -// IP Protocol version -// It seems using ipv6/ipv4 in the same stack is problematic, for this reason we -// compile for only one or the other using the SDK_IPV4=1/SDK_IPV6=1 flags for now -#if defined(SDK_IPV6) - #define LWIP_IPV6 1 - #define LWIP_IPV4 0 - -#endif -#if defined(SDK_IPV4) - #define LWIP_IPV4 1 - #define LWIP_IPV6 0 -#endif - -#define LWIP_TCP 1 -#define IP6_DEBUG 1 -#define LWIP_DEBUG 1 -#define IP_DEBUG LWIP_DBG_ON -#define LWIP_ETHERNET 1 - -#define LWIP_DBG_TYPES_ON LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_FRESH - -#define LWIP_CHKSUM_ALGORITHM 2 - -#undef TCP_MSS -#define TCP_MSS 1460 - -/* -The TCP window size can be adjusted by changing the define TCP_WND. However, -do keep in mind that this should be at least twice the size of TCP_MSS (thus -on ethernet, where TCP_MSS is 1460, it should be set to at least 2920). If -memory allows it, set this as high as possible (16-bit, so 0xFFFF is the highest -value), but keep in mind that for every active connection, the full window may -have to be buffered until it is acknowledged by the remote side (although this -buffer size can still be controlled by TCP_SND_BUF and TCP_SND_QUEUELEN). The -reason for "twice" are both the nagle algorithm and delayed ACK from the -remote peer. -*/ - -#define TCP_WND TCP_MSS*10 // max = 0xffff - -//#define LWIP_NOASSERT 1 -#define TCP_LISTEN_BACKLOG 0 - -/*------------------------------------------------------------------------------ ----------------------------------- Timers -------------------------------------- -------------------------------------------------------------------------------*/ -/* -Be careful about setting this too small. lwIP just counts the number -of times its timer is called and uses this to control time sensitive -operations (such as TCP retransmissions), rather than actually -measuring time using something more accurate. If you call the timer -functions very frequently you may see things (such as retransmissions) -happening sooner than they should. -*/ -/* these are originally defined in tcp_impl.h */ -#ifndef TCP_TMR_INTERVAL -/* The TCP timer interval in milliseconds. */ -#define TCP_TMR_INTERVAL 250 -#endif /* TCP_TMR_INTERVAL */ - -#ifndef TCP_FAST_INTERVAL -/* the fine grained timeout in milliseconds */ -#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL -#endif /* TCP_FAST_INTERVAL */ - -#ifndef TCP_SLOW_INTERVALs -/* the coarse grained timeout in milliseconds */ -#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) -#endif /* TCP_SLOW_INTERVAL */ - - -/*------------------------------------------------------------------------------ ---------------------------- Platform specific locking ------------------------- -------------------------------------------------------------------------------*/ - -/** - * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain - * critical regions during buffer allocation, deallocation and memory - * allocation and deallocation. - */ -#define SYS_LIGHTWEIGHT_PROT 0 - -/** - * NO_SYS==1: Provides VERY minimal functionality. Otherwise, - * use lwIP facilities. - */ - -/* set to 1 so we have no thread behaviour */ -#define NO_SYS 1 - -/* set to 1 so we can use our own timers */ -#define NO_SYS_NO_TIMERS 1 - - -/*------------------------------------------------------------------------------ --------------------------------- Memory options -------------------------------- -------------------------------------------------------------------------------*/ - - - -/* Misc */ -#define MEM_LIBC_MALLOC 1 -#define MEMP_MEM_MALLOC 1 - - - -/** - * 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 - */ -#define MEM_ALIGNMENT 1 - -/** - * 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. - */ -#define MEM_SIZE 1024 * 1024 * 64 -#define TCP_SND_BUF 1024 * 63 -//#define TCP_OVERSIZE TCP_MSS - -#define TCP_SND_QUEUELEN 1024 - -/*------------------------------------------------------------------------------ --------------------------------- Pbuf Options ---------------------------------- -------------------------------------------------------------------------------*/ - -/** - * PBUF_LINK_HLEN: the number of bytes that should be allocated for a - * link level header. The default is 14, the standard value for - * Ethernet. - */ -#define PBUF_LINK_HLEN 16 - -/** - * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is - * designed to accomodate single full size TCP frame in one pbuf, including - * TCP_MSS, IP header, and link header. -* - */ -#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) - - -/*------------------------------------------------------------------------------ --------------------------- Internal Memory Pool Sizes -------------------------- -------------------------------------------------------------------------------*/ - -/** - * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). - * If the application sends a lot of data out of ROM (or other static memory), - * this should be set high. - */ -#define MEMP_NUM_PBUF 256 - -/** - * MEMP_NUM_RAW_PCB: Number of raw connection PCBs - * (requires the LWIP_RAW option) - */ -#define MEMP_NUM_RAW_PCB 128 - -/** - * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One - * per active UDP "connection". - * (requires the LWIP_UDP option) - */ -#define MEMP_NUM_UDP_PCB 4 - -/** - * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. - * (requires the LWIP_TCP option) - */ -#define MEMP_NUM_TCP_PCB 128 - -/** - * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. - * (requires the LWIP_TCP option) - */ -#define MEMP_NUM_TCP_PCB_LISTEN 128 - -/** - * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. - * (requires the LWIP_TCP option) - */ -#define MEMP_NUM_TCP_SEG 1024 - -/** - * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for - * reassembly (whole packets, not fragments!) - */ -#define MEMP_NUM_REASSDATA 1 - -/** - * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing - * packets (pbufs) that are waiting for an ARP request (to resolve - * their destination address) to finish. - * (requires the ARP_QUEUEING option) - */ -#define MEMP_NUM_ARP_QUEUE 2 - -/** - * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. - * (requires NO_SYS==0) - */ -#define MEMP_NUM_SYS_TIMEOUT 3 - -/** - * MEMP_NUM_NETBUF: the number of struct netbufs. - * (only needed if you use the sequential API, like api_lib.c) - */ -#define MEMP_NUM_NETBUF 2 - -/** - * MEMP_NUM_NETCONN: the number of struct netconns. - * (only needed if you use the sequential API, like api_lib.c) - */ -#define MEMP_NUM_NETCONN 4 - -/** - * 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) - */ -#define MEMP_NUM_TCPIP_MSG_API 8 - -/** - * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used - * for incoming packets. - * (only needed if you use tcpip.c) - */ -#define MEMP_NUM_TCPIP_MSG_INPKT 8 - -/** - * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. - */ -#define PBUF_POOL_SIZE 2048 /* was 32 */ - - -/*------------------------------------------------------------------------------ ------------------------------------ ARP options -------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_ARP==1: Enable ARP functionality. - */ -#define LWIP_ARP 1 - - -/*------------------------------------------------------------------------------ ------------------------------------- IP options--------------------------------- -------------------------------------------------------------------------------*/ - -/** - * IP_FORWARD==1: Enables the ability to forward IP packets across network - * interfaces. If you are going to run lwIP on a device with only one network - * interface, define this to 0. - */ -#define IP_FORWARD 0 - -/** - * IP_OPTIONS: 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). - */ -#define IP_OPTIONS_ALLOWED 1 - -/** - * 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. - */ -#define IP_REASSEMBLY 1 - -/** - * 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. - */ -#define IP_FRAG 1 - -/** - * 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. - */ -#define IP_REASS_MAXAGE 3 - -/** - * 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! - */ -#define IP_REASS_MAX_PBUFS 4 - -/** - * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP - * fragmentation. Otherwise pbufs are allocated and reference the original - * packet data to be fragmented. -*/ -#define IP_FRAG_USES_STATIC_BUF 0 - -/** - * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. - */ -#define IP_DEFAULT_TTL 255 - - -/*------------------------------------------------------------------------------ -------------------------------- ICMP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_ICMP==1: Enable ICMP module inside the IP stack. - * Be careful, disable that make your product non-compliant to RFC1122 - */ -#define LWIP_ICMP 1 - - -/*------------------------------------------------------------------------------ -------------------------------- RAW Options ------------------------------------ -------------------------------------------------------------------------------*/ - -/** - * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. - */ -#define LWIP_RAW 1 - - -/*------------------------------------------------------------------------------ -------------------------------- DHCP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_DHCP==1: Enable DHCP module. - */ -#define LWIP_DHCP 0 - - -/*------------------------------------------------------------------------------ ------------------------------- AUTOIP Options ---------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_AUTOIP==1: Enable AUTOIP module. - */ -#define LWIP_AUTOIP 0 - - -/*------------------------------------------------------------------------------ -------------------------------- SNMP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP - * transport. - */ -#define LWIP_SNMP 0 - - -/*------------------------------------------------------------------------------ -------------------------------- IGMP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_IGMP==1: Turn on IGMP module. - */ -#define LWIP_IGMP 0 - - -/*------------------------------------------------------------------------------ --------------------------------- DNS Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS - * transport. - */ -#define LWIP_DNS 0 - - -/*------------------------------------------------------------------------------ --------------------------------- UDP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_UDP==1: Turn on UDP. - */ -#define LWIP_UDP 1 - - -/*------------------------------------------------------------------------------ --------------------------------- TCP Options ----------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_TCP==1: Turn on TCP. - */ -#define LWIP_TCP 1 - -#define LWIP_LISTEN_BACKLOG 0 - - -/*------------------------------------------------------------------------------ ---------------------------------- LOOPIF Options ------------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c - */ -#define LWIP_HAVE_LOOPIF 0 - - -/*------------------------------------------------------------------------------ ----------------------------- Sequential Layer Options -------------------------- -------------------------------------------------------------------------------*/ - -/** - * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) - */ -#define LWIP_NETCONN 0 - - -/*------------------------------------------------------------------------------ ---------------------------------- Socket Options ------------------------------- -------------------------------------------------------------------------------*/ -/** - * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) - */ -#define LWIP_SOCKET 0 - - -/*------------------------------------------------------------------------------ ------------------------------- Statistics Options ------------------------------ -------------------------------------------------------------------------------*/ - -/** - * LWIP_STATS==1: Enable statistics collection in lwip_stats. - */ -#define LWIP_STATS 0 - -/*------------------------------------------------------------------------------ ---------------------------------- PPP Options ---------------------------------- -------------------------------------------------------------------------------*/ - -/** - * PPP_SUPPORT==1: Enable PPP. - */ -#define PPP_SUPPORT 0 - -#endif /* __LWIPOPTS_H__ */ diff --git a/src/stack_drivers/picotcp/README.md b/src/stack_drivers/picotcp/README.md deleted file mode 100644 index f51c24a..0000000 --- a/src/stack_drivers/picotcp/README.md +++ /dev/null @@ -1,2 +0,0 @@ -picoTCP Network Stack Driver -==== diff --git a/src/stack_drivers/picotcp/picotcp.cpp b/src/stack_drivers/picotcp/picotcp.cpp deleted file mode 100644 index 2b0ef7d..0000000 --- a/src/stack_drivers/picotcp/picotcp.cpp +++ /dev/null @@ -1,767 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#if defined(SDK_PICOTCP) - -#include "tap.hpp" - -#include "picotcp.hpp" -#include "pico_stack.h" -#include "pico_ipv4.h" -#include "pico_icmp4.h" -#include "pico_dev_tap.h" -#include "pico_protocol.h" -#include "pico_socket.h" -#include "pico_eth.h" - -namespace ZeroTier { - - // Reference to the tap interface - // This is needed due to the fact that there's a lot going on in the tap interface - // that needs to be updated on each of the network stack's callbacks and not every - // network stack provides a mechanism for storing a reference to the tap. - // - // In future releases this will be replaced with a new structure of static pointers that - // will make it easier to maintain multiple active tap interfaces - NetconEthernetTap *picotap; - struct pico_device picodev; - - int pico_eth_send(struct pico_device *dev, void *buf, int len); - int pico_eth_poll(struct pico_device *dev, int loop_score); - - // Initialize network stack's interfaces and assign addresses - void pico_init_interface(NetconEthernetTap *tap, const InetAddress &ip) - { - picoTCP_stack *stack = tap->picostack; - if (std::find(picotap->_ips.begin(),picotap->_ips.end(),ip) == picotap->_ips.end()) { - picotap->_ips.push_back(ip); - std::sort(picotap->_ips.begin(),picotap->_ips.end()); - #if defined(SDK_IPV4) - if(ip.isV4()) - { - struct pico_ip4 ipaddr, netmask; - ipaddr.addr = *((uint32_t *)ip.rawIpData()); - netmask.addr = *((uint32_t *)ip.netmask().rawIpData()); - uint8_t mac[PICO_SIZE_ETH]; - picotap->_mac.copyTo(mac, PICO_SIZE_ETH); - DEBUG_ATTN("mac = %s", picotap->_mac.toString().c_str()); - picodev.send = pico_eth_send; // tx - picodev.poll = pico_eth_poll; // rx - picodev.mtu = picotap->_mtu; - if( 0 != stack->__pico_device_init(&(picodev), "p0", mac)) { - DEBUG_ERROR("device init failed"); - return; - } - stack->__pico_ipv4_link_add(&(picodev), ipaddr, netmask); - // DEBUG_INFO("device initialized as ipv4_addr = %s", ipv4_str); - // picostack->__pico_icmp4_ping("10.8.8.1", 20, 1000, 10000, 64, cb_ping); - } - #elif defined(SDK_IPV6) - if(ip.isV6()) - { - struct pico_ip6 ipaddr, netmask; - char ipv6_str[INET6_ADDRSTRLEN], nm_str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, ip.rawIpData(), ipv6_str, INET6_ADDRSTRLEN); - inet_ntop(AF_INET6, ip.netmask().rawIpData(), nm_str, INET6_ADDRSTRLEN); - stack->__pico_string_to_ipv6(ipv6_str, ipaddr.addr); - stack->__pico_string_to_ipv6(nm_str, netmask.addr); - stack->__pico_ipv6_link_add(&(picodev), ipaddr, netmask); - picodev.send = pico_eth_send; // tx - picodev.poll = pico_eth_poll; // rx - uint8_t mac[PICO_SIZE_ETH]; - picotap->_mac.copyTo(mac, PICO_SIZE_ETH); - DEBUG_ATTN("mac = %s", picotap->_mac.toString().c_str()); - if( 0 != stack->__pico_device_init(&(picodev), "p0", mac)) { - DEBUG_ERROR("device init failed"); - return; - } - DEBUG_ATTN("device initialized as ipv6_addr = %s", ipv6_str); - } - #endif - } - } - - // Main stack loop - void pico_loop(NetconEthernetTap *tap) - { - while(tap->_run) - { - tap->_phy.poll(ZT_PHY_POLL_INTERVAL); // in ms - tap->picostack->__pico_stack_tick(); - } - } - - // RX packets from [ZT->STACK] onto RXBUF - // Also notify the tap service that data can be read: - // [RXBUF -> (ZTSOCK->APP)] - // ----------------------------------------- - // | TAP <-> MEM BUFFER <-> STACK <-> APP | - // | | - // | APP <-> I/O BUFFER <-> STACK <-> TAP | - // | |<-----------------| | RX - // ----------------------------------------- - // After this step, buffer will be emptied periodically by pico_handleRead() - void pico_cb_tcp_read(NetconEthernetTap *tap, struct pico_socket *s) - { - Connection *conn = tap->getConnection(s); - if(conn) { - int r; - uint16_t port = 0; - union { - struct pico_ip4 ip4; - struct pico_ip6 ip6; - } peer; - - do { - int avail = DEFAULT_TCP_RX_BUF_SZ - conn->rxsz; - if(avail) { - r = tap->picostack->__pico_socket_recvfrom(s, conn->rxbuf + (conn->rxsz), SDK_MTU, (void *)&peer.ip4.addr, &port); - // DEBUG_ATTN("received packet (%d byte) from %08X:%u", r, long_be2(peer.ip4.addr), short_be(port)); - tap->_phy.setNotifyWritable(conn->sock, true); - if (r > 0) - conn->rxsz += r; - } - else - DEBUG_ERROR("not enough space left on I/O RX buffer for pico_socket(%p)", s); - } - while(r > 0); - return; - } - DEBUG_ERROR("invalid connection"); - } - - // RX packets from the stack onto internal buffer - // Also notifies the tap service that data can be read - // ----------------------------------------- - // | TAP <-> MEM BUFFER <-> STACK <-> APP | - // | | - // | APP <-> I/O BUFFER <-> STACK <-> TAP | - // | |<-----------------| | RX - // ----------------------------------------- - // After this step, buffer will be emptied periodically by pico_handleRead() - // Read payload is encapsulated as such: - // - // [addr|payload_len|payload] - // - void pico_cb_udp_read(NetconEthernetTap *tap, struct pico_socket *s) - { - Connection *conn = tap->getConnection(s); - if(conn) { - - uint16_t port = 0; - union { - struct pico_ip4 ip4; - struct pico_ip6 ip6; - } peer; - - char tmpbuf[SDK_MTU]; - unsigned char *addr_pos, *sz_pos, *payload_pos; - struct sockaddr_in addr_in; - addr_in.sin_addr.s_addr = peer.ip4.addr; - addr_in.sin_port = port; - - // RX - int r = tap->picostack->__pico_socket_recvfrom(s, tmpbuf, SDK_MTU, (void *)&peer.ip4.addr, &port); - //DEBUG_FLOW(" [ RXBUF <- STACK] Receiving (%d) from stack, copying to receving buffer", r); - - // Mutex::Lock _l2(tap->_rx_buf_m); - // struct sockaddr_in6 addr_in6; - // addr_in6.sin6_addr.s6_addr; - // addr_in6.sin6_port = Utils::ntoh(s->remote_port); - // DEBUG_ATTN("remote_port=%d, local_port=%d", s->remote_port, Utils::ntoh(s->local_port)); - picotap->_rx_buf_m.lock(); - if(conn->rxsz == DEFAULT_UDP_RX_BUF_SZ) { // if UDP buffer full - //DEBUG_FLOW(" [ RXBUF <- STACK] UDP RX buffer full. Discarding oldest payload segment"); - memmove(conn->rxbuf, conn->rxbuf + SDK_MTU, DEFAULT_UDP_RX_BUF_SZ - SDK_MTU); - addr_pos = conn->rxbuf + (DEFAULT_UDP_RX_BUF_SZ - SDK_MTU); // TODO: - sz_pos = addr_pos + sizeof(struct sockaddr_storage); - conn->rxsz -= SDK_MTU; - } - else { - addr_pos = conn->rxbuf + conn->rxsz; // where we'll prepend the size of the address - sz_pos = addr_pos + sizeof(struct sockaddr_storage); - } - payload_pos = addr_pos + sizeof(struct sockaddr_storage) + sizeof(r); - memcpy(addr_pos, &addr_in, sizeof(struct sockaddr_storage)); - - memcpy(payload_pos, tmpbuf, r); // write payload to app's socket - - // Adjust buffer size - if(r) { - conn->rxsz += SDK_MTU; - memcpy(sz_pos, &r, sizeof(r)); - } - if (r < 0) { - DEBUG_ERROR("unable to read from picosock=%p", s); - } - picotap->_rx_buf_m.unlock(); - - // TODO: Revisit logic - if(r) - tap->phyOnUnixWritable(conn->sock, NULL, true); - //DEBUG_EXTRA(" Copied onto rxbuf (%d) from stack socket", r); - return; - } - } - - // TX packets from internal buffer to network - void pico_cb_tcp_write(NetconEthernetTap *tap, struct pico_socket *s) - { - Connection *conn = tap->getConnection(s); - if(!conn) - DEBUG_ERROR("invalid connection"); - if(!conn->txsz) - return; - // Only called from a locked context, no need to lock anything - if(conn->txsz > 0) { - int r, max_write_len = conn->txsz < SDK_MTU ? conn->txsz : SDK_MTU; - if((r = tap->picostack->__pico_socket_write(s, &conn->txbuf, max_write_len)) < 0) { - DEBUG_ERROR("unable to write to picosock=%p", s); - return; - } - int sz = (conn->txsz)-r; - if(sz) - memmove(&conn->txbuf, (conn->txbuf+r), sz); - conn->txsz -= r; - - #if DEBUG_LEVEL >= MSG_TRANSFER - int max = conn->type == SOCK_STREAM ? DEFAULT_TCP_TX_BUF_SZ : DEFAULT_UDP_TX_BUF_SZ; - DEBUG_TRANS("[TCP TX] ---> :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", - (float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r); - #endif - - return; - } - } - - // Main callback for TCP connections - void pico_cb_socket_activity(uint16_t ev, struct pico_socket *s) - { - int err; - Mutex::Lock _l(picotap->_tcpconns_m); - Connection *conn = picotap->getConnection(s); - if(!conn) { - DEBUG_ERROR("invalid connection"); - } - // Accept connection (analogous to lwip_nc_accept) - if (ev & PICO_SOCK_EV_CONN) { - DEBUG_INFO("connection established with server, picosock=%p",(conn->picosock)); - uint32_t peer; - uint16_t port; - struct pico_socket *client = picotap->picostack->__pico_socket_accept(s, &peer, &port); - if(!client) { - DEBUG_EXTRA("unable to accept conn. (event might not be incoming, not necessarily an error), picosock=%p", (conn->picosock)); - } - ZT_PHY_SOCKFD_TYPE fds[2]; - if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) { - if(errno < 0) { - // FIXME: Return a value to the client - //picotap->sendReturnValue(conn, -1, errno); - DEBUG_ERROR("unable to create socketpair"); - return; - } - } - Connection *newTcpConn = new Connection(); - picotap->_Connections.push_back(newTcpConn); - newTcpConn->type = SOCK_STREAM; - newTcpConn->sock = picotap->_phy.wrapSocket(fds[0], newTcpConn); - newTcpConn->picosock = client; - int fd = picotap->_phy.getDescriptor(conn->sock); - if(sock_fd_write(fd, fds[1]) < 0) { - DEBUG_ERROR("error sending new fd to client application"); - } - DEBUG_EXTRA("conn=%p, physock=%p, listen_picosock=%p, new_picosock=%p, fd=%d", newTcpConn, newTcpConn->sock, s, client, fds[1]); - } - if (ev & PICO_SOCK_EV_FIN) { - DEBUG_INFO("socket closed. exit normally. picosock=%p\n\n", s); - //picotap->__pico_timer_add(2000, compare_results, NULL); - } - if (ev & PICO_SOCK_EV_ERR) { - DEBUG_INFO("socket error received" /*, strerror(pico_err)*/); - } - if (ev & PICO_SOCK_EV_CLOSE) { - err = picotap->picostack->__pico_socket_close(s); - DEBUG_INFO("socket closure = %d, picosock=%p", err, s); - if(err==0) { - picotap->closeConnection(conn->sock); - } - return; - } - // Read from picoTCP socket - if (ev & PICO_SOCK_EV_RD) { - if(conn->type==SOCK_STREAM) - pico_cb_tcp_read(picotap, s); - if(conn->type==SOCK_DGRAM) - pico_cb_udp_read(picotap, s); - } - // Write to picoTCP socket - if (ev & PICO_SOCK_EV_WR) { - pico_cb_tcp_write(picotap, s); - } - } - - // Called when an incoming ping is received - /* - static void pico_cb_ping(struct pico_icmp4_stats *s) - { - DEBUG_INFO(); - char host[30]; - picotap->picostack->__pico_ipv4_to_string(host, s->dst.addr); - if (s->err == 0) { - printf("%lu bytes from %s: icmp_req=%lu ttl=%lu time=%lu ms\n", s->size, - host, s->seq, s->ttl, (long unsigned int)s->time); - } else { - printf("PING %lu to %s: Error %d\n", s->seq, host, s->err); - } - } - */ - - // Called from the stack, sends data to the tap device (in our case, the ZeroTier service) - // ----------------------------------------- - // | TAP <-> MEM BUFFER <-> STACK <-> APP | - // | |<-------------------------| | TX - // | APP <-> I/O BUFFER <-> STACK <-> TAP | - // | | - // ----------------------------------------- - int pico_eth_send(struct pico_device *dev, void *buf, int len) - { - struct pico_eth_hdr *ethhdr; - ethhdr = (struct pico_eth_hdr *)buf; - - MAC src_mac; - MAC dest_mac; - src_mac.setTo(ethhdr->saddr, 6); - dest_mac.setTo(ethhdr->daddr, 6); - - picotap->_handler(picotap->_arg,NULL,picotap->_nwid,src_mac,dest_mac, - Utils::ntoh((uint16_t)ethhdr->proto),0, ((char*)buf) + sizeof(struct pico_eth_hdr),len - sizeof(struct pico_eth_hdr)); - return len; - } - - // Receives data from the tap device and encapsulates it into a ZeroTier ethernet frame and places it in a locked memory buffer - // ----------------------------------------- - // | TAP <-> MEM BUFFER <-> STACK <-> APP | - // | |--------------->| | RX - // | APP <-> I/O BUFFER <-> STACK <-> TAP | - // | | - // ----------------------------------------- - // It will then periodically be transfered into the network stack via pico_eth_poll() - void pico_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) - { - // Since picoTCP only allows the reception of frames from within the polling function, we - // must enqueue each frame into a memory structure shared by both threads. This structure will - Mutex::Lock _l(tap->_pico_frame_rxbuf_m); - - // assemble new eth header - struct pico_eth_hdr ethhdr; - from.copyTo(ethhdr.saddr, 6); - to.copyTo(ethhdr.daddr, 6); - ethhdr.proto = Utils::hton((uint16_t)etherType); - int newlen = len + sizeof(int) + sizeof(struct pico_eth_hdr); - - int mylen; - while(newlen > (MAX_PICO_FRAME_RX_BUF_SZ-tap->pico_frame_rxbuf_tot) && ethhdr.proto == 56710) - { - mylen = 0; - //DEBUG_FLOW(" [ ZTWIRE -> FBUF ] not enough space left on RX frame buffer, dropping oldest packet in buffer"); - /* - memcpy(&mylen, picotap->pico_frame_rxbuf, sizeof(len)); - memmove(tap->pico_frame_rxbuf, tap->pico_frame_rxbuf + mylen, MAX_PICO_FRAME_RX_BUF_SZ-mylen); // shift buffer - picotap->pico_frame_rxbuf_tot-=mylen; - */ - memset(tap->pico_frame_rxbuf,0,MAX_PICO_FRAME_RX_BUF_SZ); - picotap->pico_frame_rxbuf_tot=0; - } - memcpy(tap->pico_frame_rxbuf + tap->pico_frame_rxbuf_tot, &newlen, sizeof(newlen)); // size of frame + meta - memcpy(tap->pico_frame_rxbuf + tap->pico_frame_rxbuf_tot + sizeof(newlen), ðhdr, sizeof(ethhdr)); // new eth header - memcpy(tap->pico_frame_rxbuf + tap->pico_frame_rxbuf_tot + sizeof(newlen) + sizeof(ethhdr), data, len); // frame data - tap->pico_frame_rxbuf_tot += newlen; - DEBUG_FLOW(" [ ZTWIRE -> FBUF ] Move FRAME(sz=%d) into FBUF(sz=%d), data_len=%d", newlen, picotap->pico_frame_rxbuf_tot, len); - } - - // Called periodically by the stack, this removes data from the locked memory buffer (FBUF) and feeds it into the stack. - // A maximum of 'loop_score' frames can be processed in each call - // ----------------------------------------- - // | TAP <-> MEM BUFFER <-> STACK <-> APP | - // | |----------------->| | RX - // | APP <-> I/O BUFFER <-> STACK <-> TAP | - // | | - // ----------------------------------------- - int pico_eth_poll(struct pico_device *dev, int loop_score) - { - // OPTIMIZATION: The copy logic and/or buffer structure should be reworked for better performance after the BETA - // NetconEthernetTap *tap = (NetconEthernetTap*)netif->state; - Mutex::Lock _l(picotap->_pico_frame_rxbuf_m); - unsigned char frame[SDK_MTU]; - int len; - while (picotap->pico_frame_rxbuf_tot > 0 && loop_score > 0) { - //DEBUG_FLOW(" [ FBUF -> STACK] Frame buffer SZ=%d", picotap->pico_frame_rxbuf_tot); - memset(frame, 0, sizeof(frame)); - len = 0; - memcpy(&len, picotap->pico_frame_rxbuf, sizeof(len)); // get frame len - if(len >= 0) { - //DEBUG_FLOW(" [ FBUF -> STACK] Moving FRAME of size (%d) from FBUF(sz=%d) into stack",len, picotap->pico_frame_rxbuf_tot-len); - memcpy(frame, picotap->pico_frame_rxbuf + sizeof(len), len-(sizeof(len)) ); // get frame data - memmove(picotap->pico_frame_rxbuf, picotap->pico_frame_rxbuf + len, MAX_PICO_FRAME_RX_BUF_SZ-len); // shift buffer - picotap->picostack->__pico_stack_recv(dev, (uint8_t*)frame, (len-sizeof(len))); - picotap->pico_frame_rxbuf_tot-=len; - } - else { - DEBUG_ERROR("Skipping frame of size (%d)",len); - exit(0); - } - loop_score--; - } - return loop_score; - } - - // Creates a new pico_socket and Connection object to represent a new connection to be. - Connection *pico_handleSocket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc) - { - struct pico_socket * psock; - int protocol, protocol_version; - - #if defined(SDK_IPV4) - protocol_version = PICO_PROTO_IPV4; - #elif defined(SDK_IPV6) - protocol_version = PICO_PROTO_IPV6; - #endif - if(socket_rpc->socket_type == SOCK_DGRAM) { - protocol = PICO_PROTO_UDP; - psock = picotap->picostack->__pico_socket_open(protocol_version, protocol, &pico_cb_socket_activity); - } - if(socket_rpc->socket_type == SOCK_STREAM) { - protocol = PICO_PROTO_TCP; - psock = picotap->picostack->__pico_socket_open(protocol_version, protocol, &pico_cb_socket_activity); - } - - if(psock) { - DEBUG_ATTN("physock=%p, picosock=%p", sock, psock); - Connection * newConn = new Connection(); - *uptr = newConn; - newConn->type = socket_rpc->socket_type; - newConn->sock = sock; - - /* - int res = 0; - int sendbuff = UNIX_SOCK_BUF_SIZE; - socklen_t optlen = sizeof(sendbuff); - - res = setsockopt(picotap->_phy.getDescriptor(sock), SOL_SOCKET, SO_RCVBUF, &sendbuff, sizeof(sendbuff)); - if(res == -1) - //DEBUG_ERROR("Error while setting RX buffer limits"); - res = setsockopt(picotap->_phy.getDescriptor(sock), SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)); - if(res == -1) - //DEBUG_ERROR("Error while setting TX buffer limits"); - - // Get buffer size - // optlen = sizeof(sendbuff); - // res = getsockopt(picotap->_phy.getDescriptor(sock), SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen); - // DEBUG_INFO("buflen=%d", sendbuff); - */ - - newConn->local_addr = NULL; - newConn->picosock = psock; - picotap->_Connections.push_back(newConn); - memset(newConn->rxbuf, 0, DEFAULT_UDP_RX_BUF_SZ); - return newConn; - } - else - DEBUG_ERROR("failed to create pico_socket"); - return NULL; - } - - // Writes data from the I/O buffer to the network stack - // ----------------------------------------- - // | TAP <-> MEM BUFFER <-> STACK <-> APP | - // | | - // | APP <-> I/O BUFFER <-> STACK <-> TAP | - // | |----------------->| | TX - // ----------------------------------------- - void pico_handleWrite(Connection *conn) - { - if(!conn || !conn->picosock) { - DEBUG_ERROR(" invalid connection"); - return; - } - - int max, r, max_write_len = conn->txsz < SDK_MTU ? conn->txsz : SDK_MTU; - if((r = picotap->picostack->__pico_socket_write(conn->picosock, &conn->txbuf, max_write_len)) < 0) { - DEBUG_ERROR("unable to write to picosock=%p, r=%d", (conn->picosock), r); - return; - } - - // TODO: Errors - - /* - if(pico_err == PICO_ERR_EINVAL) - DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument"); - if(pico_err == PICO_ERR_EIO) - DEBUG_ERROR("PICO_ERR_EIO - input/output error"); - if(pico_err == PICO_ERR_ENOTCONN) - DEBUG_ERROR("PICO_ERR_ENOTCONN - the socket is not connected"); - if(pico_err == PICO_ERR_ESHUTDOWN) - DEBUG_ERROR("PICO_ERR_ESHUTDOWN - cannot send after transport endpoint shutdown"); - if(pico_err == PICO_ERR_EADDRNOTAVAIL) - DEBUG_ERROR("PICO_ERR_EADDRNOTAVAIL - address not available"); - if(pico_err == PICO_ERR_EHOSTUNREACH) - DEBUG_ERROR("PICO_ERR_EHOSTUNREACH - host is unreachable"); - if(pico_err == PICO_ERR_ENOMEM) - DEBUG_ERROR("PICO_ERR_ENOMEM - not enough space"); - if(pico_err == PICO_ERR_EAGAIN) - DEBUG_ERROR("PICO_ERR_EAGAIN - resource temporarily unavailable"); - */ - - // adjust buffer - int sz = (conn->txsz)-r; - if(sz) - memmove(&conn->txbuf, (conn->txbuf+r), sz); - conn->txsz -= r; - - if(conn->type == SOCK_STREAM) { - max = DEFAULT_TCP_TX_BUF_SZ; - DEBUG_TRANS("[TCP TX] ---> :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", - (float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r); - } - if(conn->type == SOCK_DGRAM) { - max = DEFAULT_UDP_TX_BUF_SZ; - DEBUG_TRANS("[UDP TX] ---> :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", - (float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r); - } - } - - // Instructs the stack to connect to a remote host - void pico_handleConnect(PhySocket *sock, PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc) - { - if(conn->picosock) { - struct sockaddr_in *addr = (struct sockaddr_in *) &connect_rpc->addr; - int ret; - // TODO: Rewrite this - #if defined(SDK_IPV4) - struct pico_ip4 zaddr; - struct sockaddr_in *in4 = (struct sockaddr_in*)&connect_rpc->addr; - char ipv4_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(in4->sin_addr), ipv4_str, INET_ADDRSTRLEN); - picotap->picostack->__pico_string_to_ipv4(ipv4_str, &(zaddr.addr)); - //DEBUG_ATTN("addr=%s:%d", ipv4_str, Utils::ntoh(addr->sin_port)); - ret = picotap->picostack->__pico_socket_connect(conn->picosock, &zaddr, addr->sin_port); - #elif defined(SDK_IPV6) // "fd56:5799:d8f6:1238:8c99:9322:30ce:418a" - struct pico_ip6 zaddr; - struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&connect_rpc->addr; - char ipv6_str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN); - picotap->picostack->__pico_string_to_ipv6(ipv6_str, zaddr.addr); - //DEBUG_ATTN("addr=%s:%d", ipv6_str, Utils::ntoh(addr->sin_port)); - ret = picotap->picostack->__pico_socket_connect(conn->picosock, &zaddr, addr->sin_port); - #endif - - memcpy(&(conn->peer_addr), &connect_rpc->addr, sizeof(struct sockaddr_storage)); - - if(ret == PICO_ERR_EPROTONOSUPPORT) - DEBUG_ERROR("PICO_ERR_EPROTONOSUPPORT"); - if(ret == PICO_ERR_EINVAL) - DEBUG_ERROR("PICO_ERR_EINVAL"); - if(ret == PICO_ERR_EHOSTUNREACH) - DEBUG_ERROR("PICO_ERR_EHOSTUNREACH"); - - picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), 0, ERR_OK); - } - } - - // Instructs the stack to bind to a given address - void pico_handleBind(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc) - { - Connection *conn = picotap->getConnection(sock); - if(!sock) { - DEBUG_ERROR("invalid connection"); - return; - } - struct sockaddr_in *addr = (struct sockaddr_in *) &bind_rpc->addr; - int ret; - // TODO: Rewrite this - #if defined(SDK_IPV4) - struct pico_ip4 zaddr; - struct sockaddr_in *in4 = (struct sockaddr_in*)&bind_rpc->addr; - char ipv4_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(in4->sin_addr), ipv4_str, INET_ADDRSTRLEN); - picotap->picostack->__pico_string_to_ipv4(ipv4_str, &(zaddr.addr)); - DEBUG_ATTN("addr=%s:%d, physock=%p, picosock=%p", ipv4_str, Utils::ntoh(addr->sin_port), sock, (conn->picosock)); - ret = picotap->picostack->__pico_socket_bind(conn->picosock, &zaddr, (uint16_t*)&(addr->sin_port)); - #elif defined(SDK_IPV6) - struct pico_ip6 zaddr; - struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&bind_rpc->addr; - char ipv6_str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN); - picotap->picostack->__pico_string_to_ipv6(ipv6_str, zaddr.addr); - DEBUG_ATTN("addr=%s:%d, physock=%p, picosock=%p", ipv6_str, Utils::ntoh(addr->sin_port), sock, (conn->picosock)); - ret = picotap->picostack->__pico_socket_bind(conn->picosock, &zaddr, (uint16_t*)&(addr->sin_port)); - #endif - if(ret < 0) { - DEBUG_ERROR("unable to bind pico_socket(%p), err=%d", (conn->picosock), ret); - if(ret == PICO_ERR_EINVAL) { - DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument"); - picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, EINVAL); - } - if(ret == PICO_ERR_ENOMEM) { - DEBUG_ERROR("PICO_ERR_ENOMEM - not enough space"); - picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, ENOMEM); - } - if(ret == PICO_ERR_ENXIO) { - DEBUG_ERROR("PICO_ERR_ENXIO - no such device or address"); - picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, ENXIO); - } - } - picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); // success - } - - // Puts a pico_socket into a listening state to receive incoming connection requests - void pico_handleListen(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc) - { - Connection *conn = picotap->getConnection(sock); - DEBUG_ATTN("physock=%p, conn=%p, picosock=%p", sock, conn, conn->picosock); - if(!sock || !conn) { - DEBUG_ERROR("invalid connection"); - return; - } - int ret, backlog = 100; - if((ret = picotap->picostack->__pico_socket_listen(conn->picosock, backlog)) < 0) - { - if(ret == PICO_ERR_EINVAL) { - DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument"); - picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, EINVAL); - } - if(ret == PICO_ERR_EISCONN) { - DEBUG_ERROR("PICO_ERR_EISCONN - socket is connected"); - picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, EISCONN); - } - } - picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); // success - } - - // Feeds data into the local app socket from the I/O buffer associated with the "connection" - // [ (APP<-ZTSOCK) <- RXBUF ] - // ----------------------------------------- - // | TAP <-> MEM BUFFER <-> STACK <-> APP | - // | | - // | APP <-> I/O BUFFER <-> STACK <-> TAP | - // | |<---------------| | RX - // ----------------------------------------- - void pico_handleRead(PhySocket *sock,void **uptr,bool lwip_invoked) - { - if(!lwip_invoked) { - // The stack thread writes to RXBUF as well - picotap->_tcpconns_m.lock(); - picotap->_rx_buf_m.lock(); - } - int tot = 0, n = -1, write_attempts = 0; - - Connection *conn = picotap->getConnection(sock); - if(conn && conn->rxsz) { - - // - if(conn->type==SOCK_DGRAM) { - // Try to write SDK_MTU-sized chunk to app socket - while(tot < SDK_MTU) { - write_attempts++; - n = picotap->_phy.streamSend(conn->sock, (conn->rxbuf)+tot, SDK_MTU); - tot += n; - DEBUG_FLOW(" [ ZTSOCK <- RXBUF] wrote = %d, errno=%d", n, errno); - // If socket is unavailable, attempt to write N times before giving up - if(errno==35) { - if(write_attempts == 1024) { - n = SDK_MTU; // say we wrote it, even though we didn't (drop packet) - tot = SDK_MTU; - } - } - } - int payload_sz, addr_sz_offset = sizeof(struct sockaddr_storage); - memcpy(&payload_sz, conn->rxbuf + addr_sz_offset, sizeof(int)); - struct sockaddr_storage addr; - memcpy(&addr, conn->rxbuf, addr_sz_offset); - // adjust buffer - //DEBUG_FLOW(" [ ZTSOCK <- RXBUF] Copying data from receiving buffer to ZT-controlled app socket (n=%d, payload_sz=%d)", n, payload_sz); - if(conn->rxsz-n > 0) { // If more remains on buffer - memcpy(conn->rxbuf, conn->rxbuf+SDK_MTU, conn->rxsz - SDK_MTU); - //DEBUG_FLOW(" [ ZTSOCK <- RXBUF] Data(%d) still on buffer, moving it up by one MTU", conn->rxsz-n); - ////memset(conn->rxbuf, 0, DEFAULT_UDP_RX_BUF_SZ); - ////conn->rxsz=SDK_MTU; - } - conn->rxsz -= SDK_MTU; - } - // - if(conn->type==SOCK_STREAM) { - n = picotap->_phy.streamSend(conn->sock, conn->rxbuf, conn->rxsz); - if(conn->rxsz-n > 0) // If more remains on buffer - memcpy(conn->rxbuf, conn->rxbuf+n, conn->rxsz - n); - conn->rxsz -= n; - } - // Notify ZT I/O loop that it has new buffer contents - if(n) { - if(conn->type==SOCK_STREAM) { - - #if DEBUG_LEVEL >= MSG_TRANSFER - float max = conn->type == SOCK_STREAM ? (float)DEFAULT_TCP_RX_BUF_SZ : (float)DEFAULT_UDP_RX_BUF_SZ; - DEBUG_TRANS("[TCP RX] <--- :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes", - (float)conn->txsz / max, (float)conn->rxsz / max, conn->sock, n); - #endif - } - if(conn->rxsz == 0) { - picotap->_phy.setNotifyWritable(sock, false); - } - else { - picotap->_phy.setNotifyWritable(sock, true); - } - } - else { - picotap->_phy.setNotifyWritable(sock, false); - } - } - if(!lwip_invoked) { - picotap->_tcpconns_m.unlock(); - picotap->_rx_buf_m.unlock(); - } - DEBUG_FLOW(" [ ZTSOCK <- RXBUF] Emitted (%d) from RXBUF(%d) to socket", tot, conn->rxsz); - } - - // Closes a pico_socket - void pico_handleClose(PhySocket *sock) - { - /* - int ret; - if(conn && conn->picosock) { - if((ret = picotap->picostack->__pico_socket_close(conn->picosock)) < 0) { - DEBUG_ERROR("error closing pico_socket(%p)", (void*)(conn->picosock)); - // sendReturnValue() - } - return; - } - DEBUG_ERROR("invalid connection or pico_socket"); - */ - } -} - -#endif // SDK_PICOTCP diff --git a/src/stack_drivers/picotcp/picotcp.hpp b/src/stack_drivers/picotcp/picotcp.hpp deleted file mode 100644 index db36b6e..0000000 --- a/src/stack_drivers/picotcp/picotcp.hpp +++ /dev/null @@ -1,299 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef SDK_PICOSTACK_H -#define SDK_PICOSTACK_H - -#if defined(SDK_PICOTCP) - -#include -#include - -#ifdef D_GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include "Utils.hpp" -#include "OSUtils.hpp" -#include "Mutex.hpp" -#include "Constants.hpp" -#include "Phy.hpp" - -#include "debug.h" - -#include "pico_stack.h" -#include "pico_ipv4.h" -#include "pico_icmp4.h" -#include "pico_dev_tap.h" -#include "pico_protocol.h" -#include "pico_socket.h" -#include "pico_device.h" -#include "pico_ipv6.h" - -#include "tap.hpp" - -// picoTCP API function signatures -#define PICO_IPV4_TO_STRING_SIG char *ipbuf, const uint32_t ip -#define PICO_TAP_CREATE_SIG char *name -#define PICO_IPV4_LINK_ADD_SIG struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask -#define PICO_DEVICE_INIT_SIG struct pico_device *dev, const char *name, uint8_t *mac -#define PICO_STACK_RECV_SIG struct pico_device *dev, uint8_t *buffer, uint32_t len -#define PICO_ICMP4_PING_SIG char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *) -#define PICO_TIMER_ADD_SIG pico_time expire, void (*timer)(pico_time, void *), void *arg -#define PICO_STRING_TO_IPV4_SIG const char *ipstr, uint32_t *ip -#define PICO_STRING_TO_IPV6_SIG const char *ipstr, uint8_t *ip -#define PICO_SOCKET_SETOPTION_SIG struct pico_socket *s, int option, void *value -#define PICO_SOCKET_SEND_SIG struct pico_socket *s, const void *buf, int len -#define PICO_SOCKET_SENDTO_SIG struct pico_socket *s, const void *buf, int len, void *dst, uint16_t remote_port -#define PICO_SOCKET_RECV_SIG struct pico_socket *s, void *buf, int len -#define PICO_SOCKET_RECVFROM_SIG struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port -#define PICO_SOCKET_OPEN_SIG uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s) -#define PICO_SOCKET_BIND_SIG struct pico_socket *s, void *local_addr, uint16_t *port -#define PICO_SOCKET_CONNECT_SIG struct pico_socket *s, const void *srv_addr, uint16_t remote_port -#define PICO_SOCKET_LISTEN_SIG struct pico_socket *s, const int backlog -#define PICO_SOCKET_READ_SIG struct pico_socket *s, void *buf, int len -#define PICO_SOCKET_WRITE_SIG struct pico_socket *s, const void *buf, int len -#define PICO_SOCKET_CLOSE_SIG struct pico_socket *s -#define PICO_SOCKET_SHUTDOWN_SIG struct pico_socket *s, int mode -#define PICO_SOCKET_ACCEPT_SIG struct pico_socket *s, void *orig, uint16_t *port -#define PICO_IPV6_LINK_ADD_SIG struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask - - -namespace ZeroTier { - - class NetconEthernetTap; - struct Connection; - - // Driver function prototypes - int pico_eth_send(struct pico_device *dev, void *buf, int len); - int pico_eth_poll(struct pico_device *dev, int loop_score); - void pico_init_interface(NetconEthernetTap *tap, const InetAddress &ip); - void pico_loop(NetconEthernetTap *tap); - void pico_cb_tcp_read(NetconEthernetTap *tap, struct pico_socket *s); - void pico_cb_udp_read(NetconEthernetTap *tap, struct pico_socket *s); - void pico_cb_tcp_write(NetconEthernetTap *tap, struct pico_socket *s); - void pico_cb_socket_activity(uint16_t ev, struct pico_socket *s); - - int pico_eth_send(struct pico_device *dev, void *buf, int len); - void pico_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - int pico_eth_poll(struct pico_device *dev, int loop_score); - Connection *pico_handleSocket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc); - void pico_handleWrite(Connection *conn); - void pico_handleConnect(PhySocket *sock, PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc); - void pico_handleBind(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc); - void pico_handleListen(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc); - void pico_handleRead(PhySocket *sock,void **uptr,bool lwip_invoked); - void pico_handleClose(PhySocket *sock); - - - /** - * Loads an instance of picoTCP stack library in a private memory arena - * - * This uses dlmopen() to load an instance of the LWIP stack into its - * own private memory space. This is done to get around the stack's - * lack of thread-safety or multi-instance support. The alternative - * would be to massively refactor the stack so everything lives in a - * state object instead of static memory space. - */ - class picoTCP_stack - { - public: - - void *_libref; - - void close() { -#if defined(__STATIC_STACK__) - return; -#elif defined(__DYNAMIC_STACK__) - dlclose(_libref); -#endif - } - - void (*_pico_stack_init)(void); - void (*_pico_stack_tick)(void); - int (*_pico_string_to_ipv4)(PICO_STRING_TO_IPV4_SIG); - int (*_pico_ipv4_to_string)(PICO_IPV4_TO_STRING_SIG); - int (*_pico_ipv4_link_add)(PICO_IPV4_LINK_ADD_SIG); - int (*_pico_device_init)(PICO_DEVICE_INIT_SIG); - int32_t (*_pico_stack_recv)(PICO_STACK_RECV_SIG); - int (*_pico_icmp4_ping)(PICO_ICMP4_PING_SIG); - int (*_pico_string_to_ipv6)(PICO_STRING_TO_IPV6_SIG); - int (*_pico_socket_setoption)(PICO_SOCKET_SETOPTION_SIG); - uint32_t (*_pico_timer_add)(PICO_TIMER_ADD_SIG); - int (*_pico_socket_send)(PICO_SOCKET_SEND_SIG); - int (*_pico_socket_sendto)(PICO_SOCKET_SENDTO_SIG); - int (*_pico_socket_recv)(PICO_SOCKET_RECV_SIG); - int (*_pico_socket_recvfrom)(PICO_SOCKET_RECVFROM_SIG); - struct pico_socket * (*_pico_socket_open)(PICO_SOCKET_OPEN_SIG); - int (*_pico_socket_bind)(PICO_SOCKET_BIND_SIG); - int (*_pico_socket_connect)(PICO_SOCKET_CONNECT_SIG); - int (*_pico_socket_listen)(PICO_SOCKET_LISTEN_SIG); - int (*_pico_socket_read)(PICO_SOCKET_READ_SIG); - int (*_pico_socket_write)(PICO_SOCKET_WRITE_SIG); - int (*_pico_socket_close)(PICO_SOCKET_CLOSE_SIG); - int (*_pico_socket_shutdown)(PICO_SOCKET_SHUTDOWN_SIG); - struct pico_socket *(*_pico_socket_accept)(PICO_SOCKET_ACCEPT_SIG); - int (*_pico_ipv6_link_add)(PICO_IPV6_LINK_ADD_SIG); - - Mutex _lock; - Mutex _lock_mem; - - picoTCP_stack(const char* path) : - _libref(NULL) - { -#if defined(__ANDROID__) || defined(__UNITY_3D__) - #define __STATIC_STACK__ -#elif defined(__linux__) && !defined(SDK_BUNDLED) - #define __DYNAMIC_STACK__ - // Dynamically load stack library - DEBUG_ATTN("loading network stack library (%s)", path); - _libref = dlmopen(LM_ID_NEWLM, path, RTLD_NOW); -#elif defined(__linux__) && defined(SDK_BUNDLED) // TODO: Determine why __STATIC_STACK__ won't work in SDK_BUNDLED mode - #define __DYNAMIC_STACK__ - DEBUG_ATTN("loading network stack library (%s)", path); - _libref = dlmopen(LM_ID_NEWLM, path, RTLD_NOW); -#elif defined(__APPLE__) - #include "TargetConditionals.h" - #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE - #include "node/Mutex.hpp" - #define __STATIC_STACK__ - // iOS Simulator or iOS device - // Do nothing, symbols are statically-linked - #elif TARGET_OS_MAC && !defined(SDK_BUNDLED) - #define __DYNAMIC_STACK__ - // Dynamically load stack library - DEBUG_ATTN("loading network stack library (%s)", path); - _libref = dlopen(path, RTLD_NOW); - #else - #define __DYNAMIC_STACK__ // should be switched to __STATIC_STACK__ - DEBUG_ATTN("loading network stack library (%s)", path); - _libref = dlopen(path, RTLD_NOW); - #endif -#endif - -#ifdef __STATIC_STACK__ // Set static references (for use in iOS) - - _pico_stack_init = (void(*)(void))&pico_stack_init; - _pico_stack_tick = (void(*)(void))&pico_stack_tick; - _pico_string_to_ipv4 = (int(*)(PICO_STRING_TO_IPV4_SIG))&pico_string_to_ipv4; - _pico_ipv4_to_string = (int(*)(PICO_IPV4_TO_STRING_SIG))&pico_ipv4_to_string; - _pico_ipv4_link_add = (int(*)(PICO_IPV4_LINK_ADD_SIG))&pico_ipv4_link_add; - _pico_device_init = (int(*)(PICO_DEVICE_INIT_SIG))&pico_device_init; - _pico_stack_recv = (int32_t(*)(PICO_STACK_RECV_SIG))&pico_stack_recv; - _pico_icmp4_ping = (int(*)(PICO_ICMP4_PING_SIG))&pico_icmp4_ping; - _pico_string_to_ipv6 = (int(*)(PICO_STRING_TO_IPV6_SIG))&pico_string_to_ipv6; - _pico_socket_setoption = (int(*)(PICO_SOCKET_SETOPTION_SIG))&pico_socket_setoption; - _pico_timer_add = (uint32_t(*)(PICO_TIMER_ADD_SIG))&pico_timer_add; - _pico_socket_send = (int(*)(PICO_SOCKET_SEND_SIG))&pico_socket_send; - _pico_socket_sendto = (int(*)(PICO_SOCKET_SENDTO_SIG))&pico_socket_sendto; - _pico_socket_recv = (int(*)(PICO_SOCKET_RECV_SIG))&pico_socket_recv; - _pico_socket_recvfrom = (int32_t(*)(PICO_SOCKET_RECVFROM_SIG))&pico_socket_recvfrom; - _pico_socket_open = (struct pico_socket*(*)(PICO_SOCKET_OPEN_SIG))&pico_socket_open; - _pico_socket_bind = (int(*)(PICO_SOCKET_BIND_SIG))&pico_socket_bind; - _pico_socket_connect = (int(*)(PICO_SOCKET_CONNECT_SIG))&pico_socket_connect; - _pico_socket_listen = (int(*)(PICO_SOCKET_LISTEN_SIG))&pico_socket_listen; - _pico_socket_read = (int(*)(PICO_SOCKET_READ_SIG))&pico_socket_read; - _pico_socket_write = (int(*)(PICO_SOCKET_WRITE_SIG))&pico_socket_write; - _pico_socket_close = (int(*)(PICO_SOCKET_CLOSE_SIG))&pico_socket_close; - _pico_socket_shutdown = (int(*)(PICO_SOCKET_SHUTDOWN_SIG))&pico_socket_shutdown; - _pico_socket_accept = (struct pico_socket*(*)(PICO_SOCKET_ACCEPT_SIG))&pico_socket_accept; - _pico_ipv6_link_add = (int(*)(PICO_IPV6_LINK_ADD_SIG))&pico_ipv6_link_add; - -#endif - -#ifdef __DYNAMIC_STACK__ // Use dynamically-loaded symbols (for use in normal desktop applications) - - if(_libref == NULL) - DEBUG_ERROR("dlerror(): %s", dlerror()); - - _pico_stack_init = (void(*)(void))dlsym(_libref, "pico_stack_init"); - _pico_stack_tick = (void(*)(void))dlsym(_libref, "pico_stack_tick"); - _pico_string_to_ipv4 = (int(*)(PICO_STRING_TO_IPV4_SIG))dlsym(_libref, "pico_string_to_ipv4"); - _pico_ipv4_to_string = (int(*)(PICO_IPV4_TO_STRING_SIG))dlsym(_libref, "pico_ipv4_to_string"); - _pico_ipv4_link_add = (int(*)(PICO_IPV4_LINK_ADD_SIG))dlsym(_libref, "pico_ipv4_link_add"); - _pico_device_init = (int(*)(PICO_DEVICE_INIT_SIG))dlsym(_libref, "pico_device_init"); - _pico_stack_recv = (int32_t(*)(PICO_STACK_RECV_SIG))dlsym(_libref, "pico_stack_recv"); - _pico_icmp4_ping = (int(*)(PICO_ICMP4_PING_SIG))dlsym(_libref, "pico_icmp4_ping"); - _pico_string_to_ipv6 = (int(*)(PICO_STRING_TO_IPV6_SIG))dlsym(_libref, "pico_string_to_ipv6"); - _pico_socket_setoption = (int(*)(PICO_SOCKET_SETOPTION_SIG))dlsym(_libref, "pico_socket_setoption"); - _pico_timer_add = (uint32_t(*)(PICO_TIMER_ADD_SIG))dlsym(_libref, "pico_timer_add"); - _pico_socket_send = (int(*)(PICO_SOCKET_SEND_SIG))dlsym(_libref, "pico_socket_send"); - _pico_socket_sendto = (int(*)(PICO_SOCKET_SENDTO_SIG))dlsym(_libref, "pico_socket_sendto"); - _pico_socket_recv = (int(*)(PICO_SOCKET_RECV_SIG))dlsym(_libref, "pico_socket_recv"); - _pico_socket_recvfrom = (int32_t(*)(PICO_SOCKET_RECVFROM_SIG))dlsym(_libref, "pico_socket_recvfrom"); - _pico_socket_open = (struct pico_socket*(*)(PICO_SOCKET_OPEN_SIG))dlsym(_libref, "pico_socket_open"); - _pico_socket_bind = (int(*)(PICO_SOCKET_BIND_SIG))dlsym(_libref, "pico_socket_bind"); - _pico_socket_connect = (int(*)(PICO_SOCKET_CONNECT_SIG))dlsym(_libref, "pico_socket_connect"); - _pico_socket_listen = (int(*)(PICO_SOCKET_LISTEN_SIG))dlsym(_libref, "pico_socket_listen"); - _pico_socket_read = (int(*)(PICO_SOCKET_READ_SIG))dlsym(_libref, "pico_socket_read"); - _pico_socket_write = (int(*)(PICO_SOCKET_WRITE_SIG))dlsym(_libref, "pico_socket_write"); - _pico_socket_close = (int(*)(PICO_SOCKET_CLOSE_SIG))dlsym(_libref, "pico_socket_close"); - _pico_socket_shutdown = (int(*)(PICO_SOCKET_SHUTDOWN_SIG))dlsym(_libref, "pico_socket_shutdown"); - _pico_socket_accept = (struct pico_socket*(*)(PICO_SOCKET_ACCEPT_SIG))dlsym(_libref, "pico_socket_accept"); - _pico_ipv6_link_add = (int(*)(PICO_IPV6_LINK_ADD_SIG))dlsym(_libref, "pico_ipv6_link_add"); - -#endif - } - - ~picoTCP_stack() - { - if (_libref) - dlclose(_libref); - } - - inline void __pico_stack_init(void) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); _pico_stack_init(); } - inline void __pico_stack_tick(void) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); _pico_stack_tick(); } - inline int __pico_ipv4_to_string(PICO_IPV4_TO_STRING_SIG) throw() {/* DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_ipv4_to_string(ipbuf, ip); } - inline int __pico_ipv4_link_add(PICO_IPV4_LINK_ADD_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock);*/ return _pico_ipv4_link_add(dev, address, netmask); } - inline int __pico_device_init(PICO_DEVICE_INIT_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_device_init(dev, name, mac); } - inline int __pico_stack_recv(PICO_STACK_RECV_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock);*/ return _pico_stack_recv(dev, buffer, len); } - inline int __pico_icmp4_ping(PICO_ICMP4_PING_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_icmp4_ping(dst, count, interval, timeout, size, cb); } - inline int __pico_string_to_ipv4(PICO_STRING_TO_IPV4_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_string_to_ipv4(ipstr, ip); } - inline int __pico_string_to_ipv6(PICO_STRING_TO_IPV6_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_string_to_ipv6(ipstr, ip); } - inline int __pico_socket_setoption(PICO_SOCKET_SETOPTION_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_socket_setoption(s, option, value); } - inline uint32_t __pico_timer_add(PICO_TIMER_ADD_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_timer_add(expire, timer, arg); } - inline int __pico_socket_send(PICO_SOCKET_SEND_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_socket_send(s, buf, len); } - inline int __pico_socket_sendto(PICO_SOCKET_SENDTO_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_socket_sendto(s, buf, len, dst, remote_port); } - inline int __pico_socket_recv(PICO_SOCKET_RECV_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_socket_recv(s, buf, len); } - inline int __pico_socket_recvfrom(PICO_SOCKET_RECVFROM_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock);*/ return _pico_socket_recvfrom(s, buf, len, orig, remote_port); } - inline struct pico_socket * __pico_socket_open(PICO_SOCKET_OPEN_SIG) throw() { /*DEBUG_ATTN();*/ return _pico_socket_open(net, proto, wakeup); } - inline int __pico_socket_bind(PICO_SOCKET_BIND_SIG) throw() { /*DEBUG_ATTN();*/ Mutex::Lock _l(_lock); return _pico_socket_bind(s, local_addr, port); } - inline int __pico_socket_connect(PICO_SOCKET_CONNECT_SIG) throw() { /*DEBUG_ATTN();*/ Mutex::Lock _l(_lock); return _pico_socket_connect(s, srv_addr, remote_port); } - inline int __pico_socket_listen(PICO_SOCKET_LISTEN_SIG) throw() { /*DEBUG_ATTN();*/ Mutex::Lock _l(_lock); return _pico_socket_listen(s, backlog); } - inline int __pico_socket_read(PICO_SOCKET_READ_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock); */ return _pico_socket_read(s, buf, len); } - inline int __pico_socket_write(PICO_SOCKET_WRITE_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock);*/ return _pico_socket_write(s, buf, len); } - inline int __pico_socket_close(PICO_SOCKET_CLOSE_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock);*/ return _pico_socket_close(s); } - inline int __pico_socket_shutdown(PICO_SOCKET_SHUTDOWN_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_socket_shutdown(s, mode); } - inline struct pico_socket * __pico_socket_accept(PICO_SOCKET_ACCEPT_SIG) throw() { /*DEBUG_ATTN();*/ /*Mutex::Lock _l(_lock);*/ return _pico_socket_accept(s, orig, port); } - inline int __pico_ipv6_link_add(PICO_IPV6_LINK_ADD_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_ipv6_link_add(dev, address, netmask); } - }; - -} // namespace ZeroTier - -#endif - -#endif // SDK_PICOTCP diff --git a/src/tap.cpp b/src/tap.cpp deleted file mode 100644 index 9672793..0000000 --- a/src/tap.cpp +++ /dev/null @@ -1,610 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tap.hpp" -#include "sdkutils.hpp" -#include "sdk.h" -#include "defs.h" -#include "debug.h" -#include "rpc.h" - -#if defined(SDK_LWIP) - #include "lwip.hpp" -#elif defined(SDK_PICOTCP) - #include "picotcp.hpp" -#elif defined(SDK_JIP) - #include "jip.hpp" -#endif - -#include "Utils.hpp" -#include "OSUtils.hpp" -#include "Constants.hpp" -#include "Phy.hpp" - -//#if !defined(__IOS__) && !defined(__ANDROID__) && !defined(__UNITY_3D__) && !defined(__XCODE__) -// const ip_addr_t ip_addr_any = { IPADDR_ANY }; -//#endif - -namespace ZeroTier { -int NetconEthernetTap::sendReturnValue(int fd, int retval, int _errno) -{ - //DEBUG_INFO("fd=%d, retval=%d, errno=%d", fd, retval, _errno); - int sz = sizeof(char) + sizeof(retval) + sizeof(errno); - char retmsg[sz]; - memset(&retmsg, 0, sizeof(retmsg)); - retmsg[0]=RPC_RETVAL; - memcpy(&retmsg[1], &retval, sizeof(retval)); - memcpy(&retmsg[1]+sizeof(retval), &_errno, sizeof(_errno)); - return write(fd, &retmsg, sz); -} -// Unpacks the buffer from an RPC command -void NetconEthernetTap::unloadRPC(void *data, pid_t &pid, pid_t &tid, - char (timestamp[RPC_TIMESTAMP_SZ]), char (CANARY[sizeof(uint64_t)]), char &cmd, void* &payload) - { - unsigned char *buf = (unsigned char*)data; - memcpy(&pid, &buf[IDX_PID], sizeof(pid_t)); - memcpy(&tid, &buf[IDX_TID], sizeof(pid_t)); - memcpy(timestamp, &buf[IDX_TIME], RPC_TIMESTAMP_SZ); - memcpy(&cmd, &buf[IDX_PAYLOAD], sizeof(char)); - memcpy(CANARY, &buf[IDX_PAYLOAD+1], CANARY_SZ); -} - -/*------------------------------------------------------------------------------ --------------------------------- Tap Service ---------------------------------- -------------------------------------------------------------------------------*/ - -NetconEthernetTap::NetconEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void*, uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg) : - _homePath(homePath), - _mac(mac), - _mtu(mtu), - _nwid(nwid), - _handler(handler), - _arg(arg), - _phy(this,false,true), - _unixListenSocket((PhySocket *)0), - _enabled(true), - _run(true) -{ - sockstate = -1; - char sockPath[4096],stackPath[4096]; - Utils::snprintf(sockPath,sizeof(sockPath),"%s%snc_%.16llx",homePath,ZT_PATH_SEPARATOR_S,_nwid,ZT_PATH_SEPARATOR_S,(unsigned long long)nwid); - _dev = sockPath; // in SDK mode, set device to be just the network ID - - // Load and initialize network stack library - #if defined(SDK_LWIP) - Utils::snprintf(stackPath,sizeof(stackPath),"%s%sliblwip.so",homePath,ZT_PATH_SEPARATOR_S); - lwipstack = new lwIP_stack(stackPath); - if(!lwipstack) { - DEBUG_ERROR("unable to dynamically load a new instance of (%s) (searched ZeroTier home path)", stackPath); - throw std::runtime_error(""); - } - lwipstack->__lwip_init(); - DEBUG_EXTRA("network stack initialized (%p)", lwipstack); - #elif defined(SDK_PICOTCP) - pico_frame_rxbuf_tot = 0; - Utils::snprintf(stackPath,sizeof(stackPath),"%s%slibpicotcp.so",homePath,ZT_PATH_SEPARATOR_S); - picostack = new picoTCP_stack(stackPath); - if(!picostack) { - DEBUG_ERROR("unable to dynamically load a new instance of (%s) (searched ZeroTier home path)", stackPath); - throw std::runtime_error(""); - } - picostack->__pico_stack_init(); - DEBUG_EXTRA("network stack initialized (%p)", picostack); - #elif defined(SDK_JIP) - Utils::snprintf(stackPath,sizeof(stackPath),"%s%slibjip.so",homePath,ZT_PATH_SEPARATOR_S); - jipstack = new jip_stack(stackPath); - #endif - _unixListenSocket = _phy.unixListen(sockPath,(void *)this); - - chmod(sockPath, 0777); // To make the RPC socket available to all users - - if (!_unixListenSocket) - DEBUG_ERROR("unable to bind to: path=%s", sockPath); - else - DEBUG_INFO("tap initialized on: path=%s", sockPath); - _thread = Thread::start(this); -} - -NetconEthernetTap::~NetconEthernetTap() -{ - _run = false; - _phy.whack(); - _phy.whack(); // TODO: Rationale? - Thread::join(_thread); - _phy.close(_unixListenSocket,false); - #if defined(SDK_LWIP) - delete lwipstack; - #endif - #if defined(SDK_PICOTCP) - delete picostack; - #endif - #if defined(SDK_JIP) - delete jipstack; - #endif -} - -void NetconEthernetTap::setEnabled(bool en) -{ - _enabled = en; -} - -bool NetconEthernetTap::enabled() const -{ - return _enabled; -} - -bool NetconEthernetTap::addIp(const InetAddress &ip) -{ - // Initialize network stack's interface, assign addresses - #if defined(SDK_LWIP) - lwip_init_interface(this, ip); - #elif defined(SDK_PICOTCP) - picotap = this; - pico_init_interface(this, ip); - #elif defined(SDK_JIP) - jip_init_interface(ip); - #endif - return true; -} - -bool NetconEthernetTap::removeIp(const InetAddress &ip) -{ - Mutex::Lock _l(_ips_m); - std::vector::iterator i(std::find(_ips.begin(),_ips.end(),ip)); - if (i == _ips.end()) - return false; - _ips.erase(i); - if (ip.isV4()) { - // TODO: De-register from network stacks - } - return true; -} - -std::vector NetconEthernetTap::ips() const -{ - Mutex::Lock _l(_ips_m); - return _ips; -} - -// Receive data from ZT tap service (virtual wire) and present it to network stack -// ----------------------------------------- -// | TAP <-> MEM BUFFER <-> STACK <-> APP | -// | |--------------->| | RX -// | APP <-> I/O BUFFER <-> STACK <-> TAP | -// | | -// ----------------------------------------- -void NetconEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - // DEBUG_EXTRA("RX packet: len=%d, etherType=%d", len, etherType); - // RX packet - #if defined(SDK_LWIP) - lwip_rx(this, from,to,etherType,data,len); - #elif defined(SDK_PICOTCP) - pico_rx(this, from,to,etherType,data,len); - #elif defined(SDK_JIP) - jip_rx(from,to,etherType,data,len); - #endif -} - -std::string NetconEthernetTap::deviceName() const -{ - return _dev; -} - -void NetconEthernetTap::setFriendlyName(const char *friendlyName) { -} - -void NetconEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) -{ - std::vector newGroups; - Mutex::Lock _l(_multicastGroups_m); - // TODO: get multicast subscriptions from LWIP - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - - std::sort(newGroups.begin(),newGroups.end()); - std::unique(newGroups.begin(),newGroups.end()); - - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } - _multicastGroups.swap(newGroups); -} - -void NetconEthernetTap::threadMain() - throw() -{ - // Enter main thread loop for network stack - #if defined(SDK_LWIP) - lwip_loop(this); - #elif defined(SDK_PICOTCP) - pico_loop(this); - #elif defined(SDK_JIP) - jip_loop(this); - #endif -} - -Connection *NetconEthernetTap::getConnection(PhySocket *sock) -{ - for(size_t i=0;i<_Connections.size();++i) { - if(_Connections[i]->sock == sock) - return _Connections[i]; - } - return NULL; -} - -Connection *NetconEthernetTap::getConnection(struct pico_socket *sock) -{ - for(size_t i=0;i<_Connections.size();++i) { - if(_Connections[i]->picosock == sock) - return _Connections[i]; - } - return NULL; -} - -void NetconEthernetTap::closeConnection(PhySocket *sock) -{ - Mutex::Lock _l(_close_m); - // Here we assume _tcpconns_m is already locked by caller - if(!sock) { - DEBUG_EXTRA("invalid PhySocket"); - return; - } - // picoTCP - #if defined(SDK_PICOTCP) - pico_handleClose(sock); - #endif - Connection *conn = getConnection(sock); - if(!conn) - return; - // lwIP - #if defined(SDK_LWIP) - lwip_handleClose(this, sock, conn); - #endif - for(size_t i=0;i<_Connections.size();++i) { - if(_Connections[i] == conn){ - _Connections.erase(_Connections.begin() + i); - delete conn; - break; - } - } - if(!sock) - return; - close(_phy.getDescriptor(sock)); - _phy.close(sock, false); -} - -void NetconEthernetTap::phyOnUnixClose(PhySocket *sock,void **uptr) { - //DEBUG_EXTRA("physock=%p", sock); - Mutex::Lock _l(_tcpconns_m); - //closeConnection(sock); -} - - -// Receive data from ZT tap service and present it to network stack -// ----------------------------------------- -// | TAP <-> MEM BUFFER <-> STACK <-> APP | -// | |--------------->| | RX -// | APP <-> I/O BUFFER <-> STACK <-> TAP | -// | | -// ----------------------------------------- -void NetconEthernetTap::handleRead(PhySocket *sock,void **uptr,bool lwip_invoked) -{ - // DEBUG_EXTRA("handleRead(physock=%p): lwip_invoked = %d\n", sock, lwip_invoked); - #if defined(SDK_PICOTCP) - pico_handleRead(sock, uptr, lwip_invoked); - #endif - #if defined(SDK_LWIP) - lwip_handleRead(this, sock, uptr, lwip_invoked); - #endif -} - -void NetconEthernetTap::phyOnUnixWritable(PhySocket *sock,void **uptr,bool lwip_invoked) -{ - handleRead(sock,uptr,lwip_invoked); -} - -void NetconEthernetTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len) -{ - //DEBUG_INFO("physock=%p, len=%d", sock, (int)len); - uint64_t CANARY_num; - pid_t pid, tid; - ssize_t wlen = len; - char tmpbuf[SDK_MTU]; - char cmd, timestamp[20], CANARY[CANARY_SZ], padding[] = {PADDING}; - void *payload; - unsigned char *buf = (unsigned char*)data; - std::pair sockdata; - PhySocket *rpcSock; - bool foundJob = false, detected_rpc = false; - Connection *conn; - // RPC - char phrase[RPC_PHRASE_SZ]; - memset(phrase, 0, RPC_PHRASE_SZ); - if(len == BUF_SZ) { - memcpy(phrase, buf, RPC_PHRASE_SZ); - if(strcmp(phrase, RPC_PHRASE) == 0) - detected_rpc = true; - } - if(detected_rpc) { - unloadRPC(data, pid, tid, timestamp, CANARY, cmd, payload); - memcpy(&CANARY_num, CANARY, CANARY_SZ); - // DEBUG_EXTRA(" RPC: physock=%p, (pid=%d, tid=%d, timestamp=%s, cmd=%d)", sock, pid, tid, timestamp, cmd); - - if(cmd == RPC_SOCKET) { - // DEBUG_INFO("RPC_SOCKET, physock=%p", sock); - // Create new lwip socket and associate it with this sock - struct socket_st socket_rpc; - memcpy(&socket_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct socket_st)); - Connection * new_conn; - if((new_conn = handleSocket(sock, uptr, &socket_rpc))) { - new_conn->pid = pid; // Merely kept to look up application path/names later, not strictly necessary - } - } else { - memcpy(&tmpbuf,data,len); - jobmap[CANARY_num] = std::pair(sock, tmpbuf); - - } - write(_phy.getDescriptor(sock), "z", 1); // RPC ACK byte to maintain order - } - // STREAM - else { - int data_start = -1, data_end = -1, canary_pos = -1, padding_pos = -1; - // Look for padding - std::string padding_pattern(padding, padding+PADDING_SZ); - std::string buffer(buf, buf + len); - padding_pos = buffer.find(padding_pattern); - canary_pos = padding_pos-CANARY_SZ; - // Grab token, next we'll use it to look up an RPC job - if(canary_pos > -1) { - memcpy(&CANARY_num, buf+canary_pos, CANARY_SZ); - if(CANARY_num != 0) { - // Find job - sockdata = jobmap[CANARY_num]; - if(!sockdata.first) { - return; - } else - foundJob = true; - } - } - conn = getConnection(sock); - if(!conn) - return; - - if(padding_pos == -1) { // [DATA] - memcpy(&conn->txbuf[conn->txsz], buf, wlen); - } else { // Padding found, implies a canary is present - // [CANARY] - if(len == CANARY_SZ+PADDING_SZ && canary_pos == 0) { - wlen = 0; // Nothing to write - } else { - // [CANARY] + [DATA] - if(len > CANARY_SZ+PADDING_SZ && canary_pos == 0) { - wlen = len - CANARY_SZ+PADDING_SZ; - data_start = padding_pos+PADDING_SZ; - memcpy((&conn->txbuf)+conn->txsz, buf+data_start, wlen); - } - // [DATA] + [CANARY] - if(len > CANARY_SZ+PADDING_SZ && canary_pos > 0 && canary_pos == len - CANARY_SZ+PADDING_SZ) { - wlen = len - CANARY_SZ+PADDING_SZ; - data_start = 0; - memcpy((&conn->txbuf)+conn->txsz, buf+data_start, wlen); - } - // [DATA] + [CANARY] + [DATA] - if(len > CANARY_SZ+PADDING_SZ && canary_pos > 0 && len > (canary_pos + CANARY_SZ+PADDING_SZ)) { - wlen = len - CANARY_SZ+PADDING_SZ; - data_start = 0; - data_end = padding_pos-CANARY_SZ; - memcpy((&conn->txbuf)+conn->txsz, buf+data_start, (data_end-data_start)+1); - memcpy((&conn->txbuf)+conn->txsz, buf+(padding_pos+PADDING_SZ), len-(canary_pos+CANARY_SZ+PADDING_SZ)); - } - } - } - - // Write data from stream - if(wlen) { - conn->txsz += wlen; - handleWrite(conn); - } - } - // Process RPC if we have a corresponding jobmap entry - if(foundJob) { - rpcSock = sockdata.first; - buf = (unsigned char*)sockdata.second; - unloadRPC(buf, pid, tid, timestamp, CANARY, cmd, payload); - //DEBUG_ERROR(" RPC: physock=%p, (pid=%d, tid=%d, timestamp=%s, cmd=%d)", sock, pid, tid, timestamp, cmd); - switch(cmd) { - case RPC_BIND: - //DEBUG_INFO("RPC_BIND, physock=%p", sock); - struct bind_st bind_rpc; - memcpy(&bind_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct bind_st)); - handleBind(sock, rpcSock, uptr, &bind_rpc); - break; - case RPC_LISTEN: - //DEBUG_INFO("RPC_LISTEN, physock=%p", sock); - struct listen_st listen_rpc; - memcpy(&listen_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct listen_st)); - handleListen(sock, rpcSock, uptr, &listen_rpc); - break; - case RPC_GETSOCKNAME: - //DEBUG_INFO("RPC_GETSOCKNAME, physock=%p", sock); - struct getsockname_st getsockname_rpc; - memcpy(&getsockname_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct getsockname_st)); - handleGetsockname(sock, rpcSock, uptr, &getsockname_rpc); - break; - case RPC_GETPEERNAME: - //DEBUG_INFO("RPC_GETPEERNAME, physock=%p", sock); - struct getsockname_st getpeername_rpc; - memcpy(&getpeername_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct getsockname_st)); - handleGetpeername(sock, rpcSock, uptr, &getpeername_rpc); - break; - case RPC_CONNECT: - //DEBUG_INFO("RPC_CONNECT, physock=%p", sock); - struct connect_st connect_rpc; - memcpy(&connect_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct connect_st)); - handleConnect(sock, rpcSock, conn, &connect_rpc); - jobmap.erase(CANARY_num); - return; // Keep open RPC, we'll use it once in nc_connected to send retval - default: - return; - break; - } - Mutex::Lock _l(_tcpconns_m); - closeConnection(sockdata.first); // close RPC after sending retval, no longer needed - jobmap.erase(CANARY_num); - } -} - -/*------------------------------------------------------------------------------ ------------------------------ RPC Handler functions ---------------------------- -------------------------------------------------------------------------------*/ - -void NetconEthernetTap::handleGetsockname(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct getsockname_st *getsockname_rpc) -{ - Mutex::Lock _l(_tcpconns_m); - Connection *conn = getConnection(sock); - if(conn->local_addr == NULL){ - DEBUG_EXTRA("no address info available. is it bound?"); - struct sockaddr_storage storage; - memset(&storage, 0, sizeof(struct sockaddr_storage)); - write(_phy.getDescriptor(rpcSock), NULL, sizeof(struct sockaddr_storage)); - return; - } - write(_phy.getDescriptor(rpcSock), conn->local_addr, sizeof(struct sockaddr_storage)); -} - -void NetconEthernetTap::handleGetpeername(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct getsockname_st *getsockname_rpc) -{ - Mutex::Lock _l(_tcpconns_m); - Connection *conn = getConnection(sock); - if(conn->peer_addr == NULL){ - DEBUG_EXTRA("no peer address info available. is it connected?"); - struct sockaddr_storage storage; - memset(&storage, 0, sizeof(struct sockaddr_storage)); - write(_phy.getDescriptor(rpcSock), NULL, sizeof(struct sockaddr_storage)); - return; - } - write(_phy.getDescriptor(rpcSock), conn->peer_addr, sizeof(struct sockaddr_storage)); -} - -Connection * NetconEthernetTap::handleSocket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc) -{ - #if defined(SDK_PICOTCP) - return pico_handleSocket(sock, uptr, socket_rpc); - #endif - #if defined(SDK_LWIP) - return lwip_handleSocket(this, sock, uptr, socket_rpc); - #endif - return NULL; -} - -Connection * NetconEthernetTap::handleSocketProxy(PhySocket *sock, int socket_type) -{ - return NULL; -} -int NetconEthernetTap::handleConnectProxy(PhySocket *sock, struct sockaddr_in *rawAddr) -{ - return -1; -} - -// Connect a stack's PCB/socket/Connection object to a remote host -void NetconEthernetTap::handleConnect(PhySocket *sock, PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc) -{ - Mutex::Lock _l(_tcpconns_m); - #if defined(SDK_PICOTCP) - pico_handleConnect(sock, rpcSock, conn, connect_rpc); - #endif - #if defined(SDK_LWIP) - lwip_handleConnect(this, sock, rpcSock, conn, connect_rpc); - #endif -} - -void NetconEthernetTap::handleBind(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc) -{ - Mutex::Lock _l(_tcpconns_m); - if(!_ips.size()) { - // We haven't been given an address yet. Binding at this stage is premature - DEBUG_ERROR("cannot bind yet. ZT address hasn't been provided"); - sendReturnValue(_phy.getDescriptor(rpcSock), -1, ENOMEM); - return; - } - #if defined(SDK_PICOTCP) - pico_handleBind(sock,rpcSock,uptr,bind_rpc); - #endif - #if defined(SDK_LWIP) - lwip_handleBind(this, sock, rpcSock, uptr, bind_rpc); - #endif -} - -void NetconEthernetTap::handleListen(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc) -{ - Mutex::Lock _l(_tcpconns_m); - #if defined(SDK_PICOTCP) - pico_handleListen(sock, rpcSock, uptr, listen_rpc); - #endif - #if defined(SDK_LWIP) - lwip_handleListen(this, sock, rpcSock, uptr, listen_rpc); - #endif -} - -// Write to the network stack (and thus out onto the network) -void NetconEthernetTap::handleWrite(Connection *conn) -{ - #if defined(SDK_PICOTCP) - pico_handleWrite(conn); - #endif - #if defined(SDK_LWIP) - lwip_handleWrite(this, conn); - #endif -} - -} // namespace ZeroTier - diff --git a/src/tap.hpp b/src/tap.hpp deleted file mode 100644 index 0f79e27..0000000 --- a/src/tap.hpp +++ /dev/null @@ -1,384 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_NETCONETHERNETTAP_HPP -#define ZT_NETCONETHERNETTAP_HPP - -#include -#include - -#include -#include -#include -#include -#include - -#include "Constants.hpp" -#include "MulticastGroup.hpp" -#include "Mutex.hpp" -#include "InetAddress.hpp" -#include "Thread.hpp" -#include "Phy.hpp" - -#include "defs.h" -#include "rpc.h" - -#if defined(SDK_LWIP) - #include "netif/etharp.h" - #include "lwip.hpp" -#elif defined(SDK_PICOTCP) - #include "picotcp.hpp" - #include "pico_protocol.h" -#endif - -// lwIP structs -struct tcp_pcb; -struct udp_pcb; - -// ZT RPC structs -struct socket_st; -struct listen_st; -struct bind_st; -struct connect_st; -struct getsockname_st; -struct accept_st; - -namespace ZeroTier { - - class NetconEthernetTap; - class LWIPStack; - - extern struct pico_device picodev; - extern NetconEthernetTap *picotap; - - /* - * TCP connection - */ - struct Connection - { - bool listening, probation, disabled; - int pid, txsz, rxsz, type; - PhySocket *rpcSock, *sock; - struct tcp_pcb *TCP_pcb; - struct udp_pcb *UDP_pcb; - struct sockaddr_storage *local_addr; // Address we've bound to locally - struct sockaddr_storage *peer_addr; // Address of connection call to remote host - unsigned short port; - unsigned char txbuf[DEFAULT_TCP_TX_BUF_SZ]; - unsigned char rxbuf[DEFAULT_TCP_RX_BUF_SZ]; - // TODO: necessary still? - int proxy_conn_state; - - // pico - struct pico_socket *picosock; - }; - - /* - * A helper for passing a reference to _phy to LWIP callbacks as a "state" - */ - struct Larg - { - NetconEthernetTap *tap; - Connection *conn; - Larg(NetconEthernetTap *_tap, Connection *conn) : tap(_tap), conn(conn) {} - }; - - /* - * Network Containers instance -- emulates an Ethernet tap device as far as OneService knows - */ - class NetconEthernetTap - { - friend class Phy; - - public: - NetconEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void*,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); - - ~NetconEthernetTap(); - - void setEnabled(bool en); - bool enabled() const; - bool addIp(const InetAddress &ip); - bool removeIp(const InetAddress &ip); - std::vector ips() const; - std::vector _ips; - - void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - std::string deviceName() const; - void setFriendlyName(const char *friendlyName); - void scanMulticastGroups(std::vector &added,std::vector &removed); - - int sendReturnValue(int fd, int retval, int _errno); - void unloadRPC(void *data, pid_t &pid, pid_t &tid, char (timestamp[RPC_TIMESTAMP_SZ]), char (CANARY[sizeof(uint64_t)]), char &cmd, void* &payload); - - void threadMain() - throw(); - - std::string _homePath; - MAC _mac; - unsigned int _mtu; - uint64_t _nwid; - void (*_handler)(void *,void*, uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - Phy _phy; - PhySocket *_unixListenSocket; - volatile bool _enabled; - volatile bool _run; - - // --- Proxy - struct sockaddr_storage proxyServerAddress; - int sockstate; // Use as flag to determine whether proxy has been started, TODO: Rename - int proxyListenSocket; - PhySocket *proxyListenPhySocket; - int startProxyServer(const char *homepath, uint64_t nwid, struct sockaddr_storage *addr); - int stopProxyServer(); - int getProxyServerAddress(struct sockaddr_storage *addr); - int getProxyServerPort(); - void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable); - // --- end Proxy - - - // lwIP - #if defined(SDK_LWIP) - netif interface, interface6; - lwIP_stack *lwipstack; - #endif - // jip - #if defined(SDK_JIP) - jip_stack *jipstack; - #endif - // picoTCP - #if defined(SDK_PICOTCP) - unsigned char pico_frame_rxbuf[MAX_PICO_FRAME_RX_BUF_SZ]; - int pico_frame_rxbuf_tot; - Mutex _pico_frame_rxbuf_m; - picoTCP_stack *picostack; - #endif - - /* - * Handles an RPC to bind an LWIP PCB to a given address and port - * - * @param PhySocket associated with this RPC connection - * @param structure containing the data and parameters for this client's RPC - * - - i := should be implemented in intercept lib - I := is implemented in intercept lib - X := is implemented in service - ? := required treatment Unknown - - := Not needed - - [ ] EACCES - The address is protected, and the user is not the superuser. - [X] EADDRINUSE - The given address is already in use. - [I] EBADF - sockfd is not a valid descriptor. - [X] EINVAL - The socket is already bound to an address. - [I] ENOTSOCK - sockfd is a descriptor for a file, not a socket. - - [X] ENOMEM - Insufficient kernel memory was available. - - - The following errors are specific to UNIX domain (AF_UNIX) sockets: - - [-] EACCES - Search permission is denied on a component of the path prefix. (See also path_resolution(7).) - [-] EADDRNOTAVAIL - A nonexistent interface was requested or the requested address was not local. - [-] EFAULT - addr points outside the user's accessible address space. - [-] EINVAL - The addrlen is wrong, or the socket was not in the AF_UNIX family. - [-] ELOOP - Too many symbolic links were encountered in resolving addr. - [-] ENAMETOOLONG - s addr is too long. - [-] ENOENT - The file does not exist. - [-] ENOTDIR - A component of the path prefix is not a directory. - [-] EROFS - The socket inode would reside on a read-only file system. - */ - void handleBind(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct bind_st *bind_rpc); - - /* - * Handles an RPC to put an LWIP PCB into LISTEN mode - * - * @param PhySocket associated with this RPC connection - * @param structure containing the data and parameters for this client's RPC - * - - i := should be implemented in intercept lib - I := is implemented in intercept lib - X := is implemented in service - ? := required treatment Unknown - - := Not needed - - [?] EADDRINUSE - Another socket is already listening on the same port. - [IX] EBADF - The argument sockfd is not a valid descriptor. - [I] ENOTSOCK - The argument sockfd is not a socket. - [I] EOPNOTSUPP - The socket is not of a type that supports the listen() operation. - */ - void handleListen(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct listen_st *listen_rpc); - - /* - * Handles an RPC to create a socket (LWIP PCB and associated socketpair) - * - * A socketpair is created, one end is kept and wrapped into a PhySocket object - * for use in the main ZT I/O loop, and one end is sent to the client. The client - * is then required to tell the service what new file descriptor it has allocated - * for this connection. After the mapping is complete, the socket can be used. - * - * @param PhySocket associated with this RPC connection - * @param structure containing the data and parameters for this client's RPC - * - - i := should be implemented in intercept lib - I := is implemented in intercept lib - X := is implemented in service - ? := required treatment Unknown - - := Not needed - - [-] EACCES - Permission to create a socket of the specified type and/or protocol is denied. - [I] EAFNOSUPPORT - The implementation does not support the specified address family. - [I] EINVAL - Unknown protocol, or protocol family not available. - [I] EINVAL - Invalid flags in type. - [I] EMFILE - Process file table overflow. - [?] ENFILE - The system limit on the total number of open files has been reached. - [X] ENOBUFS or ENOMEM - Insufficient memory is available. The socket cannot be created until sufficient resources are freed. - [?] EPROTONOSUPPORT - The protocol type or the specified protocol is not supported within this domain. - */ - Connection * handleSocket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc); - Connection * handleSocketProxy(PhySocket *sock, int socket_type); - - /* - * Handles an RPC to connect to a given address and port - * - * @param PhySocket associated with this RPC connection - * @param structure containing the data and parameters for this client's RPC - - --- Error handling in this method will only catch problems which are immedately - apprent. Some errors will need to be caught in the nc_connected(0 callback - - i := should be implemented in intercept lib - I := is implemented in intercept lib - X := is implemented in service - ? := required treatment Unknown - - := Not needed - - [-] EACCES - For UNIX domain sockets, which are identified by pathname: Write permission is denied ... - [?] EACCES, EPERM - The user tried to connect to a broadcast address without having the socket broadcast flag enabled ... - [X] EADDRINUSE - Local address is already in use. - [I] EAFNOSUPPORT - The passed address didn't have the correct address family in its sa_family field. - [X] EAGAIN - No more free local ports or insufficient entries in the routing cache. - [ ] EALREADY - The socket is nonblocking and a previous connection attempt has not yet been completed. - [IX] EBADF - The file descriptor is not a valid index in the descriptor table. - [ ] ECONNREFUSED - No-one listening on the remote address. - [i] EFAULT - The socket structure address is outside the user's address space. - [ ] EINPROGRESS - The socket is nonblocking and the connection cannot be completed immediately. - [-] EINTR - The system call was interrupted by a signal that was caught. - [X] EISCONN - The socket is already connected. - [X] ENETUNREACH - Network is unreachable. - [I] ENOTSOCK - The file descriptor is not associated with a socket. - [X] ETIMEDOUT - Timeout while attempting connection. - - [X] EINVAL - Invalid argument, SVr4, generally makes sense to set this - */ - void handleConnect(PhySocket *sock, PhySocket *rpcsock, Connection *conn, struct connect_st* connect_rpc); - int handleConnectProxy(PhySocket *sock, struct sockaddr_in *rawAddr); - - // void handleIsConnected(); - - /* - * Return the address that the socket is bound to - */ - void handleGetsockname(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct getsockname_st *getsockname_rpc); - - /* - * Return the address of the peer connected to this socket - */ - void handleGetpeername(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct getsockname_st *getsockname_rpc); - - /* - * Writes data from the application's socket to the LWIP connection - */ - void handleWrite(Connection *conn); - - // Unused -- no UDP or TCP from this thread/Phy<> - void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address, const struct sockaddr *from,void *data,unsigned long len); - void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success); - void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from); - void phyOnTcpClose(PhySocket *sock,void **uptr); - void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len); - - void handleRead(PhySocket *sock,void **uptr,bool lwip_invoked); - void phyOnTcpWritable(PhySocket *sock,void **uptr, bool lwip_invoked); - - /* - * Signals us to close the TcpConnection associated with this PhySocket - */ - void phyOnUnixClose(PhySocket *sock,void **uptr); - - /* - * Notifies us that there is data to be read from an application's socket - */ - void phyOnUnixData(PhySocket *sock,void **uptr,void *data,ssize_t len); - - /* - * Notifies us that we can write to an application's socket - */ - void phyOnUnixWritable(PhySocket *sock,void **uptr,bool lwip_invoked); - - /* - * Returns a pointer to a TcpConnection associated with a given PhySocket - */ - Connection *getConnection(PhySocket *sock); - - /* - * Returns a pointer to a TcpConnection associated with a given pico_socket - */ - Connection *getConnection(struct pico_socket *socket); - - /* - * Closes a TcpConnection, associated LWIP PCB strcuture, - * PhySocket, and underlying file descriptor - */ - void closeConnection(PhySocket *sock); - - std::vector _Connections; - - std::map > jobmap; - pid_t rpcCounter; - - Thread _thread; - std::string _dev; // path to Unix domain socket - - std::vector _multicastGroups; - Mutex _multicastGroups_m; - - Mutex _ips_m, _tcpconns_m, _rx_buf_m, _close_m; - }; - -} // namespace ZeroTier - -#endif diff --git a/src/wrappers/README.md b/src/wrappers/README.md deleted file mode 100644 index 09f7b7e..0000000 --- a/src/wrappers/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Language/Framework Wrappers -==== -These wrappers are designed to abstract the ZeroTierSDK Sockets API (implemented in `src/sockets.c`) to your native language of choice. Specific examples of how to use these are located in the `integrations` directory.. diff --git a/src/wrappers/dotnet/DotNetWrapper.cs b/src/wrappers/dotnet/DotNetWrapper.cs deleted file mode 100755 index 025be87..0000000 --- a/src/wrappers/dotnet/DotNetWrapper.cs +++ /dev/null @@ -1,417 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -using UnityEngine; -using UnityEngine.UI; -using UnityEngine.Networking; - -using System; -using System.Collections; -using System.Runtime.InteropServices; -using System.Threading; -using System.Net.Sockets; -using System.Net; -using System.IO; -using System.Collections.Generic; -using System.Globalization; - -// TODO: -/* - * check for mem leaks surrounding managed/unmanaged barrier - * find root of 2X buffer size requirement issue - * check that cross-thread oprations are handled correctly - * check that .IsRunning() doesn't bork the entire system anymore - * Allow max packet size configuration - * Handle exceptions from unmanaged code - * */ - -// Provides a bare-bones interface to ZeroTier-administered sockets -public class ZTSDK { - - // ZeroTier background thread - protected Thread ztThread; - protected List connections = new List (); - protected int MaxPacketSize; - - // Only allow one network at a time for BETA - protected bool joined_to_network = false; - protected string nwid = ""; - protected string path = ""; - - // Platform-specific paths and bundle/libary names - #if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX - const string DLL_PATH = "ZeroTierSDK_Unity3D_OSX"; - protected string rpc_path = "/Library/Application\\ Support/ZeroTier/SDK/"; - #endif - #if UNITY_IOS || UNITY_IPHONE - const string DLL_PATH = "ZeroTierSDK_Unity3D_iOS"; - protected string rpc_path = "ZeroTier/One/"; - #endif - #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN - const string DLL_PATH = "ZeroTierSDK_Unity3D_WIN"; - protected string rpc_path = ""; - #endif - #if UNITY_STANDALONE_LINUX - const string DLL_PATH = "ZeroTierSDK_Unity3D_LINUX"; - protected string rpc_path = ""; - #endif - #if UNITY_ANDROID - const string DLL_PATH = "ZeroTierSDK_Unity3D_ANDROID"; - protected string rpc_path = "ZeroTier/One/"; - #endif - -#region DLL Imports - // ZeroTier service / debug initialization - [DllImport (DLL_PATH)] - public static extern void SetDebugFunction( IntPtr fp ); - [DllImport (DLL_PATH)] - private static extern int unity_start_service(string path); - [DllImport (DLL_PATH)] - private static extern int unity_start_service_and_rpc(string path, string nwid); - [DllImport (DLL_PATH)] - protected static extern bool zts_is_running(); - [DllImport (DLL_PATH)] - protected static extern void zts_stop_service(); - - // Connection calls - [DllImport (DLL_PATH)] - protected static extern int zts_socket(int family, int type, int protocol); - - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_bind(int sockfd, System.IntPtr addr, int addrlen); - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_connect(int sockfd, System.IntPtr addr, int addrlen); - - [DllImport (DLL_PATH)] - protected static extern int zts_accept(int sockfd); - [DllImport (DLL_PATH)] - protected static extern int zts_listen(int sockfd, int backlog); - [DllImport (DLL_PATH)] - protected static extern int zts_close(int sockfd); - - // RX / TX - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_recv(int sockfd, [In, Out] IntPtr buf, int len); - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_send(int sockfd, IntPtr buf, int len); - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_set_nonblock(int sockfd); - - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_sendto(int fd, IntPtr buf, int len, int flags, System.IntPtr addr, int addrlen); - [DllImport (DLL_PATH)] - unsafe protected static extern int zts_recvfrom(int fd, [In, Out] IntPtr buf, int len, int flags, System.IntPtr addr, int addrlen); - - // ZT Network controls - [DllImport (DLL_PATH)] - protected static extern void zts_join_network(string nwid); - [DllImport (DLL_PATH)] - protected static extern void zts_leave_network(string nwid); -#endregion - - // Interop structures - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi)] - public struct sockaddr { - /// u_short->unsigned short - public ushort sa_family; - /// char[14] - [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=14)] - public string sa_data; - } - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void MyDelegate(string str); - - // Debug output callback - static void CallBackFunction(string str) { - Debug.Log("ZeroTier: " + str); - } - - - // Returns a path for RPC communications to the service - private string rpcCommPath() - { - if(path != "" && nwid != "") { - return path + "nc_" + nwid; - } - return ""; - } - - // Thread which starts the ZeroTier service - protected void zt_service_thread() - { - // Set up debug callback - MyDelegate callback_delegate = new MyDelegate( CallBackFunction ); - IntPtr intptr_delegate = Marshal.GetFunctionPointerForDelegate(callback_delegate); - SetDebugFunction( intptr_delegate ); - - // Start service - /* This new instance will communicate via a named pipe, so any - * API calls (ZeroTier.Connect(), ZeroTier.Send(), etc) will be sent to the service - * via this pipe. - */ - if(nwid.Length > 0) { - unity_start_service_and_rpc (path, nwid); - } - else { - unity_start_service(rpcCommPath()); - } - } - - // Returns the nwid of the network you're currently connected to - public string GetNetworkID() { - return nwid; - } - - // Returns whether you're currently connected to a network - public bool IsConnected() { - return nwid != ""; - } - - // Start the ZeroTier service - protected void Init() - { - ztThread = new Thread(() => { - try { - zt_service_thread(); - } catch(Exception e) { - Debug.Log(e.Message.ToString()); - } - }); - ztThread.IsBackground = true; // Allow the thread to be aborted safely - ztThread.Start(); - } - - // Initialize the ZeroTier service with a given path - public ZTSDK(string path, string nwid) { - Debug.Log("ZTSDK(): " + nwid); - - this.path = path; - this.nwid = nwid; - Init(); - } - - public ZTSDK (string path) { - this.path = path; - Init(); - } - - // Initialize the ZeroTier service - public ZTSDK() { - Init(); - } - -#region Network Handling - // Joins a ZeroTier virtual network - public bool JoinNetwork(string nwid) - { - if(!joined_to_network) { - zts_join_network(nwid); - return true; - } - return false; - } - - // Leaves a ZeroTier virtual network - public bool LeaveNetwork(string nwid) - { - if(!joined_to_network) { - return false; - } - else { - zts_leave_network(nwid); - return true; - } - } -#endregion - - // Creates a new ZeroTier-administered socket - public int Socket(int family, int type, int protocol) - { - return zts_socket (family, type, protocol); - } - - // Binds to a specific address - public int Bind(int fd, string addr, int port) - { - GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port); - IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject (); - int addrlen = Marshal.SizeOf (pSockAddr); - return zts_bind (fd, pSockAddr, addrlen); - } - - // Listens for an incoming connection request - public int Listen(int fd, int backlog) - { - return zts_listen(fd, backlog); - } - - // Accepts an incoming connection - public int Accept(int fd) - { - return zts_accept (fd); - } - - // Closes a connection - public int Close(int fd) - { - return Close (fd); - } - - // Connects to a remote host - public int Connect(int fd, string addr, int port) - { - GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port); - IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject (); - int addrlen = Marshal.SizeOf (pSockAddr); - return zts_connect (fd, pSockAddr, addrlen); - } - - public int Read(int fd, ref char[] buf, int len) - { - GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); - IntPtr ptr = handle.AddrOfPinnedObject(); - int bytes_read = zts_recv (fd, ptr, len*2); - string str = Marshal.PtrToStringAuto(ptr); - //Marshal.Copy (ptr, buf, 0, bytes_read); - buf = Marshal.PtrToStringAnsi(ptr).ToCharArray(); - return bytes_read; - } - - public int Write(int fd, char[] buf, int len) - { - GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); - IntPtr ptr = handle.AddrOfPinnedObject(); - //error = 0; - int bytes_written; - // FIXME: Sending a length of 2X the buffer size seems to fix the object pinning issue - if((bytes_written = zts_send(fd, ptr, len*2)) < 0) { - //error = (byte)bytes_written; - } - return bytes_written; - } - - // Sends data to an address - public int SendTo(int fd, char[] buf, int len, int flags, string addr, int port) - { - GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); - IntPtr ptr = handle.AddrOfPinnedObject(); - int bytes_written; - - // Form address structure - GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port); - IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject (); - int addrlen = Marshal.SizeOf (pSockAddr); - - if((bytes_written = zts_sendto(fd, ptr, len*2, flags, pSockAddr, addrlen)) < 0) { - //error = (byte)bytes_written; - } - return bytes_written; - } - - // Receives data from an address - public int RecvFrom(int fd, ref char[] buf, int len, int flags, string addr, int port) - { - GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); - IntPtr ptr = handle.AddrOfPinnedObject(); - - // Form address structure - GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port); - IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject (); - int addrlen = Marshal.SizeOf (pSockAddr); - - int bytes_read = zts_recvfrom(fd, ptr, len*2, flags, pSockAddr, addrlen); - string str = Marshal.PtrToStringAuto(ptr); - //Marshal.Copy (ptr, buf, 0, bytes_read); - buf = Marshal.PtrToStringAnsi(ptr).ToCharArray(); - return bytes_read; - } - -#region Service-Related calls - // Returns whether the ZeroTier service is currently running - public bool IsRunning() - { - return zts_is_running (); - } - - // Terminates the ZeroTier service - public void Terminate() - { - zts_stop_service (); - } -#endregion - - -// --- Utilities --- - - - // Handles IPv4 and IPv6 notation. - public static IPEndPoint CreateIPEndPoint(string endPoint) - { - string[] ep = endPoint.Split(':'); - if (ep.Length < 2) throw new FormatException("Invalid endpoint format"); - IPAddress ip; - if (ep.Length > 2) { - if (!IPAddress.TryParse(string.Join(":", ep, 0, ep.Length - 1), out ip)) { - throw new FormatException("Invalid ip-adress"); - } - } - else { - if (!IPAddress.TryParse(ep[0], out ip)) { - throw new FormatException("Invalid ip-adress"); - } - } - int port; - if (!int.TryParse(ep[ep.Length - 1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port)) { - throw new FormatException("Invalid port"); - } - return new IPEndPoint(ip, port); - } - - // Generates an unmanaged sockaddr structure from a string-formatted endpoint - public static GCHandle Generate_unmananged_sockaddr(string endpoint_str) - { - IPEndPoint ipEndPoint; - ipEndPoint = CreateIPEndPoint (endpoint_str); - SocketAddress socketAddress = ipEndPoint.Serialize (); - - // use an array of bytes instead of the sockaddr structure - byte[] sockAddrStructureBytes = new byte[socketAddress.Size]; - GCHandle sockAddrHandle = GCHandle.Alloc (sockAddrStructureBytes, GCHandleType.Pinned); - for (int i = 0; i < socketAddress.Size; ++i) { - sockAddrStructureBytes [i] = socketAddress [i]; - } - return sockAddrHandle; - } - - public static GCHandle Generate_unmanaged_buffer(byte[] buf) - { - // use an array of bytes instead of the sockaddr structure - GCHandle sockAddrHandle = GCHandle.Alloc (buf, GCHandleType.Pinned); - return sockAddrHandle; - } -} diff --git a/src/wrappers/java/JavaWrapper.java b/src/wrappers/java/JavaWrapper.java deleted file mode 100644 index f8d44ea..0000000 --- a/src/wrappers/java/JavaWrapper.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ -package ZeroTier; - -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.util.ArrayList; -import java.util.zip.ZipError; - -import android.os.ParcelFileDescriptor; -import android.util.Log; -import android.util.Pair; - -public class ZTSDK { - - // Socket families - public static int AF_UNIX = 1; - public static int AF_INET = 2; - - // Socket types - public static int SOCK_STREAM = 1; - public static int SOCK_DGRAM = 2; - - // fcntl flags - public static int O_APPEND = 1024; - public static int O_NONBLOCK = 2048; - public static int O_ASYNC = 8192; - public static int O_DIRECT = 65536; - public static int O_NOATIME = 262144; - - // fcntl cmds - public static int F_GETFL = 3; - public static int F_SETFL = 4; - - // Loads JNI code - static { System.loadLibrary("ZeroTierOneJNI"); } - - // ZeroTier service controls - public native void zt_start_service(String homeDir); - public void start_service(String homeDir) { - zt_start_service(homeDir); - } - - public native void zt_join_network(String nwid); - public void join_network(String nwid) { - zt_join_network(nwid); - } - - public native void zt_leave_network(String nwid); - public void leave_network(String nwid) { - zt_leave_network(nwid); - } - - // ------------------------------------------------------------------------------ - // ------------------------------- get_addresses() ------------------------------ - // ------------------------------------------------------------------------------ - - public native ArrayList zt_get_addresses(String nwid); - public ArrayList get_addresses(String nwid) { - int err = -1; - ArrayList addresses; - while (err < 0) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - } - addresses = zt_get_addresses(nwid); - if (addresses.size() > 0) { - return addresses; - } - } - return null; - } - - public native int zt_get_proxy_port(String nwid); - public int get_proxy_port(String nwid) { - return zt_get_proxy_port(nwid); - } - - public native boolean zt_service_is_running(); - public boolean service_is_running() { - return zt_service_is_running(); - } - - - // ------------------------------------------------------------------------------ - // ----------------------------------- socket() --------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_socket(int family, int type, int protocol); - public int socket(int family, int type, int protocol) { - return zt_socket(family, type, protocol); - } - - - // ------------------------------------------------------------------------------ - // ----------------------------------- connect() -------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_connect(int fd, String addr, int port); - - public int connect(int sock, ZTAddress zaddr, String nwid) { - return connect(sock, zaddr.Address(), zaddr.Port(), nwid); - } - - public int connect(int sock, String addr, int port, String nwid) - { - int err = -1; - ArrayList addresses; - while (err < 0) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - } - addresses = zt_get_addresses(nwid); - if (addresses.size() > 0) { - if(!addresses.get(0).startsWith("-1.-1.-1.-1/-1")) { - err = zt_connect(sock, addr, port); - } - } - } - return err; - } - - // ------------------------------------------------------------------------------ - // ------------------------------------ bind() ---------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_bind(int fd, String addr, int port); - - public int bind(int sock, ZTAddress zaddr, String nwid) { - return bind(sock, zaddr.Address(), zaddr.Port(), nwid); - } - public int bind(int sock, String addr, int port, String nwid) { - int err = -1; - ArrayList addresses; - while (err < 0) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - } - addresses = zt_get_addresses(nwid); - if (addresses.size() > 0) { - if(!addresses.get(0).startsWith("-1.-1.-1.-1/-1")) { - err = zt_bind(sock, addr, port); - } - } - } - return err; - } - - - // ------------------------------------------------------------------------------ - // ---------------------------------- accept4() --------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_accept4(int fd, String addr, int port); - public int accept4(int fd, String addr, int port) { - return zt_accept4(fd,addr,port); - } - - - // ------------------------------------------------------------------------------ - // ---------------------------------- accept() ---------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_accept(int fd, ZeroTier.ZTAddress addr); - public int accept(int fd, ZeroTier.ZTAddress addr) { - return zt_accept(fd, addr); - } - - // ------------------------------------------------------------------------------ - // ----------------------------------- listen() --------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_listen(int fd, int backlog); - public int listen(int fd, int backlog) { - return zt_listen(fd,backlog); - } - - // ------------------------------------------------------------------------------ - // ----------------------------------- close() ---------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_close(int fd); - public int close(int fd) { - return close(fd); - } - - - // ------------------------------------------------------------------------------ - // ------------------------------------ read() ---------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_read(int fd, byte[] buf, int len); - public int read(int fd, byte[] buf, int len) { - return zt_read(fd, buf, len); - } - - // ------------------------------------------------------------------------------ - // ----------------------------------- write() ---------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_write(int fd, byte[] buf, int len); - public int write(int fd, byte[] buf, int len) { - return zt_write(fd, buf, len); - } - - // ------------------------------------------------------------------------------ - // ----------------------------------- sendto() --------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_sendto(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr); - public int sendto(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr){ - return zt_sendto(fd,buf,len,flags,addr); - } - - // ------------------------------------------------------------------------------ - // ----------------------------------- send() ----------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_send(int fd, byte[] buf, int len, int flags); - public int send(int fd, byte[] buf, int len, int flags) { - return zt_send(fd, buf, len, flags); - } - - // ------------------------------------------------------------------------------ - // ---------------------------------- recvfrom() -------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_recvfrom(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr); - public int recvfrom(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr){ - return zt_recvfrom(fd,buf,len,flags,addr); - } - - // ------------------------------------------------------------------------------ - // ---------------------------------- recvfrom() -------------------------------- - // ------------------------------------------------------------------------------ - - public native int zt_fcntl(int sock, int cmd, int flag); - public int fcntl(int sock, int cmd, int flag) { - return zt_fcntl(sock, F_SETFL, O_NONBLOCK); - } - - - - //public static native int zt_getsockopt(int fd, int type, int protocol); - //public static native int zt_setsockopt(int fd, int type, int protocol); - //public static native int zt_getsockname(int fd, int type, int protocol); - - - // PROXY SERVER CONTROLS - public native boolean zt_proxy_is_running(); - public boolean proxy_is_running() { - return zt_proxy_is_running(); - } -} \ No newline at end of file diff --git a/src/wrappers/java/ZTAddress.java b/src/wrappers/java/ZTAddress.java deleted file mode 100644 index 20ad61c..0000000 --- a/src/wrappers/java/ZTAddress.java +++ /dev/null @@ -1,79 +0,0 @@ -package ZeroTier; - -import java.math.BigInteger; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.util.regex.Pattern; - -// A convenience object for moving address information across the JNI memory border. - -public class ZTAddress -{ - // int -> byte array - static public byte[] toIPByteArray(long addr){ - return new byte[]{(byte)addr,(byte)(addr>>>8),(byte)(addr>>>16),(byte)(addr>>>24)}; - } - - // byte array -> int - long toIPInt(String _addr) { - long result = 0; - for(String part: _addr.split(Pattern.quote("."))) { - result = result << 8; - result |= Integer.parseInt(part); - } - return result; - } - - public int port; - public int Port() { - return port; - } - - public long _rawAddr; - public String Address() - { - try { - return InetAddress.getByAddress(toIPByteArray(_rawAddr)).getHostAddress(); - } catch (UnknownHostException e) { - // should never happen - return null; - } - } - - public String toString() { - return Address() + ":" + Port(); - } - - public ZTAddress() - { - port = -1; - _rawAddr = -1; - } - - public ZTAddress(String _addr, int _port) - { - _rawAddr = toIPInt(_addr); - port = _port; - } - - public void ZTAddress(InetSocketAddress ins) - { - port = ins.getPort(); - _rawAddr = toIPInt(ins.getAddress().getHostAddress()); - } - - public InetSocketAddress ToInetSocketAddress() throws IllegalArgumentException { - InetSocketAddress sock_addr = null; - try { - sock_addr = new InetSocketAddress(Address(), port); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } - return sock_addr; - } - - public boolean isValid() { - return port != -1 && !Address().startsWith("-1.-1.-1.-1/-1"); - } -} \ No newline at end of file diff --git a/src/wrappers/swift/Apple-Bridging-Header.h b/src/wrappers/swift/Apple-Bridging-Header.h deleted file mode 100644 index 8d1002a..0000000 --- a/src/wrappers/swift/Apple-Bridging-Header.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// Implementations located in src/wrappers/swift/XcodeWrapper.cpp -// - -#ifndef Example_OSX_IOS_Bridging_Header_h -#define Example_OSX_IOS_Bridging_Header_h - -#include - -// ZT INTERCEPT/RPC CONTROLS -int zt_init_rpc(const char *path, const char *nwid); -int zt_start_intercept(); -void zt_disable_intercept(); -void zt_enable_intercept(); - -// ZT SERVICE CONTROLS -void zt_start_service(const char * path); -void zt_stop_service(); -void zt_start_service_and_rpc(const char * path, const char * nwid); -bool zt_service_is_running(); -void zt_join_network(const char *nwid); -void zt_leave_network(const char *nwid); -void zt_get_ipv4_address(const char *nwid, char *addrstr); -void zt_get_ipv6_address(const char *nwid, char *addrstr); - - -// SOCKS5 PROXY CONTROLS -void zt_start_proxy_server(const char *nwid, struct sockaddr_storage addr); -void zt_stop_proxy_server(const char *nwid); -void zt_proxy_is_running(const char *nwid); -void zt_get_proxy_server_address(const char *nwid, struct sockaddr_storage addr); - -// SOCKET API -int zt_connect(CONNECT_SIG); -int zt_bind(BIND_SIG); -int zt_accept(ACCEPT_SIG); -int zt_listen(LISTEN_SIG); -int zt_socket(SOCKET_SIG); -int zt_setsockopt(SETSOCKOPT_SIG); -int zt_getsockopt(GETSOCKOPT_SIG); -int zt_close(CLOSE_SIG); -int zt_getsockname(GETSOCKNAME_SIG); -int zt_getpeername(GETPEERNAME_SIG); -int zt_recvfrom(RECVFROM_SIG); -int zt_fcntl(FCNTL_SIG); -int zt_sendto(SENDTO_SIG); - -#endif /* Example_OSX_IOS_Bridging_Header_h */ - - - diff --git a/src/wrappers/swift/XcodeWrapper.cpp b/src/wrappers/swift/XcodeWrapper.cpp deleted file mode 100755 index c933e4a..0000000 --- a/src/wrappers/swift/XcodeWrapper.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include "sdk.h" -#include "XcodeWrapper.hpp" - -#define INTERCEPT_ENABLED 111 -#define INTERCEPT_DISABLED 222 - -// ZEROTIER CONTROLS -// Starts a ZeroTier service at the specified path -extern "C" void zt_start_service(const char *path, const char *nwid) { - zts_start_service(path); - //init_service(INTERCEPT_DISABLED, path); -} - -// Starts a ZeroTier service at the specified path and initializes the RPC mechanism -//extern "C" void zt_start_service_and_rpc(const char *path, const char *nwid) { -// init_service_and_rpc(INTERCEPT_DISABLED, path, nwid); -//} - -// Stops the core ZeroTier service -extern "C" void zt_stop_service() { - zts_stop_service(); -} -// Returns whether the core ZeroTier service is running -extern "C" bool zt_service_is_running() { - return zts_service_is_running(); -} -// Joins a ZeroTier virtual network -extern "C" void zt_join_network(const char *nwid) { - zts_join_network(nwid); -} -// Leaves a ZeroTier virtual network -extern "C" void zt_leave_network(const char *nwid) { - zts_leave_network(nwid); -} -// Returns a list of addresses associated with this device on the given network -extern "C" void zt_get_ipv4_address(const char *nwid, char *addrstr) { - zts_get_ipv4_address(nwid, addrstr); -} -// Returns a list of addresses associated with this device on the given network -extern "C" void zt_get_ipv6_address(const char *nwid, char *addrstr) { - zts_get_ipv6_address(nwid, addrstr); -} - - -// PROXY SERVER CONTROLS -// -extern "C" void zt_start_proxy_server(const char *homepath, const char *nwid, struct sockaddr_storage *addr) { - zts_start_proxy_server(homepath, nwid, addr); -} -// -extern "C" void zt_stop_proxy_server(const char *nwid) { - zts_stop_proxy_server(nwid); -} -// -extern "C" void zt_proxy_is_running(const char *nwid) { - zts_proxy_is_running(nwid); -} -// -extern "C" void zt_get_proxy_server_address(const char *nwid, struct sockaddr_storage *addr) { - zts_get_proxy_server_address(nwid, addr); -} -// Explicit ZT API wrappers -#if !defined(__IOS__) -// This isn't available for iOS since function interposition isn't as reliable -extern "C" void zt_init_rpc(const char *path, const char *nwid) { - zts_init_rpc(path, nwid); -} -#endif - - -// SOCKET API -// These are used in ZTSDK.swift to implement the higher-level API -extern "C" int zt_socket(SOCKET_SIG) { - return zts_socket(socket_family, socket_type, protocol); -} -extern "C" int zt_connect(CONNECT_SIG) { - return zts_connect(fd, addr, addrlen); -} -extern "C" int zt_bind(BIND_SIG){ - return zts_bind(fd, addr, addrlen); -} -extern "C" int zt_accept(ACCEPT_SIG) { - return zts_accept(fd, addr, addrlen); -} -extern "C" int zt_listen(LISTEN_SIG) { - return zts_listen(fd, backlog); -} -extern "C" int zt_setsockopt(SETSOCKOPT_SIG) { - return zts_setsockopt(fd, level, optname, optval, optlen); -} -extern "C" int zt_getsockopt(GETSOCKOPT_SIG) { - return zts_getsockopt(fd, level, optname, optval, optlen); -} -extern "C" int zt_close(CLOSE_SIG) { - return zts_close(fd); -} -extern "C" int zt_getsockname(GETSOCKNAME_SIG) { - return zts_getsockname(fd, addr, addrlen); -} -extern "C" int zt_getpeername(GETPEERNAME_SIG) { - return zts_getpeername(fd, addr, addrlen); -} -extern "C" int zt_fcntl(FCNTL_SIG) { - return zts_fcntl(fd, cmd, flags); -} -extern "C" ssize_t zt_recvfrom(RECVFROM_SIG) { - return zts_recvfrom(fd, buf, len, flags, addr, addrlen); -} -extern "C" ssize_t zt_sendto(SENDTO_SIG) { - return zts_sendto(fd, buf, len, flags, addr, addrlen); -} \ No newline at end of file diff --git a/src/wrappers/swift/XcodeWrapper.hpp b/src/wrappers/swift/XcodeWrapper.hpp deleted file mode 100755 index 6c6722e..0000000 --- a/src/wrappers/swift/XcodeWrapper.hpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef SDK_XCODE_WRAPPER_HPP -#define SDK_XCODE_WRAPPER_HPP - -#endif // SDK_XCODE_WRAPPER_HPP diff --git a/src/wrappers/swift/ztsdk.swift b/src/wrappers/swift/ztsdk.swift deleted file mode 100644 index 813bcda..0000000 --- a/src/wrappers/swift/ztsdk.swift +++ /dev/null @@ -1,198 +0,0 @@ -// -// ZTSDK.swift -// Example_iOS_App -// -// Created by Joseph Henry on 9/7/16. -// Copyright © 2016 ZeroTier Inc. All rights reserved. -// - -import Foundation - -// Convenience structure for getting address data to/from the native library -struct ZTAddress -{ - var family: Int32 - var addr: String - var port: Int16 - var data: sockaddr_in? - - init(_ family: Int32, _ addr: String, _ port: Int16) { - self.family = family - self.addr = addr - self.port = port - } - - func to_sockaddr_in() -> UnsafePointer { - var data = sockaddr_in(sin_len: UInt8(sizeof(sockaddr_in)), - sin_family: UInt8(AF_INET), - sin_port: UInt16(port).bigEndian, - sin_addr: in_addr(s_addr: 0), - sin_zero: (0,0,0,0,0,0,0,0)) - inet_pton(AF_INET, addr, &(data.sin_addr)); - return UnsafePointer([data]); - } - - func len() -> UInt8 { - return UInt8(sizeof(sockaddr_in)) - } -} - - -// Convenience wrapper class for ZeroTier/SDK/Proxy controls -// Implemented in terms of SDK_XcodeWrapper.cpp -class ZTSDK : NSObject -{ - var service_thread : NSThread! - private func ztnc_start_service(path: String?) { - if(path == nil) { - zt_start_service( - NSSearchPathForDirectoriesInDomains( - NSSearchPathDirectory.DocumentDirectory,NSSearchPathDomainMask.UserDomainMask,true)[0]) - return; - } - zt_start_service(path!) - } - - // Starts the ZeroTier background service - func start_service(path: String?) { - let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) - dispatch_async(queue) { - self.ztnc_start_service(path) - } - sleep(3) - while(service_is_running() == false) { /* waiting for service to start */ } - } - - // Stops the ZeroTier background service - func stop_service() { - zt_stop_service() - } - - // Returns whether the ZeroTier background service is running - func service_is_running() -> Bool { - return zt_service_is_running() - } - - // Joins a ZeroTier network - func join_network(nwid: String) { - zt_join_network(nwid) - } - - // Leaves a ZeroTier network - func leave_network(nwid: String) { - zt_leave_network(nwid) - } - - // Returns the IPV4 address of this device on a given ZeroTier network - func get_ipv4_address(nwid: String, inout _ addrbuf: [Int8]) { - zt_get_ipv4_address(nwid,&addrbuf) - } - - // Returns the IPV6 address of this device on a given ZeroTier network - func get_ipv6_address(nwid: String, inout _ addrbuf: [Int8]) { - zt_get_ipv6_address(nwid,&addrbuf) - } - - - // PROXY SERVER CONTROLS - // - /* - func start_proxy_server(homepath: String, nwid: String, struct sockaddr_storage *addr) { - zt_start_proxy_server(homepath, nwid, addr); - } - // - func stop_proxy_server(nwid: String) { - zt_stop_proxy_server(nwid); - } - // - func proxy_is_running(const char *homepath, const char *nwid, struct sockaddr_storage *addr) { - zt_start_proxy_server(homepath, nwid, addr); - } - // - func get_proxy_server_address(const char *nwid, struct sockaddr_storage *addr) { - zt_get_proxy_server_address(nwid, addr); - } - // Explicit ZT API wrappers - #if !defined(__IOS__) - // This isn't available for iOS since function interposition isn't as reliable - func init_rpc(const char *path, const char *nwid) { - zt_init_rpc(path, nwid); - } - #endif - - */ - - // TODO: Verify this hasn't been broken. Should check for interface addresses based on - // protocol version. (important) - - // SOCKET API - func socket(socket_family: Int32, _ socket_type: Int32, _ socket_protocol: Int32) -> Int32 { - return zt_socket(socket_family, socket_type, socket_protocol); - } - - func connect(fd: Int32, _ addr: ZTAddress, _ nwid: String? = nil) -> Int32 { - if(nwid == nil) { // no nwid is provided to check for address, try once and fail - return zt_connect(Int32(fd), addr.to_sockaddr_in(), UInt32(addr.len())); - } - while(true) { // politely wait until an address is provided. simulates a blocking call - var addrbuf = [Int8](count: 16, repeatedValue: 0) - self.get_ipv4_address(nwid!, &addrbuf) - let addr_str:String = String.fromCString(addrbuf)! - if(addr_str != "-1.-1.-1.-1/-1") { - return zt_connect(Int32(fd), addr.to_sockaddr_in(), UInt32(addr.len())); - } - } - } - func bind(fd: Int32, _ addr: ZTAddress, _ nwid: String? = nil) -> Int32 { - if(nwid == nil) { // no nwid is provided to check for address, try once and fail - return zt_bind(Int32(fd), addr.to_sockaddr_in(), UInt32(addr.len())); - } - while(true) { // politely wait until an address is provided. simulates a blocking call - var addrbuf = [Int8](count: 16, repeatedValue: 0) - self.get_ipv4_address(nwid!, &addrbuf) - let addr_str:String = String.fromCString(addrbuf)! - if(addr_str != "-1.-1.-1.-1/-1") { - return zt_bind(Int32(fd), addr.to_sockaddr_in(), UInt32(addr.len())); - } - } - } - - func accept(fd: Int32, _ addr: ZTAddress) -> Int32 { - return zt_accept(Int32(fd), UnsafeMutablePointer([addr.data]), UnsafeMutablePointer([addr.len])); - } - - func listen(fd: Int32, _ backlog: Int16) -> Int32 { - return zt_listen(Int32(fd), Int32(backlog)); - } - func setsockopt(fd: Int32, _ level: Int32, _ optname: Int32, _ optval: UnsafePointer, _ optlen: Int32) -> Int32 { - return zt_setsockopt(fd, level, optname, optval, UInt32(optlen)); - } - - func getsockopt(fd: Int32, _ level: Int32, _ optname: Int32, _ optval: UnsafeMutablePointer, _ optlen: UInt32) -> Int32 { - return zt_getsockopt(fd, level, optname, optval, UnsafeMutablePointer([optlen])); - } - - func close(fd: Int32) -> Int32 { - return zt_close(fd); - } - - func getsockname(fd: Int32, _ addr: ZTAddress) -> Int32 { - return zt_getsockname(fd, UnsafeMutablePointer([addr.data]), UnsafeMutablePointer([addr.len])); - } - - func getpeername(fd: Int32, _ addr: ZTAddress) -> Int32 { - return zt_getpeername(fd, UnsafeMutablePointer([addr.data]), UnsafeMutablePointer([addr.len])); - } - - func fcntl(fd: Int32, _ cmd: Int32, _ flags: Int32) -> Int32 { - return zt_fcntl(fd, cmd, flags); - } - - func recvfrom(fd: Int32, _ buf: UnsafeMutablePointer, _ len: Int32, _ flags: Int32, _ addr: ZTAddress) -> Int32 { - return zt_recvfrom(fd, buf, Int(len), flags, UnsafeMutablePointer([addr.data]), UnsafeMutablePointer([addr.len])); - } - - func sendto(fd: Int32, _ buf: UnsafePointer, _ len: Int32, _ flags: Int32, _ addr: ZTAddress) -> Int32 { - return zt_sendto(fd, buf, Int(len), flags, addr.to_sockaddr_in(), UInt32(addr.len())); - } -} diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index aa2475a..0000000 --- a/tests/README.md +++ /dev/null @@ -1,79 +0,0 @@ -Testing -====== - - - - -### Unit Tests - -To build the API unit tests: - - `make tests` - -All necessary binaries and scripts will be built and copied into `build/tests`. - -Running `build/tests/test.sh` will execute the automatic API unit tests. - -*** - - - - -### Docker Unit Tests - -**Running all docker tests** - - - Build the docker images: `make docker_images` - - - Run the docker tests from the docker containers: `make docker_test` - - - Check the results of the completed tests: `make docker_test_check` - -Each unit test will temporarily copy all required ZeroTier binaries into its local directory, then build the `sdk_dockerfile` and `monitor_dockerfile`. Once built, each container will be run and perform tests and monitoring specified in `sdk_entrypoint.sh` and `monitor_entrypoint.sh` - -Results will be written to the `tests/docker/_results/` directory which is a common shared volume between all containers involved in the test and will be a combination of raw and formatted dumps to files whose names reflect the test performed. In the event of failure, `FAIL.` will be prepended to the result file's name (e.g. `FAIL.my_application_1.0.2.x86_64`), likewise in the event of success, `OK.` will be prepended. - -To run unit tests: - -1) Disable SELinux. This is so the containers can use a shared volume to exchange MD5 sums and address information. - -2) Set up your own network at [https://my.zerotier.com/](https://my.zerotier.com/). For our example we'll just use the Earth network (8056c2e21c000001). Use its network id as follows: - -3) Generate two pairs of identity keys. Each public/private pair will be used by the *sdk* and *monitor* containers: - - mkdir -p /tmp/sdk_first - cp -f ./sdk/liblwip.so /tmp/sdk_first - ./zerotier-sdk-service -d -p8100 /tmp/sdk_first - while [ ! -f /tmp/sdk_first/identity.secret ]; do - sleep 0.1 - done - ./zerotier-cli -D/tmp/sdk_first join 8056c2e21c000001 - kill `cat /tmp/sdk_first/zerotier-one.pid` - - mkdir -p /tmp/sdk_second - cp -f ./sdk/liblwip.so /tmp/sdk_second - ./zerotier-sdk-service -d -p8101 /tmp/sdk_second - while [ ! -f /tmp/sdk_second/identity.secret ]; do - sleep 0.1 - done - ./zerotier-cli -D/tmp/sdk_second join 8056c2e21c000001 - kill `cat /tmp/sdk_second/zerotier-one.pid` - -4) Copy the identity files to *tests/docker*. Names will be altered during copy step so the dockerfiles know which identities to use for each image/container: - - cp /tmp/sdk_first/identity.public ./sdk/tests/docker/sdk_identity.public - cp /tmp/sdk_first/identity.secret ./sdk/tests/docker/sdk_identity.secret - - cp /tmp/sdk_second/identity.public ./sdk/tests/docker/monitor_identity.public - cp /tmp/sdk_second/identity.secret ./sdk/tests/docker/monitor_identity.secret - - -5) Place a blank network config file in the `tests/docker` directory (e.g. "8056c2e21c000001.conf") - - This will be used to inform test-specific scripts what network to use for testing - -After you've created your network and placed its blank config file in `tests/docker` run the following to perform unit tests for httpd: - - ./build.sh httpd - ./test.sh httpd - -It's useful to note that the keyword *httpd* in this example is merely a substring for a test name, this means that if we replaced it with *x86_64*, *fc23*, or *nginx*, it would run all unit tests for *x86_64*, *Fedora 23*, or *nginx* respectively. - diff --git a/tests/api_test/clients.sh b/tests/api_test/clients.sh deleted file mode 100755 index 3e7497d..0000000 --- a/tests/api_test/clients.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -echo "\n\n\n\nStarting client(s)" - -# test.sh [udp|tcp|all] [nwid] -TEST_EXECUTABLE_PATH="build/tests" -protocol=$1 -NWID=$2 -HOME_DIR=$(pwd)/$TEST_EXECUTABLE_PATH -ZT_HOME_PATH=$(pwd)/$TEST_EXECUTABLE_PATH/zerotier - -BUILD_PATH=$(pwd)/build -localAddr="127.0.0.1" - -export ZT_NC_NETWORK=$ZT_HOME_PATH/nc_$NWID -export DYLD_LIBRARY_PATH=.$HOME_DIR/libztintercept.so - -echo "network = " $NWID -echo "protocol = " $protocol -echo "ZT_NC_NETWORK = " $ZT_NC_NETWORK -echo "ZT_NC_NETWORK = " $ZT_NC_NETWORK - -echo "ZT_HOME_PATH = " $ZT_HOME_PATH -echo "DYLD_LIBRARY_PATH = " $DYLD_LIBRARY_PATH - -# Start ZeroTier service -echo "Starting ZeroTier background service..." -mkdir -p $ZT_HOME_PATH/networks.d -touch $ZT_HOME_PATH/networks.d/$NWID.conf -$BUILD_PATH/zerotier-sdk-service -U -p$RANDOM $ZT_HOME_PATH & -zt_service_pid=$! - -if [ $protocol="tcp" ]; then - echo "Starting TCP test..." - random_tcp_server_port=$RANDOM - ./$TEST_EXECUTABLE_PATH/Darwin.tcp_server.out $random_tcp_server_port & - tcp_server_pid=$! - echo "TCP SERVER AT = " $localAddr ":" $random_tcp_server_port - sleep 3 - ./$TEST_EXECUTABLE_PATH/Darwin.tcp_client.out $localAddr $random_tcp_server_port & - tcp_client_pid=$! -fi - -echo "Waiting for test to conclude..." -sleep 5 -kill -9 $zt_service_PID $tcp_server_pid $tcp_client_pid diff --git a/tests/api_test/multiclient.c b/tests/api_test/multiclient.c deleted file mode 100644 index 4441bcb..0000000 --- a/tests/api_test/multiclient.c +++ /dev/null @@ -1,60 +0,0 @@ -// TCP Client test program - -#include -#include -#include -#include -#include - -int atoi(const char *str); -int close(int filedes); - -#define MSG_SZ 128 - -int main(int argc , char *argv[]) -{ - if(argc < 3) { - printf("usage: client \n"); - return 1; - } - - int sock, port = atoi(argv[2]); - struct sockaddr_in server; - char message[MSG_SZ] , server_reply[MSG_SZ]; - - sock = socket(AF_INET , SOCK_STREAM , 0); - if (sock == -1) { - printf("could not create socket"); - } - server.sin_addr.s_addr = inet_addr(argv[1]); - server.sin_family = AF_INET; - server.sin_port = htons( port ); - - printf("connecting...\n"); - if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) { - perror("connect failed. Error"); - return 1; - } - printf("\n\n\nconnected\n"); - - char *msg = "welcome to the machine!"; - - // TX - if(send(sock, msg, strlen(msg), 0) < 0) { - printf("send failed"); - return 1; - } - else { - printf("TX: %s\n", msg); - printf("len = %ld\n", strlen(msg)); - - int bytes_read = read(sock, server_reply, MSG_SZ); - if(bytes_read < 0) - printf("\tRX: Nothing\n"); - else - printf("\tRX = (%d bytes): %s\n", bytes_read, server_reply); - } - - close(sock); - return 0; -} diff --git a/tests/api_test/multiserve.c b/tests/api_test/multiserve.c deleted file mode 100644 index 250d626..0000000 --- a/tests/api_test/multiserve.c +++ /dev/null @@ -1,66 +0,0 @@ -// TCP Server test program - -#include -#include -#include -#include -#include - -int atoi(const char *str); - -int main(int argc , char *argv[]) -{ - if(argc < 2) { - printf("usage: tcp_server \n"); - return 0; - } - - int sock, client_sock, c, read_size, port = atoi(argv[1]); - char client_message[2000]; - - char str[100]; - int comm_fd; - - struct sockaddr_in servaddr; - struct sockaddr_in client; - - sock = socket(AF_INET, SOCK_STREAM, 0); - bzero( &servaddr, sizeof(servaddr)); - - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htons(INADDR_ANY); - servaddr.sin_port = htons(port); - bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)); - - printf("listening\n"); - listen(sock , 3); - printf("waiting to accept\n"); - c = sizeof(struct sockaddr_in); - - - while(1) - { - client_sock = accept(sock, (struct sockaddr *)&client, (socklen_t*)&c); - if (client_sock < 0) { - perror("accept failed"); - return 0; - } - printf("\n\n\nconnection accepted\n reading...\n"); - - // RX - - int msglen = 1024; - unsigned long count = 0; - - int bytes_read = read(client_sock, client_message, msglen); - printf("[%lu] RX = (%d): ", count, bytes_read); - for(int i=0; i -#include -#include -#include -#include - -#define MSGSZ 1024 - -int atoi(const char *str); -int close(int filedes); - -int main(int argc , char *argv[]) -{ - if(argc < 3) { - printf("usage: client \n"); - return 1; - } - - int sock, port = atoi(argv[2]); - struct sockaddr_in server; - char message[MSGSZ] , server_reply[MSGSZ]; - - sock = socket(AF_INET , SOCK_STREAM , 0); - if (sock == -1) { - printf("could not create socket"); - } - server.sin_addr.s_addr = inet_addr(argv[1]); - server.sin_family = AF_INET; - server.sin_port = htons( port ); - - printf("connecting...\n"); - if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) { - perror("connect failed. Error"); - return 1; - } - printf("connected\n"); - - memset(message, 1, MSGSZ); - - while(1) - { - //sleep(1); - // TX - if(send(sock, message, MSGSZ, 0) < 0) { - printf("send failed"); - return 1; - } - else { - printf("TX: %s\n", message); - printf("len = %ld\n", strlen(message)); - - int bytes_read = read(sock, server_reply, MSGSZ); - if(bytes_read < 0) - printf("\tRX: Nothing\n"); - else - printf("\tRX = (%d bytes): %s\n", bytes_read, server_reply); - } - } - close(sock); - return 0; -} diff --git a/tests/api_test/pressureserver4.c b/tests/api_test/pressureserver4.c deleted file mode 100644 index 827c6ea..0000000 --- a/tests/api_test/pressureserver4.c +++ /dev/null @@ -1,67 +0,0 @@ -// TCP Server test program - -#include -#include -#include -#include -#include - - -#define MSGSZ 1024 - -int atoi(const char *str); - -int main(int argc , char *argv[]) -{ - if(argc < 2) { - printf("usage: tcp_server \n"); - return 0; - } - - int sock, client_sock, c, read_size, port = atoi(argv[1]); - char message[MSGSZ]; - - char str[MSGSZ]; - int comm_fd; - - struct sockaddr_in servaddr; - struct sockaddr_in client; - - sock = socket(AF_INET, SOCK_STREAM, 0); - bzero( &servaddr, sizeof(servaddr)); - - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htons(INADDR_ANY); - servaddr.sin_port = htons(port); - bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)); - - printf("listening\n"); - listen(sock , 3); - printf("waiting to accept\n"); - c = sizeof(struct sockaddr_in); - - client_sock = accept(sock, (struct sockaddr *)&client, (socklen_t*)&c); - if (client_sock < 0) { - perror("accept failed"); - return 0; - } - printf("connection accepted\n reading...\n"); - - // RX - - unsigned long count = 0; - while(1) - { - count++; - int bytes_read = read(client_sock, message, MSGSZ); - printf("[%lu] RX = (%d): ", count, bytes_read); - //for(int i=0; i $TEST_EXECUTABLE_PATH/tcp_server.port - ./$TEST_EXECUTABLE_PATH/$PLATFORM.tcp_server.out $random_tcp_server_port & - tcp_server_pid=$! - - # echo "TCP SERVER AT = " $localAddr ":" $random_tcp_server_port - # sleep 3 - # ./$TEST_EXECUTABLE_PATH/$PLATFORM.tcp_client.out $localAddr $random_tcp_server_port & - # tcp_client_pid=$! -fi - -echo "Waiting for test to conclude..." -echo $random_tcp_server_port -# ,$random_udp_server_port -sleep 10 -echo "Cleaning up" -kill -9 $zt_service_PID $tcp_server_pid $tcp_client_pid diff --git a/tests/api_test/tcpclient4.c b/tests/api_test/tcpclient4.c deleted file mode 100644 index cf4b345..0000000 --- a/tests/api_test/tcpclient4.c +++ /dev/null @@ -1,62 +0,0 @@ -// TCP Client test program - -#include -#include -#include -#include -#include - -int atoi(const char *str); -int close(int filedes); - -#define MSG_SZ 128 - -int main(int argc , char *argv[]) -{ - if(argc < 3) { - printf("usage: client \n"); - return 1; - } - - int sock, port = atoi(argv[2]); - struct sockaddr_in server; - char message[MSG_SZ] , server_reply[MSG_SZ]; - - sock = socket(AF_INET , SOCK_STREAM , 0); - if (sock == -1) { - printf("could not create socket"); - } - server.sin_addr.s_addr = inet_addr(argv[1]); - server.sin_family = AF_INET; - server.sin_port = htons( port ); - - printf("connecting...\n"); - if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) { - perror("connect failed. Error"); - return 1; - } - printf("connected\n"); - - char *msg = "welcome to the machine!"; - - while(1) - { - // TX - if(send(sock, msg, strlen(msg), 0) < 0) { - printf("send failed"); - return 1; - } - else { - printf("TX: %s\n", msg); - printf("len = %ld\n", strlen(msg)); - - int bytes_read = read(sock, server_reply, MSG_SZ); - if(bytes_read < 0) - printf("\tRX: Nothing\n"); - else - printf("\tRX = (%d bytes): %s\n", bytes_read, server_reply); - } - } - close(sock); - return 0; -} diff --git a/tests/api_test/tcpclient6.c b/tests/api_test/tcpclient6.c deleted file mode 100644 index a4aadd4..0000000 --- a/tests/api_test/tcpclient6.c +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include - -void error(char *msg) { - perror(msg); - exit(0); -} - -int main(int argc, char *argv[]) { - int sockfd, portno, n; - struct sockaddr_in6 serv_addr; - struct hostent *server; - char buffer[256] = "This is a string from client!"; - - if (argc < 3) { - fprintf(stderr, "Usage: %s \n", argv[0]); - exit(0); - } - portno = atoi(argv[2]); - - printf("\nIPv6 TCP Client Started...\n"); - - //Sockets Layer Call: socket() - sockfd = socket(AF_INET6, SOCK_STREAM, 0); - if (sockfd < 0) - error("ERROR opening socket"); - - //Sockets Layer Call: gethostbyname2() - server = gethostbyname2(argv[1],AF_INET6); - if (server == NULL) { - fprintf(stderr, "ERROR, no such host\n"); - exit(0); - } - - memset((char *) &serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin6_flowinfo = 0; - serv_addr.sin6_family = AF_INET6; - memmove((char *) &serv_addr.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length); - serv_addr.sin6_port = htons(portno); - - //Sockets Layer Call: connect() - if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) - error("ERROR connecting"); - - - //Sockets Layer Call: send() - n = send(sockfd,buffer, strlen(buffer)+1, 0); - if (n < 0) - error("ERROR writing to socket"); - - printf("sent %d bytes\n", n); - memset(buffer, 0, 256); - - //Sockets Layer Call: recv() - printf("reading...\n"); - n = recv(sockfd, buffer, 255, 0); - if (n < 0) - error("ERROR reading from socket"); - printf("Message from server: %s\n", buffer); - - //Sockets Layer Call: close() - close(sockfd); - - return 0; -} \ No newline at end of file diff --git a/tests/api_test/tcpserver4.c b/tests/api_test/tcpserver4.c deleted file mode 100644 index 0472f37..0000000 --- a/tests/api_test/tcpserver4.c +++ /dev/null @@ -1,62 +0,0 @@ -// TCP Server test program - -#include -#include -#include -#include -#include - -int atoi(const char *str); - -int main(int argc , char *argv[]) -{ - if(argc < 2) { - printf("usage: tcp_server \n"); - return 0; - } - - int comm_fd, sock, client_sock, c, read_size, port = atoi(argv[1]); - char client_message[2000]; - - struct sockaddr_in servaddr; - struct sockaddr_in client; - - sock = socket(AF_INET, SOCK_STREAM, 0); - bzero( &servaddr, sizeof(servaddr)); - - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htons(INADDR_ANY); - servaddr.sin_port = htons(port); - bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)); - - printf("listening\n"); - listen(sock , 3); - printf("waiting to accept\n"); - c = sizeof(struct sockaddr_in); - - client_sock = accept(sock, (struct sockaddr *)&client, (socklen_t*)&c); - if (client_sock < 0) { - perror("accept failed"); - return 0; - } - printf("connection accepted\n reading...\n"); - - // RX - - int msglen = 1024; - unsigned long count = 0; - while(1) - { - count++; - int bytes_read = read(client_sock, client_message, msglen); - printf("[%lu] RX = (%d): ", count, bytes_read); - for(int i=0; i -#include -#include -#include - -#include -#include -#include -#include - -#include - -void error(char *msg) { - perror(msg); - exit(1); -} - -int main(int argc, char *argv[]) { - int sockfd, newsockfd, portno; - socklen_t clilen; - char buffer[256]; - struct sockaddr_in6 serv_addr, cli_addr; - int n; - char client_addr_ipv6[100]; - - if (argc < 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); - exit(0); - } - - printf("\nIPv6 TCP Server Started...\n"); - - //Sockets Layer Call: socket() - sockfd = socket(AF_INET6, SOCK_STREAM, 0); - if (sockfd < 0) - error("ERROR opening socket"); - - bzero((char *) &serv_addr, sizeof(serv_addr)); - portno = atoi(argv[1]); - serv_addr.sin6_flowinfo = 0; - serv_addr.sin6_family = AF_INET6; - serv_addr.sin6_addr = in6addr_any; - serv_addr.sin6_port = htons(portno); - - - //Sockets Layer Call: bind() - if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) - error("ERROR on binding"); - - //Sockets Layer Call: listen() - listen(sockfd, 5); - clilen = sizeof(cli_addr); - - //Sockets Layer Call: accept() - newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); - if (newsockfd < 0) - error("ERROR on accept"); - - //Sockets Layer Call: inet_ntop() - inet_ntop(AF_INET6, &(cli_addr.sin6_addr),client_addr_ipv6, 100); - printf("Incoming connection from client having IPv6 address: %s\n",client_addr_ipv6); - - memset(buffer,0, 256); - - //Sockets Layer Call: recv() - n = recv(newsockfd, buffer, 255, 0); - if (n < 0) - error("ERROR reading from socket"); - - printf("Message from client: %s\n", buffer); - - //Sockets Layer Call: send() - printf("sending...\n"); - n = send(newsockfd, "Server got your message", 23+1, 0); - if (n < 0) - error("ERROR writing to socket"); - - //Sockets Layer Call: close() - close(sockfd); - close(newsockfd); - - return 0; -} diff --git a/tests/api_test/test.sh b/tests/api_test/test.sh deleted file mode 100755 index 5c171eb..0000000 --- a/tests/api_test/test.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -echo "Performing unit tests..." - -chmod 755 build/tests/servers.sh -chmod 755 build/tests/clients.sh - -./servers.sh $1 $2 $3 & -sleep 3 -./clients.sh $1 $2 $3 & diff --git a/tests/api_test/udpclient4.c b/tests/api_test/udpclient4.c deleted file mode 100755 index 663e69c..0000000 --- a/tests/api_test/udpclient4.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * udpclient.c - A simple UDP client - * usage: udpclient - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BUFSIZE 1024 - -/* - * error - wrapper for perror - */ -void error(char *msg) { - perror(msg); - exit(0); -} - -int main(int argc, char **argv) { - int sock, portno, n; - int serverlen; - struct sockaddr_in serveraddr; - struct hostent *server; - char *hostname; - char buf[BUFSIZE]; - - /* check command line arguments */ - if (argc != 3) { - fprintf(stderr,"usage: %s \n", argv[0]); - exit(0); - } - hostname = argv[1]; - portno = atoi(argv[2]); - - /* socket: create the socket */ - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) - error("ERROR opening socket"); - - /* gethostbyname: get the server's DNS entry */ - server = gethostbyname(hostname); - if (server == NULL) { - fprintf(stderr,"ERROR, no such host as %s\n", hostname); - exit(0); - } - - /* build the server's Internet address */ - bzero((char *) &serveraddr, sizeof(serveraddr)); - serveraddr.sin_family = AF_INET; - bcopy((char *)server->h_addr, - (char *)&serveraddr.sin_addr.s_addr, server->h_length); - serveraddr.sin_port = htons(portno); - - /* get a message from the user */ - char *msg = "A message to the server!\0"; - fcntl(sock, F_SETFL, O_NONBLOCK); - long count = 0; - while(1) - { - count++; - printf("\n\n\nTX(%lu)...\n", count); - sleep(1); - //usleep(10000); - //bzero(buf, BUFSIZE); - //printf("\nPlease enter msg: "); - //fgets(buf, BUFSIZE, stdin); - - /* send the message to the server */ - serverlen = sizeof(serveraddr); - n = sendto(sock, msg, strlen(msg), 0, (struct sockaddr *)&serveraddr, serverlen); - //if (n < 0) - // error("ERROR in sendto"); - - /* print the server's reply */ - memset(buf, 0, sizeof(buf)); - n = recvfrom(sock, buf, BUFSIZE, 0, (struct sockaddr *)&serveraddr, (socklen_t *)&serverlen); - //if (n < 0) - // printf("ERROR in recvfrom: %d", n); - printf("Echo from server: %s", buf); - } - return 0; -} diff --git a/tests/api_test/udpclient6.c b/tests/api_test/udpclient6.c deleted file mode 100755 index 36607fa..0000000 --- a/tests/api_test/udpclient6.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAXBUF 65536 - -int main(int argc, char* argv[]) -{ - int status; - struct addrinfo sainfo, *psinfo; - struct hostent *server; - char buffer[MAXBUF]; - - int sock, portno, n; - struct sockaddr_in6 serv_addr; - - if(argc < 2) - printf("Specify a port number\n"), exit(1); - - sock = socket(PF_INET6, SOCK_DGRAM,0); - - portno = atoi(argv[2]); - server = gethostbyname2(argv[1],AF_INET6); - memset((char *) &serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin6_flowinfo = 0; - serv_addr.sin6_family = AF_INET6; - memmove((char *) &serv_addr.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length); - serv_addr.sin6_port = htons(portno); - - sprintf(buffer,"Ciao"); - - status = sendto(sock, buffer, strlen(buffer), 0, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)); - printf("buffer : %s \t%d\n", buffer, status); - - close(sock); - return 0; -} \ No newline at end of file diff --git a/tests/api_test/udpserver4.c b/tests/api_test/udpserver4.c deleted file mode 100755 index 2280435..0000000 --- a/tests/api_test/udpserver4.c +++ /dev/null @@ -1,86 +0,0 @@ -// UDP Server test program - -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAXBUF 1024*1024 - -void echo(int sock) { - char bufin[MAXBUF]; - struct sockaddr_in remote; - int n; - socklen_t len = sizeof(remote); - long count = 0; - - while (1) { - sleep(1); - //usleep(50); - count++; - // read a datagram from the socket (put result in bufin) - n=recvfrom(sock,bufin,MAXBUF,0,(struct sockaddr *)&remote,&len); - // print out the address of the sender - printf("DGRAM from %s:%d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port)); - - if (n<0) { - perror("Error receiving data"); - } else { - printf("GOT %d BYTES (count = %ld)\n", n, count); - // Got something, just send it back - // sendto(sock,bufin,n,0,(struct sockaddr *)&remote,len); - printf("RX = %s\n", bufin); - } - } -} - -int main(int argc, char *argv[]) { - - if(argc < 2) { - printf("usage: udp_server \n"); - return 0; - } - int sock, port = atoi(argv[1]); - socklen_t len; - struct sockaddr_in skaddr; - struct sockaddr_in skaddr2; - - // Create socket - if ((sock = socket( PF_INET, SOCK_DGRAM, 0)) < 0) { - printf("error creating socket\n"); - return 0; - } - // Create address - skaddr.sin_family = AF_INET; - skaddr.sin_addr.s_addr = htonl(INADDR_ANY); - skaddr.sin_port = htons(port); - // Bind to address - if (bind(sock, (struct sockaddr *) &skaddr, sizeof(skaddr))<0) { - printf("error binding\n"); - return 0; - } - // find out what port we were assigned - len = sizeof( skaddr2 ); - //if (getsockname(sock, (struct sockaddr *) &skaddr2, &len)<0) { - // printf("error getsockname\n"); - // return 0; - //} - // Display address:port to verify it was sent over RPC correctly - /* - port = ntohs(skaddr2.sin_port); - int ip = skaddr2.sin_addr.s_addr; - unsigned char d[4]; - d[0] = ip & 0xFF; - d[1] = (ip >> 8) & 0xFF; - d[2] = (ip >> 16) & 0xFF; - d[3] = (ip >> 24) & 0xFF; - printf("bound to address: %d.%d.%d.%d : %d\n", d[0],d[1],d[2],d[3], port); - */ - // RX - echo(sock); - return(0); -} diff --git a/tests/api_test/udpserver6.c b/tests/api_test/udpserver6.c deleted file mode 100755 index 4ed977b..0000000 --- a/tests/api_test/udpserver6.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAXBUF 65536 - -int main(int argc, char *argv[]) -{ - int sock; - int n; - struct sockaddr_in6 sin6; - socklen_t sin6len; - char buffer[MAXBUF]; - - sock = socket(PF_INET6, SOCK_DGRAM,0); - sin6len = sizeof(struct sockaddr_in6); - memset(&sin6, 0, sin6len); - - sin6.sin6_port = htons(atoi(argv[1])); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = in6addr_any; - - n = bind(sock, (struct sockaddr *)&sin6, sin6len); - if(-1 == n) - perror("bind"), exit(1); - - //n = getsockname(sock, (struct sockaddr *)&sin6, &sin6len); - //printf("%d\n", ntohs(sin6.sin6_port)); - - while (1) { - sleep(1); - n = recvfrom(sock, buffer, MAXBUF, 0, (struct sockaddr *)&sin6, &sin6len); - printf("n = %d, buffer : %s\n", n, buffer); - } - - shutdown(sock, 2); - close(sock); - return 0; -} \ No newline at end of file diff --git a/tests/cleanup.sh b/tests/cleanup.sh deleted file mode 100755 index 4a79b7a..0000000 --- a/tests/cleanup.sh +++ /dev/null @@ -1,11 +0,0 @@ -killall zerotier-sdk-service - -killall Darwin.tcp_server.out -killall Darwin.tcp_client.out -killall Darwin.udp_server.out -killall Darwin.udp_client.out - -killall Linux.tcp_server.out -killall Linux.tcp_client.out -killall Linux.udp_server.out -killall Linux.udp_client.out \ No newline at end of file diff --git a/tests/docker/_remove_all.sh b/tests/docker/_remove_all.sh deleted file mode 100755 index c6090a9..0000000 --- a/tests/docker/_remove_all.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# Delete all containers -docker rm $(docker ps -a -q) -# Delete all images -docker rmi $(docker images -q) diff --git a/tests/docker/_two_party_test.sh b/tests/docker/_two_party_test.sh deleted file mode 100755 index 461157a..0000000 --- a/tests/docker/_two_party_test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# Runs test image and monitor image as daemons -test_name=${PWD##*/} -echo 'Starting containers for: ' "$test_name" -touch "$test_name".name -test_container=$(docker run -d -it -v $PWD/../../_results:/opt/results --device=/dev/net/tun "$test_name":latest) -monitor_container=$(docker run -d -it -v $PWD/../../_results:/opt/results --device=/dev/net/tun "$test_name"_monitor:latest) - -echo "waiting $sdk_test_wait_time for test to complete." -sleep $sdk_test_wait_time -docker stop $(docker ps -a -q) -docker rm $test_container -docker rm $monitor_container - -rm -f *.name \ No newline at end of file diff --git a/tests/docker/build_images.sh b/tests/docker/build_images.sh deleted file mode 100755 index 2a20748..0000000 --- a/tests/docker/build_images.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# Merely BUILDS test images - -# Remove previous test results -rm _results/*.txt - -# How long we shall wait for each test to conclude -export sdk_test_wait_time=60s -export image_build_script=_build_single_image.sh - -# Iterate over all depth=2 (relatively-speaking) directories and perform each test -find . -mindepth 2 -maxdepth 2 -type d | while read testdir; do - - if [[ $testdir != *$1* ]] - then - continue - fi - - echo "\n\n\n*** Building: '$testdir'..." - rm _results/*.tmp - - # Stage scripts - cp $image_build_script $testdir/$image_build_script - cd $testdir - - # Build test docker images - ./$image_build_script - rm $image_build_script - - cd ../../ -done diff --git a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/_build_single_image.sh b/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/_build_single_image.sh deleted file mode 100755 index d2fe99d..0000000 --- a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/_build_single_image.sh +++ /dev/null @@ -1,30 +0,0 @@ -# Builds a test docker image - -test_name=${PWD##*/} -echo 'Building dockerfiles for test: ' "$test_name" -touch "$test_name".name - -# Docker won't allow the inclusion of files outside of the build directory -cp ../../*.conf . -cp ../../zerotier-one zerotier-one -cp ../../zerotier-cli zerotier-cli -cp ../../zerotier-cli zerotier-sdk-service -cp ../../zerotier-intercept zerotier-intercept -cp ../../libztintercept.so libztintercept.so -cp ../../liblwip.so liblwip.so -cp ../../sdk_identity.public sdk_identity.public -cp ../../sdk_identity.secret sdk_identity.secret -cp ../../monitor_identity.public monitor_identity.public -cp ../../monitor_identity.secret monitor_identity.secret - -docker build --tag="$test_name" -f sdk_dockerfile . -docker build --tag="$test_name"_monitor -f monitor_dockerfile . - -rm -f zerotier-cli -rm -f zerotier-sdk-service -rm -f zerotier-intercept -rm -f *.so -rm -f *.public -rm -f *.secret -rm -f *.conf -rm -f *.name \ No newline at end of file diff --git a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/_two_party_test.sh b/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/_two_party_test.sh deleted file mode 100755 index 461157a..0000000 --- a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/_two_party_test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# Runs test image and monitor image as daemons -test_name=${PWD##*/} -echo 'Starting containers for: ' "$test_name" -touch "$test_name".name -test_container=$(docker run -d -it -v $PWD/../../_results:/opt/results --device=/dev/net/tun "$test_name":latest) -monitor_container=$(docker run -d -it -v $PWD/../../_results:/opt/results --device=/dev/net/tun "$test_name"_monitor:latest) - -echo "waiting $sdk_test_wait_time for test to complete." -sleep $sdk_test_wait_time -docker stop $(docker ps -a -q) -docker rm $test_container -docker rm $monitor_container - -rm -f *.name \ No newline at end of file diff --git a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/darkhttpd-1.11.x86_64.name b/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/darkhttpd-1.11.x86_64.name deleted file mode 100644 index e69de29..0000000 diff --git a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/monitor_dockerfile b/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/monitor_entrypoint.sh b/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/monitor_entrypoint.sh deleted file mode 100644 index 3e94118..0000000 --- a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/monitor_entrypoint.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=35 # wait for test container to come online -app_timeout_time=25 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -rm -rf "$file_path"*."$file_base" -touch "$bigfile_name" - -# Perform test -# curl --connect-timeout "$app_timeout_time" -v -o "$file_path$file_base" http://"$ncvirtip"/index.html -# Large transfer test -curl --connect-timeout "$app_timeout_time" -v -o "$bigfile_name" http://"$ncvirtip"/"$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" > "$rx_md5sumfile" -rx_md5sum=$(<$rx_md5sumfile) -tx_md5sum=$(<$tx_md5sumfile) - -echo '*** Comparing md5: ' "$rx_md5sum" ' and ' "$tx_md5sum" - -if [ "$rx_md5sum" != "$tx_md5sum" ]; -then - echo 'MD5 FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: md5 sum did not match!\n' >> "$file_path$fail$test_name.txt" -else - echo 'MD5 OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: md5 sum ok!\n' >> "$file_path$ok$test_name.txt" - cat "$rx_md5sumfile" >> "$file_path$ok$test_name.txt" - cat "$tx_md5sumfile" >> "$file_path$ok$test_name.txt" -fi - - - - - - - - - - - diff --git a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/sdk_dockerfile b/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/sdk_dockerfile deleted file mode 100644 index 2505279..0000000 --- a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/sdk_dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install darkhttpd-1.11 -RUN yum clean all - -EXPOSE 9993/udp 80/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -ADD zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/sdk_entrypoint.sh b/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/sdk_entrypoint.sh deleted file mode 100644 index dee9c46..0000000 --- a/tests/docker/darkhttpd/darkhttpd-1.11.x86_64/sdk_entrypoint.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '--- Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of="$bigfile_name" bs="$bigfile_size" count=1 -md5sum < "$bigfile_name" > "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -darkhttpd / diff --git a/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/monitor_dockerfile b/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/monitor_entrypoint.sh b/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/monitor_entrypoint.sh deleted file mode 100644 index 3e94118..0000000 --- a/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/monitor_entrypoint.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=35 # wait for test container to come online -app_timeout_time=25 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -rm -rf "$file_path"*."$file_base" -touch "$bigfile_name" - -# Perform test -# curl --connect-timeout "$app_timeout_time" -v -o "$file_path$file_base" http://"$ncvirtip"/index.html -# Large transfer test -curl --connect-timeout "$app_timeout_time" -v -o "$bigfile_name" http://"$ncvirtip"/"$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" > "$rx_md5sumfile" -rx_md5sum=$(<$rx_md5sumfile) -tx_md5sum=$(<$tx_md5sumfile) - -echo '*** Comparing md5: ' "$rx_md5sum" ' and ' "$tx_md5sum" - -if [ "$rx_md5sum" != "$tx_md5sum" ]; -then - echo 'MD5 FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: md5 sum did not match!\n' >> "$file_path$fail$test_name.txt" -else - echo 'MD5 OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: md5 sum ok!\n' >> "$file_path$ok$test_name.txt" - cat "$rx_md5sumfile" >> "$file_path$ok$test_name.txt" - cat "$tx_md5sumfile" >> "$file_path$ok$test_name.txt" -fi - - - - - - - - - - - diff --git a/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/sdk_dockerfile b/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/sdk_dockerfile deleted file mode 100644 index 8a19682..0000000 --- a/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/sdk_dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install httpd-2.4.16-1.fc23.x86_64 -RUN yum clean all - -EXPOSE 9993/udp 80/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -ADD zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/sdk_entrypoint.sh b/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/sdk_entrypoint.sh deleted file mode 100644 index 7b4fea1..0000000 --- a/tests/docker/httpd/httpd-2.4.16-1.fc23.x86_64/sdk_entrypoint.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '--- Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of=/var/www/html/"$bigfile_name" bs="$bigfile_size" count=1 -md5sum < /var/www/html/"$bigfile_name" > "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 -rm -rf /run/httpd/* /tmp/httpd* - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -/usr/sbin/httpd -X diff --git a/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/monitor_dockerfile b/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/monitor_entrypoint.sh b/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/monitor_entrypoint.sh deleted file mode 100644 index 3e94118..0000000 --- a/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/monitor_entrypoint.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=35 # wait for test container to come online -app_timeout_time=25 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -rm -rf "$file_path"*."$file_base" -touch "$bigfile_name" - -# Perform test -# curl --connect-timeout "$app_timeout_time" -v -o "$file_path$file_base" http://"$ncvirtip"/index.html -# Large transfer test -curl --connect-timeout "$app_timeout_time" -v -o "$bigfile_name" http://"$ncvirtip"/"$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" > "$rx_md5sumfile" -rx_md5sum=$(<$rx_md5sumfile) -tx_md5sum=$(<$tx_md5sumfile) - -echo '*** Comparing md5: ' "$rx_md5sum" ' and ' "$tx_md5sum" - -if [ "$rx_md5sum" != "$tx_md5sum" ]; -then - echo 'MD5 FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: md5 sum did not match!\n' >> "$file_path$fail$test_name.txt" -else - echo 'MD5 OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: md5 sum ok!\n' >> "$file_path$ok$test_name.txt" - cat "$rx_md5sumfile" >> "$file_path$ok$test_name.txt" - cat "$tx_md5sumfile" >> "$file_path$ok$test_name.txt" -fi - - - - - - - - - - - diff --git a/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/sdk_dockerfile b/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/sdk_dockerfile deleted file mode 100644 index 66d3f81..0000000 --- a/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/sdk_dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -# ZT SDK Test -FROM ubuntu:14.04 -MAINTAINER https://www.zerotier.com/ - -RUN \ - sed -i 's/# \(.*multiverse$\)/\1/g' /etc/apt/sources.list && \ - apt-get update && \ - apt-get -y upgrade && \ - apt-get -y install apache2 - -EXPOSE 9993/udp 80/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -ADD zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/sdk_entrypoint.sh b/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/sdk_entrypoint.sh deleted file mode 100644 index 7b4fea1..0000000 --- a/tests/docker/httpd/httpd-2.4.16-1.ub14.x86_64/sdk_entrypoint.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '--- Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of=/var/www/html/"$bigfile_name" bs="$bigfile_size" count=1 -md5sum < /var/www/html/"$bigfile_name" > "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 -rm -rf /run/httpd/* /tmp/httpd* - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -/usr/sbin/httpd -X diff --git a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/_two_party_test.sh b/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/_two_party_test.sh deleted file mode 100755 index 461157a..0000000 --- a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/_two_party_test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# Runs test image and monitor image as daemons -test_name=${PWD##*/} -echo 'Starting containers for: ' "$test_name" -touch "$test_name".name -test_container=$(docker run -d -it -v $PWD/../../_results:/opt/results --device=/dev/net/tun "$test_name":latest) -monitor_container=$(docker run -d -it -v $PWD/../../_results:/opt/results --device=/dev/net/tun "$test_name"_monitor:latest) - -echo "waiting $sdk_test_wait_time for test to complete." -sleep $sdk_test_wait_time -docker stop $(docker ps -a -q) -docker rm $test_container -docker rm $monitor_container - -rm -f *.name \ No newline at end of file diff --git a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/httpd-2.4.18-1.fc23.x86_64.name b/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/httpd-2.4.18-1.fc23.x86_64.name deleted file mode 100644 index e69de29..0000000 diff --git a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/monitor_dockerfile b/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/monitor_entrypoint.sh b/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/monitor_entrypoint.sh deleted file mode 100644 index 3e94118..0000000 --- a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/monitor_entrypoint.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=35 # wait for test container to come online -app_timeout_time=25 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -rm -rf "$file_path"*."$file_base" -touch "$bigfile_name" - -# Perform test -# curl --connect-timeout "$app_timeout_time" -v -o "$file_path$file_base" http://"$ncvirtip"/index.html -# Large transfer test -curl --connect-timeout "$app_timeout_time" -v -o "$bigfile_name" http://"$ncvirtip"/"$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" > "$rx_md5sumfile" -rx_md5sum=$(<$rx_md5sumfile) -tx_md5sum=$(<$tx_md5sumfile) - -echo '*** Comparing md5: ' "$rx_md5sum" ' and ' "$tx_md5sum" - -if [ "$rx_md5sum" != "$tx_md5sum" ]; -then - echo 'MD5 FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: md5 sum did not match!\n' >> "$file_path$fail$test_name.txt" -else - echo 'MD5 OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: md5 sum ok!\n' >> "$file_path$ok$test_name.txt" - cat "$rx_md5sumfile" >> "$file_path$ok$test_name.txt" - cat "$tx_md5sumfile" >> "$file_path$ok$test_name.txt" -fi - - - - - - - - - - - diff --git a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/sdk_dockerfile b/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/sdk_dockerfile deleted file mode 100644 index 0f12261..0000000 --- a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/sdk_dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install httpd-2.4.18-1.fc23.x86_64 -RUN yum clean all - -EXPOSE 9993/udp 80/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -ADD zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/sdk_entrypoint.sh b/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/sdk_entrypoint.sh deleted file mode 100644 index 314bdc2..0000000 --- a/tests/docker/httpd/httpd-2.4.18-1.fc23.x86_64/sdk_entrypoint.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of=/var/www/html/"$bigfile_name" bs="$bigfile_size" count=1 -#md5sum /var/www/html/"$bigfile_name" >> "$tx_md5sumfile" -md5sum < /var/www/html/"$bigfile_name" > "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 -rm -rf /run/httpd/* /tmp/httpd* - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -/usr/sbin/httpd -X diff --git a/tests/docker/httpd/httpd_demo/htdocs/ZeroTierIcon.png b/tests/docker/httpd/httpd_demo/htdocs/ZeroTierIcon.png deleted file mode 100644 index 4d9641b344329a3790f94206d012f2a9ce2e0750..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26898 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 diff --git a/tests/docker/httpd/httpd_demo/htdocs/index.html b/tests/docker/httpd/httpd_demo/htdocs/index.html deleted file mode 100644 index 5e57aa0..0000000 --- a/tests/docker/httpd/httpd_demo/htdocs/index.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - ZeroTier SDK Preview - - - -

- -
-
-
-
-

ZeroTier SDK Preview

- (a.k.a. super bleeding edge pre-alphe pre-release demo) -
-
-
- -
-
-
- -
- -
- - - diff --git a/tests/docker/httpd/httpd_demo/monitor_dockerfile b/tests/docker/httpd/httpd_demo/monitor_dockerfile deleted file mode 100644 index 587a85a..0000000 --- a/tests/docker/httpd/httpd_demo/monitor_dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / -ADD zerotier-one / -ADD zerotier-cli / - -# Install LWIP library used by service -ADD liblwip.so / -RUN mkdir -p ext/bin/lwip -RUN cp liblwip.so ext/bin/lwip/liblwip.so - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/httpd/httpd_demo/monitor_entrypoint.sh b/tests/docker/httpd/httpd_demo/monitor_entrypoint.sh deleted file mode 100644 index 017abbc..0000000 --- a/tests/docker/httpd/httpd_demo/monitor_entrypoint.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=25 # wait for test container to come online -app_timeout_time=15 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -echo '*** Waiting for initial identity generation...' -while [ ! -s /var/lib/zerotier-one/identity.secret ]; do - sleep 0.2 -done -echo '*** Waiting for network config...' -virtip4="" -while [ ! -s /var/lib/zerotier-one/networks.d/"$nwconf" ]; do - sleep 0.2 -done -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -rm -rf "$file_path"*."$file_base" -touch "$bigfile_name" - -# Perform test -# curl --connect-timeout "$app_timeout_time" -v -o "$file_path$file_base" http://"$ncvirtip"/index.html -# Large transfer test -curl --connect-timeout "$app_timeout_time" -v -o "$bigfile_name" http://"$ncvirtip"/"$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" >> "$rx_md5sumfile" -rx_md5sum=$(<$rx_md5sumfile) -tx_md5sum=$(<$tx_md5sumfile) - -echo '*** Comparing md5: ' "$rx_md5sum" ' and ' "$tx_md5sum" - -if [ $rx_md5sum != $tx_md5sum ]; -then - echo 'MD5 FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: md5 sum did not match!\n' >> "$file_path$fail$test_name.txt" -else - echo 'MD5 OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: md5 sum ok!\n' >> "$file_path$ok$test_name.txt" -fi - - - - - - - - - - - diff --git a/tests/docker/httpd/httpd_demo/sdk_dockerfile b/tests/docker/httpd/httpd_demo/sdk_dockerfile deleted file mode 100644 index 8d3180a..0000000 --- a/tests/docker/httpd/httpd_demo/sdk_dockerfile +++ /dev/null @@ -1,42 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install httpd-2.4.17-3.fc23.x86_64 -RUN yum clean all - -EXPOSE 9993/udp - -#include Apache -ADD htdocs/index.html / -ADD htdocs/ZeroTierIcon.png / -RUN mv index.html /var/www/html/index.html -RUN mv ZeroTierIcon.png /var/www/html/ZeroTierIcon.png - -# Install syscall intercept library -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -ADD zerotier-cli / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Install LWIP library used by service -ADD liblwip.so / -RUN mkdir -p ext/bin/lwip -RUN cp liblwip.so ext/bin/lwip/liblwip.so - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/httpd/httpd_demo/sdk_entrypoint.sh b/tests/docker/httpd/httpd_demo/sdk_entrypoint.sh deleted file mode 100644 index 75a68f4..0000000 --- a/tests/docker/httpd/httpd_demo/sdk_entrypoint.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -echo '*** Waiting for initial identity generation...' -while [ ! -s /var/lib/zerotier-one/identity.secret ]; do - sleep 0.2 -done -echo '*** Waiting for network config...' -virtip4="" -while [ ! -s /var/lib/zerotier-one/networks.d/"$nwconf" ]; do - sleep 0.2 -done -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - - -# --- Test section --- -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of=/var/www/html/"$bigfile_name" bs="$bigfile_size" count=1 -#md5sum /var/www/html/"$bigfile_name" >> "$tx_md5sumfile" -md5sum < /var/www/html/"$bigfile_name" >> "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 -rm -rf /run/httpd/* /tmp/httpd* -zerotier-intercept /usr/sbin/httpd -X diff --git a/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/monitor_dockerfile b/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/monitor_entrypoint.sh b/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/monitor_entrypoint.sh deleted file mode 100644 index 3e94118..0000000 --- a/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/monitor_entrypoint.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=35 # wait for test container to come online -app_timeout_time=25 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -rm -rf "$file_path"*."$file_base" -touch "$bigfile_name" - -# Perform test -# curl --connect-timeout "$app_timeout_time" -v -o "$file_path$file_base" http://"$ncvirtip"/index.html -# Large transfer test -curl --connect-timeout "$app_timeout_time" -v -o "$bigfile_name" http://"$ncvirtip"/"$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" > "$rx_md5sumfile" -rx_md5sum=$(<$rx_md5sumfile) -tx_md5sum=$(<$tx_md5sumfile) - -echo '*** Comparing md5: ' "$rx_md5sum" ' and ' "$tx_md5sum" - -if [ "$rx_md5sum" != "$tx_md5sum" ]; -then - echo 'MD5 FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: md5 sum did not match!\n' >> "$file_path$fail$test_name.txt" -else - echo 'MD5 OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: md5 sum ok!\n' >> "$file_path$ok$test_name.txt" - cat "$rx_md5sumfile" >> "$file_path$ok$test_name.txt" - cat "$tx_md5sumfile" >> "$file_path$ok$test_name.txt" -fi - - - - - - - - - - - diff --git a/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/nginx.conf_ b/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/nginx.conf_ deleted file mode 100644 index 7069ef0..0000000 --- a/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/nginx.conf_ +++ /dev/null @@ -1,55 +0,0 @@ -# For more information on configuration, see: -# * Official English Documentation: http://nginx.org/en/docs/ -# * Official Russian Documentation: http://nginx.org/ru/docs/ - -user nginx; -worker_processes auto; -error_log /var/log/nginx/error.log; -pid /run/nginx.pid; - -events { - worker_connections 1024; -} - -http { - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - # Load modular configuration files from the /etc/nginx/conf.d directory. - # See http://nginx.org/en/docs/ngx_core_module.html#include - # for more information. - include /etc/nginx/conf.d/*.conf; - - server { - listen 80 default_server; - #listen [::]:80 default_server; - server_name _; - root /usr/share/nginx/html; - - # Load configuration files for the default server block. - include /etc/nginx/default.d/*.conf; - - location / { - } - - error_page 404 /404.html; - location = /40x.html { - } - - error_page 500 502 503 504 /50x.html; - location = /50x.html { - } - } -} diff --git a/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/sdk_dockerfile b/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/sdk_dockerfile deleted file mode 100644 index a83c289..0000000 --- a/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/sdk_dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -# ZT SDK Test -FROM ubuntu:14.04 -MAINTAINER https://www.zerotier.com/ - - -# Install -RUN \ - sed -i 's/# \(.*multiverse$\)/\1/g' /etc/apt/sources.list && \ - apt-get update && \ - apt-get -y upgrade && \ - apt-get -y install nginx - -EXPOSE 9993/udp 80/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -ADD zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -ADD nginx.conf_ / - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/sdk_entrypoint.sh b/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/sdk_entrypoint.sh deleted file mode 100644 index ef5b8f6..0000000 --- a/tests/docker/nginx/nginx-1.4.6-1.ub14.x86_64/sdk_entrypoint.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls {*.conf,}) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -cp -f nginx.conf_ /etc/nginx/nginx.conf -nginx_html_path=/usr/share/nginx/html/ -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of="$nginx_html_path$bigfile_name" bs="$bigfile_size" count=1 -#md5sum /var/www/html/"$bigfile_name" >> "$tx_md5sumfile" -md5sum < "$nginx_html_path$bigfile_name" > "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -nginx diff --git a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/_two_party_test.sh b/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/_two_party_test.sh deleted file mode 100755 index 461157a..0000000 --- a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/_two_party_test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# Runs test image and monitor image as daemons -test_name=${PWD##*/} -echo 'Starting containers for: ' "$test_name" -touch "$test_name".name -test_container=$(docker run -d -it -v $PWD/../../_results:/opt/results --device=/dev/net/tun "$test_name":latest) -monitor_container=$(docker run -d -it -v $PWD/../../_results:/opt/results --device=/dev/net/tun "$test_name"_monitor:latest) - -echo "waiting $sdk_test_wait_time for test to complete." -sleep $sdk_test_wait_time -docker stop $(docker ps -a -q) -docker rm $test_container -docker rm $monitor_container - -rm -f *.name \ No newline at end of file diff --git a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/monitor_dockerfile b/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/monitor_entrypoint.sh b/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/monitor_entrypoint.sh deleted file mode 100644 index 3e94118..0000000 --- a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/monitor_entrypoint.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=35 # wait for test container to come online -app_timeout_time=25 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -rm -rf "$file_path"*."$file_base" -touch "$bigfile_name" - -# Perform test -# curl --connect-timeout "$app_timeout_time" -v -o "$file_path$file_base" http://"$ncvirtip"/index.html -# Large transfer test -curl --connect-timeout "$app_timeout_time" -v -o "$bigfile_name" http://"$ncvirtip"/"$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" > "$rx_md5sumfile" -rx_md5sum=$(<$rx_md5sumfile) -tx_md5sum=$(<$tx_md5sumfile) - -echo '*** Comparing md5: ' "$rx_md5sum" ' and ' "$tx_md5sum" - -if [ "$rx_md5sum" != "$tx_md5sum" ]; -then - echo 'MD5 FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: md5 sum did not match!\n' >> "$file_path$fail$test_name.txt" -else - echo 'MD5 OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: md5 sum ok!\n' >> "$file_path$ok$test_name.txt" - cat "$rx_md5sumfile" >> "$file_path$ok$test_name.txt" - cat "$tx_md5sumfile" >> "$file_path$ok$test_name.txt" -fi - - - - - - - - - - - diff --git a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/nginx.conf_ b/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/nginx.conf_ deleted file mode 100644 index 7069ef0..0000000 --- a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/nginx.conf_ +++ /dev/null @@ -1,55 +0,0 @@ -# For more information on configuration, see: -# * Official English Documentation: http://nginx.org/en/docs/ -# * Official Russian Documentation: http://nginx.org/ru/docs/ - -user nginx; -worker_processes auto; -error_log /var/log/nginx/error.log; -pid /run/nginx.pid; - -events { - worker_connections 1024; -} - -http { - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - # Load modular configuration files from the /etc/nginx/conf.d directory. - # See http://nginx.org/en/docs/ngx_core_module.html#include - # for more information. - include /etc/nginx/conf.d/*.conf; - - server { - listen 80 default_server; - #listen [::]:80 default_server; - server_name _; - root /usr/share/nginx/html; - - # Load configuration files for the default server block. - include /etc/nginx/default.d/*.conf; - - location / { - } - - error_page 404 /404.html; - location = /40x.html { - } - - error_page 500 502 503 504 /50x.html; - location = /50x.html { - } - } -} diff --git a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/sdk_dockerfile b/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/sdk_dockerfile deleted file mode 100644 index b677f0e..0000000 --- a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/sdk_dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install nginx-1:1.8.0-13.fc23.x86_64 -RUN yum clean all - -EXPOSE 9993/udp 80/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -ADD zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -ADD nginx.conf_ / - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/sdk_entrypoint.sh b/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/sdk_entrypoint.sh deleted file mode 100644 index ef5b8f6..0000000 --- a/tests/docker/nginx/nginx-1.8.0-13.fc23.x86_64/sdk_entrypoint.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls {*.conf,}) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -cp -f nginx.conf_ /etc/nginx/nginx.conf -nginx_html_path=/usr/share/nginx/html/ -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of="$nginx_html_path$bigfile_name" bs="$bigfile_size" count=1 -#md5sum /var/www/html/"$bigfile_name" >> "$tx_md5sumfile" -md5sum < "$nginx_html_path$bigfile_name" > "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -nginx diff --git a/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/monitor_dockerfile b/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/monitor_entrypoint.sh b/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/monitor_entrypoint.sh deleted file mode 100644 index 3e94118..0000000 --- a/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/monitor_entrypoint.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=35 # wait for test container to come online -app_timeout_time=25 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -rm -rf "$file_path"*."$file_base" -touch "$bigfile_name" - -# Perform test -# curl --connect-timeout "$app_timeout_time" -v -o "$file_path$file_base" http://"$ncvirtip"/index.html -# Large transfer test -curl --connect-timeout "$app_timeout_time" -v -o "$bigfile_name" http://"$ncvirtip"/"$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" > "$rx_md5sumfile" -rx_md5sum=$(<$rx_md5sumfile) -tx_md5sum=$(<$tx_md5sumfile) - -echo '*** Comparing md5: ' "$rx_md5sum" ' and ' "$tx_md5sum" - -if [ "$rx_md5sum" != "$tx_md5sum" ]; -then - echo 'MD5 FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: md5 sum did not match!\n' >> "$file_path$fail$test_name.txt" -else - echo 'MD5 OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: md5 sum ok!\n' >> "$file_path$ok$test_name.txt" - cat "$rx_md5sumfile" >> "$file_path$ok$test_name.txt" - cat "$tx_md5sumfile" >> "$file_path$ok$test_name.txt" -fi - - - - - - - - - - - diff --git a/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/nginx.conf_ b/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/nginx.conf_ deleted file mode 100644 index 7069ef0..0000000 --- a/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/nginx.conf_ +++ /dev/null @@ -1,55 +0,0 @@ -# For more information on configuration, see: -# * Official English Documentation: http://nginx.org/en/docs/ -# * Official Russian Documentation: http://nginx.org/ru/docs/ - -user nginx; -worker_processes auto; -error_log /var/log/nginx/error.log; -pid /run/nginx.pid; - -events { - worker_connections 1024; -} - -http { - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - # Load modular configuration files from the /etc/nginx/conf.d directory. - # See http://nginx.org/en/docs/ngx_core_module.html#include - # for more information. - include /etc/nginx/conf.d/*.conf; - - server { - listen 80 default_server; - #listen [::]:80 default_server; - server_name _; - root /usr/share/nginx/html; - - # Load configuration files for the default server block. - include /etc/nginx/default.d/*.conf; - - location / { - } - - error_page 404 /404.html; - location = /40x.html { - } - - error_page 500 502 503 504 /50x.html; - location = /50x.html { - } - } -} diff --git a/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/sdk_dockerfile b/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/sdk_dockerfile deleted file mode 100644 index aba97cb..0000000 --- a/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/sdk_dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install nginx-1:1.8.0-14.fc23.x86_64 -RUN yum clean all - -EXPOSE 9993/udp 80/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -ADD zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -ADD nginx.conf_ / - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/sdk_entrypoint.sh b/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/sdk_entrypoint.sh deleted file mode 100644 index ef5b8f6..0000000 --- a/tests/docker/nginx/nginx-1.8.0-14.fc23.x86_64/sdk_entrypoint.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls {*.conf,}) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -cp -f nginx.conf_ /etc/nginx/nginx.conf -nginx_html_path=/usr/share/nginx/html/ -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of="$nginx_html_path$bigfile_name" bs="$bigfile_size" count=1 -#md5sum /var/www/html/"$bigfile_name" >> "$tx_md5sumfile" -md5sum < "$nginx_html_path$bigfile_name" > "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -nginx diff --git a/tests/docker/nodejs/nodejs-0.10.36-4.fc23/httpserver.js b/tests/docker/nodejs/nodejs-0.10.36-4.fc23/httpserver.js deleted file mode 100644 index b2401c5..0000000 --- a/tests/docker/nodejs/nodejs-0.10.36-4.fc23/httpserver.js +++ /dev/null @@ -1,7 +0,0 @@ -var http = require('http'); -var server = http.createServer(function (request, response) { - response.writeHead(200, {"Content-Type": "text/plain"}); - response.end("welcome to the machine!\n"); -}); -server.listen(8080); -console.log("Server running!"); diff --git a/tests/docker/nodejs/nodejs-0.10.36-4.fc23/monitor_dockerfile b/tests/docker/nodejs/nodejs-0.10.36-4.fc23/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/nodejs/nodejs-0.10.36-4.fc23/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/nodejs/nodejs-0.10.36-4.fc23/monitor_entrypoint.sh b/tests/docker/nodejs/nodejs-0.10.36-4.fc23/monitor_entrypoint.sh deleted file mode 100644 index 4dc1931..0000000 --- a/tests/docker/nodejs/nodejs-0.10.36-4.fc23/monitor_entrypoint.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=25 # wait for test container to come online -app_timeout_time=15 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -response_string=$(curl --connect-timeout "$app_timeout_time" -v http://"$ncvirtip":8080/) - -if [[ $response_string == *"welcome to the machine!"* ]] -then - echo 'NODEJS RESPONSE OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: nodejs-server responded!\n' >> "$file_path$ok$test_name.txt" -else - echo 'NODEJS RESPONSE FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: nodejs server did NOT respond!\n' >> "$file_path$fail$test_name.txt" -fi - - - - - - diff --git a/tests/docker/nodejs/nodejs-0.10.36-4.fc23/sdk_dockerfile b/tests/docker/nodejs/nodejs-0.10.36-4.fc23/sdk_dockerfile deleted file mode 100644 index 0328b0f..0000000 --- a/tests/docker/nodejs/nodejs-0.10.36-4.fc23/sdk_dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install nodejs -RUN yum clean all - -EXPOSE 9993/udp 8080/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# -ADD httpserver.js / - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -ADD zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/nodejs/nodejs-0.10.36-4.fc23/sdk_entrypoint.sh b/tests/docker/nodejs/nodejs-0.10.36-4.fc23/sdk_entrypoint.sh deleted file mode 100644 index 676fabc..0000000 --- a/tests/docker/nodejs/nodejs-0.10.36-4.fc23/sdk_entrypoint.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) - - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so - -# --- Test section --- -echo '*** Starting application...' -sleep 0.5 -node httpserver.js \ No newline at end of file diff --git a/tests/docker/python/python/monitor_dockerfile b/tests/docker/python/python/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/python/python/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/python/python/monitor_entrypoint.sh b/tests/docker/python/python/monitor_entrypoint.sh deleted file mode 100644 index 3e94118..0000000 --- a/tests/docker/python/python/monitor_entrypoint.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=35 # wait for test container to come online -app_timeout_time=25 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -rm -rf "$file_path"*."$file_base" -touch "$bigfile_name" - -# Perform test -# curl --connect-timeout "$app_timeout_time" -v -o "$file_path$file_base" http://"$ncvirtip"/index.html -# Large transfer test -curl --connect-timeout "$app_timeout_time" -v -o "$bigfile_name" http://"$ncvirtip"/"$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" > "$rx_md5sumfile" -rx_md5sum=$(<$rx_md5sumfile) -tx_md5sum=$(<$tx_md5sumfile) - -echo '*** Comparing md5: ' "$rx_md5sum" ' and ' "$tx_md5sum" - -if [ "$rx_md5sum" != "$tx_md5sum" ]; -then - echo 'MD5 FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: md5 sum did not match!\n' >> "$file_path$fail$test_name.txt" -else - echo 'MD5 OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: md5 sum ok!\n' >> "$file_path$ok$test_name.txt" - cat "$rx_md5sumfile" >> "$file_path$ok$test_name.txt" - cat "$tx_md5sumfile" >> "$file_path$ok$test_name.txt" -fi - - - - - - - - - - - diff --git a/tests/docker/python/python/sdk_dockerfile b/tests/docker/python/python/sdk_dockerfile deleted file mode 100644 index cffc666..0000000 --- a/tests/docker/python/python/sdk_dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install python -RUN yum clean all - -EXPOSE 9993/udp 80/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -ADD zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/python/python/sdk_entrypoint.sh b/tests/docker/python/python/sdk_entrypoint.sh deleted file mode 100644 index 28260ec..0000000 --- a/tests/docker/python/python/sdk_entrypoint.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '--- Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of="$bigfile_name" bs="$bigfile_size" count=1 -md5sum < "$bigfile_name" > "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -python -m SimpleHTTPServer 80 diff --git a/tests/docker/python/python3/monitor_dockerfile b/tests/docker/python/python3/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/python/python3/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/python/python3/monitor_entrypoint.sh b/tests/docker/python/python3/monitor_entrypoint.sh deleted file mode 100644 index 3e94118..0000000 --- a/tests/docker/python/python3/monitor_entrypoint.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=35 # wait for test container to come online -app_timeout_time=25 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Curling from intercepted server at' $ncvirtip -rm -rf "$file_path"*."$file_base" -touch "$bigfile_name" - -# Perform test -# curl --connect-timeout "$app_timeout_time" -v -o "$file_path$file_base" http://"$ncvirtip"/index.html -# Large transfer test -curl --connect-timeout "$app_timeout_time" -v -o "$bigfile_name" http://"$ncvirtip"/"$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" > "$rx_md5sumfile" -rx_md5sum=$(<$rx_md5sumfile) -tx_md5sum=$(<$tx_md5sumfile) - -echo '*** Comparing md5: ' "$rx_md5sum" ' and ' "$tx_md5sum" - -if [ "$rx_md5sum" != "$tx_md5sum" ]; -then - echo 'MD5 FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: md5 sum did not match!\n' >> "$file_path$fail$test_name.txt" -else - echo 'MD5 OK' - touch "$file_path$ok$test_name.txt" - printf 'Test: md5 sum ok!\n' >> "$file_path$ok$test_name.txt" - cat "$rx_md5sumfile" >> "$file_path$ok$test_name.txt" - cat "$tx_md5sumfile" >> "$file_path$ok$test_name.txt" -fi - - - - - - - - - - - diff --git a/tests/docker/python/python3/sdk_dockerfile b/tests/docker/python/python3/sdk_dockerfile deleted file mode 100644 index 55b7d6e..0000000 --- a/tests/docker/python/python3/sdk_dockerfile +++ /dev/null @@ -1,35 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum clean all - -EXPOSE 9993/udp 80/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -ADD zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/python/python3/sdk_entrypoint.sh b/tests/docker/python/python3/sdk_entrypoint.sh deleted file mode 100644 index 4eabbe9..0000000 --- a/tests/docker/python/python3/sdk_entrypoint.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '--- Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of="$bigfile_name" bs="$bigfile_size" count=1 -md5sum < "$bigfile_name" > "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -python3 -m http.server 80 diff --git a/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/hello.lua b/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/hello.lua deleted file mode 100644 index 59a2dea..0000000 --- a/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/hello.lua +++ /dev/null @@ -1,3 +0,0 @@ -local msg = "welcome to the machine!" -redis.call("SET", "msg", msg) -return redis.call("GET", "msg") diff --git a/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/monitor_dockerfile b/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/monitor_dockerfile deleted file mode 100644 index 3c89941..0000000 --- a/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/monitor_dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -RUN yum -y install redis-3.0.4-1.fc23.x86_64 - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD hello.lua / - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/monitor_entrypoint.sh b/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/monitor_entrypoint.sh deleted file mode 100644 index bd6b70e..0000000 --- a/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/monitor_entrypoint.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=25 # wait for test container to come online -app_timeout_time=15 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Running lua script against redis host at' $ncvirtip -redis-cli -h $ncvirtip EVAL "$(cat hello.lua)" 0 > redis_response.txt -response_string=$(> "$file_path$ok$test_name.txt" -else - echo 'REDIS RESPONSE FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: redis server did NOT respond!\n' >> "$file_path$fail$test_name.txt" -fi - - - - diff --git a/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/sdk_dockerfile b/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/sdk_dockerfile deleted file mode 100644 index f307991..0000000 --- a/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/sdk_dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install redis-3.0.4-1.fc23.x86_64 -RUN yum clean all - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -EXPOSE 9993/udp 6379/udp - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -Add zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/sdk_entrypoint.sh b/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/sdk_entrypoint.sh deleted file mode 100644 index 02bee2e..0000000 --- a/tests/docker/redis/redis-3.0.4-1.fc23.x86_64/sdk_entrypoint.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) - - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -echo '*** Starting application...' -sleep 0.5 - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -/usr/bin/redis-server --port 6379 diff --git a/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/monitor_dockerfile b/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/monitor_dockerfile deleted file mode 100644 index c5c7c7e..0000000 --- a/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/monitor_dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/monitor_entrypoint.sh b/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/monitor_entrypoint.sh deleted file mode 100644 index c9181cb..0000000 --- a/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/monitor_entrypoint.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=25 # wait for test container to come online -app_timeout_time=15 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile # large, random test transfer file -rx_md5sumfile="$file_path"rx_"$bigfile_name"_md5sum"$tmp_ext" -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the Network Container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - - -# --- Test section --- -echo '*** Copying file to intercepted server at' $ncvirtip -touch "$bigfile_name" - -# Check md5 -md5sum < "$bigfile_name" > "$rx_md5sumfile" -tx_md5sum=$(<$tx_md5sumfile) - -# ... - - - - - - - - diff --git a/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/sdk_dockerfile b/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/sdk_dockerfile deleted file mode 100644 index 0e611c1..0000000 --- a/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/sdk_dockerfile +++ /dev/null @@ -1,35 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install openssh-server -RUN yum clean all - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/sdk_entrypoint.sh b/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/sdk_entrypoint.sh deleted file mode 100644 index 1216d99..0000000 --- a/tests/docker/sshd/openssh-server-7.1p1-3.fc23.x86_64/sdk_entrypoint.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) -bigfile_name=bigfile -bigfile_size=10M # size of file we want to use for the test -tx_md5sumfile="$file_path"tx_"$bigfile_name"_md5sum"$tmp_ext" - - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -./zerotier-one -d -U -p9993 -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -export ZT_NC_NWID=$dev - -# --- Test section --- -# Generate large random file for transfer test, share md5sum for monitor container to check -echo '*** Generating ' "$bigfile_size" ' file' -dd if=/dev/urandom of=/var/www/html/"$bigfile_name" bs="$bigfile_size" count=1 -md5sum < /var/www/html/"$bigfile_name" > "$tx_md5sumfile" -echo '*** Wrote MD5 sum to ' "$tx_md5sumfile" - -echo '*** Starting application...' -sleep 0.5 - -# wait for rsa public key from monitor -#while [ ! -s "$file_path$rsa_public_key_file" ]; do -# sleep 0.2 -#done - -zerotier-intercept /usr/sbin/sshd diff --git a/tests/docker/test.sh b/tests/docker/test.sh deleted file mode 100755 index a62d931..0000000 --- a/tests/docker/test.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -# Runs test images - -echo "*** Running unit tests..." - -# Remove previous test results -rm _results/*.txt - -# How long we shall wait for each test to conclude -export sdk_test_wait_time=60s - -# Test structure, in later releases more complex multi-party scripts will be included -export test_script=_two_party_test.sh - -# Iterate over all depth=2 (relatively-speaking) directories and perform each test -find . -mindepth 2 -maxdepth 2 -type d | while read testdir; do - - if [[ $testdir != *$1* ]] - then - continue - fi - - echo "*** Testing: '$testdir'..." - rm _results/*.tmp - - # Stage scripts - cp $test_script $testdir/$test_script - cd $testdir - - # Run test - ./$test_script - rm $test_script - - cd ../../ -done - -echo "*** Done" diff --git a/tests/httpserver.js b/tests/httpserver.js deleted file mode 100644 index 4513815..0000000 --- a/tests/httpserver.js +++ /dev/null @@ -1,10 +0,0 @@ -var http = require('http'); - -var server = http.createServer(function (request, response) { - response.writeHead(200, {"Content-Type": "text/plain"}); - response.end("Welcome to the machine!\n"); -}); - -server.listen(8777); - -console.log("Server running at http://127.0.0.1:8777/"); diff --git a/tests/results/README.md b/tests/results/README.md deleted file mode 100644 index 93f738c..0000000 --- a/tests/results/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Unit Test Results -==== - -This directory contains the temporary and resultant output files for the docker-based unit tests. Upon the conclusion of the suite of unit tests a check will be run, and all files in this directory will be deleted. See `start.sh` for more information. \ No newline at end of file diff --git a/tests/test.sh b/tests/test.sh deleted file mode 100644 index 3b91df8..0000000 --- a/tests/test.sh +++ /dev/null @@ -1,13 +0,0 @@ -# Calls target in makefile to build docker images and execute unit tests - -# lwIP -make clean; make -f make-linux.mk unit_test SDK_DEBUG=1 SDK_LWIP=1 SDK_IPV4=1 -./tests/unit/docker/start.sh -make clean; make -f make-linux.mk unit_test SDK_DEBUG=1 SDK_LWIP=1 SDK_IPV6=1 -./tests/unit/docker/start.sh - -# picoTCP -make clean; make -f make-linux.mk unit_test SDK_DEBUG=1 SDK_PICOTCP=1 SDK_IPV4=1 -./tests/unit/docker/start.sh -make clean; make -f make-linux.mk unit_test SDK_DEBUG=1 SDK_PICOTCP=1 SDK_IPV6=1 -./tests/unit/docker/start.sh \ No newline at end of file diff --git a/tests/unit/README.md b/tests/unit/README.md deleted file mode 100644 index 4459002..0000000 --- a/tests/unit/README.md +++ /dev/null @@ -1,94 +0,0 @@ -Docker + ZeroTier SDK -==== - -Welcome! - -Imagine a flat, encrypted, no-configuration LAN for all of your Docker containers. - -This short tutorial will show you how to enable ZeroTier functionality for your Docker software container with little to no configuration. In this example we aim to build a Docker container with ZeroTier’s Network Container service bundled right in so that it’s effortless to hook any number of your services in the container up to your virtual network. Alternatively, you can check out a docker project directory [here](docker_demo). - - -**Step 1: Build ZeroTier shared library** - -`make linux_shared_lib` - - For debug output from the SDK, use `make linux_shared_lib SDK_DEBUG=1`, or `make linux_shared_lib ZT_DEBUG=1` to see debug output from the ZeroTier service. - -**Step 2: Build your Docker image** - -`docker build --tag=redis_test .` - -The example dockerfile below incorperates a few important elements: - -1) The ZeroTier service binaries -2) Whatever ZeroTier identity keys you plan on using (if you don't already have keys you wish to use, fret not! A new identity will be generated automatically). -3) The service we've chosen to use. In this case, redis. -``` -FROM fedora:23 -# Install apps -RUN yum -y update -RUN yum -y install redis-3.0.4-1.fc23.x86_64 -RUN yum clean all -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / -EXPOSE 9993/udp 6379/udp -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libztintercept -ADD zerotier-cli / -Add zerotier-sdk-service / -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] -``` - -**Step 3: Start container** - -`docker run -d -it redis_test /bin/bash` - -**Step 4: From container, set up environment variables** - -Set our application pre-load with `export LD_PRELOAD=./libztintercept.so`. This dynamically loads our intercept library into your application which allows us to re-direct its network calls to our virtual network. - -Tell the ZeroTier Network Containers service which network to connect to with `export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_XXXXXXXXXXXXXXXX`. - -**Step 5: Run your new ZeroTier-enabled service** - -At this point, simply run your application as you normally would. It will be automatically intercepted and linked to the ZeroTier service (and hence your virtual networks!) - -`/usr/bin/redis-server --port 6379` - -*** -**Additional info** -If you'd like to know the IP address your service can be reached at on this particular virtual network, use the following: -`zerotier-cli -D/var/lib/zerotier-one/nc_XXXXXXXXXXXXXXXX listnetworks` - -## Installing in a Docker container (or any other container engine) - -If it's not immediately obvious, installation into a Docker container is easy. Just install `zerotier-sdk-service`, `libztintercept.so`, and `liblwip.so` into the container at an appropriate locations. We suggest putting it all in `/var/lib/zerotier-one` since this is the default ZeroTier home and will eliminate the need to supply a path to any of ZeroTier's services or utilities. Then, in your Docker container entry point script launch the service with *-d* to run it in the background, set the appropriate environment variables as described above, and launch your container's main application. - -The only bit of complexity is configuring which virtual network to join. ZeroTier's service automatically joins networks that have `.conf` files in `ZTHOME/networks.d` even if the `.conf` file is empty. So one way of doing this very easily is to add the following commands to your Dockerfile or container entry point script: - - mkdir -p /var/lib/zerotier-one/networks.d - touch /var/lib/zerotier-one/networks.d/8056c2e21c000001.conf - -Replace 8056c2e21c000001 with the network ID of the network you want your container to automatically join. It's also a good idea in your container's entry point script to add a small loop to wait until the container's instance of ZeroTier generates an identity and comes online. This could be something like: - - /var/lib/zerotier-one/zerotier-sdk-service -d - while [ ! -f /var/lib/zerotier-one/identity.secret ]; do - sleep 0.1 - done - # zerotier-sdk-service is now running and has generated an identity - -(Be sure you don't bundle the identity into the container, otherwise every container will try to be the same device and they will "fight" over the device's address.) - -Now each new instance of your container will automatically join the specified network on startup. Authorizing the container on a private network still requires a manual authorization step either via the ZeroTier Central web UI or the API. We're working on some ideas to automate this via bearer token auth or similar since doing this manually or with scripts for large deployments is tedious. diff --git a/tests/unit/_remove_all.sh b/tests/unit/_remove_all.sh deleted file mode 100755 index c6090a9..0000000 --- a/tests/unit/_remove_all.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# Delete all containers -docker rm $(docker ps -a -q) -# Delete all images -docker rmi $(docker images -q) diff --git a/tests/unit/docker/565799d8f658068e.conf b/tests/unit/docker/565799d8f658068e.conf deleted file mode 100644 index e69de29..0000000 diff --git a/tests/unit/docker/README.md b/tests/unit/docker/README.md deleted file mode 100644 index 10b25f8..0000000 --- a/tests/unit/docker/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Simple Docker Demo -==== - -- Type `make docker_demo` to build an image with the SDK pre-installed and a test image to serve as a monitor -- From this local directory, start both containers with `./start.sh` - -Results of the test can be found in `_results` \ No newline at end of file diff --git a/tests/unit/docker/docker_demo.name b/tests/unit/docker/docker_demo.name deleted file mode 100644 index e69de29..0000000 diff --git a/tests/unit/docker/hello.lua b/tests/unit/docker/hello.lua deleted file mode 100644 index 59a2dea..0000000 --- a/tests/unit/docker/hello.lua +++ /dev/null @@ -1,3 +0,0 @@ -local msg = "welcome to the machine!" -redis.call("SET", "msg", msg) -return redis.call("GET", "msg") diff --git a/tests/unit/docker/monitor_dockerfile b/tests/unit/docker/monitor_dockerfile deleted file mode 100644 index 3c89941..0000000 --- a/tests/unit/docker/monitor_dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -# ZT SDK Test Monitor -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -RUN yum -y install redis-3.0.4-1.fc23.x86_64 - -EXPOSE 9993/udp - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD monitor_identity.public /var/lib/zerotier-one/identity.public -ADD monitor_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -ADD hello.lua / - -ADD zerotier-one / -ADD zerotier-cli / - -# Start ZeroTier-One -ADD monitor_entrypoint.sh /monitor_entrypoint.sh -RUN chmod -v +x /monitor_entrypoint.sh -CMD ["./monitor_entrypoint.sh"] diff --git a/tests/unit/docker/monitor_entrypoint.sh b/tests/unit/docker/monitor_entrypoint.sh deleted file mode 100644 index 6b85ac2..0000000 --- a/tests/unit/docker/monitor_entrypoint.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -sdk_wait_time=60 # wait for test container to come online -app_timeout_time=15 # app-specific timeout -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -fail=FAIL. # appended to result file in event of failure -ok=OK. # appended to result file in event of success -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) - -# --- Network Config --- -echo '*** ZeroTier SDK Test Monitor' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` -done -echo '*** Starting Test...' -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Sleeping for (' "$sdk_wait_time" 's ) while we wait for the container to come online...' -sleep "$sdk_wait_time"s -ncvirtip=$(<$address_file) - -# --- Test section --- -echo '*** Running lua script against redis host at' $ncvirtip -redis-cli -h $ncvirtip EVAL "$(cat hello.lua)" 0 > redis_response.txt -response_string=$(> "$file_path$ok$test_name.txt" -else - echo 'REDIS RESPONSE FAIL' - touch "$file_path$fail$test_name.txt" - printf 'Test: redis server did NOT respond!\n' >> "$file_path$fail$test_name.txt" -fi - - - - diff --git a/tests/unit/docker/sdk_dockerfile b/tests/unit/docker/sdk_dockerfile deleted file mode 100644 index f307991..0000000 --- a/tests/unit/docker/sdk_dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# ZT SDK Test -FROM fedora:23 -MAINTAINER https://www.zerotier.com/ - -# Install apps -RUN yum -y update -RUN yum -y install redis-3.0.4-1.fc23.x86_64 -RUN yum clean all - -# Add ZT files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD sdk_identity.public /var/lib/zerotier-one/identity.public -ADD sdk_identity.secret /var/lib/zerotier-one/identity.secret -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD *.name / - -EXPOSE 9993/udp 6379/udp - -# Install LWIP library used by service -ADD liblwip.so /var/lib/zerotier-one/liblwip.so - -# Install syscall intercept library -ADD libztintercept.so / -RUN cp libztintercept.so lib/libztintercept.so -RUN ln -sf /lib/libztintercept.so /lib/libzerotierintercept - -ADD zerotier-cli / -Add zerotier-sdk-service / - -# Install test scripts -ADD sdk_entrypoint.sh /sdk_entrypoint.sh -RUN chmod -v +x /sdk_entrypoint.sh - -# Start ZeroTier-One -CMD ["./sdk_entrypoint.sh"] diff --git a/tests/unit/docker/sdk_entrypoint.sh b/tests/unit/docker/sdk_entrypoint.sh deleted file mode 100644 index 2045743..0000000 --- a/tests/unit/docker/sdk_entrypoint.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/ - -# --- Test Parameters --- -test_namefile=$(ls *.name) -test_name="${test_namefile%.*}" # test network id -nwconf=$(ls *.conf) # blank test network config file -nwid="${nwconf%.*}" # test network id -file_path=/opt/results/ # test result output file path (fs shared between host and containers) -file_base="$test_name".txt # test result output file -tmp_ext=.tmp # temporary filetype used for sharing test data between containers -address_file="$file_path$test_name"_addr"$tmp_ext" # file shared between host and containers for sharing address (optional) - -# --- Network Config --- -echo '*** ZeroTier SDK Test: ' "$test_name" -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-sdk-service -d -U -p9993 >>/tmp/zerotier-sdk-service.out 2>&1' -virtip4="" -while [ -z "$virtip4" ]; do - sleep 0.2 - virtip4=`/zerotier-cli listnetworks | grep -F $nwid | cut -d ' ' -f 9 | sed 's/,/\n/g' | grep -F '.' | cut -d / -f 1` - dev=`/zerotier-cli listnetworks | grep -F "" | cut -d ' ' -f 8 | cut -d "_" -f 2 | sed "s/^//" | tr '\n' '\0'` -done -echo '*** Up and running at' $virtip4 ' on network: ' $nwid -echo '*** Writing address to ' "$address_file" -echo $virtip4 > "$address_file" - -# --- Test section --- -echo '*** Starting application...' -sleep 0.5 - -export ZT_NC_NETWORK=/var/lib/zerotier-one/nc_"$dev" -export LD_PRELOAD=./libztintercept.so -/usr/bin/redis-server --port 6379 diff --git a/tests/unit/docker/start.sh b/tests/unit/docker/start.sh deleted file mode 100755 index 27cc29f..0000000 --- a/tests/unit/docker/start.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -# Before running this script, run: make unit_tests [COMPILE_FLAGS] to build the necessary docker images - -# Runs test sdk and monitor containers based on the images built by the makefile -test_name="docker_demo" -echo 'Starting containers for: ' "$test_name" -touch "$test_name".name -test_container=$(docker run -d -it -v $PWD/tests/results:/opt/results --privileged --device=/dev/net/tun "$test_name":latest) -monitor_container=$(docker run -d -it -v $PWD/tests/results:/opt/results --privileged --device=/dev/net/tun "$test_name"_monitor:latest) - -sleep 90 - -# By this stage, enough time should have passed for all of the unit tests to conclude -RESULTS_DIR=tests/results - -./check.sh $RESULTS_DIR/OK.docker_demo.txt -echo $(cat $RESULTS_DIR/OK.docker_demo.txt) - -rm -rf *.tmp -rm -rf *.txt \ No newline at end of file diff --git a/tests/unit/docker/stop.sh b/tests/unit/docker/stop.sh deleted file mode 100755 index ec572ed..0000000 --- a/tests/unit/docker/stop.sh +++ /dev/null @@ -1,3 +0,0 @@ -docker stop $(docker ps -a -q) -docker rm $test_container -docker rm $monitor_container diff --git a/tests/zts/zts.tcpclient4.c b/tests/zts/zts.tcpclient4.c deleted file mode 100644 index e6557f0..0000000 --- a/tests/zts/zts.tcpclient4.c +++ /dev/null @@ -1,71 +0,0 @@ -// TCP Client test program (IPV4) - -#include -#include -#include -#include -#include - -#include "sdk.h" - -int atoi(const char *str); -int close(int filedes); - -#define MSG_SZ 128 - -int main(int argc , char *argv[]) -{ - if(argc < 3) { - printf("usage: client \n"); - return 1; - } - - /* Starts ZeroTier core service in separate thread, loads user-space TCP/IP stack - and sets up a private AF_UNIX socket between ZeroTier library and your app. Any - subsequent zts_* socket API calls (shown below) are mediated over this hidden AF_UNIX - socket and are spoofed to appear as AF_INET sockets. The implementation of this API - is in src/sockets.c */ - zts_init_rpc(argv[3],argv[4]); - - int sock, port = atoi(argv[2]); - struct sockaddr_in server; - char server_reply[MSG_SZ]; - - sock = zts_socket(AF_INET , SOCK_STREAM , 0); - if (sock == -1) { - printf("could not create socket"); - } - server.sin_addr.s_addr = inet_addr(argv[1]); - server.sin_family = AF_INET; - server.sin_port = htons( port ); - - printf("connecting...\n"); - if (zts_connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) { - perror("connect failed. Error"); - return 1; - } - printf("connected\n"); - - char *msg = "welcome to the machine!"; - - while(1) - { - // TX - if(send(sock, msg, strlen(msg), 0) < 0) { - printf("send failed"); - return 1; - } - else { - printf("TX: %s\n", msg); - printf("len = %ld\n", strlen(msg)); - - int bytes_read = read(sock, server_reply, MSG_SZ); - if(bytes_read < 0) - printf("\tRX: Nothing\n"); - else - printf("\tRX = (%d bytes): %s\n", bytes_read, server_reply); - } - } - close(sock); - return 0; -} diff --git a/tests/zts/zts.tcpclient6.c b/tests/zts/zts.tcpclient6.c deleted file mode 100644 index 98fb198..0000000 --- a/tests/zts/zts.tcpclient6.c +++ /dev/null @@ -1,84 +0,0 @@ -// TCP Client test program (IPV6) - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sdk.h" - -void error(char *msg) { - perror(msg); - exit(0); -} - -int main(int argc, char *argv[]) { - int sockfd, portno, n; - struct sockaddr_in6 serv_addr; - struct hostent *server; - char buffer[256] = "This is a string from client!"; - - if(argc < 3) { - printf("usage: client \n"); - return 1; - } - - /* Starts ZeroTier core service in separate thread, loads user-space TCP/IP stack - and sets up a private AF_UNIX socket between ZeroTier library and your app. Any - subsequent zts_* socket API calls (shown below) are mediated over this hidden AF_UNIX - socket and are spoofed to appear as AF_INET sockets. The implementation of this API - is in src/sockets.c */ - zts_init_rpc(argv[3],argv[4]); - - portno = atoi(argv[2]); - - printf("\nIPv6 TCP Client Started...\n"); - - //Sockets Layer Call: socket() - sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0); - if (sockfd < 0) - error("ERROR opening socket"); - - //Sockets Layer Call: gethostbyname2() - server = gethostbyname2(argv[1],AF_INET6); - if (server == NULL) { - fprintf(stderr, "ERROR, no such host\n"); - exit(0); - } - - memset((char *) &serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin6_flowinfo = 0; - serv_addr.sin6_family = AF_INET6; - memmove((char *) &serv_addr.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length); - serv_addr.sin6_port = htons(portno); - - //Sockets Layer Call: connect() - if (zts_connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) - error("ERROR connecting"); - - - //Sockets Layer Call: send() - n = send(sockfd,buffer, strlen(buffer)+1, 0); - if (n < 0) - error("ERROR writing to socket"); - - printf("sent %d bytes\n", n); - memset(buffer, 0, 256); - - //Sockets Layer Call: recv() - printf("reading...\n"); - n = recv(sockfd, buffer, 255, 0); - if (n < 0) - error("ERROR reading from socket"); - printf("Message from server: %s\n", buffer); - - //Sockets Layer Call: close() - close(sockfd); - - return 0; -} \ No newline at end of file diff --git a/tests/zts/zts.tcpserver4.c b/tests/zts/zts.tcpserver4.c deleted file mode 100644 index 9241874..0000000 --- a/tests/zts/zts.tcpserver4.c +++ /dev/null @@ -1,71 +0,0 @@ -// TCP Server test program (IPV4) - -#include -#include -#include -#include -#include - -#include "sdk.h" - -int atoi(const char *str); - -int main(int argc , char *argv[]) -{ - if(argc < 3) { - printf("usage: server \n"); - return 1; - } - - /* Starts ZeroTier core service in separate thread, loads user-space TCP/IP stack - and sets up a private AF_UNIX socket between ZeroTier library and your app. Any - subsequent zts_* socket API calls (shown below) are mediated over this hidden AF_UNIX - socket and are spoofed to appear as AF_INET sockets. The implementation of this API - is in src/sockets.c */ - zts_init_rpc(argv[2],argv[3]); - - int sock, client_sock, c, read_size, port = atoi(argv[1]); - char client_message[2000]; - - struct sockaddr_in servaddr; - struct sockaddr_in client; - - sock = zts_socket(AF_INET, SOCK_STREAM, 0); - bzero( &servaddr, sizeof(servaddr)); - - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htons(INADDR_ANY); - servaddr.sin_port = htons(port); - zts_bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)); - - printf("listening\n"); - zts_listen(sock , 3); - printf("waiting to accept\n"); - c = sizeof(struct sockaddr_in); - - client_sock = zts_accept(sock, (struct sockaddr *)&client, (socklen_t*)&c); - if (client_sock < 0) { - perror("accept failed"); - return 0; - } - printf("connection accepted\n reading...\n"); - - // RX - - int msglen = 1024; - unsigned long count = 0; - while(1) - { - count++; - int bytes_read = read(client_sock, client_message, msglen); - printf("[%lu] RX = (%d): ", count, bytes_read); - for(int i=0; i -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include "sdk.h" - -void error(char *msg) { - perror(msg); - exit(1); -} - -int main(int argc, char *argv[]) { - int sockfd, newsockfd, portno; - socklen_t clilen; - char buffer[256]; - struct sockaddr_in6 serv_addr, cli_addr; - int n; - char client_addr_ipv6[100]; - - if(argc < 3) { - printf("usage: server \n"); - return 1; - } - - /* Starts ZeroTier core service in separate thread, loads user-space TCP/IP stack - and sets up a private AF_UNIX socket between ZeroTier library and your app. Any - subsequent zts_* socket API calls (shown below) are mediated over this hidden AF_UNIX - socket and are spoofed to appear as AF_INET sockets. The implementation of this API - is in src/sockets.c */ - zts_init_rpc(argv[2],argv[3]); - - printf("\nIPv6 TCP Server Started...\n"); - - sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0); - if (sockfd < 0) - error("ERROR opening socket"); - - bzero((char *) &serv_addr, sizeof(serv_addr)); - portno = atoi(argv[1]); - serv_addr.sin6_flowinfo = 0; - serv_addr.sin6_family = AF_INET6; - serv_addr.sin6_addr = in6addr_any; - serv_addr.sin6_port = htons(portno); - - // bind - if (zts_bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) - error("ERROR on binding"); - - // listen - zts_listen(sockfd, 5); - clilen = sizeof(cli_addr); - - // accept - newsockfd = zts_accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); - if (newsockfd < 0) - error("ERROR on accept"); - - inet_ntop(AF_INET6, &(cli_addr.sin6_addr),client_addr_ipv6, 100); - printf("Incoming connection from client having IPv6 address: %s\n",client_addr_ipv6); - - memset(buffer,0, 256); - - // recv - n = recv(newsockfd, buffer, 255, 0); - if (n < 0) - error("ERROR reading from socket"); - - printf("Message from client: %s\n", buffer); - - // send - printf("sending...\n"); - n = send(newsockfd, "Server got your message", 23+1, 0); - if (n < 0) - error("ERROR writing to socket"); - - close(sockfd); - close(newsockfd); - return 0; -} diff --git a/tests/zts/zts.udpclient4.c b/tests/zts/zts.udpclient4.c deleted file mode 100755 index ecbc200..0000000 --- a/tests/zts/zts.udpclient4.c +++ /dev/null @@ -1,94 +0,0 @@ -// UDP Client test program (IPV4) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sdk.h" - -#define BUFSIZE 1024 - -void error(char *msg) { - perror(msg); - exit(0); -} - -int main(int argc, char **argv) { - int sock, portno, n; - int serverlen; - struct sockaddr_in serveraddr; - struct hostent *server; - char *hostname; - char buf[BUFSIZE]; - - /* check command line arguments */ - if (argc != 3) { - fprintf(stderr,"usage: %s \n", argv[0]); - exit(0); - } - - /* Starts ZeroTier core service in separate thread, loads user-space TCP/IP stack - and sets up a private AF_UNIX socket between ZeroTier library and your app. Any - subsequent zts_* socket API calls (shown below) are mediated over this hidden AF_UNIX - socket and are spoofed to appear as AF_INET sockets. The implementation of this API - is in src/sockets.c */ - zts_init_rpc(argv[3],argv[4]); - - hostname = argv[1]; - portno = atoi(argv[2]); - - /* socket: create the socket */ - sock = zts_socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) - error("ERROR opening socket"); - - /* gethostbyname: get the server's DNS entry */ - server = gethostbyname(hostname); - if (server == NULL) { - fprintf(stderr,"ERROR, no such host as %s\n", hostname); - exit(0); - } - - /* build the server's Internet address */ - bzero((char *) &serveraddr, sizeof(serveraddr)); - serveraddr.sin_family = AF_INET; - bcopy((char *)server->h_addr, - (char *)&serveraddr.sin_addr.s_addr, server->h_length); - serveraddr.sin_port = htons(portno); - - /* get a message from the user */ - char *msg = "A message to the server!\0"; - fcntl(sock, F_SETFL, O_NONBLOCK); - long count = 0; - while(1) - { - count++; - printf("\n\n\nTX(%lu)...\n", count); - sleep(1); - //usleep(10000); - //bzero(buf, BUFSIZE); - //printf("\nPlease enter msg: "); - //fgets(buf, BUFSIZE, stdin); - - /* send the message to the server */ - serverlen = sizeof(serveraddr); - n = sendto(sock, msg, strlen(msg), 0, (struct sockaddr *)&serveraddr, serverlen); - //if (n < 0) - // error("ERROR in sendto"); - - /* print the server's reply */ - memset(buf, 0, sizeof(buf)); - n = zts_recvfrom(sock, buf, BUFSIZE, 0, (struct sockaddr *)&serveraddr, (socklen_t *)&serverlen); - //if (n < 0) - // printf("ERROR in recvfrom: %d", n); - printf("Echo from server: %s", buf); - } - return 0; -} diff --git a/tests/zts/zts.udpclient6.c b/tests/zts/zts.udpclient6.c deleted file mode 100755 index b1d0100..0000000 --- a/tests/zts/zts.udpclient6.c +++ /dev/null @@ -1,65 +0,0 @@ -// UDP Client test program (IPV6) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sdk.h" - -#define MAXBUF 65536 - -#define TESTBUF 1024 - -int main(int argc, char* argv[]) -{ - int status, sock, portno, n; - struct addrinfo sainfo, *psinfo; - struct hostent *server; - char buffer[MAXBUF]; - struct sockaddr_in6 serv_addr; - - if(argc < 3) { - printf("usage: client \n"); - return 1; - } - - /* Starts ZeroTier core service in separate thread, loads user-space TCP/IP stack - and sets up a private AF_UNIX socket between ZeroTier library and your app. Any - subsequent zts_* socket API calls (shown below) are mediated over this hidden AF_UNIX - socket and are spoofed to appear as AF_INET sockets. The implementation of this API - is in src/sockets.c */ - zts_init_rpc(argv[3],argv[4]); - - sock = zts_socket(AF_INET6, SOCK_DGRAM,0); - portno = atoi(argv[2]); - server = gethostbyname2(argv[1],AF_INET6); - memset((char *) &serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin6_flowinfo = 0; - serv_addr.sin6_family = AF_INET6; - memmove((char *) &serv_addr.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length); - serv_addr.sin6_port = htons(portno); - - sprintf(buffer,"Welcome to the machine"); - //memset(buffer, 1, TESTBUF); - - fcntl(sock, F_SETFL, O_NONBLOCK); - while(1) - { - //usleep(50000); - status = zts_sendto(sock, buffer, strlen(buffer), 0, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)); - if(status > 0) - printf("sendto() : %s \t%d\n", buffer, status); - } - close(sock); - - zts_stop(); /* Shut down ZT */ - return 0; -} \ No newline at end of file diff --git a/tests/zts/zts.udpserver4.c b/tests/zts/zts.udpserver4.c deleted file mode 100755 index a5cab73..0000000 --- a/tests/zts/zts.udpserver4.c +++ /dev/null @@ -1,79 +0,0 @@ -// UDP Server test program (IPV4) - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sdk.h" - -#define MAXBUF 1024*1024 - -void echo(int sock) { - char bufin[MAXBUF]; - struct sockaddr_in remote; - int n; - socklen_t len = sizeof(remote); - long count = 0; - - while(1) { - sleep(1); - count++; - // read a datagram from the socket - n=zts_recvfrom(sock,bufin,MAXBUF,0,(struct sockaddr *)&remote,&len); - // print out the address of the sender - printf("DGRAM from %s:%d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port)); - - if (n<0) { - perror("Error receiving data"); - } else { - // sendto(sock,bufin,n,0,(struct sockaddr *)&remote,len); - printf("RX (%d bytes) = %s\n", n, bufin); - } - } -} - -int main(int argc, char *argv[]) { - if(argc < 3) { - printf("usage: client \n"); - return 1; - } - - /* Starts ZeroTier core service in separate thread, loads user-space TCP/IP stack - and sets up a private AF_UNIX socket between ZeroTier library and your app. Any - subsequent zts_* socket API calls (shown below) are mediated over this hidden AF_UNIX - socket and are spoofed to appear as AF_INET sockets. The implementation of this API - is in src/sockets.c */ - zts_init_rpc(argv[2],argv[3]); - - int sock, port = atoi(argv[1]); - socklen_t len; - struct sockaddr_in skaddr; - struct sockaddr_in skaddr2; - - // Create socket - if ((sock = zts_socket( PF_INET, SOCK_DGRAM, 0)) < 0) { - printf("error creating socket\n"); - return 0; - } - // Create address - skaddr.sin_family = AF_INET; - skaddr.sin_addr.s_addr = htonl(INADDR_ANY); - skaddr.sin_port = htons(port); - // Bind to address - if (zts_bind(sock, (struct sockaddr *) &skaddr, sizeof(skaddr))<0) { - printf("error binding\n"); - return 0; - } - // find out what port we were assigned - len = sizeof( skaddr2 ); - - // RX - echo(sock); - return 0; -} diff --git a/tests/zts/zts.udpserver6.c b/tests/zts/zts.udpserver6.c deleted file mode 100755 index 1186805..0000000 --- a/tests/zts/zts.udpserver6.c +++ /dev/null @@ -1,68 +0,0 @@ -// UDP Server test program (IPV6) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sdk.h" - -#define MAXBUF 128 - -int main(int argc, char *argv[]) -{ - if(argc < 3) { - printf("usage: server \n"); - return 1; - } - - /* Starts ZeroTier core service in separate thread, loads user-space TCP/IP stack - and sets up a private AF_UNIX socket between ZeroTier library and your app. Any - subsequent zts_* socket API calls (shown below) are mediated over this hidden AF_UNIX - socket and are spoofed to appear as AF_INET sockets. The implementation of this API - is in src/sockets.c */ - zts_init_rpc(argv[2],argv[3]); - - int sock, n; - struct sockaddr_in6 sin6; - socklen_t sin6len; - - char buffer[MAXBUF]; - memset(buffer, 0, MAXBUF); - - sock = zts_socket(PF_INET6, SOCK_DGRAM,0); - sin6len = sizeof(struct sockaddr_in6); - memset(&sin6, 0, sin6len); - - sin6.sin6_port = htons(atoi(argv[1])); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = in6addr_any; - - n = zts_bind(sock, (struct sockaddr *)&sin6, sin6len); - if(-1 == n) - perror("bind"), exit(1); - - //n = getsockname(sock, (struct sockaddr *)&sin6, &sin6len); - //printf("%d\n", ntohs(sin6.sin6_port)); - - //fcntl(sock, F_SETFL, O_NONBLOCK); - while (1) { - //usleep(50000); - n = zts_recvfrom(sock, buffer, MAXBUF, 0, (struct sockaddr *)&sin6, &sin6len); - //if(n > 0) - printf("recvfrom(): n = %d, buffer : %s\n", n, buffer); - } - - shutdown(sock, 2); - close(sock); - - zts_stop(); /* Shut down ZT */ - return 0; -} \ No newline at end of file diff --git a/zto/AUTHORS.md b/zto/AUTHORS.md deleted file mode 100644 index 043ff00..0000000 --- a/zto/AUTHORS.md +++ /dev/null @@ -1,73 +0,0 @@ -## Primary Authors - - * ZeroTier Core and ZeroTier One virtual networking service
- Adam Ierymenko / adam.ierymenko@zerotier.com - - * Java JNI Interface to enable Android application development, and Android app itself (code for that is elsewhere)
- Grant Limberg / glimberg@gmail.com - - * ZeroTier SDK (formerly known as Network Containers)
- Joseph Henry / joseph.henry@zerotier.com - -## Third Party Contributors - - * A number of fixes and improvements to the new controller, other stuff.
- Kees Bos / https://github.com/keesbos/ - - * Debugging and testing, OpenWRT support fixes.
- Moritz Warning / moritzwarning@web.de - - * Debian GNU/Linux packaging, manual pages, and license compliance edits.
- Ben Finney - - * Several others made smaller contributions, which GitHub tracks here:
- https://github.com/zerotier/ZeroTierOne/graphs/contributors/ - -## Third-Party Code - -ZeroTier includes the following third party code, either in ext/ or incorporated into the ZeroTier core. - - * LZ4 compression algorithm by Yann Collet - - * Files: node/Packet.cpp (bundled within anonymous namespace) - * Home page: http://code.google.com/p/lz4/ - * License grant: BSD 2-clause - - * http-parser by Joyent, Inc. (many authors) - - * Files: ext/http-parser/* - * Home page: https://github.com/joyent/http-parser/ - * License grant: MIT/Expat - - * C++11 json (nlohmann/json) by Niels Lohmann - - * Files: ext/json/* - * Home page: https://github.com/nlohmann/json - * License grant: MIT - - * TunTapOSX by Mattias Nissler - - * Files: ext/tap-mac/tuntap/* - * Home page: http://tuntaposx.sourceforge.net/ - * License grant: BSD attribution no-endorsement - * ZeroTier Modifications: change interface name to zt#, increase max MTU, increase max devices - - * tap-windows6 by the OpenVPN project - - * Files: windows/TapDriver6/* - * Home page: https://github.com/OpenVPN/tap-windows6/ - * License grant: GNU GPL v2 - * ZeroTier Modifications: change name of driver to ZeroTier, add ioctl() to get L2 multicast memberships (source is in ext/ and modifications inherit GPL) - - * Salsa20 stream cipher, Curve25519 elliptic curve cipher, Ed25519 digital signature algorithm, and Poly1305 MAC algorithm, all by Daniel J. Bernstein - - * Files: node/Salsa20.* node/C25519.* node/Poly1305.* - * Home page: http://cr.yp.to/ - * License grant: public domain - * ZeroTier Modifications: slight cryptographically-irrelevant modifications for inclusion into ZeroTier core - - * MiniUPNPC and libnatpmp by Thomas Bernard - - * Files: ext/libnatpmp/* ext/miniupnpc/* - * Home page: http://miniupnp.free.fr/ - * License grant: BSD attribution no-endorsement diff --git a/zto/COPYING b/zto/COPYING deleted file mode 100644 index 23d42df..0000000 --- a/zto/COPYING +++ /dev/null @@ -1,17 +0,0 @@ -ZeroTier One, an endpoint server for the ZeroTier virtual network layer. -Copyright © 2011–2016 ZeroTier, Inc. - -ZeroTier One is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at -your option) any later version. - -See the file ‘LICENSE.GPL-3’ for the text of the GNU GPL version 3. -If that file is not present, see . - -.. - Local variables: - coding: utf-8 - mode: text - End: - vim: fileencoding=utf-8 filetype=text : diff --git a/zto/LICENSE.GPL-2 b/zto/LICENSE.GPL-2 deleted file mode 100644 index d159169..0000000 --- a/zto/LICENSE.GPL-2 +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/zto/LICENSE.GPL-3 b/zto/LICENSE.GPL-3 deleted file mode 100644 index 94a9ed0..0000000 --- a/zto/LICENSE.GPL-3 +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/zto/Makefile b/zto/Makefile deleted file mode 100644 index 9511862..0000000 --- a/zto/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# Common makefile -- loads make rules for each platform - -OSTYPE=$(shell uname -s) - -ifeq ($(OSTYPE),Darwin) - include make-mac.mk -endif - -ifeq ($(OSTYPE),Linux) - include make-linux.mk -endif - -ifeq ($(OSTYPE),FreeBSD) - CC=clang - CXX=clang++ - ZT_BUILD_PLATFORM=7 - include make-bsd.mk -endif -ifeq ($(OSTYPE),OpenBSD) - CC=egcc - CXX=eg++ - ZT_BUILD_PLATFORM=9 - include make-bsd.mk -endif diff --git a/zto/README.md b/zto/README.md deleted file mode 100644 index 47bfc87..0000000 --- a/zto/README.md +++ /dev/null @@ -1,125 +0,0 @@ -ZeroTier - A Planetary Ethernet Switch -====== - -ZeroTier is an enterprise Ethernet switch for planet Earth. - -It erases the LAN/WAN distinction and makes VPNs, tunnels, proxies, and other kludges arising from the inflexible nature of physical networks obsolete. Everything is encrypted end-to-end and traffic takes the most direct (peer to peer) path available. - -Visit [ZeroTier's site](https://www.zerotier.com/) for more information and [pre-built binary packages](https://www.zerotier.com/download.shtml). Apps for Android and iOS are available for free in the Google Play and Apple app stores. - -### Getting Started - -ZeroTier's basic operation is easy to understand. Devices have 10-digit *ZeroTier addresses* like `89e92ceee5` and networks have 16-digit network IDs like `8056c2e21c000001`. All it takes for a device to join a network is its 16-digit ID, and all it takes for a network to authorize a device is its 10-digit address. Everything else is automatic. - -A "device" in our terminology is any "unit of compute" capable of talking to a network: desktops, laptops, phones, servers, VMs/VPSes, containers, and even user-space applications via our [SDK](https://github.com/zerotier/ZeroTierSDK). - -For testing purposes we provide a public virtual network called *Earth* with network ID `8056c2e21c000001`. You can join it with: - - sudo zerotier-cli join 8056c2e21c000001 - -Now wait about 30 seconds and check your system with `ip addr list` or `ifconfig`. You'll see a new interface whose name starts with *zt* and it should quickly get an IPv4 and an IPv6 address. Once you see it get an IP, try pinging `earth.zerotier.net` at `29.209.112.93`. If you've joined Earth from more than one system, try pinging your other machine. If you don't want to belong to a giant Ethernet party line anymore, just type: - - sudo zerotier-cli leave 8056c2e21c000001 - -The *zt* interface will disappear. You're no longer on the network. - -To create networks of your own, you'll need a network controller. ZeroTier One (for desktops and servers) includes controller functionality in its default build that can be configured via its JSON API (see [README.md in controller/](controller/)). ZeroTier provides a hosted solution with a nice web UI and SaaS add-ons at [my.zerotier.com](https://my.zerotier.com/). Basic controller functionality is free for up to 100 devices. - -### Project Layout - - - `artwork/`: icons, logos, etc. - - `attic/`: old stuff and experimental code that we want to keep around for reference. - - `controller/`: the reference network controller implementation, which is built and included by default on desktop and server build targets. - - `debian/`: files for building Debian packages on Linux. - - `doc/`: manual pages and other documentation. - - `ext/`: third party libraries, binaries that we ship for convenience on some platforms (Mac and Windows), and installation support files. - - `include/`: include files for the ZeroTier core. - - `java/`: a JNI wrapper used with our Android mobile app. (The whole Android app is not open source but may be made so in the future.) - - `macui/`: a Macintosh menu-bar app for controlling ZeroTier One, written in Objective C. - - `node/`: the ZeroTier virtual Ethernet switch core, which is designed to be entirely separate from the rest of the code and able to be built as a stand-alone OS-independent library. Note to developers: do not use C++11 features in here, since we want this to build on old embedded platforms that lack C++11 support. C++11 can be used elsewhere. - - `osdep/`: code to support and integrate with OSes, including platform-specific stuff only built for certain targets. - - `service/`: the ZeroTier One service, which wraps the ZeroTier core and provides VPN-like connectivity to virtual networks for desktops, laptops, servers, VMs, and containers. - - `tcp-proxy/`: TCP proxy code run by ZeroTier, Inc. to provide TCP fallback (this will die soon!). - - `windows/`: Visual Studio solution files, Windows service code for ZeroTier One, and the Windows task bar app UI. - -The base path contains the ZeroTier One service main entry point (`one.cpp`), self test code, makefiles, etc. - -### Build and Platform Notes - -To build on Mac and Linux just type `make`. On FreeBSD and OpenBSD `gmake` (GNU make) is required and can be installed from packages or ports. For Windows there is a Visual Studio solution in `windows/'. - - - **Mac** - - Xcode command line tools for OSX 10.7 or newer are required. - - Tap device driver kext source is in `ext/tap-mac` and a signed pre-built binary can be found in `ext/bin/tap-mac`. You should not need to build it yourself. It's a fork of [tuntaposx](http://tuntaposx.sourceforge.net) with device names changed to `zt#`, support for a larger MTU, and tun functionality removed. - - **Linux** - - The minimum compiler versions required are GCC/G++ 4.9.3 or CLANG/CLANG++ 3.4.2. - - Linux makefiles automatically detect and prefer clang/clang++ if present as it produces smaller and slightly faster binaries in most cases. You can override by supplying CC and CXX variables on the make command line. - - CentOS 7 ships with a version of GCC/G++ that is too old, but a new enough version of CLANG can be found in the *epel* repositories. Type `yum install epel-release` and then `yum install clang` to build there. - - **Windows** - - Windows 7 or newer (and equivalent server versions) are supported. This *may* work on Vista but you're on your own there. Windows XP is not supported since it lacks many important network API functions. - - We build with Visual Studio 2015. Older versions may not work with the solution file and project files we ship and may not have new enough C++11 support. - - Pre-built signed Windows drivers are included in `ext/bin/tap-windows-ndis6`. The MSI files found there will install them on 32-bit and 64-bit systems. (These are included in our multi-architecture installer as chained MSIs.) - - Windows builds are more painful in general than other platforms and are for the adventurous. - - **FreeBSD** - - Tested most recently on FreeBSD-11. Older versions may work but we're not sure. - - GCC/G++ 4.9 and gmake are required. These can be installed from packages or ports. Type `gmake` to build. - - **OpenBSD** - - There is a limit of four network memberships on OpenBSD as there are only four tap devices (`/dev/tap0` through `/dev/tap3`). We're not sure if this can be increased. - - OpenBSD lacks `getifmaddrs` (or any equivalent method) to get interface multicast memberships. As a result multicast will only work on OpenBSD for ARP and NDP (IP/MAC lookup) and not for other purposes. - - Only tested on OpenBSD 6.0. Older versions may not work. - - GCC/G++ 4.9 and gmake are required and can be installed using `pkg_add` or from ports. They get installed in `/usr/local/bin` as `egcc` and `eg++` and our makefile is pre-configured to use them on OpenBSD. - -Typing `make selftest` will build a *zerotier-selftest* binary which unit tests various internals and reports on a few aspects of the build environment. It's a good idea to try this on novel platforms or architectures. - -### Running - -Running *zerotier-one* with -h will show help. - -On Linux and BSD you can start the service with: - - sudo ./zerotier-one -d - -A home folder for your system will automatically be created. - -The service is controlled via the JSON API, which by default is available at 127.0.0.1 port 9993. We include a *zerotier-cli* command line utility to make API calls for standard things like joining and leaving networks. The *authtoken.secret* file in the home folder contains the secret token for accessing this API. See README.md in [service/](service/) for API documentation. - -Here's where home folders live (by default) on each OS: - - * **Linux**: `/var/lib/zerotier-one` - * **FreeBSD** / **OpenBSD**: `/var/db/zerotier-one` - * **Mac**: `/Library/Application Support/ZeroTier/One` - * **Windows**: `\ProgramData\ZeroTier\One` (That's for Windows 7. The base 'shared app data' folder might be different on different Windows versions.) - -Running ZeroTier One on a Mac is the same, but OSX requires a kernel extension. We ship a signed binary build of the ZeroTier tap device driver, which can be installed on Mac with: - - sudo make install-mac-tap - -This will create the home folder for Mac, place *tap.kext* there, and set its modes correctly to enable ZeroTier One to manage it with *kextload* and *kextunload*. - -### Troubleshooting - -For most users, it just works. - -If you are running a local system firewall, we recommend adding a rule permitting UDP port 9993 inbound and outbound. If you installed binaries for Windows this should be done automatically. Other platforms might require manual editing of local firewall rules depending on your configuration. - -The Mac firewall can be found under "Security" in System Preferences. Linux has a variety of firewall configuration systems and tools. If you're using Ubuntu's *ufw*, you can do this: - - sudo ufw allow 9993/udp - -On CentOS check `/etc/sysconfig/iptables` for IPTables rules. For other distributions consult your distribution's documentation. You'll also have to check the UIs or documentation for commercial third party firewall applications like Little Snitch (Mac), McAfee Firewall Enterprise (Windows), etc. if you are running any of those. Some corporate environments might have centrally managed firewall software, so you might also have to contact IT. - -ZeroTier One peers will automatically locate each other and communicate directly over a local wired LAN *if UDP port 9993 inbound is open*. If that port is filtered, they won't be able to see each others' LAN announcement packets. If you're experiencing poor performance between devices on the same physical network, check their firewall settings. Without LAN auto-location peers must attempt "loopback" NAT traversal, which sometimes fails and in any case requires that every packet traverse your external router twice. - -Users behind certain types of firewalls and "symmetric" NAT devices may not able able to connect to external peers directly at all. ZeroTier has limited support for port prediction and will *attempt* to traverse symmetric NATs, but this doesn't always work. If P2P connectivity fails you'll be bouncing UDP packets off our relay servers resulting in slower performance. Some NAT router(s) have a configurable NAT mode, and setting this to "full cone" will eliminate this problem. If you do this you may also see a magical improvement for things like VoIP phones, Skype, BitTorrent, WebRTC, certain games, etc., since all of these use NAT traversal techniques similar to ours. - -If you're interested, there's a [technical deep dive about NAT traversal on our blog](https://www.zerotier.com/blog/?p=226). A troubleshooting tool to help you diagnose NAT issues is planned for the future as are uPnP/IGD/NAT-PMP and IPv6 transport. - -If a firewall between you and the Internet blocks ZeroTier's UDP traffic, you will fall back to last-resort TCP tunneling to rootservers over port 443 (https impersonation). This will work almost anywhere but is *very slow* compared to UDP or direct peer to peer connectivity. - -### Contributing - -Please make pull requests against the `dev` branch. The `master` branch is release, and `edge` is for unstable and work in progress changes and is not likely to work. - -### License - -The ZeroTier source code is open source and is licensed under the GNU GPL v3 (not LGPL). If you'd like to embed it in a closed-source commercial product or appliance, please e-mail [contact@zerotier.com](mailto:contact@zerotier.com) to discuss commercial licensing. Otherwise it can be used for free. diff --git a/zto/RELEASE-NOTES.md b/zto/RELEASE-NOTES.md deleted file mode 100644 index b54b7ea..0000000 --- a/zto/RELEASE-NOTES.md +++ /dev/null @@ -1,132 +0,0 @@ -ZeroTier Release Notes -====== - -# 2017-03-17 -- Version 1.2.2 - -Version 1.2.2 fixes a few bugs discovered after the 1.2.0 release. These are: - - * A bug causing unreliable multicast propagation (GitHub issue #461). - * A crash in ARM binaries due to a build chain and flags problem. - * A bug in the network controller preventing members from being listed (GitHub issue #460). - ------- - -# 2017-03-14 -- Version 1.2.0 - -Version 1.2.0 is a major milestone release representing almost nine months of work. It includes our rules engine for distributed network packet filtering and security monitoring, federated roots, and many other architectural and UI improvements and bug fixes. - -## New Features in 1.2.0 - -### The ZeroTier Rules Engine - -The largest new feature in 1.2.0, and the product of many months of work, is our advanced network rules engine. With this release we achieve traffic control, security monitoring, and micro-segmentation capability on par with many enterprise SDN solutions designed for use in advanced data centers and corporate networks. - -Rules allow you to filter packets on your network and vector traffic to security observers. Security observation can be performed in-band using REDIRECT or out of band using TEE. - -Tags and capabilites provide advanced methods for implementing fine grained permission structures and micro-segmentation schemes without bloating the size and complexity of your rules table. - -See the [rules engine announcement blog post](https://www.zerotier.com/blog/?p=927) for an in-depth discussion of theory and implementation. The [manual](https://www.zerotier.com/manual.shtml) contains detailed information on rule, tag, and capability use, and the `rule-compiler/` subfolder of the ZeroTier source tree contains a JavaScript function to compile rules in our human-readable rule definition language into rules suitable for import into a network controller. (ZeroTier Central uses this same script to compile rules on [my.zerotier.com](https://my.zerotier.com/).) - -### Root Server Federation - -It's now possible to create your own root servers and add them to the root server pool on your nodes. This is done by creating what's called a "moon," which is a signed enumeration of root servers and their stable points on the network. Refer to the [manual](https://www.zerotier.com/manual.shtml) for instructions. - -Federated roots achieve a number of things: - - * You can deploy your own infrastructure to reduce dependency on ours. - * You can deploy roots *inside your LAN* to ensure that network connectivity inside your facility still works if the Internet goes down. This is the first step toward making ZeroTier viable as an in-house SDN solution. - * Roots can be deployed inside national boundaries for countries with data residency laws or "great firewalls." (As of 1.2.0 there is still no way to force all traffic to use these roots, but that will be easy to do in a later version.) - * Last but not least this makes ZeroTier somewhat less centralized by eliminating any hard dependency on ZeroTier, Inc.'s infrastructure. - -Our roots will of course remain and continue to provide zero-configuration instant-on deployment, a secure global authority for identities, and free traffic relaying for those who can't establish peer to peer connections. - -### Local Configuration - -An element of our design philosophy is "features are bugs." This isn't an absolute dogma but more of a guiding principle. We try as hard as we can to avoid adding features, especially "knobs" that must be tweaked by a user. - -As of 1.2.0 we've decided that certain knobs are unavoidable, and so there is now a `local.conf` file that can be used to configure them. See the ZeroTier One documentation for these. They include: - - * Blacklisting interfaces you want to make sure ZeroTier doesn't use for network traffic, such as VPNs, slow links, or backplanes designated for only certain kinds of traffic. - * Turning uPnP/NAT-PMP on or off. - * Configuring software updates on Windows and Mac platforms. - * Defining trusted paths (the old trusted paths file is now deprecated) - * Setting the ZeroTier main port so it doesn't have to be changed on the command line, which is very inconvenient in many cases. - -### Improved In-Band Software Updates - -A good software update system for Windows and Mac clients has been a missing feature in previous versions. It does exist but we've been shy about using it so far due to its fragility in some environments. - -We've greatly improved this mechanism in 1.2.0. Not only does it now do a better job of actually invoking the update, but it also transfers updates in-band using the ZeroTier protocol. This means it can work in environments that do not allows http/https traffic or that force it through proxies. There's also now an update channel setting: `beta` or `release` (the default). - -Software updates are authenticated three ways: - - 1. ZeroTier's own signing key is used to sign all updates and this signature is checked prior to installation. ZeroTier, Inc.'s signatures are performed on an air-gapped machine. - - 2. Updates for Mac and Windows are signed using Apple and Microsoft (DigiCert EV) keys and will not install unless these signatures are also valid. - - 3. The new in-band update mechanism also authenticates the source of the update via ZeroTier's built-in security features. This provides transport security, while 1 and 2 provide security of the update at rest. - -Updates are now configurable via `local.conf`. There are three options: `disable`, `download`, and `apply`. The third (apply) is the default for official builds on Windows and Mac, making updates happen silently and automatically as they do for popular browsers like Chrome and Firefox. Updates are disabled by default on Linux and other Unix-type systems as these are typically updated through package managers. - -### Path Link Quality Awareness - -Version 1.2.0 is now aware of the link quality of direct paths with other 1.2.0 nodes. This information isn't used yet but is visible through the JSON API. (Quality always shows as 100% with pre-1.2.0 nodes.) Quality is measured passively with no additional overhead using a counter based packet loss detection algorithm. - -This information is visible from the command line via `listpeers`: - - 200 listpeers XXXXXXXXXX 199.XXX.XXX.XXX/9993;10574;15250;1.00 48 1.2.0 LEAF - 200 listpeers XXXXXXXXXX 195.XXX.XXX.XXX/45584;467;7608;0.44 290 1.2.0 LEAF - -The first peer's path is at 100% (1.00), while the second peer's path is suffering quite a bit of packet loss (0.44). - -Link quality awareness is a precursor to intelligent multi-path and QoS support, which will in future versions bring us to feature parity with SD-WAN products like Cisco iWAN. - -### Security Improvements - -Version 1.2.0 adds anti-DOS (denial of service) rate limits and other hardening for improved resiliency against a number of denial of service attack scenarios. - -It also adds a mechanism for instantaneous credential revocation. This can be used to revoke certificates of membership instantly to kick a node off a network (for private networks) and also to revoke capabilities and tags. The new controller sends revocations by default when a peer is de-authorized. - -Revocations propagate using a "rumor mill" peer to peer algorithm. This means that a controller need only successfully send a revocation to at least one member of a network with connections to other active members. At this point the revocation will flood through the network peer to peer very quickly. This helps make revocations more robust in the face of poor connectivity with the controller or attempts to incapacitate the controller with denial of service attacks, as well as making revocations faster on huge networks. - -### Windows and Macintosh UI Improvements (ZeroTier One) - -The Mac has a whole new UI built natively in Objective-C. It provides a pulldown similar in appearance and operation to the Mac WiFi task bar menu. - -The Windows UI has also been improved and now provides a task bar icon that can be right-clicked to manage networks. Both now expose managed route and IP permissions, allowing nodes to easily opt in to full tunnel operation if you have a router configured on your network. - -### Ad-Hoc Networks - -A special kind of public network called an ad-hoc network may be accessed by joining a network ID with the format: - - ffSSSSEEEE000000 - | | | | - | | | Reserved for future use, must be 0 - | | End of port range (hex) - | Start of port range (hex) - Reserved ZeroTier address prefix indicating a controller-less network - -Ad-hoc networks are public (no access control) networks that have no network controller. Instead their configuration and other credentials are generated locally. Ad-hoc networks permit only IPv6 UDP and TCP unicast traffic (no multicast or broadcast) using 6plane format NDP-emulated IPv6 addresses. In addition an ad-hoc network ID encodes an IP port range. UDP packets and TCP SYN (connection open) packets are only allowed to desintation ports within the encoded range. - -For example `ff00160016000000` is an ad-hoc network allowing only SSH, while `ff0000ffff000000` is an ad-hoc network allowing any UDP or TCP port. - -Keep in mind that these networks are public and anyone in the entire world can join them. Care must be taken to avoid exposing vulnerable services or sharing unwanted files or other resources. - -### Network Controller (Partial) Rewrite - -The network controller has been largely rewritten to use a simple in-filesystem JSON data store in place of SQLite, and it is now included by default in all Windows, Mac, Linux, and BSD builds. This means any desktop or server node running ZeroTier One can now be a controller with no recompilation needed. - -If you have data in an old SQLite3 controller we've included a NodeJS script in `controller/migrate-sqlite` to migrate data to the new format. If you don't migrate, members will start getting `NOT_FOUND` when they attempt to query for updates. - -## Major Bug Fixes in 1.2.0 - - * **The Windows HyperV 100% CPU bug is FINALLY DEAD**: This long-running problem turns out to have been an issue with Windows itself, but one we were triggering by placing invalid data into the Windows registry. Microsoft is aware of the issue but we've also fixed the triggering problem on our side. ZeroTier should now co-exist quite well with HyperV and should now be able to be bridged with a HyperV virtual switch. - * **Segmenation faults on musl-libc based Linux systems**: Alpine Linux and some embedded Linux systems that use musl libc (a minimal libc) experienced segmentation faults. These were due to a smaller default stack size. A work-around that sets the stack size for new threads has been added. - * **Windows firewall blocks local JSON API**: On some Windows systems the firewall likes to block 127.0.0.1:9993 for mysterious reasons. This is now fixed in the installer via the addition of another firewall exemption rule. - * **UI crash on embedded Windows due to missing fonts**: The MSI installer now ships fonts and will install them if they are not present, so this should be fixed. - -## Other Improvements in 1.2.0 - - * **Improved dead path detection**: ZeroTier is now more aggressive about expiring paths that do not seem to be active. If a path seems marginal it is re-confirmed before re-use. - * **Minor performance improvements**: We've reduced unnecessary memcpy's and made a few other performance improvements in the core. - * **Linux static binaries**: For our official packages (the ones in the download.zerotier.com apt and yum repositories) we now build Linux binaries with static linking. Hopefully this will stop all the bug reports relating to library inconsistencies, as well as allowing our deb packages to run on a wider variety of Debian-based distributions. (There are far too many of these to support officially!) The overhead for this is very small, especially since we built our static versions against musl-libc. Distribution maintainers are of course free to build dynamically linked versions for inclusion into distributions; this only affects our official binaries. diff --git a/zto/controller/EmbeddedNetworkController.cpp b/zto/controller/EmbeddedNetworkController.cpp deleted file mode 100644 index ce56e90..0000000 --- a/zto/controller/EmbeddedNetworkController.cpp +++ /dev/null @@ -1,1850 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#endif -#include - -#include -#include -#include -#include -#include - -#include "../include/ZeroTierOne.h" -#include "../node/Constants.hpp" - -#include "EmbeddedNetworkController.hpp" - -#include "../node/Node.hpp" -#include "../node/Utils.hpp" -#include "../node/CertificateOfMembership.hpp" -#include "../node/NetworkConfig.hpp" -#include "../node/Dictionary.hpp" -#include "../node/InetAddress.hpp" -#include "../node/MAC.hpp" -#include "../node/Address.hpp" - -using json = nlohmann::json; - -// API version reported via JSON control plane -#define ZT_NETCONF_CONTROLLER_API_VERSION 3 - -// Number of requests to remember in member history -#define ZT_NETCONF_DB_MEMBER_HISTORY_LENGTH 2 - -// Min duration between requests for an address/nwid combo to prevent floods -#define ZT_NETCONF_MIN_REQUEST_PERIOD 1000 - -// Nodes are considered active if they've queried in less than this long -#define ZT_NETCONF_NODE_ACTIVE_THRESHOLD (ZT_NETWORK_AUTOCONF_DELAY * 2) - -namespace ZeroTier { - -static json _renderRule(ZT_VirtualNetworkRule &rule) -{ - char tmp[128]; - json r = json::object(); - const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rule.t & 0x3f); - - switch(rt) { - case ZT_NETWORK_RULE_ACTION_DROP: - r["type"] = "ACTION_DROP"; - break; - case ZT_NETWORK_RULE_ACTION_ACCEPT: - r["type"] = "ACTION_ACCEPT"; - break; - case ZT_NETWORK_RULE_ACTION_TEE: - r["type"] = "ACTION_TEE"; - r["address"] = Address(rule.v.fwd.address).toString(); - r["flags"] = (unsigned int)rule.v.fwd.flags; - r["length"] = (unsigned int)rule.v.fwd.length; - break; - case ZT_NETWORK_RULE_ACTION_WATCH: - r["type"] = "ACTION_WATCH"; - r["address"] = Address(rule.v.fwd.address).toString(); - r["flags"] = (unsigned int)rule.v.fwd.flags; - r["length"] = (unsigned int)rule.v.fwd.length; - break; - case ZT_NETWORK_RULE_ACTION_REDIRECT: - r["type"] = "ACTION_REDIRECT"; - r["address"] = Address(rule.v.fwd.address).toString(); - r["flags"] = (unsigned int)rule.v.fwd.flags; - break; - case ZT_NETWORK_RULE_ACTION_BREAK: - r["type"] = "ACTION_BREAK"; - break; - default: - break; - } - - if (r.size() == 0) { - switch(rt) { - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - r["type"] = "MATCH_SOURCE_ZEROTIER_ADDRESS"; - r["zt"] = Address(rule.v.zt).toString(); - break; - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - r["type"] = "MATCH_DEST_ZEROTIER_ADDRESS"; - r["zt"] = Address(rule.v.zt).toString(); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - r["type"] = "MATCH_VLAN_ID"; - r["vlanId"] = (unsigned int)rule.v.vlanId; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - r["type"] = "MATCH_VLAN_PCP"; - r["vlanPcp"] = (unsigned int)rule.v.vlanPcp; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - r["type"] = "MATCH_VLAN_DEI"; - r["vlanDei"] = (unsigned int)rule.v.vlanDei; - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - r["type"] = "MATCH_MAC_SOURCE"; - Utils::snprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)rule.v.mac[0],(unsigned int)rule.v.mac[1],(unsigned int)rule.v.mac[2],(unsigned int)rule.v.mac[3],(unsigned int)rule.v.mac[4],(unsigned int)rule.v.mac[5]); - r["mac"] = tmp; - break; - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - r["type"] = "MATCH_MAC_DEST"; - Utils::snprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)rule.v.mac[0],(unsigned int)rule.v.mac[1],(unsigned int)rule.v.mac[2],(unsigned int)rule.v.mac[3],(unsigned int)rule.v.mac[4],(unsigned int)rule.v.mac[5]); - r["mac"] = tmp; - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - r["type"] = "MATCH_IPV4_SOURCE"; - r["ip"] = InetAddress(&(rule.v.ipv4.ip),4,(unsigned int)rule.v.ipv4.mask).toString(); - break; - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - r["type"] = "MATCH_IPV4_DEST"; - r["ip"] = InetAddress(&(rule.v.ipv4.ip),4,(unsigned int)rule.v.ipv4.mask).toString(); - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - r["type"] = "MATCH_IPV6_SOURCE"; - r["ip"] = InetAddress(rule.v.ipv6.ip,16,(unsigned int)rule.v.ipv6.mask).toString(); - break; - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - r["type"] = "MATCH_IPV6_DEST"; - r["ip"] = InetAddress(rule.v.ipv6.ip,16,(unsigned int)rule.v.ipv6.mask).toString(); - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - r["type"] = "MATCH_IP_TOS"; - r["mask"] = (unsigned int)rule.v.ipTos.mask; - r["start"] = (unsigned int)rule.v.ipTos.value[0]; - r["end"] = (unsigned int)rule.v.ipTos.value[1]; - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - r["type"] = "MATCH_IP_PROTOCOL"; - r["ipProtocol"] = (unsigned int)rule.v.ipProtocol; - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - r["type"] = "MATCH_ETHERTYPE"; - r["etherType"] = (unsigned int)rule.v.etherType; - break; - case ZT_NETWORK_RULE_MATCH_ICMP: - r["type"] = "MATCH_ICMP"; - r["icmpType"] = (unsigned int)rule.v.icmp.type; - if ((rule.v.icmp.flags & 0x01) != 0) - r["icmpCode"] = (unsigned int)rule.v.icmp.code; - else r["icmpCode"] = json(); - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - r["type"] = "MATCH_IP_SOURCE_PORT_RANGE"; - r["start"] = (unsigned int)rule.v.port[0]; - r["end"] = (unsigned int)rule.v.port[1]; - break; - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - r["type"] = "MATCH_IP_DEST_PORT_RANGE"; - r["start"] = (unsigned int)rule.v.port[0]; - r["end"] = (unsigned int)rule.v.port[1]; - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: - r["type"] = "MATCH_CHARACTERISTICS"; - Utils::snprintf(tmp,sizeof(tmp),"%.16llx",rule.v.characteristics); - r["mask"] = tmp; - break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - r["type"] = "MATCH_FRAME_SIZE_RANGE"; - r["start"] = (unsigned int)rule.v.frameSize[0]; - r["end"] = (unsigned int)rule.v.frameSize[1]; - break; - case ZT_NETWORK_RULE_MATCH_RANDOM: - r["type"] = "MATCH_RANDOM"; - r["probability"] = (unsigned long)rule.v.randomProbability; - break; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: - r["type"] = "MATCH_TAGS_DIFFERENCE"; - r["id"] = rule.v.tag.id; - r["value"] = rule.v.tag.value; - break; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: - r["type"] = "MATCH_TAGS_BITWISE_AND"; - r["id"] = rule.v.tag.id; - r["value"] = rule.v.tag.value; - break; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: - r["type"] = "MATCH_TAGS_BITWISE_OR"; - r["id"] = rule.v.tag.id; - r["value"] = rule.v.tag.value; - break; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: - r["type"] = "MATCH_TAGS_BITWISE_XOR"; - r["id"] = rule.v.tag.id; - r["value"] = rule.v.tag.value; - break; - case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: - r["type"] = "MATCH_TAGS_EQUAL"; - r["id"] = rule.v.tag.id; - r["value"] = rule.v.tag.value; - break; - case ZT_NETWORK_RULE_MATCH_TAG_SENDER: - r["type"] = "MATCH_TAG_SENDER"; - r["id"] = rule.v.tag.id; - r["value"] = rule.v.tag.value; - break; - case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: - r["type"] = "MATCH_TAG_RECEIVER"; - r["id"] = rule.v.tag.id; - r["value"] = rule.v.tag.value; - break; - default: - break; - } - - if (r.size() > 0) { - r["not"] = ((rule.t & 0x80) != 0); - r["or"] = ((rule.t & 0x40) != 0); - } - } - - return r; -} - -static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) -{ - if (!r.is_object()) - return false; - - const std::string t(OSUtils::jsonString(r["type"],"")); - memset(&rule,0,sizeof(ZT_VirtualNetworkRule)); - - if (OSUtils::jsonBool(r["not"],false)) - rule.t = 0x80; - else rule.t = 0x00; - if (OSUtils::jsonBool(r["or"],false)) - rule.t |= 0x40; - - bool tag = false; - if (t == "ACTION_DROP") { - rule.t |= ZT_NETWORK_RULE_ACTION_DROP; - return true; - } else if (t == "ACTION_ACCEPT") { - rule.t |= ZT_NETWORK_RULE_ACTION_ACCEPT; - return true; - } else if (t == "ACTION_TEE") { - rule.t |= ZT_NETWORK_RULE_ACTION_TEE; - rule.v.fwd.address = Utils::hexStrToU64(OSUtils::jsonString(r["address"],"0").c_str()) & 0xffffffffffULL; - rule.v.fwd.flags = (uint32_t)(OSUtils::jsonInt(r["flags"],0ULL) & 0xffffffffULL); - rule.v.fwd.length = (uint16_t)(OSUtils::jsonInt(r["length"],0ULL) & 0xffffULL); - return true; - } else if (t == "ACTION_WATCH") { - rule.t |= ZT_NETWORK_RULE_ACTION_WATCH; - rule.v.fwd.address = Utils::hexStrToU64(OSUtils::jsonString(r["address"],"0").c_str()) & 0xffffffffffULL; - rule.v.fwd.flags = (uint32_t)(OSUtils::jsonInt(r["flags"],0ULL) & 0xffffffffULL); - rule.v.fwd.length = (uint16_t)(OSUtils::jsonInt(r["length"],0ULL) & 0xffffULL); - return true; - } else if (t == "ACTION_REDIRECT") { - rule.t |= ZT_NETWORK_RULE_ACTION_REDIRECT; - rule.v.fwd.address = Utils::hexStrToU64(OSUtils::jsonString(r["address"],"0").c_str()) & 0xffffffffffULL; - rule.v.fwd.flags = (uint32_t)(OSUtils::jsonInt(r["flags"],0ULL) & 0xffffffffULL); - return true; - } else if (t == "ACTION_BREAK") { - rule.t |= ZT_NETWORK_RULE_ACTION_BREAK; - return true; - } else if (t == "MATCH_SOURCE_ZEROTIER_ADDRESS") { - rule.t |= ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS; - rule.v.zt = Utils::hexStrToU64(OSUtils::jsonString(r["zt"],"0").c_str()) & 0xffffffffffULL; - return true; - } else if (t == "MATCH_DEST_ZEROTIER_ADDRESS") { - rule.t |= ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS; - rule.v.zt = Utils::hexStrToU64(OSUtils::jsonString(r["zt"],"0").c_str()) & 0xffffffffffULL; - return true; - } else if (t == "MATCH_VLAN_ID") { - rule.t |= ZT_NETWORK_RULE_MATCH_VLAN_ID; - rule.v.vlanId = (uint16_t)(OSUtils::jsonInt(r["vlanId"],0ULL) & 0xffffULL); - return true; - } else if (t == "MATCH_VLAN_PCP") { - rule.t |= ZT_NETWORK_RULE_MATCH_VLAN_PCP; - rule.v.vlanPcp = (uint8_t)(OSUtils::jsonInt(r["vlanPcp"],0ULL) & 0xffULL); - return true; - } else if (t == "MATCH_VLAN_DEI") { - rule.t |= ZT_NETWORK_RULE_MATCH_VLAN_DEI; - rule.v.vlanDei = (uint8_t)(OSUtils::jsonInt(r["vlanDei"],0ULL) & 0xffULL); - return true; - } else if (t == "MATCH_MAC_SOURCE") { - rule.t |= ZT_NETWORK_RULE_MATCH_MAC_SOURCE; - const std::string mac(OSUtils::jsonString(r["mac"],"0")); - Utils::unhex(mac.c_str(),(unsigned int)mac.length(),rule.v.mac,6); - return true; - } else if (t == "MATCH_MAC_DEST") { - rule.t |= ZT_NETWORK_RULE_MATCH_MAC_DEST; - const std::string mac(OSUtils::jsonString(r["mac"],"0")); - Utils::unhex(mac.c_str(),(unsigned int)mac.length(),rule.v.mac,6); - return true; - } else if (t == "MATCH_IPV4_SOURCE") { - rule.t |= ZT_NETWORK_RULE_MATCH_IPV4_SOURCE; - InetAddress ip(OSUtils::jsonString(r["ip"],"0.0.0.0")); - rule.v.ipv4.ip = reinterpret_cast(&ip)->sin_addr.s_addr; - rule.v.ipv4.mask = Utils::ntoh(reinterpret_cast(&ip)->sin_port) & 0xff; - if (rule.v.ipv4.mask > 32) rule.v.ipv4.mask = 32; - return true; - } else if (t == "MATCH_IPV4_DEST") { - rule.t |= ZT_NETWORK_RULE_MATCH_IPV4_DEST; - InetAddress ip(OSUtils::jsonString(r["ip"],"0.0.0.0")); - rule.v.ipv4.ip = reinterpret_cast(&ip)->sin_addr.s_addr; - rule.v.ipv4.mask = Utils::ntoh(reinterpret_cast(&ip)->sin_port) & 0xff; - if (rule.v.ipv4.mask > 32) rule.v.ipv4.mask = 32; - return true; - } else if (t == "MATCH_IPV6_SOURCE") { - rule.t |= ZT_NETWORK_RULE_MATCH_IPV6_SOURCE; - InetAddress ip(OSUtils::jsonString(r["ip"],"::0")); - memcpy(rule.v.ipv6.ip,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); - rule.v.ipv6.mask = Utils::ntoh(reinterpret_cast(&ip)->sin6_port) & 0xff; - if (rule.v.ipv6.mask > 128) rule.v.ipv6.mask = 128; - return true; - } else if (t == "MATCH_IPV6_DEST") { - rule.t |= ZT_NETWORK_RULE_MATCH_IPV6_DEST; - InetAddress ip(OSUtils::jsonString(r["ip"],"::0")); - memcpy(rule.v.ipv6.ip,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); - rule.v.ipv6.mask = Utils::ntoh(reinterpret_cast(&ip)->sin6_port) & 0xff; - if (rule.v.ipv6.mask > 128) rule.v.ipv6.mask = 128; - return true; - } else if (t == "MATCH_IP_TOS") { - rule.t |= ZT_NETWORK_RULE_MATCH_IP_TOS; - rule.v.ipTos.mask = (uint8_t)(OSUtils::jsonInt(r["mask"],0ULL) & 0xffULL); - rule.v.ipTos.value[0] = (uint8_t)(OSUtils::jsonInt(r["start"],0ULL) & 0xffULL); - rule.v.ipTos.value[1] = (uint8_t)(OSUtils::jsonInt(r["end"],0ULL) & 0xffULL); - return true; - } else if (t == "MATCH_IP_PROTOCOL") { - rule.t |= ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; - rule.v.ipProtocol = (uint8_t)(OSUtils::jsonInt(r["ipProtocol"],0ULL) & 0xffULL); - return true; - } else if (t == "MATCH_ETHERTYPE") { - rule.t |= ZT_NETWORK_RULE_MATCH_ETHERTYPE; - rule.v.etherType = (uint16_t)(OSUtils::jsonInt(r["etherType"],0ULL) & 0xffffULL); - return true; - } else if (t == "MATCH_ICMP") { - rule.t |= ZT_NETWORK_RULE_MATCH_ICMP; - rule.v.icmp.type = (uint8_t)(OSUtils::jsonInt(r["icmpType"],0ULL) & 0xffULL); - json &code = r["icmpCode"]; - if (code.is_null()) { - rule.v.icmp.code = 0; - rule.v.icmp.flags = 0x00; - } else { - rule.v.icmp.code = (uint8_t)(OSUtils::jsonInt(code,0ULL) & 0xffULL); - rule.v.icmp.flags = 0x01; - } - return true; - } else if (t == "MATCH_IP_SOURCE_PORT_RANGE") { - rule.t |= ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE; - rule.v.port[0] = (uint16_t)(OSUtils::jsonInt(r["start"],0ULL) & 0xffffULL); - rule.v.port[1] = (uint16_t)(OSUtils::jsonInt(r["end"],(uint64_t)rule.v.port[0]) & 0xffffULL); - return true; - } else if (t == "MATCH_IP_DEST_PORT_RANGE") { - rule.t |= ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE; - rule.v.port[0] = (uint16_t)(OSUtils::jsonInt(r["start"],0ULL) & 0xffffULL); - rule.v.port[1] = (uint16_t)(OSUtils::jsonInt(r["end"],(uint64_t)rule.v.port[0]) & 0xffffULL); - return true; - } else if (t == "MATCH_CHARACTERISTICS") { - rule.t |= ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; - if (r.count("mask")) { - json &v = r["mask"]; - if (v.is_number()) { - rule.v.characteristics = v; - } else { - std::string tmp = v; - rule.v.characteristics = Utils::hexStrToU64(tmp.c_str()); - } - } - return true; - } else if (t == "MATCH_FRAME_SIZE_RANGE") { - rule.t |= ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE; - rule.v.frameSize[0] = (uint16_t)(OSUtils::jsonInt(r["start"],0ULL) & 0xffffULL); - rule.v.frameSize[1] = (uint16_t)(OSUtils::jsonInt(r["end"],(uint64_t)rule.v.frameSize[0]) & 0xffffULL); - return true; - } else if (t == "MATCH_RANDOM") { - rule.t |= ZT_NETWORK_RULE_MATCH_RANDOM; - rule.v.randomProbability = (uint32_t)(OSUtils::jsonInt(r["probability"],0ULL) & 0xffffffffULL); - return true; - } else if (t == "MATCH_TAGS_DIFFERENCE") { - rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE; - tag = true; - } else if (t == "MATCH_TAGS_BITWISE_AND") { - rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND; - tag = true; - } else if (t == "MATCH_TAGS_BITWISE_OR") { - rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR; - tag = true; - } else if (t == "MATCH_TAGS_BITWISE_XOR") { - rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR; - tag = true; - } else if (t == "MATCH_TAGS_EQUAL") { - rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_EQUAL; - tag = true; - } else if (t == "MATCH_TAG_SENDER") { - rule.t |= ZT_NETWORK_RULE_MATCH_TAG_SENDER; - tag = true; - } else if (t == "MATCH_TAG_RECEIVER") { - rule.t |= ZT_NETWORK_RULE_MATCH_TAG_RECEIVER; - tag = true; - } - if (tag) { - rule.v.tag.id = (uint32_t)(OSUtils::jsonInt(r["id"],0ULL) & 0xffffffffULL); - rule.v.tag.value = (uint32_t)(OSUtils::jsonInt(r["value"],0ULL) & 0xffffffffULL); - return true; - } - - return false; -} - -EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *dbPath) : - _startTime(OSUtils::now()), - _threadsStarted(false), - _db(dbPath), - _node(node) -{ - OSUtils::mkdir(dbPath); - OSUtils::lockDownFile(dbPath,true); // networks might contain auth tokens, etc., so restrict directory permissions -} - -EmbeddedNetworkController::~EmbeddedNetworkController() -{ - Mutex::Lock _l(_threads_m); - if (_threadsStarted) { - for(int i=0;i<(ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT*2);++i) - _queue.post((_RQEntry *)0); - for(int i=0;i_sender = sender; - this->_signingId = signingId; -} - -void EmbeddedNetworkController::request( - uint64_t nwid, - const InetAddress &fromAddr, - uint64_t requestPacketId, - const Identity &identity, - const Dictionary &metaData) -{ - if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) - return; - - { - Mutex::Lock _l(_threads_m); - if (!_threadsStarted) { - for(int i=0;inwid = nwid; - qe->requestPacketId = requestPacketId; - qe->fromAddr = fromAddr; - qe->identity = identity; - qe->metaData = metaData; - _queue.post(qe); -} - -unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( - const std::vector &path, - const std::map &urlArgs, - const std::map &headers, - const std::string &body, - std::string &responseBody, - std::string &responseContentType) -{ - if ((path.size() > 0)&&(path[0] == "network")) { - - if ((path.size() >= 2)&&(path[1].length() == 16)) { - const uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); - char nwids[24]; - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid); - - json network; - { - Mutex::Lock _l(_db_m); - network = _db.get("network",nwids); - } - if (!network.size()) - return 404; - - if (path.size() >= 3) { - - if (path[2] == "member") { - - if (path.size() >= 4) { - const uint64_t address = Utils::hexStrToU64(path[3].c_str()); - - json member; - { - Mutex::Lock _l(_db_m); - member = _db.get("network",nwids,"member",Address(address).toString()); - } - if (!member.size()) - return 404; - - _addMemberNonPersistedFields(member,OSUtils::now()); - responseBody = OSUtils::jsonDump(member); - responseContentType = "application/json"; - - return 200; - } else { - - Mutex::Lock _l(_db_m); - - responseBody = "{"; - _db.filter((std::string("network/") + nwids + "/member/"),[&responseBody](const std::string &n,const json &member) { - if ((member.is_object())&&(member.size() > 0)) { - responseBody.append((responseBody.length() == 1) ? "\"" : ",\""); - responseBody.append(OSUtils::jsonString(member["id"],"0")); - responseBody.append("\":"); - responseBody.append(OSUtils::jsonString(member["revision"],"0")); - } - return true; // never delete - }); - responseBody.push_back('}'); - responseContentType = "application/json"; - - return 200; - } - - } // else 404 - - } else { - - const uint64_t now = OSUtils::now(); - _NetworkMemberInfo nmi; - _getNetworkMemberInfo(now,nwid,nmi); - _addNetworkNonPersistedFields(network,now,nmi); - responseBody = OSUtils::jsonDump(network); - responseContentType = "application/json"; - return 200; - - } - } else if (path.size() == 1) { - - std::set networkIds; - { - Mutex::Lock _l(_db_m); - _db.filter("network/",[&networkIds](const std::string &n,const json &obj) { - if (n.length() == (16 + 8)) - networkIds.insert(n.substr(8)); - return true; // do not delete - }); - } - - responseBody.push_back('['); - for(std::set::iterator i(networkIds.begin());i!=networkIds.end();++i) { - responseBody.append((responseBody.length() == 1) ? "\"" : ",\""); - responseBody.append(*i); - responseBody.append("\""); - } - responseBody.push_back(']'); - responseContentType = "application/json"; - return 200; - - } // else 404 - - } else { - - char tmp[4096]; - Utils::snprintf(tmp,sizeof(tmp),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now()); - responseBody = tmp; - responseContentType = "application/json"; - return 200; - - } - - return 404; -} - -unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( - const std::vector &path, - const std::map &urlArgs, - const std::map &headers, - const std::string &body, - std::string &responseBody, - std::string &responseContentType) -{ - if (path.empty()) - return 404; - - json b; - try { - b = OSUtils::jsonParse(body); - if (!b.is_object()) { - responseBody = "{ \"message\": \"body is not a JSON object\" }"; - responseContentType = "application/json"; - return 400; - } - } catch ( ... ) { - responseBody = "{ \"message\": \"body JSON is invalid\" }"; - responseContentType = "application/json"; - return 400; - } - const uint64_t now = OSUtils::now(); - - if (path[0] == "network") { - - if ((path.size() >= 2)&&(path[1].length() == 16)) { - uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); - char nwids[24]; - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid); - - if (path.size() >= 3) { - - if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) { - uint64_t address = Utils::hexStrToU64(path[3].c_str()); - char addrs[24]; - Utils::snprintf(addrs,sizeof(addrs),"%.10llx",(unsigned long long)address); - - json member; - { - Mutex::Lock _l(_db_m); - member = _db.get("network",nwids,"member",Address(address).toString()); - } - json origMember(member); // for detecting changes - _initMember(member); - - try { - if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"],false); - if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"],false); - - if (b.count("authorized")) { - const bool newAuth = OSUtils::jsonBool(b["authorized"],false); - if (newAuth != OSUtils::jsonBool(member["authorized"],false)) { - member["authorized"] = newAuth; - member[((newAuth) ? "lastAuthorizedTime" : "lastDeauthorizedTime")] = now; - - json ah; - ah["a"] = newAuth; - ah["by"] = "api"; - ah["ts"] = now; - ah["ct"] = json(); - ah["c"] = json(); - member["authHistory"].push_back(ah); - - // Member is being de-authorized, so spray Revocation objects to all online members - if (!newAuth) { - _clearNetworkMemberInfoCache(nwid); - Revocation rev(_node->prng(),nwid,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(address),Revocation::CREDENTIAL_TYPE_COM); - rev.sign(_signingId); - Mutex::Lock _l(_lastRequestTime_m); - for(std::map< std::pair,uint64_t >::iterator i(_lastRequestTime.begin());i!=_lastRequestTime.end();++i) { - if ((now - i->second) < ZT_NETWORK_AUTOCONF_DELAY) - _node->ncSendRevocation(Address(i->first.first),rev); - } - } - } - } - - if (b.count("ipAssignments")) { - json &ipa = b["ipAssignments"]; - if (ipa.is_array()) { - json mipa(json::array()); - for(unsigned long i=0;i mtags; - for(unsigned long i=0;i::iterator t(mtags.begin());t!=mtags.end();++t) { - json ta = json::array(); - ta.push_back(t->first); - ta.push_back(t->second); - mtagsa.push_back(ta); - } - member["tags"] = mtagsa; - } - } - - if (b.count("capabilities")) { - json &capabilities = b["capabilities"]; - if (capabilities.is_array()) { - json mcaps = json::array(); - for(unsigned long i=0;itestId),sizeof(test->testId)); - test->credentialNetworkId = nwid; - test->ptr = (void *)this; - json hops = b["hops"]; - if (hops.is_array()) { - for(unsigned long i=0;ihops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(s.c_str()) & 0xffffffffffULL; - } - ++test->hopCount; - } else if (hops2.is_string()) { - std::string s = hops2; - test->hops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(s.c_str()) & 0xffffffffffULL; - ++test->hopCount; - } - } - } - test->reportAtEveryHop = (OSUtils::jsonBool(b["reportAtEveryHop"],true) ? 1 : 0); - - if (!test->hopCount) { - _tests.pop_back(); - responseBody = "{ \"message\": \"a test must contain at least one hop\" }"; - responseContentType = "application/json"; - return 400; - } - - test->timestamp = OSUtils::now(); - - if (_node) { - _node->circuitTestBegin((void *)0,test,&(EmbeddedNetworkController::_circuitTestCallback)); - } else { - _tests.pop_back(); - return 500; - } - - char json[512]; - Utils::snprintf(json,sizeof(json),"{\"testId\":\"%.16llx\",\"timestamp\":%llu}",test->testId,test->timestamp); - responseBody = json; - responseContentType = "application/json"; - - return 200; - - } // else 404 - - } else { - // POST to network ID - - json network; - { - Mutex::Lock _l(_db_m); - - // Magic ID ending with ______ picks a random unused network ID - if (path[1].substr(10) == "______") { - nwid = 0; - uint64_t nwidPrefix = (Utils::hexStrToU64(path[1].substr(0,10).c_str()) << 24) & 0xffffffffff000000ULL; - uint64_t nwidPostfix = 0; - for(unsigned long k=0;k<100000;++k) { // sanity limit on trials - Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix)); - uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL); - if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL; - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)tryNwid); - if (_db.get("network",nwids).size() <= 0) { - nwid = tryNwid; - break; - } - } - if (!nwid) - return 503; - } - - network = _db.get("network",nwids); - } - json origNetwork(network); // for detecting changes - _initNetwork(network); - - try { - if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],""); - if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true); - if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false); - if (b.count("allowPassiveBridging")) network["allowPassiveBridging"] = OSUtils::jsonBool(b["allowPassiveBridging"],false); - if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL); - - if (b.count("v4AssignMode")) { - json nv4m; - json &v4m = b["v4AssignMode"]; - if (v4m.is_string()) { // backward compatibility - nv4m["zt"] = (OSUtils::jsonString(v4m,"") == "zt"); - } else if (v4m.is_object()) { - nv4m["zt"] = OSUtils::jsonBool(v4m["zt"],false); - } else nv4m["zt"] = false; - network["v4AssignMode"] = nv4m; - } - - if (b.count("v6AssignMode")) { - json nv6m; - json &v6m = b["v6AssignMode"]; - if (!nv6m.is_object()) nv6m = json::object(); - if (v6m.is_string()) { // backward compatibility - std::vector v6ms(OSUtils::split(OSUtils::jsonString(v6m,"").c_str(),",","","")); - std::sort(v6ms.begin(),v6ms.end()); - v6ms.erase(std::unique(v6ms.begin(),v6ms.end()),v6ms.end()); - nv6m["rfc4193"] = false; - nv6m["zt"] = false; - nv6m["6plane"] = false; - for(std::vector::iterator i(v6ms.begin());i!=v6ms.end();++i) { - if (*i == "rfc4193") - nv6m["rfc4193"] = true; - else if (*i == "zt") - nv6m["zt"] = true; - else if (*i == "6plane") - nv6m["6plane"] = true; - } - } else if (v6m.is_object()) { - if (v6m.count("rfc4193")) nv6m["rfc4193"] = OSUtils::jsonBool(v6m["rfc4193"],false); - if (v6m.count("zt")) nv6m["zt"] = OSUtils::jsonBool(v6m["zt"],false); - if (v6m.count("6plane")) nv6m["6plane"] = OSUtils::jsonBool(v6m["6plane"],false); - } else { - nv6m["rfc4193"] = false; - nv6m["zt"] = false; - nv6m["6plane"] = false; - } - network["v6AssignMode"] = nv6m; - } - - if (b.count("routes")) { - json &rts = b["routes"]; - if (rts.is_array()) { - json nrts = json::array(); - for(unsigned long i=0;i()); - InetAddress v; - if (via.is_string()) v.fromString(via.get()); - if ( ((t.ss_family == AF_INET)||(t.ss_family == AF_INET6)) && (t.netmaskBitsValid()) ) { - json tmp; - tmp["target"] = t.toString(); - if (v.ss_family == t.ss_family) - tmp["via"] = v.toIpString(); - else tmp["via"] = json(); - nrts.push_back(tmp); - } - } - } - } - network["routes"] = nrts; - } - } - - if (b.count("ipAssignmentPools")) { - json &ipp = b["ipAssignmentPools"]; - if (ipp.is_array()) { - json nipp = json::array(); - for(unsigned long i=0;i 0) { - json t = json::object(); - t["token"] = tstr; - t["expires"] = OSUtils::jsonInt(token["expires"],0ULL); - t["maxUsesPerMember"] = OSUtils::jsonInt(token["maxUsesPerMember"],0ULL); - nat.push_back(t); - } - } - } - network["authTokens"] = nat; - } - } - - if (b.count("capabilities")) { - json &capabilities = b["capabilities"]; - if (capabilities.is_array()) { - std::map< uint64_t,json > ncaps; - for(unsigned long i=0;i::iterator c(ncaps.begin());c!=ncaps.end();++c) - ncapsa.push_back(c->second); - network["capabilities"] = ncapsa; - } - } - - if (b.count("tags")) { - json &tags = b["tags"]; - if (tags.is_array()) { - std::map< uint64_t,json > ntags; - for(unsigned long i=0;i::iterator t(ntags.begin());t!=ntags.end();++t) - ntagsa.push_back(t->second); - network["tags"] = ntagsa; - } - } - - } catch ( ... ) { - responseBody = "{ \"message\": \"exception occurred while parsing body variables\" }"; - responseContentType = "application/json"; - return 400; - } - - network["id"] = nwids; - network["nwid"] = nwids; // legacy - - if (network != origNetwork) { - json &revj = network["revision"]; - network["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); - network["lastModified"] = now; - { - Mutex::Lock _l(_db_m); - _db.put("network",nwids,network); - } - - // Send an update to all members of the network - _db.filter((std::string("network/") + nwids + "/member/"),[this,&now,&nwid](const std::string &n,const json &obj) { - _pushMemberUpdate(now,nwid,obj); - return true; // do not delete - }); - } - - _NetworkMemberInfo nmi; - _getNetworkMemberInfo(now,nwid,nmi); - _addNetworkNonPersistedFields(network,now,nmi); - - responseBody = OSUtils::jsonDump(network); - responseContentType = "application/json"; - return 200; - } // else 404 - - } // else 404 - - } else if (path[0] == "dbtest") { - - json testRec; - const uint64_t now = OSUtils::now(); - testRec["clock"] = now; - testRec["uptime"] = (now - _startTime); - _db.put("dbtest",testRec); - - } - - return 404; -} - -unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE( - const std::vector &path, - const std::map &urlArgs, - const std::map &headers, - const std::string &body, - std::string &responseBody, - std::string &responseContentType) -{ - if (path.empty()) - return 404; - - if (path[0] == "network") { - if ((path.size() >= 2)&&(path[1].length() == 16)) { - const uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); - - char nwids[24]; - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid); - json network; - { - Mutex::Lock _l(_db_m); - network = _db.get("network",nwids); - } - if (!network.size()) - return 404; - - if (path.size() >= 3) { - if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) { - const uint64_t address = Utils::hexStrToU64(path[3].c_str()); - - Mutex::Lock _l(_db_m); - - json member = _db.get("network",nwids,"member",Address(address).toString()); - _db.erase("network",nwids,"member",Address(address).toString()); - - if (!member.size()) - return 404; - responseBody = OSUtils::jsonDump(member); - responseContentType = "application/json"; - return 200; - } - } else { - Mutex::Lock _l(_db_m); - - std::string pfx("network/"); pfx.append(nwids); - _db.filter(pfx,[](const std::string &n,const json &obj) { - return false; // delete - }); - - Mutex::Lock _l2(_nmiCache_m); - _nmiCache.erase(nwid); - - responseBody = OSUtils::jsonDump(network); - responseContentType = "application/json"; - return 200; - } - } // else 404 - - } // else 404 - - return 404; -} - -void EmbeddedNetworkController::threadMain() - throw() -{ - uint64_t lastCircuitTestCheck = 0; - for(;;) { - _RQEntry *const qe = _queue.get(); // waits on next request - if (!qe) break; // enqueue a NULL to terminate threads - try { - _request(qe->nwid,qe->fromAddr,qe->requestPacketId,qe->identity,qe->metaData); - } catch ( ... ) {} - delete qe; - - uint64_t now = OSUtils::now(); - if ((now - lastCircuitTestCheck) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) { - lastCircuitTestCheck = now; - Mutex::Lock _l(_tests_m); - for(std::list< ZT_CircuitTest >::iterator i(_tests.begin());i!=_tests.end();) { - if ((now - i->timestamp) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) { - _node->circuitTestEnd(&(*i)); - _tests.erase(i++); - } else ++i; - } - } - } -} - -void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report) -{ - char tmp[1024],id[128]; - EmbeddedNetworkController *const self = reinterpret_cast(test->ptr); - - if ((!test)||(!report)||(!test->credentialNetworkId)) return; // sanity check - - const uint64_t now = OSUtils::now(); - Utils::snprintf(id,sizeof(id),"network/%.16llx/test/%.16llx-%.16llx-%.10llx-%.10llx",test->credentialNetworkId,test->testId,now,report->upstream,report->current); - Utils::snprintf(tmp,sizeof(tmp), - "{\"id\": \"%s\"," - "\"timestamp\": %llu," - "\"networkId\": \"%.16llx\"," - "\"testId\": \"%.16llx\"," - "\"upstream\": \"%.10llx\"," - "\"current\": \"%.10llx\"," - "\"receivedTimestamp\": %llu," - "\"sourcePacketId\": \"%.16llx\"," - "\"flags\": %llu," - "\"sourcePacketHopCount\": %u," - "\"errorCode\": %u," - "\"vendor\": %d," - "\"protocolVersion\": %u," - "\"majorVersion\": %u," - "\"minorVersion\": %u," - "\"revision\": %u," - "\"platform\": %d," - "\"architecture\": %d," - "\"receivedOnLocalAddress\": \"%s\"," - "\"receivedFromRemoteAddress\": \"%s\"," - "\"receivedFromLinkQuality\": %f}", - id + 30, // last bit only, not leading path - (unsigned long long)test->timestamp, - (unsigned long long)test->credentialNetworkId, - (unsigned long long)test->testId, - (unsigned long long)report->upstream, - (unsigned long long)report->current, - (unsigned long long)now, - (unsigned long long)report->sourcePacketId, - (unsigned long long)report->flags, - report->sourcePacketHopCount, - report->errorCode, - (int)report->vendor, - report->protocolVersion, - report->majorVersion, - report->minorVersion, - report->revision, - (int)report->platform, - (int)report->architecture, - reinterpret_cast(&(report->receivedOnLocalAddress))->toString().c_str(), - reinterpret_cast(&(report->receivedFromRemoteAddress))->toString().c_str(), - ((double)report->receivedFromLinkQuality / (double)ZT_PATH_LINK_QUALITY_MAX)); - - Mutex::Lock _l(self->_db_m); - self->_db.writeRaw(id,std::string(tmp)); -} - -void EmbeddedNetworkController::_request( - uint64_t nwid, - const InetAddress &fromAddr, - uint64_t requestPacketId, - const Identity &identity, - const Dictionary &metaData) -{ - if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) - return; - - const uint64_t now = OSUtils::now(); - - if (requestPacketId) { - Mutex::Lock _l(_lastRequestTime_m); - uint64_t &lrt = _lastRequestTime[std::pair(identity.address().toInt(),nwid)]; - if ((now - lrt) <= ZT_NETCONF_MIN_REQUEST_PERIOD) - return; - lrt = now; - } - - char nwids[24]; - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid); - json network; - json member; - { - Mutex::Lock _l(_db_m); - network = _db.get("network",nwids); - member = _db.get("network",nwids,"member",identity.address().toString()); - } - - if (!network.size()) { - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_OBJECT_NOT_FOUND); - return; - } - - const bool newMember = (member.size() == 0); - - json origMember(member); // for detecting modification later - _initMember(member); - - { - std::string haveIdStr(OSUtils::jsonString(member["identity"],"")); - if (haveIdStr.length() > 0) { - // If we already know this member's identity perform a full compare. This prevents - // a "collision" from being able to auth onto our network in place of an already - // known member. - try { - if (Identity(haveIdStr.c_str()) != identity) { - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); - return; - } - } catch ( ... ) { - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); - return; - } - } else { - // If we do not yet know this member's identity, learn it. - member["identity"] = identity.toString(false); - } - } - - // These are always the same, but make sure they are set - member["id"] = identity.address().toString(); - member["address"] = member["id"]; - member["nwid"] = nwids; - - // Determine whether and how member is authorized - const char *authorizedBy = (const char *)0; - bool autoAuthorized = false; - json autoAuthCredentialType,autoAuthCredential; - if (OSUtils::jsonBool(member["authorized"],false)) { - authorizedBy = "memberIsAuthorized"; - } else if (!OSUtils::jsonBool(network["private"],true)) { - authorizedBy = "networkIsPublic"; - json &ahist = member["authHistory"]; - if ((!ahist.is_array())||(ahist.size() == 0)) - autoAuthorized = true; - } else { - char presentedAuth[512]; - if (metaData.get(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH,presentedAuth,sizeof(presentedAuth)) > 0) { - presentedAuth[511] = (char)0; // sanity check - - // Check for bearer token presented by member - if ((strlen(presentedAuth) > 6)&&(!strncmp(presentedAuth,"token:",6))) { - const char *const presentedToken = presentedAuth + 6; - - json &authTokens = network["authTokens"]; - if (authTokens.is_array()) { - for(unsigned long i=0;i now))&&(tstr == presentedToken)) { - bool usable = (maxUses == 0); - if (!usable) { - uint64_t useCount = 0; - json &ahist = member["authHistory"]; - if (ahist.is_array()) { - for(unsigned long j=0;j= ZT_NETCONF_DB_MEMBER_HISTORY_LENGTH) - break; - } - } - member["recentLog"] = recentLog; - - // Also only do this on real requests - member["lastRequestMetaData"] = metaData.data(); - } - - // If they are not authorized, STOP! - if (!authorizedBy) { - if (origMember != member) { - member["lastModified"] = now; - Mutex::Lock _l(_db_m); - _db.put("network",nwids,"member",identity.address().toString(),member); - } - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); - return; - } - - // ------------------------------------------------------------------------- - // If we made it this far, they are authorized. - // ------------------------------------------------------------------------- - - NetworkConfig nc; - _NetworkMemberInfo nmi; - _getNetworkMemberInfo(now,nwid,nmi); - - uint64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; - if (now > nmi.mostRecentDeauthTime) { - // If we recently de-authorized a member, shrink credential TTL/max delta to - // be below the threshold required to exclude it. Cap this to a min/max to - // prevent jitter or absurdly large values. - const uint64_t deauthWindow = now - nmi.mostRecentDeauthTime; - if (deauthWindow < ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA) { - credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA; - } else if (deauthWindow < (ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA + 5000ULL)) { - credentialtmd = deauthWindow - 5000ULL; - } - } - - nc.networkId = nwid; - nc.type = OSUtils::jsonBool(network["private"],true) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; - nc.timestamp = now; - nc.credentialTimeMaxDelta = credentialtmd; - nc.revision = OSUtils::jsonInt(network["revision"],0ULL); - nc.issuedTo = identity.address(); - if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; - if (OSUtils::jsonBool(network["allowPassiveBridging"],false)) nc.flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; - Utils::scopy(nc.name,sizeof(nc.name),OSUtils::jsonString(network["name"],"").c_str()); - nc.multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL); - - for(std::set
::const_iterator ab(nmi.activeBridges.begin());ab!=nmi.activeBridges.end();++ab) { - nc.addSpecialist(*ab,ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE); - } - - json &v4AssignMode = network["v4AssignMode"]; - json &v6AssignMode = network["v6AssignMode"]; - json &ipAssignmentPools = network["ipAssignmentPools"]; - json &routes = network["routes"]; - json &rules = network["rules"]; - json &capabilities = network["capabilities"]; - json &tags = network["tags"]; - json &memberCapabilities = member["capabilities"]; - json &memberTags = member["tags"]; - - if (metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,0) <= 0) { - // Old versions with no rules engine support get an allow everything rule. - // Since rules are enforced bidirectionally, newer versions *will* still - // enforce rules on the inbound side. - nc.ruleCount = 1; - nc.rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT; - } else { - if (rules.is_array()) { - for(unsigned long i=0;i= ZT_MAX_NETWORK_RULES) - break; - if (_parseRule(rules[i],nc.rules[nc.ruleCount])) - ++nc.ruleCount; - } - } - - std::map< uint64_t,json * > capsById; - if (!memberCapabilities.is_array()) - memberCapabilities = json::array(); - if (capabilities.is_array()) { - for(unsigned long i=0;i::const_iterator ctmp = capsById.find(capId); - if (ctmp != capsById.end()) { - json *cap = ctmp->second; - if ((cap)&&(cap->is_object())&&(cap->size() > 0)) { - ZT_VirtualNetworkRule capr[ZT_MAX_CAPABILITY_RULES]; - unsigned int caprc = 0; - json &caprj = (*cap)["rules"]; - if ((caprj.is_array())&&(caprj.size() > 0)) { - for(unsigned long j=0;j= ZT_MAX_CAPABILITY_RULES) - break; - if (_parseRule(caprj[j],capr[caprc])) - ++caprc; - } - } - nc.capabilities[nc.capabilityCount] = Capability((uint32_t)capId,nwid,now,1,capr,caprc); - if (nc.capabilities[nc.capabilityCount].sign(_signingId,identity.address())) - ++nc.capabilityCount; - if (nc.capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES) - break; - } - } - } - - std::map< uint32_t,uint32_t > memberTagsById; - if (memberTags.is_array()) { - for(unsigned long i=0;i::const_iterator t(memberTagsById.begin());t!=memberTagsById.end();++t) { - if (nc.tagCount >= ZT_MAX_NETWORK_TAGS) - break; - nc.tags[nc.tagCount] = Tag(nwid,now,identity.address(),t->first,t->second); - if (nc.tags[nc.tagCount].sign(_signingId)) - ++nc.tagCount; - } - } - - if (routes.is_array()) { - for(unsigned long i=0;i= ZT_MAX_NETWORK_ROUTES) - break; - json &route = routes[i]; - json &target = route["target"]; - json &via = route["via"]; - if (target.is_string()) { - const InetAddress t(target.get()); - InetAddress v; - if (via.is_string()) v.fromString(via.get()); - if ((t.ss_family == AF_INET)||(t.ss_family == AF_INET6)) { - ZT_VirtualNetworkRoute *r = &(nc.routes[nc.routeCount]); - *(reinterpret_cast(&(r->target))) = t; - if (v.ss_family == t.ss_family) - *(reinterpret_cast(&(r->via))) = v; - ++nc.routeCount; - } - } - } - } - - const bool noAutoAssignIps = OSUtils::jsonBool(member["noAutoAssignIps"],false); - - if ((v6AssignMode.is_object())&&(!noAutoAssignIps)) { - if ((OSUtils::jsonBool(v6AssignMode["rfc4193"],false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { - nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv6rfc4193(nwid,identity.address().toInt()); - nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; - } - if ((OSUtils::jsonBool(v6AssignMode["6plane"],false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { - nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv66plane(nwid,identity.address().toInt()); - nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; - } - } - - bool haveManagedIpv4AutoAssignment = false; - bool haveManagedIpv6AutoAssignment = false; // "special" NDP-emulated address types do not count - json ipAssignments = member["ipAssignments"]; // we want to make a copy - if (ipAssignments.is_array()) { - for(unsigned long i=0;i(&(nc.routes[rk].target))->containsAddress(ip)) ) - routedNetmaskBits = reinterpret_cast(&(nc.routes[rk].target))->netmaskBits(); - } - - if (routedNetmaskBits > 0) { - if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) { - ip.setPort(routedNetmaskBits); - nc.staticIps[nc.staticIpCount++] = ip; - } - if (ip.ss_family == AF_INET) - haveManagedIpv4AutoAssignment = true; - else if (ip.ss_family == AF_INET6) - haveManagedIpv6AutoAssignment = true; - } - } - } else { - ipAssignments = json::array(); - } - - if ( (ipAssignmentPools.is_array()) && ((v6AssignMode.is_object())&&(OSUtils::jsonBool(v6AssignMode["zt"],false))) && (!haveManagedIpv6AutoAssignment) && (!noAutoAssignIps) ) { - for(unsigned long p=0;((p s[1])&&((e[1] - s[1]) >= 0xffffffffffULL)) { - // First see if we can just cram a ZeroTier ID into the higher 64 bits. If so do that. - xx[0] = Utils::hton(x[0]); - xx[1] = Utils::hton(x[1] + identity.address().toInt()); - } else { - // Otherwise pick random addresses -- this technically doesn't explore the whole range if the lower 64 bit range is >= 1 but that won't matter since that would be huge anyway - Utils::getSecureRandom((void *)xx,16); - if ((e[0] > s[0])) - xx[0] %= (e[0] - s[0]); - else xx[0] = 0; - if ((e[1] > s[1])) - xx[1] %= (e[1] - s[1]); - else xx[1] = 0; - xx[0] = Utils::hton(x[0] + xx[0]); - xx[1] = Utils::hton(x[1] + xx[1]); - } - - InetAddress ip6((const void *)xx,16,0); - - // Check if this IP is within a local-to-Ethernet routed network - int routedNetmaskBits = 0; - for(unsigned int rk=0;rk(&(nc.routes[rk].target))->containsAddress(ip6)) ) - routedNetmaskBits = reinterpret_cast(&(nc.routes[rk].target))->netmaskBits(); - } - - // If it's routed, then try to claim and assign it and if successful end loop - if ((routedNetmaskBits > 0)&&(!nmi.allocatedIps.count(ip6))) { - ipAssignments.push_back(ip6.toIpString()); - member["ipAssignments"] = ipAssignments; - ip6.setPort((unsigned int)routedNetmaskBits); - if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) - nc.staticIps[nc.staticIpCount++] = ip6; - haveManagedIpv6AutoAssignment = true; - _clearNetworkMemberInfoCache(nwid); // clear cache to prevent IP assignment duplication on many rapid assigns - break; - } - } - } - } - } - } - - if ( (ipAssignmentPools.is_array()) && ((v4AssignMode.is_object())&&(OSUtils::jsonBool(v4AssignMode["zt"],false))) && (!haveManagedIpv4AutoAssignment) && (!noAutoAssignIps) ) { - for(unsigned long p=0;((p(&ipRangeStartIA)->sin_addr.s_addr)); - uint32_t ipRangeEnd = Utils::ntoh((uint32_t)(reinterpret_cast(&ipRangeEndIA)->sin_addr.s_addr)); - if ((ipRangeEnd < ipRangeStart)||(ipRangeStart == 0)) - continue; - uint32_t ipRangeLen = ipRangeEnd - ipRangeStart; - - // Start with the LSB of the member's address - uint32_t ipTrialCounter = (uint32_t)(identity.address().toInt() & 0xffffffff); - - for(uint32_t k=ipRangeStart,trialCount=0;((k<=ipRangeEnd)&&(trialCount < 1000));++k,++trialCount) { - uint32_t ip = (ipRangeLen > 0) ? (ipRangeStart + (ipTrialCounter % ipRangeLen)) : ipRangeStart; - ++ipTrialCounter; - if ((ip & 0x000000ff) == 0x000000ff) - continue; // don't allow addresses that end in .255 - - // Check if this IP is within a local-to-Ethernet routed network - int routedNetmaskBits = -1; - for(unsigned int rk=0;rk(&(nc.routes[rk].target))->sin_addr.s_addr)); - int targetBits = Utils::ntoh((uint16_t)(reinterpret_cast(&(nc.routes[rk].target))->sin_port)); - if ((ip & (0xffffffff << (32 - targetBits))) == targetIp) { - routedNetmaskBits = targetBits; - break; - } - } - } - - // If it's routed, then try to claim and assign it and if successful end loop - const InetAddress ip4(Utils::hton(ip),0); - if ((routedNetmaskBits > 0)&&(!nmi.allocatedIps.count(ip4))) { - ipAssignments.push_back(ip4.toIpString()); - member["ipAssignments"] = ipAssignments; - if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) { - struct sockaddr_in *const v4ip = reinterpret_cast(&(nc.staticIps[nc.staticIpCount++])); - v4ip->sin_family = AF_INET; - v4ip->sin_port = Utils::hton((uint16_t)routedNetmaskBits); - v4ip->sin_addr.s_addr = Utils::hton(ip); - } - haveManagedIpv4AutoAssignment = true; - _clearNetworkMemberInfoCache(nwid); // clear cache to prevent IP assignment duplication on many rapid assigns - break; - } - } - } - } - } - } - - // Issue a certificate of ownership for all static IPs - if (nc.staticIpCount) { - nc.certificatesOfOwnership[0] = CertificateOfOwnership(nwid,now,identity.address(),1); - for(unsigned int i=0;incSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR); - return; - } - - if (member != origMember) { - member["lastModified"] = now; - Mutex::Lock _l(_db_m); - _db.put("network",nwids,"member",identity.address().toString(),member); - } - - _sender->ncSendConfig(nwid,requestPacketId,identity.address(),nc,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6); -} - -void EmbeddedNetworkController::_getNetworkMemberInfo(uint64_t now,uint64_t nwid,_NetworkMemberInfo &nmi) -{ - char pfx[256]; - Utils::snprintf(pfx,sizeof(pfx),"network/%.16llx/member",nwid); - - { - Mutex::Lock _l(_nmiCache_m); - std::map::iterator c(_nmiCache.find(nwid)); - if ((c != _nmiCache.end())&&((now - c->second.nmiTimestamp) < 1000)) { // a short duration cache but limits CPU use on big networks - nmi = c->second; - return; - } - } - - { - Mutex::Lock _l(_db_m); - _db.filter(pfx,[&nmi,&now](const std::string &n,const json &member) { - try { - if (OSUtils::jsonBool(member["authorized"],false)) { - ++nmi.authorizedMemberCount; - - if (member.count("recentLog")) { - const json &mlog = member["recentLog"]; - if ((mlog.is_array())&&(mlog.size() > 0)) { - const json &mlog1 = mlog[0]; - if (mlog1.is_object()) { - if ((now - OSUtils::jsonInt(mlog1["ts"],0ULL)) < ZT_NETCONF_NODE_ACTIVE_THRESHOLD) - ++nmi.activeMemberCount; - } - } - } - - if (OSUtils::jsonBool(member["activeBridge"],false)) { - nmi.activeBridges.insert(Address(Utils::hexStrToU64(OSUtils::jsonString(member["id"],"0000000000").c_str()))); - } - - if (member.count("ipAssignments")) { - const json &mips = member["ipAssignments"]; - if (mips.is_array()) { - for(unsigned long i=0;i 0)&&(mdstr.length() > 0)) { - const Identity id(idstr); - bool online; - { - Mutex::Lock _l(_lastRequestTime_m); - std::map< std::pair,uint64_t >::iterator lrt(_lastRequestTime.find(std::pair(id.address().toInt(),nwid))); - online = ( (lrt != _lastRequestTime.end()) && ((now - lrt->second) < ZT_NETWORK_AUTOCONF_DELAY) ); - } - if (online) { - Dictionary *metaData = new Dictionary(mdstr.c_str()); - try { - this->request(nwid,InetAddress(),0,id,*metaData); - } catch ( ... ) {} - delete metaData; - } - } - } catch ( ... ) {} -} - -} // namespace ZeroTier diff --git a/zto/controller/EmbeddedNetworkController.hpp b/zto/controller/EmbeddedNetworkController.hpp deleted file mode 100644 index 0ae2f3b..0000000 --- a/zto/controller/EmbeddedNetworkController.hpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_SQLITENETWORKCONTROLLER_HPP -#define ZT_SQLITENETWORKCONTROLLER_HPP - -#include - -#include -#include -#include -#include -#include - -#include "../node/Constants.hpp" - -#include "../node/NetworkController.hpp" -#include "../node/Mutex.hpp" -#include "../node/Utils.hpp" -#include "../node/Address.hpp" -#include "../node/InetAddress.hpp" - -#include "../osdep/OSUtils.hpp" -#include "../osdep/Thread.hpp" -#include "../osdep/BlockingQueue.hpp" - -#include "../ext/json/json.hpp" - -#include "JSONDB.hpp" - -// Number of background threads to start -- not actually started until needed -#define ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT 4 - -// TTL for circuit tests -#define ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION 120000 - -namespace ZeroTier { - -class Node; - -class EmbeddedNetworkController : public NetworkController -{ -public: - /** - * @param node Parent node - * @param dbPath Path to store data - */ - EmbeddedNetworkController(Node *node,const char *dbPath); - virtual ~EmbeddedNetworkController(); - - virtual void init(const Identity &signingId,Sender *sender); - - virtual void request( - uint64_t nwid, - const InetAddress &fromAddr, - uint64_t requestPacketId, - const Identity &identity, - const Dictionary &metaData); - - unsigned int handleControlPlaneHttpGET( - const std::vector &path, - const std::map &urlArgs, - const std::map &headers, - const std::string &body, - std::string &responseBody, - std::string &responseContentType); - unsigned int handleControlPlaneHttpPOST( - const std::vector &path, - const std::map &urlArgs, - const std::map &headers, - const std::string &body, - std::string &responseBody, - std::string &responseContentType); - unsigned int handleControlPlaneHttpDELETE( - const std::vector &path, - const std::map &urlArgs, - const std::map &headers, - const std::string &body, - std::string &responseBody, - std::string &responseContentType); - - void threadMain() - throw(); - -private: - struct _RQEntry - { - uint64_t nwid; - uint64_t requestPacketId; - InetAddress fromAddr; - Identity identity; - Dictionary metaData; - }; - - // Gathers a bunch of statistics about members of a network, IP assignments, etc. that we need in various places - struct _NetworkMemberInfo - { - _NetworkMemberInfo() : authorizedMemberCount(0),activeMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {} - std::set
activeBridges; - std::set allocatedIps; - unsigned long authorizedMemberCount; - unsigned long activeMemberCount; - unsigned long totalMemberCount; - uint64_t mostRecentDeauthTime; - uint64_t nmiTimestamp; // time this NMI structure was computed - }; - - static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report); - void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary &metaData); - void _getNetworkMemberInfo(uint64_t now,uint64_t nwid,_NetworkMemberInfo &nmi); - inline void _clearNetworkMemberInfoCache(const uint64_t nwid) { Mutex::Lock _l(_nmiCache_m); _nmiCache.erase(nwid); } - void _pushMemberUpdate(uint64_t now,uint64_t nwid,const nlohmann::json &member); - - // These init objects with default and static/informational fields - inline void _initMember(nlohmann::json &member) - { - if (!member.count("authorized")) member["authorized"] = false; - if (!member.count("authHistory")) member["authHistory"] = nlohmann::json::array(); - if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array(); - if (!member.count("recentLog")) member["recentLog"] = nlohmann::json::array(); - if (!member.count("activeBridge")) member["activeBridge"] = false; - if (!member.count("tags")) member["tags"] = nlohmann::json::array(); - if (!member.count("capabilities")) member["capabilities"] = nlohmann::json::array(); - if (!member.count("creationTime")) member["creationTime"] = OSUtils::now(); - if (!member.count("noAutoAssignIps")) member["noAutoAssignIps"] = false; - if (!member.count("revision")) member["revision"] = 0ULL; - if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL; - if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL; - member["objtype"] = "member"; - } - inline void _initNetwork(nlohmann::json &network) - { - if (!network.count("private")) network["private"] = true; - if (!network.count("creationTime")) network["creationTime"] = OSUtils::now(); - if (!network.count("name")) network["name"] = ""; - if (!network.count("multicastLimit")) network["multicastLimit"] = (uint64_t)32; - if (!network.count("enableBroadcast")) network["enableBroadcast"] = true; - if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}}; - if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}}; - if (!network.count("authTokens")) network["authTokens"] = nlohmann::json::array(); - if (!network.count("capabilities")) network["capabilities"] = nlohmann::json::array(); - if (!network.count("tags")) network["tags"] = nlohmann::json::array(); - if (!network.count("routes")) network["routes"] = nlohmann::json::array(); - if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array(); - if (!network.count("rules")) { - // If unspecified, rules are set to allow anything and behave like a flat L2 segment - network["rules"] = {{ - { "not",false }, - { "or", false }, - { "type","ACTION_ACCEPT" } - }}; - } - network["objtype"] = "network"; - } - inline void _addNetworkNonPersistedFields(nlohmann::json &network,uint64_t now,const _NetworkMemberInfo &nmi) - { - network["clock"] = now; - network["authorizedMemberCount"] = nmi.authorizedMemberCount; - network["activeMemberCount"] = nmi.activeMemberCount; - network["totalMemberCount"] = nmi.totalMemberCount; - } - inline void _addMemberNonPersistedFields(nlohmann::json &member,uint64_t now) - { - member["clock"] = now; - } - - const uint64_t _startTime; - - BlockingQueue<_RQEntry *> _queue; - Thread _threads[ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT]; - bool _threadsStarted; - Mutex _threads_m; - - std::map _nmiCache; - Mutex _nmiCache_m; - - JSONDB _db; - Mutex _db_m; - - Node *const _node; - std::string _path; - - NetworkController::Sender *_sender; - Identity _signingId; - - std::list< ZT_CircuitTest > _tests; - Mutex _tests_m; - - std::map< std::pair,uint64_t > _lastRequestTime; // last request time by - Mutex _lastRequestTime_m; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/controller/JSONDB.cpp b/zto/controller/JSONDB.cpp deleted file mode 100644 index 8b6de9b..0000000 --- a/zto/controller/JSONDB.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "JSONDB.hpp" - -namespace ZeroTier { - -static const nlohmann::json _EMPTY_JSON(nlohmann::json::object()); - -bool JSONDB::writeRaw(const std::string &n,const std::string &obj) -{ - if (!_isValidObjectName(n)) - return false; - - const std::string path(_genPath(n,true)); - if (!path.length()) - return false; - - const std::string buf(obj); - if (!OSUtils::writeFile(path.c_str(),buf)) - return false; - - return true; -} - -bool JSONDB::put(const std::string &n,const nlohmann::json &obj) -{ - if (!_isValidObjectName(n)) - return false; - - const std::string path(_genPath(n,true)); - if (!path.length()) - return false; - - const std::string buf(OSUtils::jsonDump(obj)); - if (!OSUtils::writeFile(path.c_str(),buf)) - return false; - - _E &e = _db[n]; - e.obj = obj; - - return true; -} - -const nlohmann::json &JSONDB::get(const std::string &n) -{ - if (!_isValidObjectName(n)) - return _EMPTY_JSON; - - std::map::iterator e(_db.find(n)); - if (e != _db.end()) - return e->second.obj; - - const std::string path(_genPath(n,false)); - if (!path.length()) - return _EMPTY_JSON; - std::string buf; - if (!OSUtils::readFile(path.c_str(),buf)) - return _EMPTY_JSON; - - _E &e2 = _db[n]; - try { - e2.obj = OSUtils::jsonParse(buf); - } catch ( ... ) { - e2.obj = _EMPTY_JSON; - buf = "{}"; - } - - return e2.obj; -} - -void JSONDB::erase(const std::string &n) -{ - if (!_isValidObjectName(n)) - return; - - std::string path(_genPath(n,true)); - if (!path.length()) - return; - - OSUtils::rm(path.c_str()); - _db.erase(n); -} - -void JSONDB::_reload(const std::string &p,const std::string &b) -{ - std::vector dl(OSUtils::listDirectory(p.c_str())); - for(std::vector::const_iterator di(dl.begin());di!=dl.end();++di) { - if ((di->length() > 5)&&(di->substr(di->length() - 5) == ".json")) { - this->get(b + di->substr(0,di->length() - 5)); - } else { - this->_reload((p + ZT_PATH_SEPARATOR + *di),(b + *di + ZT_PATH_SEPARATOR)); - } - } -} - -bool JSONDB::_isValidObjectName(const std::string &n) -{ - if (n.length() == 0) - return false; - const char *p = n.c_str(); - char c; - // For security reasons we should not allow dots, backslashes, or other path characters or potential path characters. - while ((c = *(p++))) { - if (!( ((c >= 'a')&&(c <= 'z')) || ((c >= 'A')&&(c <= 'Z')) || ((c >= '0')&&(c <= '9')) || (c == '/') || (c == '_') || (c == '~') || (c == '-') )) - return false; - } - return true; -} - -std::string JSONDB::_genPath(const std::string &n,bool create) -{ - std::vector pt(OSUtils::split(n.c_str(),"/","","")); - if (pt.size() == 0) - return std::string(); - - std::string p(_basePath); - if (create) OSUtils::mkdir(p.c_str()); - for(unsigned long i=0,j=(unsigned long)(pt.size()-1);i. - */ - -#ifndef ZT_JSONDB_HPP -#define ZT_JSONDB_HPP - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../ext/json/json.hpp" -#include "../osdep/OSUtils.hpp" - -namespace ZeroTier { - -/** - * Hierarchical JSON store that persists into the filesystem - */ -class JSONDB -{ -public: - JSONDB(const std::string &basePath) : - _basePath(basePath) - { - _reload(_basePath,std::string()); - } - - inline void reload() - { - _db.clear(); - _reload(_basePath,std::string()); - } - - bool writeRaw(const std::string &n,const std::string &obj); - - bool put(const std::string &n,const nlohmann::json &obj); - - inline bool put(const std::string &n1,const std::string &n2,const nlohmann::json &obj) { return this->put((n1 + "/" + n2),obj); } - inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3),obj); } - inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3 + "/" + n4),obj); } - inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5),obj); } - - const nlohmann::json &get(const std::string &n); - - inline const nlohmann::json &get(const std::string &n1,const std::string &n2) { return this->get((n1 + "/" + n2)); } - inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3) { return this->get((n1 + "/" + n2 + "/" + n3)); } - inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4) { return this->get((n1 + "/" + n2 + "/" + n3 + "/" + n4)); } - inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5) { return this->get((n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5)); } - - void erase(const std::string &n); - - inline void erase(const std::string &n1,const std::string &n2) { this->erase(n1 + "/" + n2); } - inline void erase(const std::string &n1,const std::string &n2,const std::string &n3) { this->erase(n1 + "/" + n2 + "/" + n3); } - inline void erase(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4) { this->erase(n1 + "/" + n2 + "/" + n3 + "/" + n4); } - inline void erase(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5) { this->erase(n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5); } - - template - inline void filter(const std::string &prefix,F func) - { - for(std::map::iterator i(_db.lower_bound(prefix));i!=_db.end();) { - if ((i->first.length() >= prefix.length())&&(!memcmp(i->first.data(),prefix.data(),prefix.length()))) { - if (!func(i->first,get(i->first))) { - std::map::iterator i2(i); ++i2; - this->erase(i->first); - i = i2; - } else ++i; - } else break; - } - } - - inline bool operator==(const JSONDB &db) const { return ((_basePath == db._basePath)&&(_db == db._db)); } - inline bool operator!=(const JSONDB &db) const { return (!(*this == db)); } - -private: - void _reload(const std::string &p,const std::string &b); - bool _isValidObjectName(const std::string &n); - std::string _genPath(const std::string &n,bool create); - - struct _E - { - nlohmann::json obj; - inline bool operator==(const _E &e) const { return (obj == e.obj); } - inline bool operator!=(const _E &e) const { return (obj != e.obj); } - }; - - std::string _basePath; - std::map _db; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/controller/README.md b/zto/controller/README.md deleted file mode 100644 index db8d015..0000000 --- a/zto/controller/README.md +++ /dev/null @@ -1,248 +0,0 @@ -Network Controller Microservice -====== - -Every ZeroTier virtual network has a *network controller*. This is our reference implementation and is the same one we use to power our own hosted services at [my.zerotier.com](https://my.zerotier.com/). Network controllers act as configuration servers and certificate authorities for the members of networks. Controllers are located on the network by simply parsing out the first 10 digits of a network's 16-digit network ID: these are the address of the controller. - -As of ZeroTier One version 1.2.0 this code is included in normal builds for desktop, laptop, and server (Linux, etc.) targets, allowing any device to create virtual networks without having to be rebuilt from source with special flags to enable this feature. While this does offer a convenient way to create ad-hoc networks or experiment, we recommend running a dedicated controller somewhere secure and stable for any "serious" use case. - -Controller data is stored in JSON format under `controller.d` in the ZeroTier working directory. It can be copied, rsync'd, placed in `git`, etc. The files under `controller.d` should not be modified in place while the controller is running or data loss may result, and if they are edited directly take care not to save corrupt JSON since that can also lead to data loss when the controller is restarted. Going through the API is strongly preferred to directly modifying these files. - -### Upgrading from Older (1.1.14 or earlier) Versions - -Older versions of this code used a SQLite database instead of in-filesystem JSON. A migration utility called `migrate-sqlite` is included here and *must* be used to migrate this data to the new format. If the controller is started with an old `controller.db` in its working directory it will terminate after printing an error to *stderr*. This is done to prevent "surprises" for those running DIY controllers using the old code. - -The migration tool is written in nodeJS and can be used like this: - - cd migrate-sqlite - npm install - node migrate.js - -Very old versions of nodeJS may have issues. We tested it with version 7. - -### Scalability and Reliability - -Controllers can in theory host up to 2^24 networks and serve many millions of devices (or more), but we recommend spreading large numbers of networks across many controllers for load balancing and fault tolerance reasons. Since the controller uses the filesystem as its data store we recommend fast filesystems and fast SSD drives for heavily loaded controllers. - -Since ZeroTier nodes are mobile and do not need static IPs, implementing high availability fail-over for controllers is easy. Just replicate their working directories from master to backup and have something automatically fire up the backup if the master goes down. Many modern orchestration tools have built-in support for this. It would also be possible in theory to run controllers on a replicated or distributed filesystem, but we haven't tested this yet. - -### Dockerizing Controllers - -ZeroTier network controllers can easily be run in Docker or other container systems. Since containers do not need to actually join networks, extra privilege options like "--device=/dev/net/tun --privileged" are not needed. You'll just need to map the local JSON API port of the running controller and allow it to access the Internet (over UDP/9993 at a minimum) so things can reach and query it. - -### Network Controller API - -The controller API is hosted via the same JSON API endpoint that ZeroTier One uses for local control (usually at 127.0.0.1 port 9993). All controller options are routed under the `/controller` base path. - -The controller microservice does not implement any fine-grained access control (authentication is via authtoken.secret just like the regular JSON API) or other complex mangement features. It just takes network and network member configurations and reponds to controller queries. We have an enterprise product called [ZeroTier Central](https://my.zerotier.com/) that we host as a service (and that companies can license to self-host) that does this. - -All working network IDs on a controller must begin with the controller's ZeroTier address. The API will *allow* "foreign" networks to be added but the controller will have no way of doing anything with them since nobody will know to query it. (In the future we might support secondaries, which would make this relevant.) - -The JSON API is *very* sensitive about types. Integers must be integers and strings strings, etc. Incorrectly typed and unrecognized fields may result in ignored fields or a 400 (bad request) error. - -#### `/controller` - - * Purpose: Check for controller function and return controller status - * Methods: GET - * Returns: { object } - -| Field | Type | Description | Writable | -| ------------------ | ----------- | ------------------------------------------------- | -------- | -| controller | boolean | Always 'true' | no | -| apiVersion | integer | Controller API version, currently 3 | no | -| clock | integer | Current clock on controller, ms since epoch | no | - -#### `/controller/network` - - * Purpose: List all networks hosted by this controller - * Methods: GET - * Returns: [ string, ... ] - -This returns an array of 16-digit hexadecimal network IDs. - -#### `/controller/network/` - - * Purpose: Create, configure, and delete hosted networks - * Methods: GET, POST, DELETE - * Returns: { object } - -By making queries to this path you can create, configure, and delete networks. DELETE is final, so don't do it unless you really mean it. - -When POSTing new networks take care that their IDs are not in use, otherwise you may overwrite an existing one. To create a new network with a random unused ID, POST to `/controller/network/##########______`. The #'s are the controller's 10-digit ZeroTier address and they're followed by six underscores. Check the `nwid` field of the returned JSON object for your network's newly allocated ID. Subsequent POSTs to this network must refer to its actual path. - -| Field | Type | Description | Writable | -| --------------------- | ------------- | ------------------------------------------------- | -------- | -| id | string | 16-digit network ID | no | -| nwid | string | 16-digit network ID (old, but still around) | no | -| clock | integer | Current clock, ms since epoch | no | -| name | string | A short name for this network | YES | -| private | boolean | Is access control enabled? | YES | -| enableBroadcast | boolean | Ethernet ff:ff:ff:ff:ff:ff allowed? | YES | -| allowPassiveBridging | boolean | Allow any member to bridge (very experimental) | YES | -| v4AssignMode | object | IPv4 management and assign options (see below) | YES | -| v6AssignMode | object | IPv6 management and assign options (see below) | YES | -| multicastLimit | integer | Maximum recipients for a multicast packet | YES | -| creationTime | integer | Time network was first created | no | -| revision | integer | Network config revision counter | no | -| authorizedMemberCount | integer | Number of authorized members (for private nets) | no | -| activeMemberCount | integer | Number of members that appear to be online | no | -| totalMemberCount | integer | Total known members of this network | no | -| routes | array[object] | Managed IPv4 and IPv6 routes; see below | YES | -| ipAssignmentPools | array[object] | IP auto-assign ranges; see below | YES | -| rules | array[object] | Traffic rules; see below | YES | - -Recent changes: - - * The `ipLocalRoutes` field appeared in older versions but is no longer present. Routes will now show up in `routes`. - * The `relays` field is gone since network preferred relays are gone. This capability is replaced by VL1 level federation ("federated roots"). - -Other important points: - - * Networks without rules won't carry any traffic. If you don't specify any on network creation an "accept anything" rule set will automatically be added. - * Managed IP address assignments and IP assignment pools that do not fall within a route configured in `routes` are ignored and won't be used or sent to members. - * The default for `private` is `true` and this is probably what you want. Turning `private` off means *anyone* can join your network with only its 16-digit network ID. It's also impossible to de-authorize a member as these networks don't issue or enforce certificates. Such "party line" networks are used for decentralized app backplanes, gaming, and testing but are otherwise not common. - -**Auto-Assign Modes:** - -Auto assign modes (`v4AssignMode` and `v6AssignMode`) contain objects that map assignment modes to booleans. - -For IPv4 the only valid setting is `zt` which, if true, causes IPv4 addresses to be auto-assigned from `ipAssignmentPools` to members that do not have an IPv4 assignment. Note that active bridges are exempt and will not get auto-assigned IPs since this can interfere with bridging. (You can still manually assign one if you want.) - -IPv6 includes this option and two others: `6plane` and `rfc4193`. These assign private IPv6 addresses to each member based on a deterministic assignment scheme that allows members to emulate IPv6 NDP to skip multicast for better performance and scalability. The `rfc4193` mode gives every member a /128 on a /88 network, while `6plane` gives every member a /80 within a /40 network but uses NDP emulation to route *all* IPs under that /80 to its owner. The `6plane` mode is great for use cases like Docker since it allows every member to assign IPv6 addresses within its /80 that just work instantly and globally across the network. - -**IP assignment pool object format:** - -| Field | Type | Description | -| --------------------- | ------------- | ------------------------------------------------- | -| ipRangeStart | string | Starting IP address in range | -| ipRangeEnd | string | Ending IP address in range (inclusive) | - -Pools are only used if auto-assignment is on for the given address type (IPv4 or IPv6) and if the entire range falls within a managed route. - -IPv6 ranges work just like IPv4 ranges and look like this: - - { - "ipRangeStart": "fd00:feed:feed:beef:0000:0000:0000:0000", - "ipRangeEnd": "fd00:feed:feed:beef:ffff:ffff:ffff:ffff" - } - -(You can POST a shortened-form IPv6 address but the API will always report back un-shortened canonical form addresses.) - -That defines a range within network `fd00:feed:feed:beef::/64` that contains up to 2^64 addresses. If an IPv6 range is large enough, the controller will assign addresses by placing each member's device ID into the address in a manner similar to the RFC4193 and 6PLANE modes. Otherwise it will assign addresses at random. - -**Rule object format:** - -Each rule is actually a sequence of zero or more `MATCH_` entries in the rule array followed by an `ACTION_` entry that describes what to do if all the preceding entries match. An `ACTION_` without any preceding `MATCH_` entries is always taken, so setting a single `ACTION_ACCEPT` rule yields a network that allows all traffic. If no rules are present the default action is `ACTION_DROP`. - -Rules are evaluated in the order in which they appear in the array. There is currently a limit of 256 entries per network. Capabilities should be used if a larger and more complex rule set is needed since they allow rules to be grouped by purpose and only shipped to members that need them. - -Each rule table entry has two common fields. - -| Field | Type | Description | -| --------------------- | ------------- | ------------------------------------------------- | -| type | string | Entry type (all caps, case sensitive) | -| not | boolean | If true, MATCHes match if they don't match | - -The following fields may or may not be present depending on rule type: - -| Field | Type | Description | -| --------------------- | ------------- | ------------------------------------------------- | -| zt | string | 10-digit hex ZeroTier address | -| etherType | integer | Ethernet frame type | -| mac | string | Hex MAC address (with or without :'s) | -| ip | string | IPv4 or IPv6 address | -| ipTos | integer | IP type of service | -| ipProtocol | integer | IP protocol (e.g. TCP) | -| start | integer | Start of an integer range (e.g. port range) | -| end | integer | End of an integer range (inclusive) | -| id | integer | Tag ID | -| value | integer | Tag value or comparison value | -| mask | integer | Bit mask (for characteristics flags) | - -The entry types and their additional fields are: - -| Entry type | Description | Fields | -| ------------------------------- | ----------------------------------------------------------------- | -------------- | -| `ACTION_DROP` | Drop any packets matching this rule | (none) | -| `ACTION_ACCEPT` | Accept any packets matching this rule | (none) | -| `ACTION_TEE` | Send a copy of this packet to a node (rule parsing continues) | `zt` | -| `ACTION_REDIRECT` | Redirect this packet to another node | `zt` | -| `ACTION_DEBUG_LOG` | Output debug info on match (if built with rules engine debug) | (none) | -| `MATCH_SOURCE_ZEROTIER_ADDRESS` | Match VL1 ZeroTier address of packet sender. | `zt` | -| `MATCH_DEST_ZEROTIER_ADDRESS` | Match VL1 ZeroTier address of recipient | `zt` | -| `MATCH_ETHERTYPE` | Match Ethernet frame type | `etherType` | -| `MATCH_MAC_SOURCE` | Match source Ethernet MAC address | `mac` | -| `MATCH_MAC_DEST` | Match destination Ethernet MAC address | `mac` | -| `MATCH_IPV4_SOURCE` | Match source IPv4 address | `ip` | -| `MATCH_IPV4_DEST` | Match destination IPv4 address | `ip` | -| `MATCH_IPV6_SOURCE` | Match source IPv6 address | `ip` | -| `MATCH_IPV6_DEST` | Match destination IPv6 address | `ip` | -| `MATCH_IP_TOS` | Match IP TOS field | `ipTos` | -| `MATCH_IP_PROTOCOL` | Match IP protocol field | `ipProtocol` | -| `MATCH_IP_SOURCE_PORT_RANGE` | Match a source IP port range | `start`,`end` | -| `MATCH_IP_DEST_PORT_RANGE` | Match a destination IP port range | `start`,`end` | -| `MATCH_CHARACTERISTICS` | Match on characteristics flags | `mask`,`value` | -| `MATCH_FRAME_SIZE_RANGE` | Match a range of Ethernet frame sizes | `start`,`end` | -| `MATCH_TAGS_SAMENESS` | Match if both sides' tags differ by no more than value | `id`,`value` | -| `MATCH_TAGS_BITWISE_AND` | Match if both sides' tags AND to value | `id`,`value` | -| `MATCH_TAGS_BITWISE_OR` | Match if both sides' tags OR to value | `id`,`value` | -| `MATCH_TAGS_BITWISE_XOR` | Match if both sides` tags XOR to value | `id`,`value` | - -Important notes about rules engine behavior: - - * IPv4 and IPv6 IP address rules do not match for frames that are not IPv4 or IPv6 respectively. - * `ACTION_DEBUG_LOG` is a no-op on nodes not built with `ZT_RULES_ENGINE_DEBUGGING` enabled (see Network.cpp). If that is enabled nodes will dump a trace of rule evaluation results to *stdout* when this action is encountered but will otherwise keep evaluating rules. This is used for basic "smoke testing" of the rules engine. - * Multicast packets and packets destined for bridged devices treated a little differently. They are matched more than once. They are matched at the point of send with a NULL ZeroTier destination address, meaning that `MATCH_DEST_ZEROTIER_ADDRESS` is useless. That's because the true VL1 destination is not yet known. Then they are matched again for each true VL1 destination. On these later subsequent matches TEE actions are ignored and REDIRECT rules are interpreted as DROPs. This prevents multiple TEE or REDIRECT packets from being sent to third party devices. - * Rules in capabilities are always matched as if the current device is the sender (inbound == false). A capability specifies sender side rules that can be enforced on both sides. - -#### `/controller/network//member` - - * Purpose: Get a set of all members on this network - * Methods: GET - * Returns: { object } - -This returns a JSON object containing all member IDs as keys and their `memberRevisionCounter` values as values. - -#### `/controller/network//active` - - * Purpose: Get a set of all active members on this network - * Methods: GET - * Returns: { object } - -This returns an object containing all currently online members and the most recent `recentLog` entries for their last request. - -#### `/controller/network//member/
` - - * Purpose: Create, authorize, or remove a network member - * Methods: GET, POST, DELETE - * Returns: { object } - -| Field | Type | Description | Writable | -| --------------------- | ------------- | ------------------------------------------------- | -------- | -| id | string | Member's 10-digit ZeroTier address | no | -| address | string | Member's 10-digit ZeroTier address | no | -| nwid | string | 16-digit network ID | no | -| clock | integer | Current clock, ms since epoch | no | -| authorized | boolean | Is member authorized? (for private networks) | YES | -| authHistory | array[object] | History of auth changes, latest at end | no | -| activeBridge | boolean | Member is able to bridge to other Ethernet nets | YES | -| identity | string | Member's public ZeroTier identity (if known) | no | -| ipAssignments | array[string] | Managed IP address assignments | YES | -| memberRevision | integer | Member revision counter | no | -| recentLog | array[object] | Recent member activity log; see below | no | - -Note that managed IP assignments are only used if they fall within a managed route. Otherwise they are ignored. - -**Recent log object format:** - -| Field | Type | Description | -| --------------------- | ------------- | ------------------------------------------------- | -| ts | integer | Time of request, ms since epoch | -| auth | boolean | Was member authorized? | -| authBy | string | How was member authorized? | -| vMajor | integer | Client major version or -1 if unknown | -| vMinor | integer | Client minor version or -1 if unknown | -| vRev | integer | Client revision or -1 if unknown | -| vProto | integer | ZeroTier protocol version reported by client | -| fromAddr | string | Physical address if known | - -The controller can only know a member's `fromAddr` if it's able to establish a direct path to it. Members behind very restrictive firewalls may not have this information since the controller will be receiving the member's requests by way of a relay. ZeroTier does not back-trace IP paths as packets are relayed since this would add a lot of protocol overhead. diff --git a/zto/controller/migrate-sqlite/migrate.js b/zto/controller/migrate-sqlite/migrate.js deleted file mode 100644 index ac9678a..0000000 --- a/zto/controller/migrate-sqlite/migrate.js +++ /dev/null @@ -1,320 +0,0 @@ -'use strict'; - -var sqlite3 = require('sqlite3').verbose(); -var fs = require('fs'); -var async = require('async'); - -function blobToIPv4(b) -{ - if (!b) - return null; - if (b.length !== 16) - return null; - return b.readUInt8(12).toString()+'.'+b.readUInt8(13).toString()+'.'+b.readUInt8(14).toString()+'.'+b.readUInt8(15).toString(); -} -function blobToIPv6(b) -{ - if (!b) - return null; - if (b.length !== 16) - return null; - var s = ''; - for(var i=0;i<16;++i) { - var x = b.readUInt8(i).toString(16); - if (x.length === 1) - s += '0'; - s += x; - if ((((i+1) & 1) === 0)&&(i !== 15)) - s += ':'; - } - return s; -} - -if (process.argv.length !== 4) { - console.log('ZeroTier Old Sqlite3 Controller DB Migration Utility'); - console.log('(c)2017 ZeroTier, Inc. [GPL3]'); - console.log(''); - console.log('Usage: node migrate.js '); - console.log(''); - console.log('The first argument must be the path to the old Sqlite3 controller.db'); - console.log('file. The second must be the path to the EMPTY controller.d database'); - console.log('directory for a new (1.1.17 or newer) controller. If this path does'); - console.log('not exist it will be created.'); - console.log(''); - console.log('WARNING: this will ONLY work correctly on a 1.1.14 controller database.'); - console.log('If your controller is old you should first upgrade to 1.1.14 and run the'); - console.log('controller so that it will brings its Sqlite3 database up to the latest'); - console.log('version before running this migration.'); - console.log(''); - process.exit(1); -} - -var oldDbPath = process.argv[2]; -var newDbPath = process.argv[3]; - -console.log('Starting migrate of "'+oldDbPath+'" to "'+newDbPath+'"...'); -console.log(''); - -var old = new sqlite3.Database(oldDbPath); - -var networks = {}; - -var nodeIdentities = {}; -var networkCount = 0; -var memberCount = 0; -var routeCount = 0; -var ipAssignmentPoolCount = 0; -var ipAssignmentCount = 0; -var ruleCount = 0; -var oldSchemaVersion = -1; - -async.series([function(nextStep) { - - old.each('SELECT v from Config WHERE k = \'schemaVersion\'',function(err,row) { - oldSchemaVersion = parseInt(row.v)||-1; - },nextStep); - -},function(nextStep) { - - if (oldSchemaVersion !== 4) { - console.log('FATAL: this MUST be run on a 1.1.14 controller.db! Upgrade your old'); - console.log('controller to 1.1.14 first and run it once to bring its DB up to date.'); - return process.exit(1); - } - - console.log('Reading networks...'); - old.each('SELECT * FROM Network',function(err,row) { - if ((typeof row.id === 'string')&&(row.id.length === 16)) { - var flags = parseInt(row.flags)||0; - networks[row.id] = { - id: row.id, - nwid: row.id, - objtype: 'network', - authTokens: [], - capabilities: [], - creationTime: parseInt(row.creationTime)||0, - enableBroadcast: !!row.enableBroadcast, - ipAssignmentPools: [], - lastModified: Date.now(), - multicastLimit: row.multicastLimit||32, - name: row.name||'', - private: !!row.private, - revision: parseInt(row.revision)||1, - rules: [{ 'type': 'ACTION_ACCEPT' }], // populated later if there are defined rules, otherwise default is allow all - routes: [], - v4AssignMode: { - 'zt': ((flags & 1) !== 0) - }, - v6AssignMode: { - '6plane': ((flags & 4) !== 0), - 'rfc4193': ((flags & 2) !== 0), - 'zt': ((flags & 8) !== 0) - }, - _members: {} // temporary - }; - ++networkCount; - //console.log(networks[row.id]); - } - },nextStep); - -},function(nextStep) { - - console.log(' '+networkCount+' networks.'); - console.log('Reading network route definitions...'); - old.each('SELECT * from Route WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) { - var network = networks[row.networkId]; - if (network) { - var rt = { - target: (((row.ipVersion == 4) ? blobToIPv4(row.target) : blobToIPv6(row.target))+'/'+row.targetNetmaskBits), - via: ((row.via) ? ((row.ipVersion == 4) ? blobToIPv4(row.via) : blobToIPv6(row.via)) : null) - }; - network.routes.push(rt); - ++routeCount; - } - },nextStep); - -},function(nextStep) { - - console.log(' '+routeCount+' routes in '+networkCount+' networks.'); - console.log('Reading IP assignment pools...'); - old.each('SELECT * FROM IpAssignmentPool WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) { - var network = networks[row.networkId]; - if (network) { - var p = { - ipRangeStart: ((row.ipVersion == 4) ? blobToIPv4(row.ipRangeStart) : blobToIPv6(row.ipRangeStart)), - ipRangeEnd: ((row.ipVersion == 4) ? blobToIPv4(row.ipRangeEnd) : blobToIPv6(row.ipRangeEnd)) - }; - network.ipAssignmentPools.push(p); - ++ipAssignmentPoolCount; - } - },nextStep); - -},function(nextStep) { - - console.log(' '+ipAssignmentPoolCount+' IP assignment pools in '+networkCount+' networks.'); - console.log('Reading known node identities...'); - old.each('SELECT * FROM Node',function(err,row) { - nodeIdentities[row.id] = row.identity; - },nextStep); - -},function(nextStep) { - - console.log(' '+Object.keys(nodeIdentities).length+' known identities.'); - console.log('Reading network members...'); - old.each('SELECT * FROM Member',function(err,row) { - var network = networks[row.networkId]; - if (network) { - network._members[row.nodeId] = { - id: row.nodeId, - address: row.nodeId, - objtype: 'member', - authorized: !!row.authorized, - activeBridge: !!row.activeBridge, - authHistory: [], - capabilities: [], - creationTime: 0, - identity: nodeIdentities[row.nodeId]||null, - ipAssignments: [], - lastAuthorizedTime: (row.authorized) ? Date.now() : 0, - lastDeauthorizedTime: (row.authorized) ? 0 : Date.now(), - lastModified: Date.now(), - lastRequestMetaData: '', - noAutoAssignIps: false, - nwid: row.networkId, - revision: parseInt(row.memberRevision)||1, - tags: [], - recentLog: [] - }; - ++memberCount; - //console.log(network._members[row.nodeId]); - } - },nextStep); - -},function(nextStep) { - - console.log(' '+memberCount+' members of '+networkCount+' networks.'); - console.log('Reading static IP assignments...'); - old.each('SELECT * FROM IpAssignment WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) { - var network = networks[row.networkId]; - if (network) { - var member = network._members[row.nodeId]; - if ((member)&&((member.authorized)||(!network['private']))) { // don't mirror assignments to unauthorized members to avoid conflicts - if (row.ipVersion == 4) { - member.ipAssignments.push(blobToIPv4(row.ip)); - ++ipAssignmentCount; - } else if (row.ipVersion == 6) { - member.ipAssignments.push(blobToIPv6(row.ip)); - ++ipAssignmentCount; - } - } - } - },nextStep); - -},function(nextStep) { - - // Old versions only supported Ethertype whitelisting, so that's - // all we mirror forward. The other fields were always unused. - - console.log(' '+ipAssignmentCount+' IP assignments for '+memberCount+' authorized members of '+networkCount+' networks.'); - console.log('Reading allowed Ethernet types (old basic rules)...'); - var etherTypesByNetwork = {}; - old.each('SELECT DISTINCT networkId,ruleNo,etherType FROM Rule WHERE "action" = \'accept\'',function(err,row) { - if (row.networkId in networks) { - var et = parseInt(row.etherType)||0; - var ets = etherTypesByNetwork[row.networkId]; - if (!ets) - etherTypesByNetwork[row.networkId] = [ et ]; - else ets.push(et); - } - },function(err) { - if (err) return nextStep(err); - for(var nwid in etherTypesByNetwork) { - var ets = etherTypesByNetwork[nwid].sort(); - var network = networks[nwid]; - if (network) { - var rules = []; - if (ets.indexOf(0) >= 0) { - // If 0 is in the list, all Ethernet types are allowed so we accept all. - rules.push({ 'type': 'ACTION_ACCEPT' }); - } else { - // Otherwise we whitelist. - for(var i=0;i 0) { - try { - fs.mkdirSync(nwBase+network.id); - } catch (e) {} - var mbase = nwBase+network.id+'/member'; - try { - fs.mkdirSync(mbase,0o700); - } catch (e) {} - mbase = mbase + '/'; - - for(var mi=0;mi", - "license": "GPL-3.0", - "dependencies": { - "async": "^2.1.4", - "sqlite3": "^3.1.8" - } -} diff --git a/zto/ext/README.md b/zto/ext/README.md deleted file mode 100644 index be9484c..0000000 --- a/zto/ext/README.md +++ /dev/null @@ -1,10 +0,0 @@ -Miscellaneous Stuff -====== - -This subfolder contains: - - * Bundled third party libraries that are compiled into the binary on platforms and Linux distributions where they are not available on the system. - - * Pre-compiled binaries for some platforms, such as pre-built and signed drivers for Mac and Windows. - - * Miscellaneous files used by installers and packages on various platform targets. diff --git a/zto/ext/bin/tap-mac/tap.kext/Contents/Info.plist b/zto/ext/bin/tap-mac/tap.kext/Contents/Info.plist deleted file mode 100644 index c20eefa..0000000 --- a/zto/ext/bin/tap-mac/tap.kext/Contents/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - tap - CFBundleIdentifier - com.zerotier.tap - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - tap - CFBundlePackageType - KEXT - CFBundleShortVersionString - 20150118 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - OSBundleLibraries - - com.apple.kpi.mach - 8.0 - com.apple.kpi.bsd - 8.0 - com.apple.kpi.libkern - 8.0 - com.apple.kpi.unsupported - 8.0 - - - - diff --git a/zto/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap b/zto/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap deleted file mode 100755 index 48bf9625551ea8af1d97fe3a0868e499ab55a48c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50496 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 diff --git a/zto/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeResources b/zto/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeResources deleted file mode 100644 index 0710b40..0000000 --- a/zto/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeResources +++ /dev/null @@ -1,105 +0,0 @@ - - - - - files - - files2 - - rules - - ^Resources/ - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^version.plist$ - - - rules2 - - .*\.dSYM($|/) - - weight - 11 - - ^(.*/)?\.DS_Store$ - - omit - - weight - 2000 - - ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ - - nested - - weight - 10 - - ^.* - - ^Info\.plist$ - - omit - - weight - 20 - - ^PkgInfo$ - - omit - - weight - 20 - - ^Resources/ - - weight - 20 - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^[^/]+$ - - nested - - weight - 10 - - ^embedded\.provisionprofile$ - - weight - 20 - - ^version\.plist$ - - weight - 20 - - - - diff --git a/zto/ext/bin/tap-windows-ndis6/x64/zttap300.cat b/zto/ext/bin/tap-windows-ndis6/x64/zttap300.cat deleted file mode 100644 index 8b9114c71d0508a0d374dd70c48529922751feff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10017 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 S#)0h5lVtOoWwgp$m;Vd3glSFy diff --git a/zto/ext/bin/tap-windows-ndis6/x64/zttap300.inf b/zto/ext/bin/tap-windows-ndis6/x64/zttap300.inf deleted file mode 100644 index 453797b..0000000 --- a/zto/ext/bin/tap-windows-ndis6/x64/zttap300.inf +++ /dev/null @@ -1,143 +0,0 @@ -; -; ZeroTier One Virtual Network Port NDIS6 Driver -; -; Based on the OpenVPN tap-windows6 driver version 9.21.1 git -; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3. -; See: https://github.com/OpenVPN/tap-windows6 -; -; Modified by ZeroTier, Inc. - https://www.zerotier.com/ -; -; (1) Comment out 'tun' functionality and related features such as DHCP -; emulation, since we don't use any of that. Just want straight 'tap'. -; (2) Added custom IOCTL to enumerate L2 multicast memberships. -; (3) Increase maximum number of multicast memberships to 128. -; (4) Set default and max device MTU to 2800. -; (5) Rename/rebrand driver as ZeroTier network port driver. -; -; Original copyright below. Modifications released under GPLv2 as well. -; -; **************************************************************************** -; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * -; * This program is free software; you can redistribute it and/or modify * -; * it under the terms of the GNU General Public License version 2 * -; * as published by the Free Software Foundation. * -; **************************************************************************** -; - -[Version] -Signature = "$Windows NT$" -CatalogFile = zttap300.cat -ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} -Provider = %Provider% -Class = Net -DriverVer=08/13/2015,6.2.9200.20557 - -[Strings] -DeviceDescription = "ZeroTier One Virtual Port" -Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat. - -; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back! -[Manufacturer] -%Provider%=zttap300,NTamd64 - -[zttap300] -%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated -%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy - -[zttap300.NTamd64] -%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated -%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy - -;----------------- Characteristics ------------ -; NCF_PHYSICAL = 0x04 -; NCF_VIRTUAL = 0x01 -; NCF_SOFTWARE_ENUMERATED = 0x02 -; NCF_HIDDEN = 0x08 -; NCF_NO_SERVICE = 0x10 -; NCF_HAS_UI = 0x80 -;----------------- Characteristics ------------ -[zttap300.ndi] -CopyFiles = zttap300.driver, zttap300.files -AddReg = zttap300.reg -AddReg = zttap300.params.reg -Characteristics = 0x81 -*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD -*MediaType = 0x0 ; NdisMedium802_3 -*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 - -[zttap300.ndi.Services] -AddService = zttap300, 2, zttap300.service - -[zttap300.reg] -HKR, Ndi, Service, 0, "zttap300" -HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows. -HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" -HKR, , Manufacturer, 0, "%Provider%" -HKR, , ProductName, 0, "%DeviceDescription%" - -[zttap300.params.reg] -HKR, Ndi\params\MTU, ParamDesc, 0, "MTU" -HKR, Ndi\params\MTU, Type, 0, "int" -HKR, Ndi\params\MTU, Default, 0, "2800" -HKR, Ndi\params\MTU, Optional, 0, "0" -HKR, Ndi\params\MTU, Min, 0, "100" -HKR, Ndi\params\MTU, Max, 0, "2800" -HKR, Ndi\params\MTU, Step, 0, "1" -HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status" -HKR, Ndi\params\MediaStatus, Type, 0, "enum" -HKR, Ndi\params\MediaStatus, Default, 0, "0" -HKR, Ndi\params\MediaStatus, Optional, 0, "0" -HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled" -HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected" -HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address" -HKR, Ndi\params\MAC, Type, 0, "edit" -HKR, Ndi\params\MAC, Optional, 0, "1" -HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access" -HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum" -HKR, Ndi\params\AllowNonAdmin, Default, 0, "0" -HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0" -HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed" -HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed" - -;---------- Service Type ------------- -; SERVICE_KERNEL_DRIVER = 0x01 -; SERVICE_WIN32_OWN_PROCESS = 0x10 -;---------- Service Type ------------- - -;---------- Start Mode --------------- -; SERVICE_BOOT_START = 0x0 -; SERVICE_SYSTEM_START = 0x1 -; SERVICE_AUTO_START = 0x2 -; SERVICE_DEMAND_START = 0x3 -; SERVICE_DISABLED = 0x4 -;---------- Start Mode --------------- - -[zttap300.service] -DisplayName = %DeviceDescription% -ServiceType = 1 -StartType = 3 -ErrorControl = 1 -LoadOrderGroup = NDIS -ServiceBinary = %12%\zttap300.sys - -;----------------- Copy Flags ------------ -; COPYFLG_NOSKIP = 0x02 -; COPYFLG_NOVERSIONCHECK = 0x04 -;----------------- Copy Flags ------------ - -[SourceDisksNames] -1 = %DeviceDescription%, zttap300.sys - -[SourceDisksFiles] -zttap300.sys = 1 - -[DestinationDirs] -zttap300.files = 11 -zttap300.driver = 12 - -[zttap300.files] -; - -[zttap300.driver] -zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK - diff --git a/zto/ext/bin/tap-windows-ndis6/x64/zttap300.sys b/zto/ext/bin/tap-windows-ndis6/x64/zttap300.sys deleted file mode 100644 index 3d846a53a0a093ccc8041341b2149013990c4de2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30488 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 U9KEYW^RFs&$|kQSahH7l7jLDT6#xJL diff --git a/zto/ext/bin/tap-windows-ndis6/x86/zttap300.cat b/zto/ext/bin/tap-windows-ndis6/x86/zttap300.cat deleted file mode 100644 index 44347f54f0234a8657ba55acb725805f3bea9017..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10017 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 Dt+AX9 diff --git a/zto/ext/http-parser/AUTHORS b/zto/ext/http-parser/AUTHORS deleted file mode 100644 index 5323b68..0000000 --- a/zto/ext/http-parser/AUTHORS +++ /dev/null @@ -1,68 +0,0 @@ -# Authors ordered by first contribution. -Ryan Dahl -Jeremy Hinegardner -Sergey Shepelev -Joe Damato -tomika -Phoenix Sol -Cliff Frey -Ewen Cheslack-Postava -Santiago Gala -Tim Becker -Jeff Terrace -Ben Noordhuis -Nathan Rajlich -Mark Nottingham -Aman Gupta -Tim Becker -Sean Cunningham -Peter Griess -Salman Haq -Cliff Frey -Jon Kolb -Fouad Mardini -Paul Querna -Felix Geisendörfer -koichik -Andre Caron -Ivo Raisr -James McLaughlin -David Gwynne -Thomas LE ROUX -Randy Rizun -Andre Louis Caron -Simon Zimmermann -Erik Dubbelboer -Martell Malone -Bertrand Paquet -BogDan Vatra -Peter Faiman -Corey Richardson -Tóth Tamás -Cam Swords -Chris Dickinson -Uli Köhler -Charlie Somerville -Patrik Stutz -Fedor Indutny -runner -Alexis Campailla -David Wragg -Vinnie Falco -Alex Butum -Rex Feng -Alex Kocharin -Mark Koopman -Helge Heß -Alexis La Goutte -George Miroshnykov -Maciej Małecki -Marc O'Morain -Jeff Pinner -Timothy J Fontaine -Akagi201 -Romain Giraud -Jay Satiro -Arne Steen -Kjell Schubert -Olivier Mengué diff --git a/zto/ext/http-parser/LICENSE-MIT b/zto/ext/http-parser/LICENSE-MIT deleted file mode 100644 index 58010b3..0000000 --- a/zto/ext/http-parser/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright -Igor Sysoev. - -Additional changes are licensed under the same terms as NGINX and -copyright Joyent, Inc. and other Node contributors. All rights reserved. - -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/zto/ext/http-parser/README.md b/zto/ext/http-parser/README.md deleted file mode 100644 index 439b309..0000000 --- a/zto/ext/http-parser/README.md +++ /dev/null @@ -1,246 +0,0 @@ -HTTP Parser -=========== - -[![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)](https://travis-ci.org/nodejs/http-parser) - -This is a parser for HTTP messages written in C. It parses both requests and -responses. The parser is designed to be used in performance HTTP -applications. It does not make any syscalls nor allocations, it does not -buffer data, it can be interrupted at anytime. Depending on your -architecture, it only requires about 40 bytes of data per message -stream (in a web server that is per connection). - -Features: - - * No dependencies - * Handles persistent streams (keep-alive). - * Decodes chunked encoding. - * Upgrade support - * Defends against buffer overflow attacks. - -The parser extracts the following information from HTTP messages: - - * Header fields and values - * Content-Length - * Request method - * Response status code - * Transfer-Encoding - * HTTP version - * Request URL - * Message body - - -Usage ------ - -One `http_parser` object is used per TCP connection. Initialize the struct -using `http_parser_init()` and set the callbacks. That might look something -like this for a request parser: -```c -http_parser_settings settings; -settings.on_url = my_url_callback; -settings.on_header_field = my_header_field_callback; -/* ... */ - -http_parser *parser = malloc(sizeof(http_parser)); -http_parser_init(parser, HTTP_REQUEST); -parser->data = my_socket; -``` - -When data is received on the socket execute the parser and check for errors. - -```c -size_t len = 80*1024, nparsed; -char buf[len]; -ssize_t recved; - -recved = recv(fd, buf, len, 0); - -if (recved < 0) { - /* Handle error. */ -} - -/* Start up / continue the parser. - * Note we pass recved==0 to signal that EOF has been received. - */ -nparsed = http_parser_execute(parser, &settings, buf, recved); - -if (parser->upgrade) { - /* handle new protocol */ -} else if (nparsed != recved) { - /* Handle error. Usually just close the connection. */ -} -``` - -HTTP needs to know where the end of the stream is. For example, sometimes -servers send responses without Content-Length and expect the client to -consume input (for the body) until EOF. To tell http_parser about EOF, give -`0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors -can still be encountered during an EOF, so one must still be prepared -to receive them. - -Scalar valued message information such as `status_code`, `method`, and the -HTTP version are stored in the parser structure. This data is only -temporally stored in `http_parser` and gets reset on each new message. If -this information is needed later, copy it out of the structure during the -`headers_complete` callback. - -The parser decodes the transfer-encoding for both requests and responses -transparently. That is, a chunked encoding is decoded before being sent to -the on_body callback. - - -The Special Problem of Upgrade ------------------------------- - -HTTP supports upgrading the connection to a different protocol. An -increasingly common example of this is the WebSocket protocol which sends -a request like - - GET /demo HTTP/1.1 - Upgrade: WebSocket - Connection: Upgrade - Host: example.com - Origin: http://example.com - WebSocket-Protocol: sample - -followed by non-HTTP data. - -(See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the -WebSocket protocol.) - -To support this, the parser will treat this as a normal HTTP message without a -body, issuing both on_headers_complete and on_message_complete callbacks. However -http_parser_execute() will stop parsing at the end of the headers and return. - -The user is expected to check if `parser->upgrade` has been set to 1 after -`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied -offset by the return value of `http_parser_execute()`. - - -Callbacks ---------- - -During the `http_parser_execute()` call, the callbacks set in -`http_parser_settings` will be executed. The parser maintains state and -never looks behind, so buffering the data is not necessary. If you need to -save certain data for later usage, you can do that from the callbacks. - -There are two types of callbacks: - -* notification `typedef int (*http_cb) (http_parser*);` - Callbacks: on_message_begin, on_headers_complete, on_message_complete. -* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);` - Callbacks: (requests only) on_url, - (common) on_header_field, on_header_value, on_body; - -Callbacks must return 0 on success. Returning a non-zero value indicates -error to the parser, making it exit immediately. - -For cases where it is necessary to pass local information to/from a callback, -the `http_parser` object's `data` field can be used. -An example of such a case is when using threads to handle a socket connection, -parse a request, and then give a response over that socket. By instantiation -of a thread-local struct containing relevant data (e.g. accepted socket, -allocated memory for callbacks to write into, etc), a parser's callbacks are -able to communicate data between the scope of the thread and the scope of the -callback in a threadsafe manner. This allows http-parser to be used in -multi-threaded contexts. - -Example: -```c - typedef struct { - socket_t sock; - void* buffer; - int buf_len; - } custom_data_t; - - -int my_url_callback(http_parser* parser, const char *at, size_t length) { - /* access to thread local custom_data_t struct. - Use this access save parsed data for later use into thread local - buffer, or communicate over socket - */ - parser->data; - ... - return 0; -} - -... - -void http_parser_thread(socket_t sock) { - int nparsed = 0; - /* allocate memory for user data */ - custom_data_t *my_data = malloc(sizeof(custom_data_t)); - - /* some information for use by callbacks. - * achieves thread -> callback information flow */ - my_data->sock = sock; - - /* instantiate a thread-local parser */ - http_parser *parser = malloc(sizeof(http_parser)); - http_parser_init(parser, HTTP_REQUEST); /* initialise parser */ - /* this custom data reference is accessible through the reference to the - parser supplied to callback functions */ - parser->data = my_data; - - http_parser_settings settings; /* set up callbacks */ - settings.on_url = my_url_callback; - - /* execute parser */ - nparsed = http_parser_execute(parser, &settings, buf, recved); - - ... - /* parsed information copied from callback. - can now perform action on data copied into thread-local memory from callbacks. - achieves callback -> thread information flow */ - my_data->buffer; - ... -} - -``` - -In case you parse HTTP message in chunks (i.e. `read()` request line -from socket, parse, read half headers, parse, etc) your data callbacks -may be called more than once. Http-parser guarantees that data pointer is only -valid for the lifetime of callback. You can also `read()` into a heap allocated -buffer to avoid copying memory around if this fits your application. - -Reading headers may be a tricky task if you read/parse headers partially. -Basically, you need to remember whether last header callback was field or value -and apply the following logic: - - (on_header_field and on_header_value shortened to on_h_*) - ------------------------ ------------ -------------------------------------------- - | State (prev. callback) | Callback | Description/action | - ------------------------ ------------ -------------------------------------------- - | nothing (first call) | on_h_field | Allocate new buffer and copy callback data | - | | | into it | - ------------------------ ------------ -------------------------------------------- - | value | on_h_field | New header started. | - | | | Copy current name,value buffers to headers | - | | | list and allocate new buffer for new name | - ------------------------ ------------ -------------------------------------------- - | field | on_h_field | Previous name continues. Reallocate name | - | | | buffer and append callback data to it | - ------------------------ ------------ -------------------------------------------- - | field | on_h_value | Value for current header started. Allocate | - | | | new buffer and copy callback data to it | - ------------------------ ------------ -------------------------------------------- - | value | on_h_value | Value continues. Reallocate value buffer | - | | | and append callback data to it | - ------------------------ ------------ -------------------------------------------- - - -Parsing URLs ------------- - -A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`. -Users of this library may wish to use it to parse URLs constructed from -consecutive `on_url` callbacks. - -See examples of reading in headers: - -* [partial example](http://gist.github.com/155877) in C -* [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C -* [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript diff --git a/zto/ext/http-parser/http_parser.c b/zto/ext/http-parser/http_parser.c deleted file mode 100644 index 895bf0c..0000000 --- a/zto/ext/http-parser/http_parser.c +++ /dev/null @@ -1,2470 +0,0 @@ -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev - * - * Additional changes are licensed under the same terms as NGINX and - * copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * 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. - */ -#include "http_parser.h" -#include -#include -#include -#include -#include -#include - -#ifndef ULLONG_MAX -# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ -#endif - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -#ifndef BIT_AT -# define BIT_AT(a, i) \ - (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ - (1 << ((unsigned int) (i) & 7)))) -#endif - -#ifndef ELEM_AT -# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) -#endif - -#define SET_ERRNO(e) \ -do { \ - parser->http_errno = (e); \ -} while(0) - -#define CURRENT_STATE() p_state -#define UPDATE_STATE(V) p_state = (enum state) (V); -#define RETURN(V) \ -do { \ - parser->state = CURRENT_STATE(); \ - return (V); \ -} while (0); -#define REEXECUTE() \ - goto reexecute; \ - - -#ifdef __GNUC__ -# define LIKELY(X) __builtin_expect(!!(X), 1) -# define UNLIKELY(X) __builtin_expect(!!(X), 0) -#else -# define LIKELY(X) (X) -# define UNLIKELY(X) (X) -#endif - - -/* Run the notify callback FOR, returning ER if it fails */ -#define CALLBACK_NOTIFY_(FOR, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (LIKELY(settings->on_##FOR)) { \ - parser->state = CURRENT_STATE(); \ - if (UNLIKELY(0 != settings->on_##FOR(parser))) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - UPDATE_STATE(parser->state); \ - \ - /* We either errored above or got paused; get out */ \ - if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ - return (ER); \ - } \ - } \ -} while (0) - -/* Run the notify callback FOR and consume the current byte */ -#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) - -/* Run the notify callback FOR and don't consume the current byte */ -#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) - -/* Run data callback FOR with LEN bytes, returning ER if it fails */ -#define CALLBACK_DATA_(FOR, LEN, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (FOR##_mark) { \ - if (LIKELY(settings->on_##FOR)) { \ - parser->state = CURRENT_STATE(); \ - if (UNLIKELY(0 != \ - settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - UPDATE_STATE(parser->state); \ - \ - /* We either errored above or got paused; get out */ \ - if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ - return (ER); \ - } \ - } \ - FOR##_mark = NULL; \ - } \ -} while (0) - -/* Run the data callback FOR and consume the current byte */ -#define CALLBACK_DATA(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) - -/* Run the data callback FOR and don't consume the current byte */ -#define CALLBACK_DATA_NOADVANCE(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) - -/* Set the mark FOR; non-destructive if mark is already set */ -#define MARK(FOR) \ -do { \ - if (!FOR##_mark) { \ - FOR##_mark = p; \ - } \ -} while (0) - -/* Don't allow the total size of the HTTP headers (including the status - * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect - * embedders against denial-of-service attacks where the attacker feeds - * us a never-ending header that the embedder keeps buffering. - * - * This check is arguably the responsibility of embedders but we're doing - * it on the embedder's behalf because most won't bother and this way we - * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger - * than any reasonable request or response so this should never affect - * day-to-day operation. - */ -#define COUNT_HEADER_SIZE(V) \ -do { \ - parser->nread += (V); \ - if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \ - SET_ERRNO(HPE_HEADER_OVERFLOW); \ - goto error; \ - } \ -} while (0) - - -#define PROXY_CONNECTION "proxy-connection" -#define CONNECTION "connection" -#define CONTENT_LENGTH "content-length" -#define TRANSFER_ENCODING "transfer-encoding" -#define UPGRADE "upgrade" -#define CHUNKED "chunked" -#define KEEP_ALIVE "keep-alive" -#define CLOSE "close" - - -static const char *method_strings[] = - { -#define XX(num, name, string) #string, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -/* Tokens as defined by rfc 2616. Also lowercases them. - * token = 1* - * separators = "(" | ")" | "<" | ">" | "@" - * | "," | ";" | ":" | "\" | <"> - * | "/" | "[" | "]" | "?" | "=" - * | "{" | "}" | SP | HT - */ -static const char tokens[256] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0, '!', 0, '#', '$', '%', '&', '\'', -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 0, 0, '*', '+', 0, '-', '.', 0, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - '0', '1', '2', '3', '4', '5', '6', '7', -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - '8', '9', 0, 0, 0, 0, 0, 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 'x', 'y', 'z', 0, 0, 0, '^', '_', -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 'x', 'y', 'z', 0, '|', 0, '~', 0 }; - - -static const int8_t unhex[256] = - {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; - - -#if HTTP_PARSER_STRICT -# define T(v) 0 -#else -# define T(v) v -#endif - - -static const uint8_t normal_url_char[32] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; - -#undef T - -enum state - { s_dead = 1 /* important that this is > 0 */ - - , s_start_req_or_res - , s_res_or_resp_H - , s_start_res - , s_res_H - , s_res_HT - , s_res_HTT - , s_res_HTTP - , s_res_first_http_major - , s_res_http_major - , s_res_first_http_minor - , s_res_http_minor - , s_res_first_status_code - , s_res_status_code - , s_res_status_start - , s_res_status - , s_res_line_almost_done - - , s_start_req - - , s_req_method - , s_req_spaces_before_url - , s_req_schema - , s_req_schema_slash - , s_req_schema_slash_slash - , s_req_server_start - , s_req_server - , s_req_server_with_at - , s_req_path - , s_req_query_string_start - , s_req_query_string - , s_req_fragment_start - , s_req_fragment - , s_req_http_start - , s_req_http_H - , s_req_http_HT - , s_req_http_HTT - , s_req_http_HTTP - , s_req_first_http_major - , s_req_http_major - , s_req_first_http_minor - , s_req_http_minor - , s_req_line_almost_done - - , s_header_field_start - , s_header_field - , s_header_value_discard_ws - , s_header_value_discard_ws_almost_done - , s_header_value_discard_lws - , s_header_value_start - , s_header_value - , s_header_value_lws - - , s_header_almost_done - - , s_chunk_size_start - , s_chunk_size - , s_chunk_parameters - , s_chunk_size_almost_done - - , s_headers_almost_done - , s_headers_done - - /* Important: 's_headers_done' must be the last 'header' state. All - * states beyond this must be 'body' states. It is used for overflow - * checking. See the PARSING_HEADER() macro. - */ - - , s_chunk_data - , s_chunk_data_almost_done - , s_chunk_data_done - - , s_body_identity - , s_body_identity_eof - - , s_message_done - }; - - -#define PARSING_HEADER(state) (state <= s_headers_done) - - -enum header_states - { h_general = 0 - , h_C - , h_CO - , h_CON - - , h_matching_connection - , h_matching_proxy_connection - , h_matching_content_length - , h_matching_transfer_encoding - , h_matching_upgrade - - , h_connection - , h_content_length - , h_transfer_encoding - , h_upgrade - - , h_matching_transfer_encoding_chunked - , h_matching_connection_token_start - , h_matching_connection_keep_alive - , h_matching_connection_close - , h_matching_connection_upgrade - , h_matching_connection_token - - , h_transfer_encoding_chunked - , h_connection_keep_alive - , h_connection_close - , h_connection_upgrade - }; - -enum http_host_state - { - s_http_host_dead = 1 - , s_http_userinfo_start - , s_http_userinfo - , s_http_host_start - , s_http_host_v6_start - , s_http_host - , s_http_host_v6 - , s_http_host_v6_end - , s_http_host_v6_zone_start - , s_http_host_v6_zone - , s_http_host_port_start - , s_http_host_port -}; - -/* Macros for character classes; depends on strict-mode */ -#define CR '\r' -#define LF '\n' -#define LOWER(c) (unsigned char)(c | 0x20) -#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') -#define IS_NUM(c) ((c) >= '0' && (c) <= '9') -#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) -#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) -#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ - (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ - (c) == ')') -#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ - (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ - (c) == '$' || (c) == ',') - -#define STRICT_TOKEN(c) (tokens[(unsigned char)c]) - -#if HTTP_PARSER_STRICT -#define TOKEN(c) (tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) -#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') -#else -#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) \ - (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) -#define IS_HOST_CHAR(c) \ - (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') -#endif - -/** - * Verify that a char is a valid visible (printable) US-ASCII - * character or %x80-FF - **/ -#define IS_HEADER_CHAR(ch) \ - (ch == CR || ch == LF || ch == 9 || ((unsigned char)ch > 31 && ch != 127)) - -#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) - - -#if HTTP_PARSER_STRICT -# define STRICT_CHECK(cond) \ -do { \ - if (cond) { \ - SET_ERRNO(HPE_STRICT); \ - goto error; \ - } \ -} while (0) -# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) -#else -# define STRICT_CHECK(cond) -# define NEW_MESSAGE() start_state -#endif - - -/* Map errno values to strings for human-readable output */ -#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, -static struct { - const char *name; - const char *description; -} http_strerror_tab[] = { - HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) -}; -#undef HTTP_STRERROR_GEN - -int http_message_needs_eof(const http_parser *parser); - -/* Our URL parser. - * - * This is designed to be shared by http_parser_execute() for URL validation, - * hence it has a state transition + byte-for-byte interface. In addition, it - * is meant to be embedded in http_parser_parse_url(), which does the dirty - * work of turning state transitions URL components for its API. - * - * This function should only be invoked with non-space characters. It is - * assumed that the caller cares about (and can detect) the transition between - * URL and non-URL states by looking for these. - */ -static enum state -parse_url_char(enum state s, const char ch) -{ - if (ch == ' ' || ch == '\r' || ch == '\n') { - return s_dead; - } - -#if HTTP_PARSER_STRICT - if (ch == '\t' || ch == '\f') { - return s_dead; - } -#endif - - switch (s) { - case s_req_spaces_before_url: - /* Proxied requests are followed by scheme of an absolute URI (alpha). - * All methods except CONNECT are followed by '/' or '*'. - */ - - if (ch == '/' || ch == '*') { - return s_req_path; - } - - if (IS_ALPHA(ch)) { - return s_req_schema; - } - - break; - - case s_req_schema: - if (IS_ALPHA(ch)) { - return s; - } - - if (ch == ':') { - return s_req_schema_slash; - } - - break; - - case s_req_schema_slash: - if (ch == '/') { - return s_req_schema_slash_slash; - } - - break; - - case s_req_schema_slash_slash: - if (ch == '/') { - return s_req_server_start; - } - - break; - - case s_req_server_with_at: - if (ch == '@') { - return s_dead; - } - - /* FALLTHROUGH */ - case s_req_server_start: - case s_req_server: - if (ch == '/') { - return s_req_path; - } - - if (ch == '?') { - return s_req_query_string_start; - } - - if (ch == '@') { - return s_req_server_with_at; - } - - if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { - return s_req_server; - } - - break; - - case s_req_path: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - return s_req_query_string_start; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_query_string_start: - case s_req_query_string: - if (IS_URL_CHAR(ch)) { - return s_req_query_string; - } - - switch (ch) { - case '?': - /* allow extra '?' in query string */ - return s_req_query_string; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_fragment_start: - if (IS_URL_CHAR(ch)) { - return s_req_fragment; - } - - switch (ch) { - case '?': - return s_req_fragment; - - case '#': - return s; - } - - break; - - case s_req_fragment: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - case '#': - return s; - } - - break; - - default: - break; - } - - /* We should never fall out of the switch above unless there's an error */ - return s_dead; -} - -size_t http_parser_execute (http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len) -{ - char c, ch; - int8_t unhex_val; - const char *p = data; - const char *header_field_mark = 0; - const char *header_value_mark = 0; - const char *url_mark = 0; - const char *body_mark = 0; - const char *status_mark = 0; - enum state p_state = (enum state) parser->state; - const unsigned int lenient = parser->lenient_http_headers; - - /* We're in an error state. Don't bother doing anything. */ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return 0; - } - - if (len == 0) { - switch (CURRENT_STATE()) { - case s_body_identity_eof: - /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if - * we got paused. - */ - CALLBACK_NOTIFY_NOADVANCE(message_complete); - return 0; - - case s_dead: - case s_start_req_or_res: - case s_start_res: - case s_start_req: - return 0; - - default: - SET_ERRNO(HPE_INVALID_EOF_STATE); - return 1; - } - } - - - if (CURRENT_STATE() == s_header_field) - header_field_mark = data; - if (CURRENT_STATE() == s_header_value) - header_value_mark = data; - switch (CURRENT_STATE()) { - case s_req_path: - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_server: - case s_req_server_with_at: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - url_mark = data; - break; - case s_res_status: - status_mark = data; - break; - default: - break; - } - - for (p=data; p != data + len; p++) { - ch = *p; - - if (PARSING_HEADER(CURRENT_STATE())) - COUNT_HEADER_SIZE(1); - -reexecute: - switch (CURRENT_STATE()) { - - case s_dead: - /* this state is used after a 'Connection: close' message - * the parser will error out if it reads another message - */ - if (LIKELY(ch == CR || ch == LF)) - break; - - SET_ERRNO(HPE_CLOSED_CONNECTION); - goto error; - - case s_start_req_or_res: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (ch == 'H') { - UPDATE_STATE(s_res_or_resp_H); - - CALLBACK_NOTIFY(message_begin); - } else { - parser->type = HTTP_REQUEST; - UPDATE_STATE(s_start_req); - REEXECUTE(); - } - - break; - } - - case s_res_or_resp_H: - if (ch == 'T') { - parser->type = HTTP_RESPONSE; - UPDATE_STATE(s_res_HT); - } else { - if (UNLIKELY(ch != 'E')) { - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - parser->type = HTTP_REQUEST; - parser->method = HTTP_HEAD; - parser->index = 2; - UPDATE_STATE(s_req_method); - } - break; - - case s_start_res: - { - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - switch (ch) { - case 'H': - UPDATE_STATE(s_res_H); - break; - - case CR: - case LF: - break; - - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - CALLBACK_NOTIFY(message_begin); - break; - } - - case s_res_H: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_res_HT); - break; - - case s_res_HT: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_res_HTT); - break; - - case s_res_HTT: - STRICT_CHECK(ch != 'P'); - UPDATE_STATE(s_res_HTTP); - break; - - case s_res_HTTP: - STRICT_CHECK(ch != '/'); - UPDATE_STATE(s_res_first_http_major); - break; - - case s_res_first_http_major: - if (UNLIKELY(ch < '0' || ch > '9')) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - UPDATE_STATE(s_res_http_major); - break; - - /* major HTTP version or dot */ - case s_res_http_major: - { - if (ch == '.') { - UPDATE_STATE(s_res_first_http_minor); - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (UNLIKELY(parser->http_major > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_res_first_http_minor: - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - UPDATE_STATE(s_res_http_minor); - break; - - /* minor HTTP version or end of request line */ - case s_res_http_minor: - { - if (ch == ' ') { - UPDATE_STATE(s_res_first_status_code); - break; - } - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (UNLIKELY(parser->http_minor > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - case s_res_first_status_code: - { - if (!IS_NUM(ch)) { - if (ch == ' ') { - break; - } - - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - parser->status_code = ch - '0'; - UPDATE_STATE(s_res_status_code); - break; - } - - case s_res_status_code: - { - if (!IS_NUM(ch)) { - switch (ch) { - case ' ': - UPDATE_STATE(s_res_status_start); - break; - case CR: - UPDATE_STATE(s_res_line_almost_done); - break; - case LF: - UPDATE_STATE(s_header_field_start); - break; - default: - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - break; - } - - parser->status_code *= 10; - parser->status_code += ch - '0'; - - if (UNLIKELY(parser->status_code > 999)) { - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - - break; - } - - case s_res_status_start: - { - if (ch == CR) { - UPDATE_STATE(s_res_line_almost_done); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_field_start); - break; - } - - MARK(status); - UPDATE_STATE(s_res_status); - parser->index = 0; - break; - } - - case s_res_status: - if (ch == CR) { - UPDATE_STATE(s_res_line_almost_done); - CALLBACK_DATA(status); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_field_start); - CALLBACK_DATA(status); - break; - } - - break; - - case s_res_line_almost_done: - STRICT_CHECK(ch != LF); - UPDATE_STATE(s_header_field_start); - break; - - case s_start_req: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (UNLIKELY(!IS_ALPHA(ch))) { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - parser->method = (enum http_method) 0; - parser->index = 1; - switch (ch) { - case 'A': parser->method = HTTP_ACL; break; - case 'B': parser->method = HTTP_BIND; break; - case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; - case 'D': parser->method = HTTP_DELETE; break; - case 'G': parser->method = HTTP_GET; break; - case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; /* or LINK */ break; - case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; - case 'N': parser->method = HTTP_NOTIFY; break; - case 'O': parser->method = HTTP_OPTIONS; break; - case 'P': parser->method = HTTP_POST; - /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ - break; - case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break; - case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; - case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break; - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - UPDATE_STATE(s_req_method); - - CALLBACK_NOTIFY(message_begin); - - break; - } - - case s_req_method: - { - const char *matcher; - if (UNLIKELY(ch == '\0')) { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - matcher = method_strings[parser->method]; - if (ch == ' ' && matcher[parser->index] == '\0') { - UPDATE_STATE(s_req_spaces_before_url); - } else if (ch == matcher[parser->index]) { - ; /* nada */ - } else if (IS_ALPHA(ch)) { - - switch (parser->method << 16 | parser->index << 8 | ch) { -#define XX(meth, pos, ch, new_meth) \ - case (HTTP_##meth << 16 | pos << 8 | ch): \ - parser->method = HTTP_##new_meth; break; - - XX(POST, 1, 'U', PUT) - XX(POST, 1, 'A', PATCH) - XX(CONNECT, 1, 'H', CHECKOUT) - XX(CONNECT, 2, 'P', COPY) - XX(MKCOL, 1, 'O', MOVE) - XX(MKCOL, 1, 'E', MERGE) - XX(MKCOL, 2, 'A', MKACTIVITY) - XX(MKCOL, 3, 'A', MKCALENDAR) - XX(SUBSCRIBE, 1, 'E', SEARCH) - XX(REPORT, 2, 'B', REBIND) - XX(POST, 1, 'R', PROPFIND) - XX(PROPFIND, 4, 'P', PROPPATCH) - XX(PUT, 2, 'R', PURGE) - XX(LOCK, 1, 'I', LINK) - XX(UNLOCK, 2, 'S', UNSUBSCRIBE) - XX(UNLOCK, 2, 'B', UNBIND) - XX(UNLOCK, 3, 'I', UNLINK) -#undef XX - - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (ch == '-' && - parser->index == 1 && - parser->method == HTTP_MKCOL) { - parser->method = HTTP_MSEARCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - ++parser->index; - break; - } - - case s_req_spaces_before_url: - { - if (ch == ' ') break; - - MARK(url); - if (parser->method == HTTP_CONNECT) { - UPDATE_STATE(s_req_server_start); - } - - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - - break; - } - - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - { - switch (ch) { - /* No whitespace allowed here */ - case ' ': - case CR: - case LF: - SET_ERRNO(HPE_INVALID_URL); - goto error; - default: - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - - break; - } - - case s_req_server: - case s_req_server_with_at: - case s_req_path: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - { - switch (ch) { - case ' ': - UPDATE_STATE(s_req_http_start); - CALLBACK_DATA(url); - break; - case CR: - case LF: - parser->http_major = 0; - parser->http_minor = 9; - UPDATE_STATE((ch == CR) ? - s_req_line_almost_done : - s_header_field_start); - CALLBACK_DATA(url); - break; - default: - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - break; - } - - case s_req_http_start: - switch (ch) { - case 'H': - UPDATE_STATE(s_req_http_H); - break; - case ' ': - break; - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - break; - - case s_req_http_H: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_req_http_HT); - break; - - case s_req_http_HT: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_req_http_HTT); - break; - - case s_req_http_HTT: - STRICT_CHECK(ch != 'P'); - UPDATE_STATE(s_req_http_HTTP); - break; - - case s_req_http_HTTP: - STRICT_CHECK(ch != '/'); - UPDATE_STATE(s_req_first_http_major); - break; - - /* first digit of major HTTP version */ - case s_req_first_http_major: - if (UNLIKELY(ch < '1' || ch > '9')) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - UPDATE_STATE(s_req_http_major); - break; - - /* major HTTP version or dot */ - case s_req_http_major: - { - if (ch == '.') { - UPDATE_STATE(s_req_first_http_minor); - break; - } - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (UNLIKELY(parser->http_major > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_req_first_http_minor: - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - UPDATE_STATE(s_req_http_minor); - break; - - /* minor HTTP version or end of request line */ - case s_req_http_minor: - { - if (ch == CR) { - UPDATE_STATE(s_req_line_almost_done); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_field_start); - break; - } - - /* XXX allow spaces after digit? */ - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (UNLIKELY(parser->http_minor > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* end of request line */ - case s_req_line_almost_done: - { - if (UNLIKELY(ch != LF)) { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - UPDATE_STATE(s_header_field_start); - break; - } - - case s_header_field_start: - { - if (ch == CR) { - UPDATE_STATE(s_headers_almost_done); - break; - } - - if (ch == LF) { - /* they might be just sending \n instead of \r\n so this would be - * the second \n to denote the end of headers*/ - UPDATE_STATE(s_headers_almost_done); - REEXECUTE(); - } - - c = TOKEN(ch); - - if (UNLIKELY(!c)) { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - MARK(header_field); - - parser->index = 0; - UPDATE_STATE(s_header_field); - - switch (c) { - case 'c': - parser->header_state = h_C; - break; - - case 'p': - parser->header_state = h_matching_proxy_connection; - break; - - case 't': - parser->header_state = h_matching_transfer_encoding; - break; - - case 'u': - parser->header_state = h_matching_upgrade; - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_field: - { - const char* start = p; - for (; p != data + len; p++) { - ch = *p; - c = TOKEN(ch); - - if (!c) - break; - - switch (parser->header_state) { - case h_general: - break; - - case h_C: - parser->index++; - parser->header_state = (c == 'o' ? h_CO : h_general); - break; - - case h_CO: - parser->index++; - parser->header_state = (c == 'n' ? h_CON : h_general); - break; - - case h_CON: - parser->index++; - switch (c) { - case 'n': - parser->header_state = h_matching_connection; - break; - case 't': - parser->header_state = h_matching_content_length; - break; - default: - parser->header_state = h_general; - break; - } - break; - - /* connection */ - - case h_matching_connection: - parser->index++; - if (parser->index > sizeof(CONNECTION)-1 - || c != CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* proxy-connection */ - - case h_matching_proxy_connection: - parser->index++; - if (parser->index > sizeof(PROXY_CONNECTION)-1 - || c != PROXY_CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* content-length */ - - case h_matching_content_length: - parser->index++; - if (parser->index > sizeof(CONTENT_LENGTH)-1 - || c != CONTENT_LENGTH[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { - parser->header_state = h_content_length; - } - break; - - /* transfer-encoding */ - - case h_matching_transfer_encoding: - parser->index++; - if (parser->index > sizeof(TRANSFER_ENCODING)-1 - || c != TRANSFER_ENCODING[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { - parser->header_state = h_transfer_encoding; - } - break; - - /* upgrade */ - - case h_matching_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE)-1 - || c != UPGRADE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(UPGRADE)-2) { - parser->header_state = h_upgrade; - } - break; - - case h_connection: - case h_content_length: - case h_transfer_encoding: - case h_upgrade: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - assert(0 && "Unknown header_state"); - break; - } - } - - COUNT_HEADER_SIZE(p - start); - - if (p == data + len) { - --p; - break; - } - - if (ch == ':') { - UPDATE_STATE(s_header_value_discard_ws); - CALLBACK_DATA(header_field); - break; - } - - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - case s_header_value_discard_ws: - if (ch == ' ' || ch == '\t') break; - - if (ch == CR) { - UPDATE_STATE(s_header_value_discard_ws_almost_done); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_value_discard_lws); - break; - } - - /* FALLTHROUGH */ - - case s_header_value_start: - { - MARK(header_value); - - UPDATE_STATE(s_header_value); - parser->index = 0; - - c = LOWER(ch); - - switch (parser->header_state) { - case h_upgrade: - parser->flags |= F_UPGRADE; - parser->header_state = h_general; - break; - - case h_transfer_encoding: - /* looking for 'Transfer-Encoding: chunked' */ - if ('c' == c) { - parser->header_state = h_matching_transfer_encoding_chunked; - } else { - parser->header_state = h_general; - } - break; - - case h_content_length: - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - if (parser->flags & F_CONTENTLENGTH) { - SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); - goto error; - } - - parser->flags |= F_CONTENTLENGTH; - parser->content_length = ch - '0'; - break; - - case h_connection: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - parser->header_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - parser->header_state = h_matching_connection_close; - } else if (c == 'u') { - parser->header_state = h_matching_connection_upgrade; - } else { - parser->header_state = h_matching_connection_token; - } - break; - - /* Multi-value `Connection` header */ - case h_matching_connection_token_start: - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_value: - { - const char* start = p; - enum header_states h_state = (enum header_states) parser->header_state; - for (; p != data + len; p++) { - ch = *p; - if (ch == CR) { - UPDATE_STATE(s_header_almost_done); - parser->header_state = h_state; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_almost_done); - COUNT_HEADER_SIZE(p - start); - parser->header_state = h_state; - CALLBACK_DATA_NOADVANCE(header_value); - REEXECUTE(); - } - - if (!lenient && !IS_HEADER_CHAR(ch)) { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - c = LOWER(ch); - - switch (h_state) { - case h_general: - { - const char* p_cr; - const char* p_lf; - size_t limit = data + len - p; - - limit = MIN(limit, HTTP_MAX_HEADER_SIZE); - - p_cr = (const char*) memchr(p, CR, limit); - p_lf = (const char*) memchr(p, LF, limit); - if (p_cr != NULL) { - if (p_lf != NULL && p_cr >= p_lf) - p = p_lf; - else - p = p_cr; - } else if (UNLIKELY(p_lf != NULL)) { - p = p_lf; - } else { - p = data + len; - } - --p; - - break; - } - - case h_connection: - case h_transfer_encoding: - assert(0 && "Shouldn't get here."); - break; - - case h_content_length: - { - uint64_t t; - - if (ch == ' ') break; - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - parser->header_state = h_state; - goto error; - } - - t = parser->content_length; - t *= 10; - t += ch - '0'; - - /* Overflow? Test against a conservative limit for simplicity. */ - if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - parser->header_state = h_state; - goto error; - } - - parser->content_length = t; - break; - } - - /* Transfer-Encoding: chunked */ - case h_matching_transfer_encoding_chunked: - parser->index++; - if (parser->index > sizeof(CHUNKED)-1 - || c != CHUNKED[parser->index]) { - h_state = h_general; - } else if (parser->index == sizeof(CHUNKED)-2) { - h_state = h_transfer_encoding_chunked; - } - break; - - case h_matching_connection_token_start: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - h_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - h_state = h_matching_connection_close; - } else if (c == 'u') { - h_state = h_matching_connection_upgrade; - } else if (STRICT_TOKEN(c)) { - h_state = h_matching_connection_token; - } else if (c == ' ' || c == '\t') { - /* Skip lws */ - } else { - h_state = h_general; - } - break; - - /* looking for 'Connection: keep-alive' */ - case h_matching_connection_keep_alive: - parser->index++; - if (parser->index > sizeof(KEEP_ALIVE)-1 - || c != KEEP_ALIVE[parser->index]) { - h_state = h_matching_connection_token; - } else if (parser->index == sizeof(KEEP_ALIVE)-2) { - h_state = h_connection_keep_alive; - } - break; - - /* looking for 'Connection: close' */ - case h_matching_connection_close: - parser->index++; - if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { - h_state = h_matching_connection_token; - } else if (parser->index == sizeof(CLOSE)-2) { - h_state = h_connection_close; - } - break; - - /* looking for 'Connection: upgrade' */ - case h_matching_connection_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE) - 1 || - c != UPGRADE[parser->index]) { - h_state = h_matching_connection_token; - } else if (parser->index == sizeof(UPGRADE)-2) { - h_state = h_connection_upgrade; - } - break; - - case h_matching_connection_token: - if (ch == ',') { - h_state = h_matching_connection_token_start; - parser->index = 0; - } - break; - - case h_transfer_encoding_chunked: - if (ch != ' ') h_state = h_general; - break; - - case h_connection_keep_alive: - case h_connection_close: - case h_connection_upgrade: - if (ch == ',') { - if (h_state == h_connection_keep_alive) { - parser->flags |= F_CONNECTION_KEEP_ALIVE; - } else if (h_state == h_connection_close) { - parser->flags |= F_CONNECTION_CLOSE; - } else if (h_state == h_connection_upgrade) { - parser->flags |= F_CONNECTION_UPGRADE; - } - h_state = h_matching_connection_token_start; - parser->index = 0; - } else if (ch != ' ') { - h_state = h_matching_connection_token; - } - break; - - default: - UPDATE_STATE(s_header_value); - h_state = h_general; - break; - } - } - parser->header_state = h_state; - - COUNT_HEADER_SIZE(p - start); - - if (p == data + len) - --p; - break; - } - - case s_header_almost_done: - { - if (UNLIKELY(ch != LF)) { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - UPDATE_STATE(s_header_value_lws); - break; - } - - case s_header_value_lws: - { - if (ch == ' ' || ch == '\t') { - UPDATE_STATE(s_header_value_start); - REEXECUTE(); - } - - /* finished the header */ - switch (parser->header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - case h_connection_upgrade: - parser->flags |= F_CONNECTION_UPGRADE; - break; - default: - break; - } - - UPDATE_STATE(s_header_field_start); - REEXECUTE(); - } - - case s_header_value_discard_ws_almost_done: - { - STRICT_CHECK(ch != LF); - UPDATE_STATE(s_header_value_discard_lws); - break; - } - - case s_header_value_discard_lws: - { - if (ch == ' ' || ch == '\t') { - UPDATE_STATE(s_header_value_discard_ws); - break; - } else { - switch (parser->header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_connection_upgrade: - parser->flags |= F_CONNECTION_UPGRADE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - default: - break; - } - - /* header value was empty */ - MARK(header_value); - UPDATE_STATE(s_header_field_start); - CALLBACK_DATA_NOADVANCE(header_value); - REEXECUTE(); - } - } - - case s_headers_almost_done: - { - STRICT_CHECK(ch != LF); - - if (parser->flags & F_TRAILING) { - /* End of a chunked request */ - UPDATE_STATE(s_message_done); - CALLBACK_NOTIFY_NOADVANCE(chunk_complete); - REEXECUTE(); - } - - /* Cannot use chunked encoding and a content-length header together - per the HTTP specification. */ - if ((parser->flags & F_CHUNKED) && - (parser->flags & F_CONTENTLENGTH)) { - SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); - goto error; - } - - UPDATE_STATE(s_headers_done); - - /* Set this here so that on_headers_complete() callbacks can see it */ - parser->upgrade = - ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) == - (F_UPGRADE | F_CONNECTION_UPGRADE) || - parser->method == HTTP_CONNECT); - - /* Here we call the headers_complete callback. This is somewhat - * different than other callbacks because if the user returns 1, we - * will interpret that as saying that this message has no body. This - * is needed for the annoying case of recieving a response to a HEAD - * request. - * - * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so - * we have to simulate it by handling a change in errno below. - */ - if (settings->on_headers_complete) { - switch (settings->on_headers_complete(parser)) { - case 0: - break; - - case 2: - parser->upgrade = 1; - - case 1: - parser->flags |= F_SKIPBODY; - break; - - default: - SET_ERRNO(HPE_CB_headers_complete); - RETURN(p - data); /* Error */ - } - } - - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - RETURN(p - data); - } - - REEXECUTE(); - } - - case s_headers_done: - { - int hasBody; - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - hasBody = parser->flags & F_CHUNKED || - (parser->content_length > 0 && parser->content_length != ULLONG_MAX); - if (parser->upgrade && (parser->method == HTTP_CONNECT || - (parser->flags & F_SKIPBODY) || !hasBody)) { - /* Exit, the rest of the message is in a different protocol. */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - RETURN((p - data) + 1); - } - - if (parser->flags & F_SKIPBODY) { - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } else if (parser->flags & F_CHUNKED) { - /* chunked encoding - ignore Content-Length header */ - UPDATE_STATE(s_chunk_size_start); - } else { - if (parser->content_length == 0) { - /* Content-Length header given but zero: Content-Length: 0\r\n */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } else if (parser->content_length != ULLONG_MAX) { - /* Content-Length header given and non-zero */ - UPDATE_STATE(s_body_identity); - } else { - if (!http_message_needs_eof(parser)) { - /* Assume content-length 0 - read the next */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } else { - /* Read body until EOF */ - UPDATE_STATE(s_body_identity_eof); - } - } - } - - break; - } - - case s_body_identity: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* The difference between advancing content_length and p is because - * the latter will automaticaly advance on the next loop iteration. - * Further, if content_length ends up at 0, we want to see the last - * byte again for our message complete callback. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - UPDATE_STATE(s_message_done); - - /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. - * - * The alternative to doing this is to wait for the next byte to - * trigger the data callback, just as in every other case. The - * problem with this is that this makes it difficult for the test - * harness to distinguish between complete-on-EOF and - * complete-on-length. It's not clear that this distinction is - * important for applications, but let's keep it for now. - */ - CALLBACK_DATA_(body, p - body_mark + 1, p - data); - REEXECUTE(); - } - - break; - } - - /* read until EOF */ - case s_body_identity_eof: - MARK(body); - p = data + len - 1; - - break; - - case s_message_done: - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - if (parser->upgrade) { - /* Exit, the rest of the message is in a different protocol. */ - RETURN((p - data) + 1); - } - break; - - case s_chunk_size_start: - { - assert(parser->nread == 1); - assert(parser->flags & F_CHUNKED); - - unhex_val = unhex[(unsigned char)ch]; - if (UNLIKELY(unhex_val == -1)) { - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - parser->content_length = unhex_val; - UPDATE_STATE(s_chunk_size); - break; - } - - case s_chunk_size: - { - uint64_t t; - - assert(parser->flags & F_CHUNKED); - - if (ch == CR) { - UPDATE_STATE(s_chunk_size_almost_done); - break; - } - - unhex_val = unhex[(unsigned char)ch]; - - if (unhex_val == -1) { - if (ch == ';' || ch == ' ') { - UPDATE_STATE(s_chunk_parameters); - break; - } - - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - t = parser->content_length; - t *= 16; - t += unhex_val; - - /* Overflow? Test against a conservative limit for simplicity. */ - if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - case s_chunk_parameters: - { - assert(parser->flags & F_CHUNKED); - /* just ignore this shit. TODO check for overflow */ - if (ch == CR) { - UPDATE_STATE(s_chunk_size_almost_done); - break; - } - break; - } - - case s_chunk_size_almost_done: - { - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - if (parser->content_length == 0) { - parser->flags |= F_TRAILING; - UPDATE_STATE(s_header_field_start); - } else { - UPDATE_STATE(s_chunk_data); - } - CALLBACK_NOTIFY(chunk_header); - break; - } - - case s_chunk_data: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->flags & F_CHUNKED); - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* See the explanation in s_body_identity for why the content - * length and data pointers are managed this way. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - UPDATE_STATE(s_chunk_data_almost_done); - } - - break; - } - - case s_chunk_data_almost_done: - assert(parser->flags & F_CHUNKED); - assert(parser->content_length == 0); - STRICT_CHECK(ch != CR); - UPDATE_STATE(s_chunk_data_done); - CALLBACK_DATA(body); - break; - - case s_chunk_data_done: - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - parser->nread = 0; - UPDATE_STATE(s_chunk_size_start); - CALLBACK_NOTIFY(chunk_complete); - break; - - default: - assert(0 && "unhandled state"); - SET_ERRNO(HPE_INVALID_INTERNAL_STATE); - goto error; - } - } - - /* Run callbacks for any marks that we have leftover after we ran our of - * bytes. There should be at most one of these set, so it's OK to invoke - * them in series (unset marks will not result in callbacks). - * - * We use the NOADVANCE() variety of callbacks here because 'p' has already - * overflowed 'data' and this allows us to correct for the off-by-one that - * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' - * value that's in-bounds). - */ - - assert(((header_field_mark ? 1 : 0) + - (header_value_mark ? 1 : 0) + - (url_mark ? 1 : 0) + - (body_mark ? 1 : 0) + - (status_mark ? 1 : 0)) <= 1); - - CALLBACK_DATA_NOADVANCE(header_field); - CALLBACK_DATA_NOADVANCE(header_value); - CALLBACK_DATA_NOADVANCE(url); - CALLBACK_DATA_NOADVANCE(body); - CALLBACK_DATA_NOADVANCE(status); - - RETURN(len); - -error: - if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { - SET_ERRNO(HPE_UNKNOWN); - } - - RETURN(p - data); -} - - -/* Does the parser need to see an EOF to find the end of the message? */ -int -http_message_needs_eof (const http_parser *parser) -{ - if (parser->type == HTTP_REQUEST) { - return 0; - } - - /* See RFC 2616 section 4.4 */ - if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ - parser->status_code == 204 || /* No Content */ - parser->status_code == 304 || /* Not Modified */ - parser->flags & F_SKIPBODY) { /* response to a HEAD request */ - return 0; - } - - if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { - return 0; - } - - return 1; -} - - -int -http_should_keep_alive (const http_parser *parser) -{ - if (parser->http_major > 0 && parser->http_minor > 0) { - /* HTTP/1.1 */ - if (parser->flags & F_CONNECTION_CLOSE) { - return 0; - } - } else { - /* HTTP/1.0 or earlier */ - if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { - return 0; - } - } - - return !http_message_needs_eof(parser); -} - - -const char * -http_method_str (enum http_method m) -{ - return ELEM_AT(method_strings, m, ""); -} - - -void -http_parser_init (http_parser *parser, enum http_parser_type t) -{ - void *data = parser->data; /* preserve application data */ - memset(parser, 0, sizeof(*parser)); - parser->data = data; - parser->type = t; - parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); - parser->http_errno = HPE_OK; -} - -void -http_parser_settings_init(http_parser_settings *settings) -{ - memset(settings, 0, sizeof(*settings)); -} - -const char * -http_errno_name(enum http_errno err) { - assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); - return http_strerror_tab[err].name; -} - -const char * -http_errno_description(enum http_errno err) { - assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); - return http_strerror_tab[err].description; -} - -static enum http_host_state -http_parse_host_char(enum http_host_state s, const char ch) { - switch(s) { - case s_http_userinfo: - case s_http_userinfo_start: - if (ch == '@') { - return s_http_host_start; - } - - if (IS_USERINFO_CHAR(ch)) { - return s_http_userinfo; - } - break; - - case s_http_host_start: - if (ch == '[') { - return s_http_host_v6_start; - } - - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - break; - - case s_http_host: - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - /* FALLTHROUGH */ - case s_http_host_v6_end: - if (ch == ':') { - return s_http_host_port_start; - } - - break; - - case s_http_host_v6: - if (ch == ']') { - return s_http_host_v6_end; - } - - /* FALLTHROUGH */ - case s_http_host_v6_start: - if (IS_HEX(ch) || ch == ':' || ch == '.') { - return s_http_host_v6; - } - - if (s == s_http_host_v6 && ch == '%') { - return s_http_host_v6_zone_start; - } - break; - - case s_http_host_v6_zone: - if (ch == ']') { - return s_http_host_v6_end; - } - - /* FALLTHROUGH */ - case s_http_host_v6_zone_start: - /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */ - if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' || - ch == '~') { - return s_http_host_v6_zone; - } - break; - - case s_http_host_port: - case s_http_host_port_start: - if (IS_NUM(ch)) { - return s_http_host_port; - } - - break; - - default: - break; - } - return s_http_host_dead; -} - -static int -http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { - enum http_host_state s; - - const char *p; - size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; - - assert(u->field_set & (1 << UF_HOST)); - - u->field_data[UF_HOST].len = 0; - - s = found_at ? s_http_userinfo_start : s_http_host_start; - - for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { - enum http_host_state new_s = http_parse_host_char(s, *p); - - if (new_s == s_http_host_dead) { - return 1; - } - - switch(new_s) { - case s_http_host: - if (s != s_http_host) { - u->field_data[UF_HOST].off = p - buf; - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6: - if (s != s_http_host_v6) { - u->field_data[UF_HOST].off = p - buf; - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6_zone_start: - case s_http_host_v6_zone: - u->field_data[UF_HOST].len++; - break; - - case s_http_host_port: - if (s != s_http_host_port) { - u->field_data[UF_PORT].off = p - buf; - u->field_data[UF_PORT].len = 0; - u->field_set |= (1 << UF_PORT); - } - u->field_data[UF_PORT].len++; - break; - - case s_http_userinfo: - if (s != s_http_userinfo) { - u->field_data[UF_USERINFO].off = p - buf ; - u->field_data[UF_USERINFO].len = 0; - u->field_set |= (1 << UF_USERINFO); - } - u->field_data[UF_USERINFO].len++; - break; - - default: - break; - } - s = new_s; - } - - /* Make sure we don't end somewhere unexpected */ - switch (s) { - case s_http_host_start: - case s_http_host_v6_start: - case s_http_host_v6: - case s_http_host_v6_zone_start: - case s_http_host_v6_zone: - case s_http_host_port_start: - case s_http_userinfo: - case s_http_userinfo_start: - return 1; - default: - break; - } - - return 0; -} - -void -http_parser_url_init(struct http_parser_url *u) { - memset(u, 0, sizeof(*u)); -} - -int -http_parser_parse_url(const char *buf, size_t buflen, int is_connect, - struct http_parser_url *u) -{ - enum state s; - const char *p; - enum http_parser_url_fields uf, old_uf; - int found_at = 0; - - u->port = u->field_set = 0; - s = is_connect ? s_req_server_start : s_req_spaces_before_url; - old_uf = UF_MAX; - - for (p = buf; p < buf + buflen; p++) { - s = parse_url_char(s, *p); - - /* Figure out the next field that we're operating on */ - switch (s) { - case s_dead: - return 1; - - /* Skip delimeters */ - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_query_string_start: - case s_req_fragment_start: - continue; - - case s_req_schema: - uf = UF_SCHEMA; - break; - - case s_req_server_with_at: - found_at = 1; - - /* FALLTROUGH */ - case s_req_server: - uf = UF_HOST; - break; - - case s_req_path: - uf = UF_PATH; - break; - - case s_req_query_string: - uf = UF_QUERY; - break; - - case s_req_fragment: - uf = UF_FRAGMENT; - break; - - default: - assert(!"Unexpected state"); - return 1; - } - - /* Nothing's changed; soldier on */ - if (uf == old_uf) { - u->field_data[uf].len++; - continue; - } - - u->field_data[uf].off = p - buf; - u->field_data[uf].len = 1; - - u->field_set |= (1 << uf); - old_uf = uf; - } - - /* host must be present if there is a schema */ - /* parsing http:///toto will fail */ - if ((u->field_set & (1 << UF_SCHEMA)) && - (u->field_set & (1 << UF_HOST)) == 0) { - return 1; - } - - if (u->field_set & (1 << UF_HOST)) { - if (http_parse_host(buf, u, found_at) != 0) { - return 1; - } - } - - /* CONNECT requests can only contain "hostname:port" */ - if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { - return 1; - } - - if (u->field_set & (1 << UF_PORT)) { - /* Don't bother with endp; we've already validated the string */ - unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); - - /* Ports have a max value of 2^16 */ - if (v > 0xffff) { - return 1; - } - - u->port = (uint16_t) v; - } - - return 0; -} - -void -http_parser_pause(http_parser *parser, int paused) { - /* Users should only be pausing/unpausing a parser that is not in an error - * state. In non-debug builds, there's not much that we can do about this - * other than ignore it. - */ - if (HTTP_PARSER_ERRNO(parser) == HPE_OK || - HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { - SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); - } else { - assert(0 && "Attempting to pause parser in error state"); - } -} - -int -http_body_is_final(const struct http_parser *parser) { - return parser->state == s_message_done; -} - -unsigned long -http_parser_version(void) { - return HTTP_PARSER_VERSION_MAJOR * 0x10000 | - HTTP_PARSER_VERSION_MINOR * 0x00100 | - HTTP_PARSER_VERSION_PATCH * 0x00001; -} diff --git a/zto/ext/http-parser/http_parser.h b/zto/ext/http-parser/http_parser.h deleted file mode 100644 index 45c72a0..0000000 --- a/zto/ext/http-parser/http_parser.h +++ /dev/null @@ -1,432 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * 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. - */ -#ifndef http_parser_h -#define http_parser_h -#ifdef __cplusplus -extern "C" { -#endif - -/* Also update SONAME in the Makefile whenever you change these. */ -#define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 7 -#define HTTP_PARSER_VERSION_PATCH 1 - -#include -#if defined(_WIN32) && !defined(__MINGW32__) && \ - (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) -#include -#include -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -#include -#endif - -/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run - * faster - */ -#ifndef HTTP_PARSER_STRICT -# define HTTP_PARSER_STRICT 1 -#endif - -/* Maximium header size allowed. If the macro is not defined - * before including this header then the default is used. To - * change the maximum header size, define the macro in the build - * environment (e.g. -DHTTP_MAX_HEADER_SIZE=). To remove - * the effective limit on the size of the header, define the macro - * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) - */ -#ifndef HTTP_MAX_HEADER_SIZE -# define HTTP_MAX_HEADER_SIZE (80*1024) -#endif - -typedef struct http_parser http_parser; -typedef struct http_parser_settings http_parser_settings; - - -/* Callbacks should return non-zero to indicate an error. The parser will - * then halt execution. - * - * The one exception is on_headers_complete. In a HTTP_RESPONSE parser - * returning '1' from on_headers_complete will tell the parser that it - * should not expect a body. This is used when receiving a response to a - * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: - * chunked' headers that indicate the presence of a body. - * - * Returning `2` from on_headers_complete will tell parser that it should not - * expect neither a body nor any futher responses on this connection. This is - * useful for handling responses to a CONNECT request which may not contain - * `Upgrade` or `Connection: upgrade` headers. - * - * http_data_cb does not return data chunks. It will be called arbitrarily - * many times for each string. E.G. you might get 10 callbacks for "on_url" - * each providing just a few characters more data. - */ -typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); -typedef int (*http_cb) (http_parser*); - - -/* Status Codes */ -#define HTTP_STATUS_MAP(XX) \ - XX(100, CONTINUE, Continue) \ - XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \ - XX(102, PROCESSING, Processing) \ - XX(200, OK, OK) \ - XX(201, CREATED, Created) \ - XX(202, ACCEPTED, Accepted) \ - XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \ - XX(204, NO_CONTENT, No Content) \ - XX(205, RESET_CONTENT, Reset Content) \ - XX(206, PARTIAL_CONTENT, Partial Content) \ - XX(207, MULTI_STATUS, Multi-Status) \ - XX(208, ALREADY_REPORTED, Already Reported) \ - XX(226, IM_USED, IM Used) \ - XX(300, MULTIPLE_CHOICES, Multiple Choices) \ - XX(301, MOVED_PERMANENTLY, Moved Permanently) \ - XX(302, FOUND, Found) \ - XX(303, SEE_OTHER, See Other) \ - XX(304, NOT_MODIFIED, Not Modified) \ - XX(305, USE_PROXY, Use Proxy) \ - XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \ - XX(308, PERMANENT_REDIRECT, Permanent Redirect) \ - XX(400, BAD_REQUEST, Bad Request) \ - XX(401, UNAUTHORIZED, Unauthorized) \ - XX(402, PAYMENT_REQUIRED, Payment Required) \ - XX(403, FORBIDDEN, Forbidden) \ - XX(404, NOT_FOUND, Not Found) \ - XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \ - XX(406, NOT_ACCEPTABLE, Not Acceptable) \ - XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \ - XX(408, REQUEST_TIMEOUT, Request Timeout) \ - XX(409, CONFLICT, Conflict) \ - XX(410, GONE, Gone) \ - XX(411, LENGTH_REQUIRED, Length Required) \ - XX(412, PRECONDITION_FAILED, Precondition Failed) \ - XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \ - XX(414, URI_TOO_LONG, URI Too Long) \ - XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \ - XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \ - XX(417, EXPECTATION_FAILED, Expectation Failed) \ - XX(421, MISDIRECTED_REQUEST, Misdirected Request) \ - XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \ - XX(423, LOCKED, Locked) \ - XX(424, FAILED_DEPENDENCY, Failed Dependency) \ - XX(426, UPGRADE_REQUIRED, Upgrade Required) \ - XX(428, PRECONDITION_REQUIRED, Precondition Required) \ - XX(429, TOO_MANY_REQUESTS, Too Many Requests) \ - XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \ - XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \ - XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \ - XX(501, NOT_IMPLEMENTED, Not Implemented) \ - XX(502, BAD_GATEWAY, Bad Gateway) \ - XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \ - XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \ - XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \ - XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \ - XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \ - XX(508, LOOP_DETECTED, Loop Detected) \ - XX(510, NOT_EXTENDED, Not Extended) \ - XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \ - -enum http_status - { -#define XX(num, name, string) HTTP_STATUS_##name = num, - HTTP_STATUS_MAP(XX) -#undef XX - }; - - -/* Request Methods */ -#define HTTP_METHOD_MAP(XX) \ - XX(0, DELETE, DELETE) \ - XX(1, GET, GET) \ - XX(2, HEAD, HEAD) \ - XX(3, POST, POST) \ - XX(4, PUT, PUT) \ - /* pathological */ \ - XX(5, CONNECT, CONNECT) \ - XX(6, OPTIONS, OPTIONS) \ - XX(7, TRACE, TRACE) \ - /* WebDAV */ \ - XX(8, COPY, COPY) \ - XX(9, LOCK, LOCK) \ - XX(10, MKCOL, MKCOL) \ - XX(11, MOVE, MOVE) \ - XX(12, PROPFIND, PROPFIND) \ - XX(13, PROPPATCH, PROPPATCH) \ - XX(14, SEARCH, SEARCH) \ - XX(15, UNLOCK, UNLOCK) \ - XX(16, BIND, BIND) \ - XX(17, REBIND, REBIND) \ - XX(18, UNBIND, UNBIND) \ - XX(19, ACL, ACL) \ - /* subversion */ \ - XX(20, REPORT, REPORT) \ - XX(21, MKACTIVITY, MKACTIVITY) \ - XX(22, CHECKOUT, CHECKOUT) \ - XX(23, MERGE, MERGE) \ - /* upnp */ \ - XX(24, MSEARCH, M-SEARCH) \ - XX(25, NOTIFY, NOTIFY) \ - XX(26, SUBSCRIBE, SUBSCRIBE) \ - XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ - /* RFC-5789 */ \ - XX(28, PATCH, PATCH) \ - XX(29, PURGE, PURGE) \ - /* CalDAV */ \ - XX(30, MKCALENDAR, MKCALENDAR) \ - /* RFC-2068, section 19.6.1.2 */ \ - XX(31, LINK, LINK) \ - XX(32, UNLINK, UNLINK) \ - -enum http_method - { -#define XX(num, name, string) HTTP_##name = num, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; - - -/* Flag values for http_parser.flags field */ -enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_CONNECTION_UPGRADE = 1 << 3 - , F_TRAILING = 1 << 4 - , F_UPGRADE = 1 << 5 - , F_SKIPBODY = 1 << 6 - , F_CONTENTLENGTH = 1 << 7 - }; - - -/* Map for errno-related constants - * - * The provided argument should be a macro that takes 2 arguments. - */ -#define HTTP_ERRNO_MAP(XX) \ - /* No error */ \ - XX(OK, "success") \ - \ - /* Callback-related errors */ \ - XX(CB_message_begin, "the on_message_begin callback failed") \ - XX(CB_url, "the on_url callback failed") \ - XX(CB_header_field, "the on_header_field callback failed") \ - XX(CB_header_value, "the on_header_value callback failed") \ - XX(CB_headers_complete, "the on_headers_complete callback failed") \ - XX(CB_body, "the on_body callback failed") \ - XX(CB_message_complete, "the on_message_complete callback failed") \ - XX(CB_status, "the on_status callback failed") \ - XX(CB_chunk_header, "the on_chunk_header callback failed") \ - XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ - \ - /* Parsing-related errors */ \ - XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ - XX(HEADER_OVERFLOW, \ - "too many header bytes seen; overflow detected") \ - XX(CLOSED_CONNECTION, \ - "data received after completed connection: close message") \ - XX(INVALID_VERSION, "invalid HTTP version") \ - XX(INVALID_STATUS, "invalid HTTP status code") \ - XX(INVALID_METHOD, "invalid HTTP method") \ - XX(INVALID_URL, "invalid URL") \ - XX(INVALID_HOST, "invalid host") \ - XX(INVALID_PORT, "invalid port") \ - XX(INVALID_PATH, "invalid path") \ - XX(INVALID_QUERY_STRING, "invalid query string") \ - XX(INVALID_FRAGMENT, "invalid fragment") \ - XX(LF_EXPECTED, "LF character expected") \ - XX(INVALID_HEADER_TOKEN, "invalid character in header") \ - XX(INVALID_CONTENT_LENGTH, \ - "invalid character in content-length header") \ - XX(UNEXPECTED_CONTENT_LENGTH, \ - "unexpected content-length header") \ - XX(INVALID_CHUNK_SIZE, \ - "invalid character in chunk size header") \ - XX(INVALID_CONSTANT, "invalid constant string") \ - XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ - XX(STRICT, "strict mode assertion failed") \ - XX(PAUSED, "parser is paused") \ - XX(UNKNOWN, "an unknown error occurred") - - -/* Define HPE_* values for each errno value above */ -#define HTTP_ERRNO_GEN(n, s) HPE_##n, -enum http_errno { - HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) -}; -#undef HTTP_ERRNO_GEN - - -/* Get an http_errno value from an http_parser */ -#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) - - -struct http_parser { - /** PRIVATE **/ - unsigned int type : 2; /* enum http_parser_type */ - unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ - unsigned int state : 7; /* enum state from http_parser.c */ - unsigned int header_state : 7; /* enum header_state from http_parser.c */ - unsigned int index : 7; /* index into current matcher */ - unsigned int lenient_http_headers : 1; - - uint32_t nread; /* # bytes read in various scenarios */ - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ - - /** READ-ONLY **/ - unsigned short http_major; - unsigned short http_minor; - unsigned int status_code : 16; /* responses only */ - unsigned int method : 8; /* requests only */ - unsigned int http_errno : 7; - - /* 1 = Upgrade header was present and the parser has exited because of that. - * 0 = No upgrade header present. - * Should be checked when http_parser_execute() returns in addition to - * error checking. - */ - unsigned int upgrade : 1; - - /** PUBLIC **/ - void *data; /* A pointer to get hook to the "connection" or "socket" object */ -}; - - -struct http_parser_settings { - http_cb on_message_begin; - http_data_cb on_url; - http_data_cb on_status; - http_data_cb on_header_field; - http_data_cb on_header_value; - http_cb on_headers_complete; - http_data_cb on_body; - http_cb on_message_complete; - /* When on_chunk_header is called, the current chunk length is stored - * in parser->content_length. - */ - http_cb on_chunk_header; - http_cb on_chunk_complete; -}; - - -enum http_parser_url_fields - { UF_SCHEMA = 0 - , UF_HOST = 1 - , UF_PORT = 2 - , UF_PATH = 3 - , UF_QUERY = 4 - , UF_FRAGMENT = 5 - , UF_USERINFO = 6 - , UF_MAX = 7 - }; - - -/* Result structure for http_parser_parse_url(). - * - * Callers should index into field_data[] with UF_* values iff field_set - * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and - * because we probably have padding left over), we convert any port to - * a uint16_t. - */ -struct http_parser_url { - uint16_t field_set; /* Bitmask of (1 << UF_*) values */ - uint16_t port; /* Converted UF_PORT string */ - - struct { - uint16_t off; /* Offset into buffer in which field starts */ - uint16_t len; /* Length of run in buffer */ - } field_data[UF_MAX]; -}; - - -/* Returns the library version. Bits 16-23 contain the major version number, - * bits 8-15 the minor version number and bits 0-7 the patch level. - * Usage example: - * - * unsigned long version = http_parser_version(); - * unsigned major = (version >> 16) & 255; - * unsigned minor = (version >> 8) & 255; - * unsigned patch = version & 255; - * printf("http_parser v%u.%u.%u\n", major, minor, patch); - */ -unsigned long http_parser_version(void); - -void http_parser_init(http_parser *parser, enum http_parser_type type); - - -/* Initialize http_parser_settings members to 0 - */ -void http_parser_settings_init(http_parser_settings *settings); - - -/* Executes the parser. Returns number of parsed bytes. Sets - * `parser->http_errno` on error. */ -size_t http_parser_execute(http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len); - - -/* If http_should_keep_alive() in the on_headers_complete or - * on_message_complete callback returns 0, then this should be - * the last message on the connection. - * If you are the server, respond with the "Connection: close" header. - * If you are the client, close the connection. - */ -int http_should_keep_alive(const http_parser *parser); - -/* Returns a string version of the HTTP method. */ -const char *http_method_str(enum http_method m); - -/* Return a string name of the given error */ -const char *http_errno_name(enum http_errno err); - -/* Return a string description of the given error */ -const char *http_errno_description(enum http_errno err); - -/* Initialize all http_parser_url members to 0 */ -void http_parser_url_init(struct http_parser_url *u); - -/* Parse a URL; return nonzero on failure */ -int http_parser_parse_url(const char *buf, size_t buflen, - int is_connect, - struct http_parser_url *u); - -/* Pause or un-pause the parser; a nonzero value pauses */ -void http_parser_pause(http_parser *parser, int paused); - -/* Checks if this is the final chunk of the body. */ -int http_body_is_final(const http_parser *parser); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/zto/ext/json/LICENSE.MIT b/zto/ext/json/LICENSE.MIT deleted file mode 100644 index e2ac489..0000000 --- a/zto/ext/json/LICENSE.MIT +++ /dev/null @@ -1,22 +0,0 @@ -The library is licensed under the MIT License -: - -Copyright (c) 2013-2016 Niels Lohmann - -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/zto/ext/json/README.md b/zto/ext/json/README.md deleted file mode 100644 index 4bcbe97..0000000 --- a/zto/ext/json/README.md +++ /dev/null @@ -1,538 +0,0 @@ -[![JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif)](https://github.com/nlohmann/json/releases) - -[![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json) -[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json) -[![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) -[![Try online](https://img.shields.io/badge/try-online-blue.svg)](http://melpon.org/wandbox/permlink/fsf5FqYe6GoX68W6) -[![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) -[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) -[![Github Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) -[![Github Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](http://github.com/nlohmann/json/issues) -[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/289/badge)](https://bestpractices.coreinfrastructure.org/projects/289) - -## Design goals - -There are myriads of [JSON](http://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals: - -- **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you'll know what I mean. - -- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/src/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. - -- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/blob/master/test/src/unit.cpp) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) that there are no memory leaks. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). - -Other aspects were not so important to us: - -- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs. - -- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) may be even faster (but would consist of more files which makes the integration harder). - -See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information. - - -## Integration - -The single required source, file `json.hpp` is in the `src` directory or [released here](https://github.com/nlohmann/json/releases). All you need to do is add - -```cpp -#include "json.hpp" - -// for convenience -using json = nlohmann::json; -``` - -to the files you want to use JSON objects. That's it. Do not forget to set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang). - -:beer: If you are using OS X and [Homebrew](http://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann_json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann_json --HEAD`. - - -## Examples - -Here are some examples to give you an idea how to use the class. - -Assume you want to create the JSON object - -```json -{ - "pi": 3.141, - "happy": true, - "name": "Niels", - "nothing": null, - "answer": { - "everything": 42 - }, - "list": [1, 0, 2], - "object": { - "currency": "USD", - "value": 42.99 - } -} -``` - -With the JSON class, you could write: - -```cpp -// create an empty structure (null) -json j; - -// add a number that is stored as double (note the implicit conversion of j to an object) -j["pi"] = 3.141; - -// add a Boolean that is stored as bool -j["happy"] = true; - -// add a string that is stored as std::string -j["name"] = "Niels"; - -// add another null object by passing nullptr -j["nothing"] = nullptr; - -// add an object inside the object -j["answer"]["everything"] = 42; - -// add an array that is stored as std::vector (using an initializer list) -j["list"] = { 1, 0, 2 }; - -// add another object (using an initializer list of pairs) -j["object"] = { {"currency", "USD"}, {"value", 42.99} }; - -// instead, you could also write (which looks very similar to the JSON above) -json j2 = { - {"pi", 3.141}, - {"happy", true}, - {"name", "Niels"}, - {"nothing", nullptr}, - {"answer", { - {"everything", 42} - }}, - {"list", {1, 0, 2}}, - {"object", { - {"currency", "USD"}, - {"value", 42.99} - }} -}; -``` - -Note that in all these cases, you never need to "tell" the compiler which JSON value you want to use. If you want to be explicit or express some edge cases, the functions `json::array` and `json::object` will help: - -```cpp -// a way to express the empty array [] -json empty_array_explicit = json::array(); - -// ways to express the empty object {} -json empty_object_implicit = json({}); -json empty_object_explicit = json::object(); - -// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]] -json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) }; -``` - - -### Serialization / Deserialization - -You can create an object (deserialization) by appending `_json` to a string literal: - -```cpp -// create object from string literal -json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; - -// or even nicer with a raw string literal -auto j2 = R"( - { - "happy": true, - "pi": 3.141 - } -)"_json; - -// or explicitly -auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }"); -``` - -You can also get a string representation (serialize): - -```cpp -// explicit conversion to string -std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141} - -// serialization with pretty printing -// pass in the amount of spaces to indent -std::cout << j.dump(4) << std::endl; -// { -// "happy": true, -// "pi": 3.141 -// } -``` - -You can also use streams to serialize and deserialize: - -```cpp -// deserialize from standard input -json j; -std::cin >> j; - -// serialize to standard output -std::cout << j; - -// the setw manipulator was overloaded to set the indentation for pretty printing -std::cout << std::setw(4) << j << std::endl; -``` - -These operators work for any subclasses of `std::istream` or `std::ostream`. - -Please note that setting the exception bit for `failbit` is inappropriate for this use case. It will result in program termination due to the `noexcept` specifier in use. - - -### STL-like access - -We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirement. - -```cpp -// create an array using push_back -json j; -j.push_back("foo"); -j.push_back(1); -j.push_back(true); - -// iterate the array -for (json::iterator it = j.begin(); it != j.end(); ++it) { - std::cout << *it << '\n'; -} - -// range-based for -for (auto& element : j) { - std::cout << element << '\n'; -} - -// getter/setter -const std::string tmp = j[0]; -j[1] = 42; -bool foo = j.at(2); - -// other stuff -j.size(); // 3 entries -j.empty(); // false -j.type(); // json::value_t::array -j.clear(); // the array is empty again - -// convenience type checkers -j.is_null(); -j.is_boolean(); -j.is_number(); -j.is_object(); -j.is_array(); -j.is_string(); - -// comparison -j == "[\"foo\", 1, true]"_json; // true - -// create an object -json o; -o["foo"] = 23; -o["bar"] = false; -o["baz"] = 3.141; - -// special iterator member functions for objects -for (json::iterator it = o.begin(); it != o.end(); ++it) { - std::cout << it.key() << " : " << it.value() << "\n"; -} - -// find an entry -if (o.find("foo") != o.end()) { - // there is an entry with key "foo" -} - -// or simpler using count() -int foo_present = o.count("foo"); // 1 -int fob_present = o.count("fob"); // 0 - -// delete an entry -o.erase("foo"); -``` - - -### Conversion from STL containers - -Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON types (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends how the elements are ordered in the respective STL container. - -```cpp -std::vector c_vector {1, 2, 3, 4}; -json j_vec(c_vector); -// [1, 2, 3, 4] - -std::deque c_deque {1.2, 2.3, 3.4, 5.6}; -json j_deque(c_deque); -// [1.2, 2.3, 3.4, 5.6] - -std::list c_list {true, true, false, true}; -json j_list(c_list); -// [true, true, false, true] - -std::forward_list c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; -json j_flist(c_flist); -// [12345678909876, 23456789098765, 34567890987654, 45678909876543] - -std::array c_array {{1, 2, 3, 4}}; -json j_array(c_array); -// [1, 2, 3, 4] - -std::set c_set {"one", "two", "three", "four", "one"}; -json j_set(c_set); // only one entry for "one" is used -// ["four", "one", "three", "two"] - -std::unordered_set c_uset {"one", "two", "three", "four", "one"}; -json j_uset(c_uset); // only one entry for "one" is used -// maybe ["two", "three", "four", "one"] - -std::multiset c_mset {"one", "two", "one", "four"}; -json j_mset(c_mset); // both entries for "one" are used -// maybe ["one", "two", "one", "four"] - -std::unordered_multiset c_umset {"one", "two", "one", "four"}; -json j_umset(c_umset); // both entries for "one" are used -// maybe ["one", "two", "one", "four"] -``` - -Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON types (see examples above) can be used to to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. - -```cpp -std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; -json j_map(c_map); -// {"one": 1, "three": 3, "two": 2 } - -std::unordered_map c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} }; -json j_umap(c_umap); -// {"one": 1.2, "two": 2.3, "three": 3.4} - -std::multimap c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; -json j_mmap(c_mmap); // only one entry for key "three" is used -// maybe {"one": true, "two": true, "three": true} - -std::unordered_multimap c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; -json j_ummap(c_ummap); // only one entry for key "three" is used -// maybe {"one": true, "two": true, "three": true} -``` - -### JSON Pointer and JSON Patch - -The library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as alternative means to address structured values. On top of this, **JSON Patch** ([RFC 6902](https://tools.ietf.org/html/rfc6902)) allows to describe differences between two JSON values - effectively allowing patch and diff operations known from Unix. - -```cpp -// a JSON value -json j_original = R"({ - "baz": ["one", "two", "three"], - "foo": "bar" -})"_json; - -// access members with a JSON pointer (RFC 6901) -j_original["/baz/1"_json_pointer]; -// "two" - -// a JSON patch (RFC 6902) -json j_patch = R"([ - { "op": "replace", "path": "/baz", "value": "boo" }, - { "op": "add", "path": "/hello", "value": ["world"] }, - { "op": "remove", "path": "/foo"} -])"_json; - -// apply the patch -json j_result = j_original.patch(j_patch); -// { -// "baz": "boo", -// "hello": ["world"] -// } - -// calculate a JSON patch from two JSON values -json::diff(j_result, j_original); -// [ -// { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] }, -// { "op": "remove","path": "/hello" }, -// { "op": "add", "path": "/foo", "value": "bar" } -// ] -``` - - -### Implicit conversions - -The type of the JSON object is determined automatically by the expression to store. Likewise, the stored value is implicitly converted. - -```cpp -// strings -std::string s1 = "Hello, world!"; -json js = s1; -std::string s2 = js; - -// Booleans -bool b1 = true; -json jb = b1; -bool b2 = jb; - -// numbers -int i = 42; -json jn = i; -double f = jn; - -// etc. -``` - -You can also explicitly ask for the value: - -```cpp -std::string vs = js.get(); -bool vb = jb.get(); -int vi = jn.get(); - -// etc. -``` - - -## Supported compilers - -Though it's 2016 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: - -- GCC 4.9 - 6.0 (and possibly later) -- Clang 3.4 - 3.9 (and possibly later) -- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) - -I would be happy to learn about other compilers/versions. - -Please note: - -- GCC 4.8 does not work because of two bugs ([55817](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55817) and [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)) in the C++11 support. Note there is a [pull request](https://github.com/nlohmann/json/pull/212) to fix some of the issues. -- Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. - - ``` - APP_STL := c++_shared - NDK_TOOLCHAIN_VERSION := clang3.6 - APP_CPPFLAGS += -frtti -fexceptions - ``` - - The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10. - -- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219). - -The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json) and [AppVeyor](https://ci.appveyor.com/project/nlohmann/json): - -| Compiler | Operating System | Version String | -|-----------------|------------------------------|----------------| -| GCC 4.9.3 | Ubuntu 14.04.4 LTS | g++-4.9 (Ubuntu 4.9.3-8ubuntu2~14.04) 4.9.3 | -| GCC 5.3.0 | Ubuntu 14.04.4 LTS | g++-5 (Ubuntu 5.3.0-3ubuntu1~14.04) 5.3.0 20151204 | -| GCC 6.1.1 | Ubuntu 14.04.4 LTS | g++-6 (Ubuntu 6.1.1-3ubuntu11~14.04.1) 6.1.1 20160511 | -| Clang 3.6.0 | Ubuntu 14.04.4 LTS | clang version 3.6.0 (tags/RELEASE_360/final) | -| Clang 3.6.1 | Ubuntu 14.04.4 LTS | clang version 3.6.1 (tags/RELEASE_361/final) | -| Clang 3.6.2 | Ubuntu 14.04.4 LTS | clang version 3.6.2 (tags/RELEASE_362/final) | -| Clang 3.7.0 | Ubuntu 14.04.4 LTS | clang version 3.7.0 (tags/RELEASE_370/final) | -| Clang 3.7.1 | Ubuntu 14.04.4 LTS | clang version 3.7.1 (tags/RELEASE_371/final) | -| Clang 3.8.0 | Ubuntu 14.04.4 LTS | clang version 3.8.0 (tags/RELEASE_380/final) | -| Clang 3.8.1 | Ubuntu 14.04.4 LTS | clang version 3.8.1 (tags/RELEASE_381/final) | -| Clang Xcode 6.1 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn) | -| Clang Xcode 6.2 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn) | -| Clang Xcode 6.3 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn) | -| Clang Xcode 6.4 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) | -| Clang Xcode 7.1 | Darwin Kernel Version 14.5.0 (OSX 10.10.5) | Apple LLVM version 7.0.0 (clang-700.1.76) | -| Clang Xcode 7.2 | Darwin Kernel Version 15.0.0 (OSX 10.10.5) | Apple LLVM version 7.0.2 (clang-700.1.81) | -| Clang Xcode 7.3 | Darwin Kernel Version 15.0.0 (OSX 10.10.5) | Apple LLVM version 7.3.0 (clang-703.0.29) | -| Clang Xcode 8.0 | Darwin Kernel Version 15.6.0 (OSX 10.11.6) | Apple LLVM version 8.0.0 (clang-800.0.38) | -| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25123.0 | - - -## License - - - -The class is licensed under the [MIT License](http://opensource.org/licenses/MIT): - -Copyright © 2013-2016 [Niels Lohmann](http://nlohmann.me) - -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. - - -## Thanks - -I deeply appreciate the help of the following people. - -- [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization. -- [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes. -- [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries. -- [wancw](https://github.com/wanwc) fixed a bug that hindered the class to compile with Clang. -- Tomas Åblad found a bug in the iterator implementation. -- [Joshua C. Randall](https://github.com/jrandall) fixed a bug in the floating-point serialization. -- [Aaron Burghardt](https://github.com/aburgh) implemented code to parse streams incrementally. Furthermore, he greatly improved the parser class by allowing the definition of a filter function to discard undesired elements while parsing. -- [Daniel Kopeček](https://github.com/dkopecek) fixed a bug in the compilation with GCC 5.0. -- [Florian Weber](https://github.com/Florianjw) fixed a bug in and improved the performance of the comparison operators. -- [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping. -- [易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums. -- [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio. -- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. -- [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling. -- [dariomt](https://github.com/dariomt) fixed some typos in the examples. -- [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation. -- [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue. -- [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation. -- [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. -- [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values. -- [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. -- [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. -- [406345](https://github.com/406345) fixed two small warnings. -- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function. -- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines. -- [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers. -- [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file. -- [msm-](https://github.com/msm-) added support for american fuzzy lop. -- [Annihil](https://github.com/Annihil) fixed an example in the README file. -- [Themercee](https://github.com/Themercee) noted a wrong URL in the README file. -- [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`. -- [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212). -- [zewt](https://github.com/zewt) added useful notes to the README file about Android. -- [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake. -- [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files. -- [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal). -- [Mário Feroldi](https://github.com/thelostt) fixed a small typo. -- [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release. -- [Damien](https://github.com/dtoma) fixed one of the last conversion warnings. -- [Thomas Braun](https://github.com/t-b) fixed a warning in a test case. -- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). -- [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation. -- [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`. -- [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion. -- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable. -- [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file. - -Thanks a lot for helping out! - - -## Notes - -- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726). -- As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. -- The library supports **Unicode input** as follows: - - Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 7159](http://rfc7159.net/rfc7159#rfc.section.8.1). - - Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse errors. - - [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library. - - Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors. - - -## Execute unit tests - -To compile and run the tests, you need to execute - -```sh -$ make check - -=============================================================================== -All tests passed (8905491 assertions in 36 test cases) -``` - -Alternatively, you can use [CMake](https://cmake.org) and run - -```sh -$ mkdir build -$ cd build -$ cmake .. -$ make -$ ctest -``` - -For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/zto/ext/json/json.hpp b/zto/ext/json/json.hpp deleted file mode 100644 index 9d48e7a..0000000 --- a/zto/ext/json/json.hpp +++ /dev/null @@ -1,12275 +0,0 @@ -/* - __ _____ _____ _____ - __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 2.0.10 -|_____|_____|_____|_|___| https://github.com/nlohmann/json - -Licensed under the MIT License . -Copyright (c) 2013-2017 Niels Lohmann . - -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. -*/ - -#ifndef NLOHMANN_JSON_HPP -#define NLOHMANN_JSON_HPP - -#include // all_of, for_each, transform -#include // array -#include // assert -#include // isdigit -#include // and, not, or -#include // isfinite, ldexp, signbit -#include // nullptr_t, ptrdiff_t, size_t -#include // int64_t, uint64_t -#include // strtod, strtof, strtold, strtoul -#include // strlen -#include // function, hash, less -#include // initializer_list -#include // setw -#include // istream, ostream -#include // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator -#include // numeric_limits -#include // locale -#include // map -#include // addressof, allocator, allocator_traits, unique_ptr -#include // accumulate -#include // stringstream -#include // domain_error, invalid_argument, out_of_range -#include // getline, stoi, string, to_string -#include // add_pointer, enable_if, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_floating_point, is_integral, is_nothrow_move_assignable, std::is_nothrow_move_constructible, std::is_pointer, std::is_reference, std::is_same, remove_const, remove_pointer, remove_reference -#include // declval, forward, make_pair, move, pair, swap -#include // vector - -// exclude unsupported compilers -#if defined(__clang__) - #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) - #if CLANG_VERSION < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#elif defined(__GNUC__) - #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) - #if GCC_VERSION < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#endif - -// disable float-equal warnings on GCC/clang -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" -#endif - -// allow for portable deprecation warnings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) -#else - #define JSON_DEPRECATED -#endif - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ - - -/*! -@brief unnamed namespace with internal helper functions -@since version 1.0.0 -*/ -namespace -{ -/*! -@brief Helper to determine whether there's a key_type for T. - -Thus helper is used to tell associative containers apart from other containers -such as sequence containers. For instance, `std::map` passes the test as it -contains a `mapped_type`, whereas `std::vector` fails the test. - -@sa http://stackoverflow.com/a/7728728/266378 -@since version 1.0.0, overworked in version 2.0.6 -*/ -template -struct has_mapped_type -{ - private: - template - static int detect(U&&); - - static void detect(...); - public: - static constexpr bool value = - std::is_integral()))>::value; -}; - -} - -/*! -@brief a class to store JSON values - -@tparam ObjectType type for JSON objects (`std::map` by default; will be used -in @ref object_t) -@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used -in @ref array_t) -@tparam StringType type for JSON strings and object keys (`std::string` by -default; will be used in @ref string_t) -@tparam BooleanType type for JSON booleans (`bool` by default; will be used -in @ref boolean_t) -@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by -default; will be used in @ref number_integer_t) -@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c -`uint64_t` by default; will be used in @ref number_unsigned_t) -@tparam NumberFloatType type for JSON floating-point numbers (`double` by -default; will be used in @ref number_float_t) -@tparam AllocatorType type of the allocator to use (`std::allocator` by -default) - -@requirement The class satisfies the following concept requirements: -- Basic - - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): - JSON values can be default constructed. The result will be a JSON null value. - - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): - A JSON value can be constructed from an rvalue argument. - - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): - A JSON value can be copy-constructed from an lvalue expression. - - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): - A JSON value van be assigned from an rvalue argument. - - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): - A JSON value can be copy-assigned from an lvalue expression. - - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): - JSON values can be destructed. -- Layout - - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): - JSON values have - [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): - All non-static data members are private and standard layout types, the class - has no virtual functions or (virtual) base classes. -- Library-wide - - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): - JSON values can be compared with `==`, see @ref - operator==(const_reference,const_reference). - - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): - JSON values can be compared with `<`, see @ref - operator<(const_reference,const_reference). - - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): - Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of - other compatible types, using unqualified function call @ref swap(). - - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): - JSON values can be compared against `std::nullptr_t` objects which are used - to model the `null` value. -- Container - - [Container](http://en.cppreference.com/w/cpp/concept/Container): - JSON values can be used like STL containers and provide iterator access. - - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); - JSON values can be used like STL containers and provide reverse iterator - access. - -@invariant The member variables @a m_value and @a m_type have the following -relationship: -- If `m_type == value_t::object`, then `m_value.object != nullptr`. -- If `m_type == value_t::array`, then `m_value.array != nullptr`. -- If `m_type == value_t::string`, then `m_value.string != nullptr`. -The invariants are checked by member function assert_invariant(). - -@internal -@note ObjectType trick from http://stackoverflow.com/a/9860911 -@endinternal - -@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange -Format](http://rfc7159.net/rfc7159) - -@since version 1.0.0 - -@nosubgrouping -*/ -template < - template class ObjectType = std::map, - template class ArrayType = std::vector, - class StringType = std::string, - class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator - > -class basic_json -{ - private: - /// workaround type for MSVC - using basic_json_t = basic_json; - - public: - // forward declarations - template class iter_impl; - template class json_reverse_iterator; - class json_pointer; - - ///////////////////// - // container types // - ///////////////////// - - /// @name container types - /// The canonic container types to use @ref basic_json like any other STL - /// container. - /// @{ - - /// the type of elements in a basic_json container - using value_type = basic_json; - - /// the type of an element reference - using reference = value_type&; - /// the type of an element const reference - using const_reference = const value_type&; - - /// a type to represent differences between iterators - using difference_type = std::ptrdiff_t; - /// a type to represent container sizes - using size_type = std::size_t; - - /// the allocator type - using allocator_type = AllocatorType; - - /// the type of an element pointer - using pointer = typename std::allocator_traits::pointer; - /// the type of an element const pointer - using const_pointer = typename std::allocator_traits::const_pointer; - - /// an iterator for a basic_json container - using iterator = iter_impl; - /// a const iterator for a basic_json container - using const_iterator = iter_impl; - /// a reverse iterator for a basic_json container - using reverse_iterator = json_reverse_iterator; - /// a const reverse iterator for a basic_json container - using const_reverse_iterator = json_reverse_iterator; - - /// @} - - - /*! - @brief returns the allocator associated with the container - */ - static allocator_type get_allocator() - { - return allocator_type(); - } - - - /////////////////////////// - // JSON value data types // - /////////////////////////// - - /// @name JSON value data types - /// The data types to store a JSON value. These types are derived from - /// the template arguments passed to class @ref basic_json. - /// @{ - - /*! - @brief a type for an object - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: - > An object is an unordered collection of zero or more name/value pairs, - > where a name is a string and a value is a string, number, boolean, null, - > object, or array. - - To store objects in C++, a type is defined by the template parameters - described below. - - @tparam ObjectType the container to store objects (e.g., `std::map` or - `std::unordered_map`) - @tparam StringType the type of the keys or names (e.g., `std::string`). - The comparison function `std::less` is used to order elements - inside the container. - @tparam AllocatorType the allocator to use for objects (e.g., - `std::allocator`) - - #### Default type - - With the default values for @a ObjectType (`std::map`), @a StringType - (`std::string`), and @a AllocatorType (`std::allocator`), the default - value for @a object_t is: - - @code {.cpp} - std::map< - std::string, // key_type - basic_json, // value_type - std::less, // key_compare - std::allocator> // allocator_type - > - @endcode - - #### Behavior - - The choice of @a object_t influences the behavior of the JSON class. With - the default type, objects have the following behavior: - - - When all names are unique, objects will be interoperable in the sense - that all software implementations receiving that object will agree on - the name-value mappings. - - When the names within an object are not unique, later stored name/value - pairs overwrite previously stored name/value pairs, leaving the used - names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will - be treated as equal and both stored as `{"key": 1}`. - - Internally, name/value pairs are stored in lexicographical order of the - names. Objects will also be serialized (see @ref dump) in this order. - For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored - and serialized as `{"a": 2, "b": 1}`. - - When comparing objects, the order of the name/value pairs is irrelevant. - This makes objects interoperable in the sense that they will not be - affected by these differences. For instance, `{"b": 1, "a": 2}` and - `{"a": 2, "b": 1}` will be treated as equal. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the maximum depth of nesting. - - In this class, the object's limit of nesting is not constraint explicitly. - However, a maximum depth of nesting may be introduced by the compiler or - runtime environment. A theoretical limit can be queried by calling the - @ref max_size function of a JSON object. - - #### Storage - - Objects are stored as pointers in a @ref basic_json type. That is, for any - access to object values, a pointer of type `object_t*` must be - dereferenced. - - @sa @ref array_t -- type for an array value - - @since version 1.0.0 - - @note The order name/value pairs are added to the object is *not* - preserved by the library. Therefore, iterating an object may return - name/value pairs in a different order than they were originally stored. In - fact, keys will be traversed in alphabetical order as `std::map` with - `std::less` is used by default. Please note this behavior conforms to [RFC - 7159](http://rfc7159.net/rfc7159), because any order implements the - specified "unordered" nature of JSON objects. - */ - using object_t = ObjectType, - AllocatorType>>; - - /*! - @brief a type for an array - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: - > An array is an ordered sequence of zero or more values. - - To store objects in C++, a type is defined by the template parameters - explained below. - - @tparam ArrayType container type to store arrays (e.g., `std::vector` or - `std::list`) - @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) - - #### Default type - - With the default values for @a ArrayType (`std::vector`) and @a - AllocatorType (`std::allocator`), the default value for @a array_t is: - - @code {.cpp} - std::vector< - basic_json, // value_type - std::allocator // allocator_type - > - @endcode - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the maximum depth of nesting. - - In this class, the array's limit of nesting is not constraint explicitly. - However, a maximum depth of nesting may be introduced by the compiler or - runtime environment. A theoretical limit can be queried by calling the - @ref max_size function of a JSON array. - - #### Storage - - Arrays are stored as pointers in a @ref basic_json type. That is, for any - access to array values, a pointer of type `array_t*` must be dereferenced. - - @sa @ref object_t -- type for an object value - - @since version 1.0.0 - */ - using array_t = ArrayType>; - - /*! - @brief a type for a string - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: - > A string is a sequence of zero or more Unicode characters. - - To store objects in C++, a type is defined by the template parameter - described below. Unicode values are split by the JSON class into - byte-sized characters during deserialization. - - @tparam StringType the container to store strings (e.g., `std::string`). - Note this container is used for keys/names in objects, see @ref object_t. - - #### Default type - - With the default values for @a StringType (`std::string`), the default - value for @a string_t is: - - @code {.cpp} - std::string - @endcode - - #### String comparison - - [RFC 7159](http://rfc7159.net/rfc7159) states: - > Software implementations are typically required to test names of object - > members for equality. Implementations that transform the textual - > representation into sequences of Unicode code units and then perform the - > comparison numerically, code unit by code unit, are interoperable in the - > sense that implementations will agree in all cases on equality or - > inequality of two strings. For example, implementations that compare - > strings with escaped characters unconverted may incorrectly find that - > `"a\\b"` and `"a\u005Cb"` are not equal. - - This implementation is interoperable as it does compare strings code unit - by code unit. - - #### Storage - - String values are stored as pointers in a @ref basic_json type. That is, - for any access to string values, a pointer of type `string_t*` must be - dereferenced. - - @since version 1.0.0 - */ - using string_t = StringType; - - /*! - @brief a type for a boolean - - [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a - type which differentiates the two literals `true` and `false`. - - To store objects in C++, a type is defined by the template parameter @a - BooleanType which chooses the type to use. - - #### Default type - - With the default values for @a BooleanType (`bool`), the default value for - @a boolean_t is: - - @code {.cpp} - bool - @endcode - - #### Storage - - Boolean values are stored directly inside a @ref basic_json type. - - @since version 1.0.0 - */ - using boolean_t = BooleanType; - - /*! - @brief a type for a number (integer) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store integer numbers in C++, a type is defined by the template - parameter @a NumberIntegerType which chooses the type to use. - - #### Default type - - With the default values for @a NumberIntegerType (`int64_t`), the default - value for @a number_integer_t is: - - @code {.cpp} - int64_t - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in integer literals lead to an interpretation as octal - number. Internally, the value will be stored as decimal number. For - instance, the C++ integer literal `010` will be serialized to `8`. - During deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the range and precision of numbers. - - When the default type is used, the maximal integer number that can be - stored is `9223372036854775807` (INT64_MAX) and the minimal integer number - that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers - that are out of range will yield over/underflow when used in a - constructor. During deserialization, too large or small integer numbers - will be automatically be stored as @ref number_unsigned_t or @ref - number_float_t. - - [RFC 7159](http://rfc7159.net/rfc7159) further states: - > Note that when such software is used, numbers that are integers and are - > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense - > that implementations will agree exactly on their numeric values. - - As this range is a subrange of the exactly supported range [INT64_MIN, - INT64_MAX], this class's integer type is interoperable. - - #### Storage - - Integer number values are stored directly inside a @ref basic_json type. - - @sa @ref number_float_t -- type for number values (floating-point) - - @sa @ref number_unsigned_t -- type for number values (unsigned integer) - - @since version 1.0.0 - */ - using number_integer_t = NumberIntegerType; - - /*! - @brief a type for a number (unsigned) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store unsigned integer numbers in C++, a type is defined by the - template parameter @a NumberUnsignedType which chooses the type to use. - - #### Default type - - With the default values for @a NumberUnsignedType (`uint64_t`), the - default value for @a number_unsigned_t is: - - @code {.cpp} - uint64_t - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in integer literals lead to an interpretation as octal - number. Internally, the value will be stored as decimal number. For - instance, the C++ integer literal `010` will be serialized to `8`. - During deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the range and precision of numbers. - - When the default type is used, the maximal integer number that can be - stored is `18446744073709551615` (UINT64_MAX) and the minimal integer - number that can be stored is `0`. Integer numbers that are out of range - will yield over/underflow when used in a constructor. During - deserialization, too large or small integer numbers will be automatically - be stored as @ref number_integer_t or @ref number_float_t. - - [RFC 7159](http://rfc7159.net/rfc7159) further states: - > Note that when such software is used, numbers that are integers and are - > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense - > that implementations will agree exactly on their numeric values. - - As this range is a subrange (when considered in conjunction with the - number_integer_t type) of the exactly supported range [0, UINT64_MAX], - this class's integer type is interoperable. - - #### Storage - - Integer number values are stored directly inside a @ref basic_json type. - - @sa @ref number_float_t -- type for number values (floating-point) - @sa @ref number_integer_t -- type for number values (integer) - - @since version 2.0.0 - */ - using number_unsigned_t = NumberUnsignedType; - - /*! - @brief a type for a number (floating-point) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store floating-point numbers in C++, a type is defined by the template - parameter @a NumberFloatType which chooses the type to use. - - #### Default type - - With the default values for @a NumberFloatType (`double`), the default - value for @a number_float_t is: - - @code {.cpp} - double - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in floating-point literals will be ignored. Internally, - the value will be stored as decimal number. For instance, the C++ - floating-point literal `01.2` will be serialized to `1.2`. During - deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) states: - > This specification allows implementations to set limits on the range and - > precision of numbers accepted. Since software that implements IEEE - > 754-2008 binary64 (double precision) numbers is generally available and - > widely used, good interoperability can be achieved by implementations - > that expect no more precision or range than these provide, in the sense - > that implementations will approximate JSON numbers within the expected - > precision. - - This implementation does exactly follow this approach, as it uses double - precision floating-point numbers. Note values smaller than - `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` - will be stored as NaN internally and be serialized to `null`. - - #### Storage - - Floating-point number values are stored directly inside a @ref basic_json - type. - - @sa @ref number_integer_t -- type for number values (integer) - - @sa @ref number_unsigned_t -- type for number values (unsigned integer) - - @since version 1.0.0 - */ - using number_float_t = NumberFloatType; - - /// @} - - - /////////////////////////// - // JSON type enumeration // - /////////////////////////// - - /*! - @brief the JSON type enumeration - - This enumeration collects the different JSON types. It is internally used - to distinguish the stored values, and the functions @ref is_null(), @ref - is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref - is_number() (with @ref is_number_integer(), @ref is_number_unsigned(), and - @ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and - @ref is_structured() rely on it. - - @note There are three enumeration entries (number_integer, - number_unsigned, and number_float), because the library distinguishes - these three types for numbers: @ref number_unsigned_t is used for unsigned - integers, @ref number_integer_t is used for signed integers, and @ref - number_float_t is used for floating-point numbers or to approximate - integers which do not fit in the limits of their respective type. - - @sa @ref basic_json(const value_t value_type) -- create a JSON value with - the default value for a given type - - @since version 1.0.0 - */ - enum class value_t : uint8_t - { - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function - }; - - - private: - - /// helper for exception-safe object creation - template - static T* create(Args&& ... args) - { - AllocatorType alloc; - auto deleter = [&](T * object) - { - alloc.deallocate(object, 1); - }; - std::unique_ptr object(alloc.allocate(1), deleter); - alloc.construct(object.get(), std::forward(args)...); - assert(object.get() != nullptr); - return object.release(); - } - - //////////////////////// - // JSON value storage // - //////////////////////// - - /*! - @brief a JSON value - - The actual storage for a JSON value of the @ref basic_json class. This - union combines the different storage types for the JSON value types - defined in @ref value_t. - - JSON type | value_t type | used type - --------- | --------------- | ------------------------ - object | object | pointer to @ref object_t - array | array | pointer to @ref array_t - string | string | pointer to @ref string_t - boolean | boolean | @ref boolean_t - number | number_integer | @ref number_integer_t - number | number_unsigned | @ref number_unsigned_t - number | number_float | @ref number_float_t - null | null | *no value is stored* - - @note Variable-length types (objects, arrays, and strings) are stored as - pointers. The size of the union should not exceed 64 bits if the default - value types are used. - - @since version 1.0.0 - */ - union json_value - { - /// object (stored with pointer to save storage) - object_t* object; - /// array (stored with pointer to save storage) - array_t* array; - /// string (stored with pointer to save storage) - string_t* string; - /// boolean - boolean_t boolean; - /// number (integer) - number_integer_t number_integer; - /// number (unsigned integer) - number_unsigned_t number_unsigned; - /// number (floating-point) - number_float_t number_float; - - /// default constructor (for null values) - json_value() = default; - /// constructor for booleans - json_value(boolean_t v) noexcept : boolean(v) {} - /// constructor for numbers (integer) - json_value(number_integer_t v) noexcept : number_integer(v) {} - /// constructor for numbers (unsigned) - json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} - /// constructor for numbers (floating-point) - json_value(number_float_t v) noexcept : number_float(v) {} - /// constructor for empty values of a given type - json_value(value_t t) - { - switch (t) - { - case value_t::object: - { - object = create(); - break; - } - - case value_t::array: - { - array = create(); - break; - } - - case value_t::string: - { - string = create(""); - break; - } - - case value_t::boolean: - { - boolean = boolean_t(false); - break; - } - - case value_t::number_integer: - { - number_integer = number_integer_t(0); - break; - } - - case value_t::number_unsigned: - { - number_unsigned = number_unsigned_t(0); - break; - } - - case value_t::number_float: - { - number_float = number_float_t(0.0); - break; - } - - case value_t::null: - { - break; - } - - default: - { - if (t == value_t::null) - { - throw std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10"); // LCOV_EXCL_LINE - } - break; - } - } - } - - /// constructor for strings - json_value(const string_t& value) - { - string = create(value); - } - - /// constructor for objects - json_value(const object_t& value) - { - object = create(value); - } - - /// constructor for arrays - json_value(const array_t& value) - { - array = create(value); - } - }; - - /*! - @brief checks the class invariants - - This function asserts the class invariants. It needs to be called at the - end of every constructor to make sure that created objects respect the - invariant. Furthermore, it has to be called each time the type of a JSON - value is changed, because the invariant expresses a relationship between - @a m_type and @a m_value. - */ - void assert_invariant() const - { - assert(m_type != value_t::object or m_value.object != nullptr); - assert(m_type != value_t::array or m_value.array != nullptr); - assert(m_type != value_t::string or m_value.string != nullptr); - } - - public: - ////////////////////////// - // JSON parser callback // - ////////////////////////// - - /*! - @brief JSON callback events - - This enumeration lists the parser events that can trigger calling a - callback function of type @ref parser_callback_t during parsing. - - @image html callback_events.png "Example when certain parse events are triggered" - - @since version 1.0.0 - */ - enum class parse_event_t : uint8_t - { - /// the parser read `{` and started to process a JSON object - object_start, - /// the parser read `}` and finished processing a JSON object - object_end, - /// the parser read `[` and started to process a JSON array - array_start, - /// the parser read `]` and finished processing a JSON array - array_end, - /// the parser read a key of a value in an object - key, - /// the parser finished reading a JSON value - value - }; - - /*! - @brief per-element parser callback type - - With a parser callback function, the result of parsing a JSON text can be - influenced. When passed to @ref parse(std::istream&, const - parser_callback_t) or @ref parse(const CharT, const parser_callback_t), - it is called on certain events (passed as @ref parse_event_t via parameter - @a event) with a set recursion depth @a depth and context JSON value - @a parsed. The return value of the callback function is a boolean - indicating whether the element that emitted the callback shall be kept or - not. - - We distinguish six scenarios (determined by the event type) in which the - callback function can be called. The following table describes the values - of the parameters @a depth, @a event, and @a parsed. - - parameter @a event | description | parameter @a depth | parameter @a parsed - ------------------ | ----------- | ------------------ | ------------------- - parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded - parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key - parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object - parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded - parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array - parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value - - @image html callback_events.png "Example when certain parse events are triggered" - - Discarding a value (i.e., returning `false`) has different effects - depending on the context in which function was called: - - - Discarded values in structured types are skipped. That is, the parser - will behave as if the discarded value was never read. - - In case a value outside a structured type is skipped, it is replaced - with `null`. This case happens if the top-level element is skipped. - - @param[in] depth the depth of the recursion during parsing - - @param[in] event an event of type parse_event_t indicating the context in - the callback function has been called - - @param[in,out] parsed the current intermediate parse result; note that - writing to this value has no effect for parse_event_t::key events - - @return Whether the JSON value which called the function during parsing - should be kept (`true`) or not (`false`). In the latter case, it is either - skipped completely or replaced by an empty discarded object. - - @sa @ref parse(std::istream&, parser_callback_t) or - @ref parse(const CharT, const parser_callback_t) for examples - - @since version 1.0.0 - */ - using parser_callback_t = std::function; - - - ////////////////// - // constructors // - ////////////////// - - /// @name constructors and destructors - /// Constructors of class @ref basic_json, copy/move constructor, copy - /// assignment, static functions creating objects, and the destructor. - /// @{ - - /*! - @brief create an empty value with a given type - - Create an empty JSON value with a given type. The value will be default - initialized with an empty value which depends on the type: - - Value type | initial value - ----------- | ------------- - null | `null` - boolean | `false` - string | `""` - number | `0` - object | `{}` - array | `[]` - - @param[in] value_type the type of the value to create - - @complexity Constant. - - @throw std::bad_alloc if allocation for object, array, or string value - fails - - @liveexample{The following code shows the constructor for different @ref - value_t values,basic_json__value_t} - - @sa @ref basic_json(std::nullptr_t) -- create a `null` value - @sa @ref basic_json(boolean_t value) -- create a boolean value - @sa @ref basic_json(const string_t&) -- create a string value - @sa @ref basic_json(const object_t&) -- create a object value - @sa @ref basic_json(const array_t&) -- create a array value - @sa @ref basic_json(const number_float_t) -- create a number - (floating-point) value - @sa @ref basic_json(const number_integer_t) -- create a number (integer) - value - @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned) - value - - @since version 1.0.0 - */ - basic_json(const value_t value_type) - : m_type(value_type), m_value(value_type) - { - assert_invariant(); - } - - /*! - @brief create a null object - - Create a `null` JSON value. It either takes a null pointer as parameter - (explicitly creating `null`) or no parameter (implicitly creating `null`). - The passed null pointer itself is not read -- it is only used to choose - the right constructor. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this constructor never throws - exceptions. - - @liveexample{The following code shows the constructor with and without a - null pointer parameter.,basic_json__nullptr_t} - - @since version 1.0.0 - */ - basic_json(std::nullptr_t = nullptr) noexcept - : basic_json(value_t::null) - { - assert_invariant(); - } - - /*! - @brief create an object (explicit) - - Create an object JSON value with a given content. - - @param[in] val a value for the object - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for object value fails - - @liveexample{The following code shows the constructor with an @ref - object_t parameter.,basic_json__object_t} - - @sa @ref basic_json(const CompatibleObjectType&) -- create an object value - from a compatible STL container - - @since version 1.0.0 - */ - basic_json(const object_t& val) - : m_type(value_t::object), m_value(val) - { - assert_invariant(); - } - - /*! - @brief create an object (implicit) - - Create an object JSON value with a given content. This constructor allows - any type @a CompatibleObjectType that can be used to construct values of - type @ref object_t. - - @tparam CompatibleObjectType An object type whose `key_type` and - `value_type` is compatible to @ref object_t. Examples include `std::map`, - `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with - a `key_type` of `std::string`, and a `value_type` from which a @ref - basic_json value can be constructed. - - @param[in] val a value for the object - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for object value fails - - @liveexample{The following code shows the constructor with several - compatible object type parameters.,basic_json__CompatibleObjectType} - - @sa @ref basic_json(const object_t&) -- create an object value - - @since version 1.0.0 - */ - template::value and - std::is_constructible::value, int>::type = 0> - basic_json(const CompatibleObjectType& val) - : m_type(value_t::object) - { - using std::begin; - using std::end; - m_value.object = create(begin(val), end(val)); - assert_invariant(); - } - - /*! - @brief create an array (explicit) - - Create an array JSON value with a given content. - - @param[in] val a value for the array - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for array value fails - - @liveexample{The following code shows the constructor with an @ref array_t - parameter.,basic_json__array_t} - - @sa @ref basic_json(const CompatibleArrayType&) -- create an array value - from a compatible STL containers - - @since version 1.0.0 - */ - basic_json(const array_t& val) - : m_type(value_t::array), m_value(val) - { - assert_invariant(); - } - - /*! - @brief create an array (implicit) - - Create an array JSON value with a given content. This constructor allows - any type @a CompatibleArrayType that can be used to construct values of - type @ref array_t. - - @tparam CompatibleArrayType An object type whose `value_type` is - compatible to @ref array_t. Examples include `std::vector`, `std::deque`, - `std::list`, `std::forward_list`, `std::array`, `std::set`, - `std::unordered_set`, `std::multiset`, and `unordered_multiset` with a - `value_type` from which a @ref basic_json value can be constructed. - - @param[in] val a value for the array - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for array value fails - - @liveexample{The following code shows the constructor with several - compatible array type parameters.,basic_json__CompatibleArrayType} - - @sa @ref basic_json(const array_t&) -- create an array value - - @since version 1.0.0 - */ - template::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value and - std::is_constructible::value, int>::type = 0> - basic_json(const CompatibleArrayType& val) - : m_type(value_t::array) - { - using std::begin; - using std::end; - m_value.array = create(begin(val), end(val)); - assert_invariant(); - } - - /*! - @brief create a string (explicit) - - Create an string JSON value with a given content. - - @param[in] val a value for the string - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for string value fails - - @liveexample{The following code shows the constructor with an @ref - string_t parameter.,basic_json__string_t} - - @sa @ref basic_json(const typename string_t::value_type*) -- create a - string value from a character pointer - @sa @ref basic_json(const CompatibleStringType&) -- create a string value - from a compatible string container - - @since version 1.0.0 - */ - basic_json(const string_t& val) - : m_type(value_t::string), m_value(val) - { - assert_invariant(); - } - - /*! - @brief create a string (explicit) - - Create a string JSON value with a given content. - - @param[in] val a literal value for the string - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for string value fails - - @liveexample{The following code shows the constructor with string literal - parameter.,basic_json__string_t_value_type} - - @sa @ref basic_json(const string_t&) -- create a string value - @sa @ref basic_json(const CompatibleStringType&) -- create a string value - from a compatible string container - - @since version 1.0.0 - */ - basic_json(const typename string_t::value_type* val) - : basic_json(string_t(val)) - { - assert_invariant(); - } - - /*! - @brief create a string (implicit) - - Create a string JSON value with a given content. - - @param[in] val a value for the string - - @tparam CompatibleStringType an string type which is compatible to @ref - string_t, for instance `std::string`. - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for string value fails - - @liveexample{The following code shows the construction of a string value - from a compatible type.,basic_json__CompatibleStringType} - - @sa @ref basic_json(const string_t&) -- create a string value - @sa @ref basic_json(const typename string_t::value_type*) -- create a - string value from a character pointer - - @since version 1.0.0 - */ - template::value, int>::type = 0> - basic_json(const CompatibleStringType& val) - : basic_json(string_t(val)) - { - assert_invariant(); - } - - /*! - @brief create a boolean (explicit) - - Creates a JSON boolean type from a given value. - - @param[in] val a boolean value to store - - @complexity Constant. - - @liveexample{The example below demonstrates boolean - values.,basic_json__boolean_t} - - @since version 1.0.0 - */ - basic_json(boolean_t val) noexcept - : m_type(value_t::boolean), m_value(val) - { - assert_invariant(); - } - - /*! - @brief create an integer number (explicit) - - Create an integer number JSON value with a given content. - - @tparam T A helper type to remove this function via SFINAE in case @ref - number_integer_t is the same as `int`. In this case, this constructor - would have the same signature as @ref basic_json(const int value). Note - the helper type @a T is not visible in this constructor's interface. - - @param[in] val an integer to create a JSON number from - - @complexity Constant. - - @liveexample{The example below shows the construction of an integer - number value.,basic_json__number_integer_t} - - @sa @ref basic_json(const int) -- create a number value (integer) - @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number - value (integer) from a compatible number type - - @since version 1.0.0 - */ - template::value) and - std::is_same::value, int>::type = 0> - basic_json(const number_integer_t val) noexcept - : m_type(value_t::number_integer), m_value(val) - { - assert_invariant(); - } - - /*! - @brief create an integer number from an enum type (explicit) - - Create an integer number JSON value with a given content. - - @param[in] val an integer to create a JSON number from - - @note This constructor allows to pass enums directly to a constructor. As - C++ has no way of specifying the type of an anonymous enum explicitly, we - can only rely on the fact that such values implicitly convert to int. As - int may already be the same type of number_integer_t, we may need to - switch off the constructor @ref basic_json(const number_integer_t). - - @complexity Constant. - - @liveexample{The example below shows the construction of an integer - number value from an anonymous enum.,basic_json__const_int} - - @sa @ref basic_json(const number_integer_t) -- create a number value - (integer) - @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number - value (integer) from a compatible number type - - @since version 1.0.0 - */ - basic_json(const int val) noexcept - : m_type(value_t::number_integer), - m_value(static_cast(val)) - { - assert_invariant(); - } - - /*! - @brief create an integer number (implicit) - - Create an integer number JSON value with a given content. This constructor - allows any type @a CompatibleNumberIntegerType that can be used to - construct values of type @ref number_integer_t. - - @tparam CompatibleNumberIntegerType An integer type which is compatible to - @ref number_integer_t. Examples include the types `int`, `int32_t`, - `long`, and `short`. - - @param[in] val an integer to create a JSON number from - - @complexity Constant. - - @liveexample{The example below shows the construction of several integer - number values from compatible - types.,basic_json__CompatibleIntegerNumberType} - - @sa @ref basic_json(const number_integer_t) -- create a number value - (integer) - @sa @ref basic_json(const int) -- create a number value (integer) - - @since version 1.0.0 - */ - template::value and - std::numeric_limits::is_integer and - std::numeric_limits::is_signed, - CompatibleNumberIntegerType>::type = 0> - basic_json(const CompatibleNumberIntegerType val) noexcept - : m_type(value_t::number_integer), - m_value(static_cast(val)) - { - assert_invariant(); - } - - /*! - @brief create an unsigned integer number (explicit) - - Create an unsigned integer number JSON value with a given content. - - @tparam T helper type to compare number_unsigned_t and unsigned int (not - visible in) the interface. - - @param[in] val an integer to create a JSON number from - - @complexity Constant. - - @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number - value (unsigned integer) from a compatible number type - - @since version 2.0.0 - */ - template::value) and - std::is_same::value, int>::type = 0> - basic_json(const number_unsigned_t val) noexcept - : m_type(value_t::number_unsigned), m_value(val) - { - assert_invariant(); - } - - /*! - @brief create an unsigned number (implicit) - - Create an unsigned number JSON value with a given content. This - constructor allows any type @a CompatibleNumberUnsignedType that can be - used to construct values of type @ref number_unsigned_t. - - @tparam CompatibleNumberUnsignedType An integer type which is compatible - to @ref number_unsigned_t. Examples may include the types `unsigned int`, - `uint32_t`, or `unsigned short`. - - @param[in] val an unsigned integer to create a JSON number from - - @complexity Constant. - - @sa @ref basic_json(const number_unsigned_t) -- create a number value - (unsigned) - - @since version 2.0.0 - */ - template::value and - std::numeric_limits::is_integer and - not std::numeric_limits::is_signed, - CompatibleNumberUnsignedType>::type = 0> - basic_json(const CompatibleNumberUnsignedType val) noexcept - : m_type(value_t::number_unsigned), - m_value(static_cast(val)) - { - assert_invariant(); - } - - /*! - @brief create a floating-point number (explicit) - - Create a floating-point number JSON value with a given content. - - @param[in] val a floating-point value to create a JSON number from - - @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 - disallows NaN values: - > Numeric values that cannot be represented in the grammar below (such as - > Infinity and NaN) are not permitted. - In case the parameter @a val is not a number, a JSON null value is created - instead. - - @complexity Constant. - - @liveexample{The following example creates several floating-point - values.,basic_json__number_float_t} - - @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number - value (floating-point) from a compatible number type - - @since version 1.0.0 - */ - basic_json(const number_float_t val) noexcept - : m_type(value_t::number_float), m_value(val) - { - // replace infinity and NAN by null - if (not std::isfinite(val)) - { - m_type = value_t::null; - m_value = json_value(); - } - - assert_invariant(); - } - - /*! - @brief create an floating-point number (implicit) - - Create an floating-point number JSON value with a given content. This - constructor allows any type @a CompatibleNumberFloatType that can be used - to construct values of type @ref number_float_t. - - @tparam CompatibleNumberFloatType A floating-point type which is - compatible to @ref number_float_t. Examples may include the types `float` - or `double`. - - @param[in] val a floating-point to create a JSON number from - - @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 - disallows NaN values: - > Numeric values that cannot be represented in the grammar below (such as - > Infinity and NaN) are not permitted. - In case the parameter @a val is not a number, a JSON null value is - created instead. - - @complexity Constant. - - @liveexample{The example below shows the construction of several - floating-point number values from compatible - types.,basic_json__CompatibleNumberFloatType} - - @sa @ref basic_json(const number_float_t) -- create a number value - (floating-point) - - @since version 1.0.0 - */ - template::value and - std::is_floating_point::value>::type> - basic_json(const CompatibleNumberFloatType val) noexcept - : basic_json(number_float_t(val)) - { - assert_invariant(); - } - - /*! - @brief create a container (array or object) from an initializer list - - Creates a JSON value of type array or object from the passed initializer - list @a init. In case @a type_deduction is `true` (default), the type of - the JSON value to be created is deducted from the initializer list @a init - according to the following rules: - - 1. If the list is empty, an empty JSON object value `{}` is created. - 2. If the list consists of pairs whose first element is a string, a JSON - object value is created where the first elements of the pairs are - treated as keys and the second elements are as values. - 3. In all other cases, an array is created. - - The rules aim to create the best fit between a C++ initializer list and - JSON values. The rationale is as follows: - - 1. The empty initializer list is written as `{}` which is exactly an empty - JSON object. - 2. C++ has now way of describing mapped types other than to list a list of - pairs. As JSON requires that keys must be of type string, rule 2 is the - weakest constraint one can pose on initializer lists to interpret them - as an object. - 3. In all other cases, the initializer list could not be interpreted as - JSON object type, so interpreting it as JSON array type is safe. - - With the rules described above, the following JSON values cannot be - expressed by an initializer list: - - - the empty array (`[]`): use @ref array(std::initializer_list) - with an empty initializer list in this case - - arrays whose elements satisfy rule 2: use @ref - array(std::initializer_list) with the same initializer list - in this case - - @note When used without parentheses around an empty initializer list, @ref - basic_json() is called instead of this function, yielding the JSON null - value. - - @param[in] init initializer list with JSON values - - @param[in] type_deduction internal parameter; when set to `true`, the type - of the JSON value is deducted from the initializer list @a init; when set - to `false`, the type provided via @a manual_type is forced. This mode is - used by the functions @ref array(std::initializer_list) and - @ref object(std::initializer_list). - - @param[in] manual_type internal parameter; when @a type_deduction is set - to `false`, the created JSON value will use the provided type (only @ref - value_t::array and @ref value_t::object are valid); when @a type_deduction - is set to `true`, this parameter has no effect - - @throw std::domain_error if @a type_deduction is `false`, @a manual_type - is `value_t::object`, but @a init contains an element which is not a pair - whose first element is a string; example: `"cannot create object from - initializer list"` - - @complexity Linear in the size of the initializer list @a init. - - @liveexample{The example below shows how JSON values are created from - initializer lists.,basic_json__list_init_t} - - @sa @ref array(std::initializer_list) -- create a JSON array - value from an initializer list - @sa @ref object(std::initializer_list) -- create a JSON object - value from an initializer list - - @since version 1.0.0 - */ - basic_json(std::initializer_list init, - bool type_deduction = true, - value_t manual_type = value_t::array) - { - // check if each element is an array with two elements whose first - // element is a string - bool is_an_object = std::all_of(init.begin(), init.end(), - [](const basic_json & element) - { - return element.is_array() and element.size() == 2 and element[0].is_string(); - }); - - // adjust type if type deduction is not wanted - if (not type_deduction) - { - // if array is wanted, do not create an object though possible - if (manual_type == value_t::array) - { - is_an_object = false; - } - - // if object is wanted but impossible, throw an exception - if (manual_type == value_t::object and not is_an_object) - { - throw std::domain_error("cannot create object from initializer list"); - } - } - - if (is_an_object) - { - // the initializer list is a list of pairs -> create object - m_type = value_t::object; - m_value = value_t::object; - - std::for_each(init.begin(), init.end(), [this](const basic_json & element) - { - m_value.object->emplace(*(element[0].m_value.string), element[1]); - }); - } - else - { - // the initializer list describes an array -> create array - m_type = value_t::array; - m_value.array = create(init); - } - - assert_invariant(); - } - - /*! - @brief explicitly create an array from an initializer list - - Creates a JSON array value from a given initializer list. That is, given a - list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the - initializer list is empty, the empty array `[]` is created. - - @note This function is only needed to express two edge cases that cannot - be realized with the initializer list constructor (@ref - basic_json(std::initializer_list, bool, value_t)). These cases - are: - 1. creating an array whose elements are all pairs whose first element is a - string -- in this case, the initializer list constructor would create an - object, taking the first elements as keys - 2. creating an empty array -- passing the empty initializer list to the - initializer list constructor yields an empty object - - @param[in] init initializer list with JSON values to create an array from - (optional) - - @return JSON array value - - @complexity Linear in the size of @a init. - - @liveexample{The following code shows an example for the `array` - function.,array} - - @sa @ref basic_json(std::initializer_list, bool, value_t) -- - create a JSON value from an initializer list - @sa @ref object(std::initializer_list) -- create a JSON object - value from an initializer list - - @since version 1.0.0 - */ - static basic_json array(std::initializer_list init = - std::initializer_list()) - { - return basic_json(init, false, value_t::array); - } - - /*! - @brief explicitly create an object from an initializer list - - Creates a JSON object value from a given initializer list. The initializer - lists elements must be pairs, and their first elements must be strings. If - the initializer list is empty, the empty object `{}` is created. - - @note This function is only added for symmetry reasons. In contrast to the - related function @ref array(std::initializer_list), there are - no cases which can only be expressed by this function. That is, any - initializer list @a init can also be passed to the initializer list - constructor @ref basic_json(std::initializer_list, bool, - value_t). - - @param[in] init initializer list to create an object from (optional) - - @return JSON object value - - @throw std::domain_error if @a init is not a pair whose first elements are - strings; thrown by - @ref basic_json(std::initializer_list, bool, value_t) - - @complexity Linear in the size of @a init. - - @liveexample{The following code shows an example for the `object` - function.,object} - - @sa @ref basic_json(std::initializer_list, bool, value_t) -- - create a JSON value from an initializer list - @sa @ref array(std::initializer_list) -- create a JSON array - value from an initializer list - - @since version 1.0.0 - */ - static basic_json object(std::initializer_list init = - std::initializer_list()) - { - return basic_json(init, false, value_t::object); - } - - /*! - @brief construct an array with count copies of given value - - Constructs a JSON array value by creating @a cnt copies of a passed value. - In case @a cnt is `0`, an empty array is created. As postcondition, - `std::distance(begin(),end()) == cnt` holds. - - @param[in] cnt the number of JSON copies of @a val to create - @param[in] val the JSON value to copy - - @complexity Linear in @a cnt. - - @liveexample{The following code shows examples for the @ref - basic_json(size_type\, const basic_json&) - constructor.,basic_json__size_type_basic_json} - - @since version 1.0.0 - */ - basic_json(size_type cnt, const basic_json& val) - : m_type(value_t::array) - { - m_value.array = create(cnt, val); - assert_invariant(); - } - - /*! - @brief construct a JSON container given an iterator range - - Constructs the JSON value with the contents of the range `[first, last)`. - The semantics depends on the different types a JSON value can have: - - In case of primitive types (number, boolean, or string), @a first must - be `begin()` and @a last must be `end()`. In this case, the value is - copied. Otherwise, std::out_of_range is thrown. - - In case of structured types (array, object), the constructor behaves as - similar versions for `std::vector`. - - In case of a null type, std::domain_error is thrown. - - @tparam InputIT an input iterator type (@ref iterator or @ref - const_iterator) - - @param[in] first begin of the range to copy from (included) - @param[in] last end of the range to copy from (excluded) - - @pre Iterators @a first and @a last must be initialized. **This - precondition is enforced with an assertion.** - - @throw std::domain_error if iterators are not compatible; that is, do not - belong to the same JSON value; example: `"iterators are not compatible"` - @throw std::out_of_range if iterators are for a primitive type (number, - boolean, or string) where an out of range error can be detected easily; - example: `"iterators out of range"` - @throw std::bad_alloc if allocation for object, array, or string fails - @throw std::domain_error if called with a null value; example: `"cannot - use construct with iterators from null"` - - @complexity Linear in distance between @a first and @a last. - - @liveexample{The example below shows several ways to create JSON values by - specifying a subrange with iterators.,basic_json__InputIt_InputIt} - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type = 0> - basic_json(InputIT first, InputIT last) - { - assert(first.m_object != nullptr); - assert(last.m_object != nullptr); - - // make sure iterator fits the current value - if (first.m_object != last.m_object) - { - throw std::domain_error("iterators are not compatible"); - } - - // copy type from first iterator - m_type = first.m_object->m_type; - - // check if iterator range is complete for primitive values - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) - { - throw std::out_of_range("iterators out of range"); - } - break; - } - - default: - { - break; - } - } - - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = first.m_object->m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_value.number_unsigned = first.m_object->m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_value.number_float = first.m_object->m_value.number_float; - break; - } - - case value_t::boolean: - { - m_value.boolean = first.m_object->m_value.boolean; - break; - } - - case value_t::string: - { - m_value = *first.m_object->m_value.string; - break; - } - - case value_t::object: - { - m_value.object = create(first.m_it.object_iterator, last.m_it.object_iterator); - break; - } - - case value_t::array: - { - m_value.array = create(first.m_it.array_iterator, last.m_it.array_iterator); - break; - } - - default: - { - throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); - } - } - - assert_invariant(); - } - - /*! - @brief construct a JSON value given an input stream - - @param[in,out] i stream to read a serialized JSON value from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @deprecated This constructor is deprecated and will be removed in version - 3.0.0 to unify the interface of the library. Deserialization will be - done by stream operators or by calling one of the `parse` functions, - e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls - like `json j(i);` for an input stream @a i need to be replaced by - `json j = json::parse(i);`. See the example below. - - @liveexample{The example below demonstrates constructing a JSON value from - a `std::stringstream` with and without callback - function.,basic_json__istream} - - @since version 2.0.0, deprecated in version 2.0.3, to be removed in - version 3.0.0 - */ - JSON_DEPRECATED - explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr) - { - *this = parser(i, cb).parse(); - assert_invariant(); - } - - /////////////////////////////////////// - // other constructors and destructor // - /////////////////////////////////////// - - /*! - @brief copy constructor - - Creates a copy of a given JSON value. - - @param[in] other the JSON value to copy - - @complexity Linear in the size of @a other. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - As postcondition, it holds: `other == basic_json(other)`. - - @throw std::bad_alloc if allocation for object, array, or string fails. - - @liveexample{The following code shows an example for the copy - constructor.,basic_json__basic_json} - - @since version 1.0.0 - */ - basic_json(const basic_json& other) - : m_type(other.m_type) - { - // check of passed value is valid - other.assert_invariant(); - - switch (m_type) - { - case value_t::object: - { - m_value = *other.m_value.object; - break; - } - - case value_t::array: - { - m_value = *other.m_value.array; - break; - } - - case value_t::string: - { - m_value = *other.m_value.string; - break; - } - - case value_t::boolean: - { - m_value = other.m_value.boolean; - break; - } - - case value_t::number_integer: - { - m_value = other.m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_value = other.m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_value = other.m_value.number_float; - break; - } - - default: - { - break; - } - } - - assert_invariant(); - } - - /*! - @brief move constructor - - Move constructor. Constructs a JSON value with the contents of the given - value @a other using move semantics. It "steals" the resources from @a - other and leaves it as JSON null value. - - @param[in,out] other value to move to this object - - @post @a other is a JSON null value - - @complexity Constant. - - @liveexample{The code below shows the move constructor explicitly called - via std::move.,basic_json__moveconstructor} - - @since version 1.0.0 - */ - basic_json(basic_json&& other) noexcept - : m_type(std::move(other.m_type)), - m_value(std::move(other.m_value)) - { - // check that passed value is valid - other.assert_invariant(); - - // invalidate payload - other.m_type = value_t::null; - other.m_value = {}; - - assert_invariant(); - } - - /*! - @brief copy assignment - - Copy assignment operator. Copies a JSON value via the "copy and swap" - strategy: It is expressed in terms of the copy constructor, destructor, - and the swap() member function. - - @param[in] other value to copy from - - @complexity Linear. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - @liveexample{The code below shows and example for the copy assignment. It - creates a copy of value `a` which is then swapped with `b`. Finally\, the - copy of `a` (which is the null value after the swap) is - destroyed.,basic_json__copyassignment} - - @since version 1.0.0 - */ - reference& operator=(basic_json other) noexcept ( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) - { - // check that passed value is valid - other.assert_invariant(); - - using std::swap; - swap(m_type, other.m_type); - swap(m_value, other.m_value); - - assert_invariant(); - return *this; - } - - /*! - @brief destructor - - Destroys the JSON value and frees all allocated memory. - - @complexity Linear. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - All stored elements are destroyed and all memory is freed. - - @since version 1.0.0 - */ - ~basic_json() - { - assert_invariant(); - - switch (m_type) - { - case value_t::object: - { - AllocatorType alloc; - alloc.destroy(m_value.object); - alloc.deallocate(m_value.object, 1); - break; - } - - case value_t::array: - { - AllocatorType alloc; - alloc.destroy(m_value.array); - alloc.deallocate(m_value.array, 1); - break; - } - - case value_t::string: - { - AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - break; - } - - default: - { - // all other types need no specific destructor - break; - } - } - } - - /// @} - - public: - /////////////////////// - // object inspection // - /////////////////////// - - /// @name object inspection - /// Functions to inspect the type of a JSON value. - /// @{ - - /*! - @brief serialization - - Serialization function for JSON values. The function tries to mimic - Python's `json.dumps()` function, and currently supports its @a indent - parameter. - - @param[in] indent If indent is nonnegative, then array elements and object - members will be pretty-printed with that indent level. An indent level of - `0` will only insert newlines. `-1` (the default) selects the most compact - representation. - - @return string containing the serialization of the JSON value - - @complexity Linear. - - @liveexample{The following example shows the effect of different @a indent - parameters to the result of the serialization.,dump} - - @see https://docs.python.org/2/library/json.html#json.dump - - @since version 1.0.0 - */ - string_t dump(const int indent = -1) const - { - std::stringstream ss; - // fix locale problems - ss.imbue(std::locale::classic()); - - // 6, 15 or 16 digits of precision allows round-trip IEEE 754 - // string->float->string, string->double->string or string->long - // double->string; to be safe, we read this value from - // std::numeric_limits::digits10 - ss.precision(std::numeric_limits::digits10); - - if (indent >= 0) - { - dump(ss, true, static_cast(indent)); - } - else - { - dump(ss, false, 0); - } - - return ss.str(); - } - - /*! - @brief return the type of the JSON value (explicit) - - Return the type of the JSON value as a value from the @ref value_t - enumeration. - - @return the type of the JSON value - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `type()` for all JSON - types.,type} - - @since version 1.0.0 - */ - constexpr value_t type() const noexcept - { - return m_type; - } - - /*! - @brief return whether type is primitive - - This function returns true iff the JSON type is primitive (string, number, - boolean, or null). - - @return `true` if type is primitive (string, number, boolean, or null), - `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_primitive()` for all JSON - types.,is_primitive} - - @sa @ref is_structured() -- returns whether JSON value is structured - @sa @ref is_null() -- returns whether JSON value is `null` - @sa @ref is_string() -- returns whether JSON value is a string - @sa @ref is_boolean() -- returns whether JSON value is a boolean - @sa @ref is_number() -- returns whether JSON value is a number - - @since version 1.0.0 - */ - constexpr bool is_primitive() const noexcept - { - return is_null() or is_string() or is_boolean() or is_number(); - } - - /*! - @brief return whether type is structured - - This function returns true iff the JSON type is structured (array or - object). - - @return `true` if type is structured (array or object), `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_structured()` for all JSON - types.,is_structured} - - @sa @ref is_primitive() -- returns whether value is primitive - @sa @ref is_array() -- returns whether value is an array - @sa @ref is_object() -- returns whether value is an object - - @since version 1.0.0 - */ - constexpr bool is_structured() const noexcept - { - return is_array() or is_object(); - } - - /*! - @brief return whether value is null - - This function returns true iff the JSON value is null. - - @return `true` if type is null, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_null()` for all JSON - types.,is_null} - - @since version 1.0.0 - */ - constexpr bool is_null() const noexcept - { - return m_type == value_t::null; - } - - /*! - @brief return whether value is a boolean - - This function returns true iff the JSON value is a boolean. - - @return `true` if type is boolean, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_boolean()` for all JSON - types.,is_boolean} - - @since version 1.0.0 - */ - constexpr bool is_boolean() const noexcept - { - return m_type == value_t::boolean; - } - - /*! - @brief return whether value is a number - - This function returns true iff the JSON value is a number. This includes - both integer and floating-point values. - - @return `true` if type is number (regardless whether integer, unsigned - integer or floating-type), `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number()` for all JSON - types.,is_number} - - @sa @ref is_number_integer() -- check if value is an integer or unsigned - integer number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 1.0.0 - */ - constexpr bool is_number() const noexcept - { - return is_number_integer() or is_number_float(); - } - - /*! - @brief return whether value is an integer number - - This function returns true iff the JSON value is an integer or unsigned - integer number. This excludes floating-point values. - - @return `true` if type is an integer or unsigned integer number, `false` - otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_integer()` for all - JSON types.,is_number_integer} - - @sa @ref is_number() -- check if value is a number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 1.0.0 - */ - constexpr bool is_number_integer() const noexcept - { - return m_type == value_t::number_integer or m_type == value_t::number_unsigned; - } - - /*! - @brief return whether value is an unsigned integer number - - This function returns true iff the JSON value is an unsigned integer - number. This excludes floating-point and (signed) integer values. - - @return `true` if type is an unsigned integer number, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_unsigned()` for all - JSON types.,is_number_unsigned} - - @sa @ref is_number() -- check if value is a number - @sa @ref is_number_integer() -- check if value is an integer or unsigned - integer number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 2.0.0 - */ - constexpr bool is_number_unsigned() const noexcept - { - return m_type == value_t::number_unsigned; - } - - /*! - @brief return whether value is a floating-point number - - This function returns true iff the JSON value is a floating-point number. - This excludes integer and unsigned integer values. - - @return `true` if type is a floating-point number, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_float()` for all - JSON types.,is_number_float} - - @sa @ref is_number() -- check if value is number - @sa @ref is_number_integer() -- check if value is an integer number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - - @since version 1.0.0 - */ - constexpr bool is_number_float() const noexcept - { - return m_type == value_t::number_float; - } - - /*! - @brief return whether value is an object - - This function returns true iff the JSON value is an object. - - @return `true` if type is object, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_object()` for all JSON - types.,is_object} - - @since version 1.0.0 - */ - constexpr bool is_object() const noexcept - { - return m_type == value_t::object; - } - - /*! - @brief return whether value is an array - - This function returns true iff the JSON value is an array. - - @return `true` if type is array, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_array()` for all JSON - types.,is_array} - - @since version 1.0.0 - */ - constexpr bool is_array() const noexcept - { - return m_type == value_t::array; - } - - /*! - @brief return whether value is a string - - This function returns true iff the JSON value is a string. - - @return `true` if type is string, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_string()` for all JSON - types.,is_string} - - @since version 1.0.0 - */ - constexpr bool is_string() const noexcept - { - return m_type == value_t::string; - } - - /*! - @brief return whether value is discarded - - This function returns true iff the JSON value was discarded during parsing - with a callback function (see @ref parser_callback_t). - - @note This function will always be `false` for JSON values after parsing. - That is, discarded values can only occur during parsing, but will be - removed when inside a structured value or replaced by null in other cases. - - @return `true` if type is discarded, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_discarded()` for all JSON - types.,is_discarded} - - @since version 1.0.0 - */ - constexpr bool is_discarded() const noexcept - { - return m_type == value_t::discarded; - } - - /*! - @brief return the type of the JSON value (implicit) - - Implicitly return the type of the JSON value as a value from the @ref - value_t enumeration. - - @return the type of the JSON value - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies the @ref value_t operator for - all JSON types.,operator__value_t} - - @since version 1.0.0 - */ - constexpr operator value_t() const noexcept - { - return m_type; - } - - /// @} - - private: - ////////////////// - // value access // - ////////////////// - - /// get an object (explicit) - template::value and - std::is_convertible::value, int>::type = 0> - T get_impl(T*) const - { - if (is_object()) - { - return T(m_value.object->begin(), m_value.object->end()); - } - else - { - throw std::domain_error("type must be object, but is " + type_name()); - } - } - - /// get an object (explicit) - object_t get_impl(object_t*) const - { - if (is_object()) - { - return *(m_value.object); - } - else - { - throw std::domain_error("type must be object, but is " + type_name()); - } - } - - /// get an array (explicit) - template::value and - not std::is_same::value and - not std::is_arithmetic::value and - not std::is_convertible::value and - not has_mapped_type::value, int>::type = 0> - T get_impl(T*) const - { - if (is_array()) - { - T to_vector; - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) - { - return i.get(); - }); - return to_vector; - } - else - { - throw std::domain_error("type must be array, but is " + type_name()); - } - } - - /// get an array (explicit) - template::value and - not std::is_same::value, int>::type = 0> - std::vector get_impl(std::vector*) const - { - if (is_array()) - { - std::vector to_vector; - to_vector.reserve(m_value.array->size()); - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) - { - return i.get(); - }); - return to_vector; - } - else - { - throw std::domain_error("type must be array, but is " + type_name()); - } - } - - /// get an array (explicit) - template::value and - not has_mapped_type::value, int>::type = 0> - T get_impl(T*) const - { - if (is_array()) - { - return T(m_value.array->begin(), m_value.array->end()); - } - else - { - throw std::domain_error("type must be array, but is " + type_name()); - } - } - - /// get an array (explicit) - array_t get_impl(array_t*) const - { - if (is_array()) - { - return *(m_value.array); - } - else - { - throw std::domain_error("type must be array, but is " + type_name()); - } - } - - /// get a string (explicit) - template::value, int>::type = 0> - T get_impl(T*) const - { - if (is_string()) - { - return *m_value.string; - } - else - { - throw std::domain_error("type must be string, but is " + type_name()); - } - } - - /// get a number (explicit) - template::value, int>::type = 0> - T get_impl(T*) const - { - switch (m_type) - { - case value_t::number_integer: - { - return static_cast(m_value.number_integer); - } - - case value_t::number_unsigned: - { - return static_cast(m_value.number_unsigned); - } - - case value_t::number_float: - { - return static_cast(m_value.number_float); - } - - default: - { - throw std::domain_error("type must be number, but is " + type_name()); - } - } - } - - /// get a boolean (explicit) - constexpr boolean_t get_impl(boolean_t*) const - { - return is_boolean() - ? m_value.boolean - : throw std::domain_error("type must be boolean, but is " + type_name()); - } - - /// get a pointer to the value (object) - object_t* get_impl_ptr(object_t*) noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (object) - constexpr const object_t* get_impl_ptr(const object_t*) const noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (array) - array_t* get_impl_ptr(array_t*) noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (array) - constexpr const array_t* get_impl_ptr(const array_t*) const noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (string) - string_t* get_impl_ptr(string_t*) noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (string) - constexpr const string_t* get_impl_ptr(const string_t*) const noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (boolean) - boolean_t* get_impl_ptr(boolean_t*) noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } - - /// get a pointer to the value (boolean) - constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } - - /// get a pointer to the value (integer number) - number_integer_t* get_impl_ptr(number_integer_t*) noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } - - /// get a pointer to the value (integer number) - constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } - - /// get a pointer to the value (unsigned number) - number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (unsigned number) - constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (floating-point number) - number_float_t* get_impl_ptr(number_float_t*) noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } - - /// get a pointer to the value (floating-point number) - constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } - - /*! - @brief helper function to implement get_ref() - - This funcion helps to implement get_ref() without code duplication for - const and non-const overloads - - @tparam ThisType will be deduced as `basic_json` or `const basic_json` - - @throw std::domain_error if ReferenceType does not match underlying value - type of the current JSON - */ - template - static ReferenceType get_ref_impl(ThisType& obj) - { - // helper type - using PointerType = typename std::add_pointer::type; - - // delegate the call to get_ptr<>() - auto ptr = obj.template get_ptr(); - - if (ptr != nullptr) - { - return *ptr; - } - else - { - throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + - obj.type_name()); - } - } - - public: - - /// @name value access - /// Direct access to the stored value of a JSON value. - /// @{ - - /*! - @brief get a value (explicit) - - Explicit type conversion between the JSON value and a compatible value. - - @tparam ValueType non-pointer type compatible to the JSON value, for - instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays - - @return copy of the JSON value, converted to type @a ValueType - - @throw std::domain_error in case passed type @a ValueType is incompatible - to JSON; example: `"type must be object, but is null"` - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,get__ValueType_const} - - @internal - The idea of using a casted null pointer to choose the correct - implementation is from . - @endinternal - - @sa @ref operator ValueType() const for implicit conversion - @sa @ref get() for pointer-member access - - @since version 1.0.0 - */ - template::value, int>::type = 0> - ValueType get() const - { - return get_impl(static_cast(nullptr)); - } - - /*! - @brief get a pointer value (explicit) - - Explicit pointer access to the internally stored JSON value. No copies are - made. - - @warning The pointer becomes invalid if the underlying JSON object - changes. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} - - @sa @ref get_ptr() for explicit pointer-member access - - @since version 1.0.0 - */ - template::value, int>::type = 0> - PointerType get() noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } - - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template::value, int>::type = 0> - constexpr const PointerType get() const noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } - - /*! - @brief get a pointer value (implicit) - - Implicit pointer access to the internally stored JSON value. No copies are - made. - - @warning Writing data to the pointee of the result yields an undefined - state. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. Enforced by a static - assertion. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get_ptr} - - @since version 1.0.0 - */ - template::value, int>::type = 0> - PointerType get_ptr() noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() - return get_impl_ptr(static_cast(nullptr)); - } - - /*! - @brief get a pointer value (implicit) - @copydoc get_ptr() - */ - template::value and - std::is_const::type>::value, int>::type = 0> - constexpr const PointerType get_ptr() const noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() const - return get_impl_ptr(static_cast(nullptr)); - } - - /*! - @brief get a reference value (implicit) - - Implict reference access to the internally stored JSON value. No copies - are made. - - @warning Writing data to the referee of the result yields an undefined - state. - - @tparam ReferenceType reference type; must be a reference to @ref array_t, - @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or - @ref number_float_t. Enforced by static assertion. - - @return reference to the internally stored JSON value if the requested - reference type @a ReferenceType fits to the JSON value; throws - std::domain_error otherwise - - @throw std::domain_error in case passed type @a ReferenceType is - incompatible with the stored JSON value - - @complexity Constant. - - @liveexample{The example shows several calls to `get_ref()`.,get_ref} - - @since version 1.1.0 - */ - template::value, int>::type = 0> - ReferenceType get_ref() - { - // delegate call to get_ref_impl - return get_ref_impl(*this); - } - - /*! - @brief get a reference value (implicit) - @copydoc get_ref() - */ - template::value and - std::is_const::type>::value, int>::type = 0> - ReferenceType get_ref() const - { - // delegate call to get_ref_impl - return get_ref_impl(*this); - } - - /*! - @brief get a value (implicit) - - Implicit type conversion between the JSON value and a compatible value. - The call is realized by calling @ref get() const. - - @tparam ValueType non-pointer type compatible to the JSON value, for - instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays. The character type of @ref string_t - as well as an initializer list of this type is excluded to avoid - ambiguities as these types implicitly convert to `std::string`. - - @return copy of the JSON value, converted to type @a ValueType - - @throw std::domain_error in case passed type @a ValueType is incompatible - to JSON, thrown by @ref get() const - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,operator__ValueType} - - @since version 1.0.0 - */ - template < typename ValueType, typename std::enable_if < - not std::is_pointer::value and - not std::is_same::value -#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015 - and not std::is_same>::value -#endif - , int >::type = 0 > - operator ValueType() const - { - // delegate the call to get<>() const - return get(); - } - - /// @} - - - //////////////////// - // element access // - //////////////////// - - /// @name element access - /// Access to the JSON value. - /// @{ - - /*! - @brief access specified array element with bounds checking - - Returns a reference to the element at specified location @a idx, with - bounds checking. - - @param[in] idx index of the element to access - - @return reference to the element at index @a idx - - @throw std::domain_error if the JSON value is not an array; example: - `"cannot use at() with string"` - @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()`; example: `"array index 7 is out of range"` - - @complexity Constant. - - @liveexample{The example below shows how array elements can be read and - written using `at()`.,at__size_type} - - @since version 1.0.0 - */ - reference at(size_type idx) - { - // at only works for arrays - if (is_array()) - { - try - { - return m_value.array->at(idx); - } - catch (std::out_of_range&) - { - // create better exception explanation - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); - } - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } - } - - /*! - @brief access specified array element with bounds checking - - Returns a const reference to the element at specified location @a idx, - with bounds checking. - - @param[in] idx index of the element to access - - @return const reference to the element at index @a idx - - @throw std::domain_error if the JSON value is not an array; example: - `"cannot use at() with string"` - @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()`; example: `"array index 7 is out of range"` - - @complexity Constant. - - @liveexample{The example below shows how array elements can be read using - `at()`.,at__size_type_const} - - @since version 1.0.0 - */ - const_reference at(size_type idx) const - { - // at only works for arrays - if (is_array()) - { - try - { - return m_value.array->at(idx); - } - catch (std::out_of_range&) - { - // create better exception explanation - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); - } - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } - } - - /*! - @brief access specified object element with bounds checking - - Returns a reference to the element at with specified key @a key, with - bounds checking. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if the JSON value is not an object; example: - `"cannot use at() with boolean"` - @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()`; example: `"key "the fast" not found"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using `at()`.,at__object_t_key_type} - - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - reference at(const typename object_t::key_type& key) - { - // at only works for objects - if (is_object()) - { - try - { - return m_value.object->at(key); - } - catch (std::out_of_range&) - { - // create better exception explanation - throw std::out_of_range("key '" + key + "' not found"); - } - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } - } - - /*! - @brief access specified object element with bounds checking - - Returns a const reference to the element at with specified key @a key, - with bounds checking. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @throw std::domain_error if the JSON value is not an object; example: - `"cannot use at() with boolean"` - @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()`; example: `"key "the fast" not found"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - `at()`.,at__object_t_key_type_const} - - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - const_reference at(const typename object_t::key_type& key) const - { - // at only works for objects - if (is_object()) - { - try - { - return m_value.object->at(key); - } - catch (std::out_of_range&) - { - // create better exception explanation - throw std::out_of_range("key '" + key + "' not found"); - } - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } - } - - /*! - @brief access specified array element - - Returns a reference to the element at specified location @a idx. - - @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), - then the array is silently filled up with `null` values to make `idx` a - valid reference to the last stored element. - - @param[in] idx index of the element to access - - @return reference to the element at index @a idx - - @throw std::domain_error if JSON is not an array or null; example: - `"cannot use operator[] with string"` - - @complexity Constant if @a idx is in the range of the array. Otherwise - linear in `idx - size()`. - - @liveexample{The example below shows how array elements can be read and - written using `[]` operator. Note the addition of `null` - values.,operatorarray__size_type} - - @since version 1.0.0 - */ - reference operator[](size_type idx) - { - // implicitly convert null value to an empty array - if (is_null()) - { - m_type = value_t::array; - m_value.array = create(); - assert_invariant(); - } - - // operator[] only works for arrays - if (is_array()) - { - // fill up array with null values if given idx is outside range - if (idx >= m_value.array->size()) - { - m_value.array->insert(m_value.array->end(), - idx - m_value.array->size() + 1, - basic_json()); - } - - return m_value.array->operator[](idx); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } - } - - /*! - @brief access specified array element - - Returns a const reference to the element at specified location @a idx. - - @param[in] idx index of the element to access - - @return const reference to the element at index @a idx - - @throw std::domain_error if JSON is not an array; example: `"cannot use - operator[] with null"` - - @complexity Constant. - - @liveexample{The example below shows how array elements can be read using - the `[]` operator.,operatorarray__size_type_const} - - @since version 1.0.0 - */ - const_reference operator[](size_type idx) const - { - // const operator[] only works for arrays - if (is_array()) - { - return m_value.array->operator[](idx); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - reference operator[](const typename object_t::key_type& key) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - // operator[] only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } - } - - /*! - @brief read-only access specified object element - - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. - - @warning If the element with key @a key does not exist, the behavior is - undefined. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @pre The element with key @a key must exist. **This precondition is - enforced with an assertion.** - - @throw std::domain_error if JSON is not an object; example: `"cannot use - operator[] with null"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - const_reference operator[](const typename object_t::key_type& key) const - { - // const operator[] only works for objects - if (is_object()) - { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - template - reference operator[](T * (&key)[n]) - { - return operator[](static_cast(key)); - } - - /*! - @brief read-only access specified object element - - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. - - @warning If the element with key @a key does not exist, the behavior is - undefined. - - @note This function is required for compatibility reasons with Clang. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @throw std::domain_error if JSON is not an object; example: `"cannot use - operator[] with null"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - template - const_reference operator[](T * (&key)[n]) const - { - return operator[](static_cast(key)); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.1.0 - */ - template - reference operator[](T* key) - { - // implicitly convert null to object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // at only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } - } - - /*! - @brief read-only access specified object element - - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. - - @warning If the element with key @a key does not exist, the behavior is - undefined. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @pre The element with key @a key must exist. **This precondition is - enforced with an assertion.** - - @throw std::domain_error if JSON is not an object; example: `"cannot use - operator[] with null"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.1.0 - */ - template - const_reference operator[](T* key) const - { - // at only works for objects - if (is_object()) - { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } - } - - /*! - @brief access specified object element with default value - - Returns either a copy of an object's element at the specified key @a key - or a given default value if no element with key @a key exists. - - The function is basically equivalent to executing - @code {.cpp} - try { - return at(key); - } catch(std::out_of_range) { - return default_value; - } - @endcode - - @note Unlike @ref at(const typename object_t::key_type&), this function - does not throw if the given key @a key was not found. - - @note Unlike @ref operator[](const typename object_t::key_type& key), this - function does not implicitly add an element to the position defined by @a - key. This function is furthermore also applicable to const objects. - - @param[in] key key of the element to access - @param[in] default_value the value to return if @a key is not found - - @tparam ValueType type compatible to JSON values, for instance `int` for - JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for - JSON arrays. Note the type of the expected value at @a key and the default - value @a default_value must be compatible. - - @return copy of the element at key @a key or @a default_value if @a key - is not found - - @throw std::domain_error if JSON is not an object; example: `"cannot use - value() with null"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be queried - with a default value.,basic_json__value} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - - @since version 1.0.0 - */ - template::value, int>::type = 0> - ValueType value(const typename object_t::key_type& key, ValueType default_value) const - { - // at only works for objects - if (is_object()) - { - // if key is found, return value and given default value otherwise - const auto it = find(key); - if (it != end()) - { - return *it; - } - else - { - return default_value; - } - } - else - { - throw std::domain_error("cannot use value() with " + type_name()); - } - } - - /*! - @brief overload for a default value of type const char* - @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const - */ - string_t value(const typename object_t::key_type& key, const char* default_value) const - { - return value(key, string_t(default_value)); - } - - /*! - @brief access specified object element via JSON Pointer with default value - - Returns either a copy of an object's element at the specified key @a key - or a given default value if no element with key @a key exists. - - The function is basically equivalent to executing - @code {.cpp} - try { - return at(ptr); - } catch(std::out_of_range) { - return default_value; - } - @endcode - - @note Unlike @ref at(const json_pointer&), this function does not throw - if the given key @a key was not found. - - @param[in] ptr a JSON pointer to the element to access - @param[in] default_value the value to return if @a ptr found no value - - @tparam ValueType type compatible to JSON values, for instance `int` for - JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for - JSON arrays. Note the type of the expected value at @a key and the default - value @a default_value must be compatible. - - @return copy of the element at key @a key or @a default_value if @a key - is not found - - @throw std::domain_error if JSON is not an object; example: `"cannot use - value() with null"` - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be queried - with a default value.,basic_json__value_ptr} - - @sa @ref operator[](const json_pointer&) for unchecked access by reference - - @since version 2.0.2 - */ - template::value, int>::type = 0> - ValueType value(const json_pointer& ptr, ValueType default_value) const - { - // at only works for objects - if (is_object()) - { - // if pointer resolves a value, return it or use default value - try - { - return ptr.get_checked(this); - } - catch (std::out_of_range&) - { - return default_value; - } - } - else - { - throw std::domain_error("cannot use value() with " + type_name()); - } - } - - /*! - @brief overload for a default value of type const char* - @copydoc basic_json::value(const json_pointer&, ValueType) const - */ - string_t value(const json_pointer& ptr, const char* default_value) const - { - return value(ptr, string_t(default_value)); - } - - /*! - @brief access the first element - - Returns a reference to the first element in the container. For a JSON - container `c`, the expression `c.front()` is equivalent to `*c.begin()`. - - @return In case of a structured type (array or object), a reference to the - first element is returned. In case of number, string, or boolean values, a - reference to the value is returned. - - @complexity Constant. - - @pre The JSON value must not be `null` (would throw `std::out_of_range`) - or an empty array or object (undefined behavior, **guarded by - assertions**). - @post The JSON value remains unchanged. - - @throw std::out_of_range when called on `null` value - - @liveexample{The following code shows an example for `front()`.,front} - - @sa @ref back() -- access the last element - - @since version 1.0.0 - */ - reference front() - { - return *begin(); - } - - /*! - @copydoc basic_json::front() - */ - const_reference front() const - { - return *cbegin(); - } - - /*! - @brief access the last element - - Returns a reference to the last element in the container. For a JSON - container `c`, the expression `c.back()` is equivalent to - @code {.cpp} - auto tmp = c.end(); - --tmp; - return *tmp; - @endcode - - @return In case of a structured type (array or object), a reference to the - last element is returned. In case of number, string, or boolean values, a - reference to the value is returned. - - @complexity Constant. - - @pre The JSON value must not be `null` (would throw `std::out_of_range`) - or an empty array or object (undefined behavior, **guarded by - assertions**). - @post The JSON value remains unchanged. - - @throw std::out_of_range when called on `null` value. - - @liveexample{The following code shows an example for `back()`.,back} - - @sa @ref front() -- access the first element - - @since version 1.0.0 - */ - reference back() - { - auto tmp = end(); - --tmp; - return *tmp; - } - - /*! - @copydoc basic_json::back() - */ - const_reference back() const - { - auto tmp = cend(); - --tmp; - return *tmp; - } - - /*! - @brief remove element given an iterator - - Removes the element specified by iterator @a pos. The iterator @a pos must - be valid and dereferenceable. Thus the `end()` iterator (which is valid, - but is not dereferenceable) cannot be used as a value for @a pos. - - If called on a primitive type other than `null`, the resulting JSON value - will be `null`. - - @param[in] pos iterator to the element to remove - @return Iterator following the last removed element. If the iterator @a - pos refers to the last element, the `end()` iterator is returned. - - @tparam IteratorType an @ref iterator or @ref const_iterator - - @post Invalidates iterators and references at or after the point of the - erase, including the `end()` iterator. - - @throw std::domain_error if called on a `null` value; example: `"cannot - use erase() with null"` - @throw std::domain_error if called on an iterator which does not belong to - the current JSON value; example: `"iterator does not fit current value"` - @throw std::out_of_range if called on a primitive type with invalid - iterator (i.e., any iterator which is not `begin()`); example: `"iterator - out of range"` - - @complexity The complexity depends on the type: - - objects: amortized constant - - arrays: linear in distance between pos and the end of the container - - strings: linear in the length of the string - - other types: constant - - @liveexample{The example shows the result of `erase()` for different JSON - types.,erase__IteratorType} - - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type - = 0> - IteratorType erase(IteratorType pos) - { - // make sure iterator fits the current value - if (this != pos.m_object) - { - throw std::domain_error("iterator does not fit current value"); - } - - IteratorType result = end(); - - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (not pos.m_it.primitive_iterator.is_begin()) - { - throw std::out_of_range("iterator out of range"); - } - - if (is_string()) - { - AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - m_value.string = nullptr; - } - - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); - break; - } - - default: - { - throw std::domain_error("cannot use erase() with " + type_name()); - } - } - - return result; - } - - /*! - @brief remove elements given an iterator range - - Removes the element specified by the range `[first; last)`. The iterator - @a first does not need to be dereferenceable if `first == last`: erasing - an empty range is a no-op. - - If called on a primitive type other than `null`, the resulting JSON value - will be `null`. - - @param[in] first iterator to the beginning of the range to remove - @param[in] last iterator past the end of the range to remove - @return Iterator following the last removed element. If the iterator @a - second refers to the last element, the `end()` iterator is returned. - - @tparam IteratorType an @ref iterator or @ref const_iterator - - @post Invalidates iterators and references at or after the point of the - erase, including the `end()` iterator. - - @throw std::domain_error if called on a `null` value; example: `"cannot - use erase() with null"` - @throw std::domain_error if called on iterators which does not belong to - the current JSON value; example: `"iterators do not fit current value"` - @throw std::out_of_range if called on a primitive type with invalid - iterators (i.e., if `first != begin()` and `last != end()`); example: - `"iterators out of range"` - - @complexity The complexity depends on the type: - - objects: `log(size()) + std::distance(first, last)` - - arrays: linear in the distance between @a first and @a last, plus linear - in the distance between @a last and end of the container - - strings: linear in the length of the string - - other types: constant - - @liveexample{The example shows the result of `erase()` for different JSON - types.,erase__IteratorType_IteratorType} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type - = 0> - IteratorType erase(IteratorType first, IteratorType last) - { - // make sure iterator fits the current value - if (this != first.m_object or this != last.m_object) - { - throw std::domain_error("iterators do not fit current value"); - } - - IteratorType result = end(); - - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) - { - throw std::out_of_range("iterators out of range"); - } - - if (is_string()) - { - AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - m_value.string = nullptr; - } - - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - default: - { - throw std::domain_error("cannot use erase() with " + type_name()); - } - } - - return result; - } - - /*! - @brief remove element from a JSON object given a key - - Removes elements from a JSON object with the key value @a key. - - @param[in] key value of the elements to remove - - @return Number of elements removed. If @a ObjectType is the default - `std::map` type, the return value will always be `0` (@a key was not - found) or `1` (@a key was found). - - @post References and iterators to the erased elements are invalidated. - Other references and iterators are not affected. - - @throw std::domain_error when called on a type other than JSON object; - example: `"cannot use erase() with null"` - - @complexity `log(size()) + count(key)` - - @liveexample{The example shows the effect of `erase()`.,erase__key_type} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - size_type erase(const typename object_t::key_type& key) - { - // this erase only works for objects - if (is_object()) - { - return m_value.object->erase(key); - } - else - { - throw std::domain_error("cannot use erase() with " + type_name()); - } - } - - /*! - @brief remove element from a JSON array given an index - - Removes element from a JSON array at the index @a idx. - - @param[in] idx index of the element to remove - - @throw std::domain_error when called on a type other than JSON array; - example: `"cannot use erase() with null"` - @throw std::out_of_range when `idx >= size()`; example: `"array index 17 - is out of range"` - - @complexity Linear in distance between @a idx and the end of the container. - - @liveexample{The example shows the effect of `erase()`.,erase__size_type} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - - @since version 1.0.0 - */ - void erase(const size_type idx) - { - // this erase only works for arrays - if (is_array()) - { - if (idx >= size()) - { - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); - } - - m_value.array->erase(m_value.array->begin() + static_cast(idx)); - } - else - { - throw std::domain_error("cannot use erase() with " + type_name()); - } - } - - /// @} - - - //////////// - // lookup // - //////////// - - /// @name lookup - /// @{ - - /*! - @brief find an element in a JSON object - - Finds an element in a JSON object with key equivalent to @a key. If the - element is not found or the JSON value is not an object, end() is - returned. - - @note This method always returns @ref end() when executed on a JSON type - that is not an object. - - @param[in] key key value of the element to search for - - @return Iterator to an element with key equivalent to @a key. If no such - element is found or the JSON value is not an object, past-the-end (see - @ref end()) iterator is returned. - - @complexity Logarithmic in the size of the JSON object. - - @liveexample{The example shows how `find()` is used.,find__key_type} - - @since version 1.0.0 - */ - iterator find(typename object_t::key_type key) - { - auto result = end(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(key); - } - - return result; - } - - /*! - @brief find an element in a JSON object - @copydoc find(typename object_t::key_type) - */ - const_iterator find(typename object_t::key_type key) const - { - auto result = cend(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(key); - } - - return result; - } - - /*! - @brief returns the number of occurrences of a key in a JSON object - - Returns the number of elements with key @a key. If ObjectType is the - default `std::map` type, the return value will always be `0` (@a key was - not found) or `1` (@a key was found). - - @note This method always returns `0` when executed on a JSON type that is - not an object. - - @param[in] key key value of the element to count - - @return Number of elements with key @a key. If the JSON value is not an - object, the return value will be `0`. - - @complexity Logarithmic in the size of the JSON object. - - @liveexample{The example shows how `count()` is used.,count} - - @since version 1.0.0 - */ - size_type count(typename object_t::key_type key) const - { - // return 0 for all nonobject types - return is_object() ? m_value.object->count(key) : 0; - } - - /// @} - - - /////////////// - // iterators // - /////////////// - - /// @name iterators - /// @{ - - /*! - @brief returns an iterator to the first element - - Returns an iterator to the first element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return iterator to the first element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - @liveexample{The following code shows an example for `begin()`.,begin} - - @sa @ref cbegin() -- returns a const iterator to the beginning - @sa @ref end() -- returns an iterator to the end - @sa @ref cend() -- returns a const iterator to the end - - @since version 1.0.0 - */ - iterator begin() noexcept - { - iterator result(this); - result.set_begin(); - return result; - } - - /*! - @copydoc basic_json::cbegin() - */ - const_iterator begin() const noexcept - { - return cbegin(); - } - - /*! - @brief returns a const iterator to the first element - - Returns a const iterator to the first element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return const iterator to the first element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).begin()`. - - @liveexample{The following code shows an example for `cbegin()`.,cbegin} - - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref end() -- returns an iterator to the end - @sa @ref cend() -- returns a const iterator to the end - - @since version 1.0.0 - */ - const_iterator cbegin() const noexcept - { - const_iterator result(this); - result.set_begin(); - return result; - } - - /*! - @brief returns an iterator to one past the last element - - Returns an iterator to one past the last element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return iterator one past the last element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - @liveexample{The following code shows an example for `end()`.,end} - - @sa @ref cend() -- returns a const iterator to the end - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref cbegin() -- returns a const iterator to the beginning - - @since version 1.0.0 - */ - iterator end() noexcept - { - iterator result(this); - result.set_end(); - return result; - } - - /*! - @copydoc basic_json::cend() - */ - const_iterator end() const noexcept - { - return cend(); - } - - /*! - @brief returns a const iterator to one past the last element - - Returns a const iterator to one past the last element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return const iterator one past the last element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).end()`. - - @liveexample{The following code shows an example for `cend()`.,cend} - - @sa @ref end() -- returns an iterator to the end - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref cbegin() -- returns a const iterator to the beginning - - @since version 1.0.0 - */ - const_iterator cend() const noexcept - { - const_iterator result(this); - result.set_end(); - return result; - } - - /*! - @brief returns an iterator to the reverse-beginning - - Returns an iterator to the reverse-beginning; that is, the last element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `reverse_iterator(end())`. - - @liveexample{The following code shows an example for `rbegin()`.,rbegin} - - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref crend() -- returns a const reverse iterator to the end - - @since version 1.0.0 - */ - reverse_iterator rbegin() noexcept - { - return reverse_iterator(end()); - } - - /*! - @copydoc basic_json::crbegin() - */ - const_reverse_iterator rbegin() const noexcept - { - return crbegin(); - } - - /*! - @brief returns an iterator to the reverse-end - - Returns an iterator to the reverse-end; that is, one before the first - element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `reverse_iterator(begin())`. - - @liveexample{The following code shows an example for `rend()`.,rend} - - @sa @ref crend() -- returns a const reverse iterator to the end - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - - @since version 1.0.0 - */ - reverse_iterator rend() noexcept - { - return reverse_iterator(begin()); - } - - /*! - @copydoc basic_json::crend() - */ - const_reverse_iterator rend() const noexcept - { - return crend(); - } - - /*! - @brief returns a const reverse iterator to the last element - - Returns a const iterator to the reverse-beginning; that is, the last - element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).rbegin()`. - - @liveexample{The following code shows an example for `crbegin()`.,crbegin} - - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref crend() -- returns a const reverse iterator to the end - - @since version 1.0.0 - */ - const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator(cend()); - } - - /*! - @brief returns a const reverse iterator to one before the first - - Returns a const reverse iterator to the reverse-end; that is, one before - the first element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).rend()`. - - @liveexample{The following code shows an example for `crend()`.,crend} - - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - - @since version 1.0.0 - */ - const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator(cbegin()); - } - - private: - // forward declaration - template class iteration_proxy; - - public: - /*! - @brief wrapper to access iterator member functions in range-based for - - This function allows to access @ref iterator::key() and @ref - iterator::value() during range-based for loops. In these loops, a - reference to the JSON values is returned, so there is no access to the - underlying iterator. - - @note The name of this function is not yet final and may change in the - future. - */ - static iteration_proxy iterator_wrapper(reference cont) - { - return iteration_proxy(cont); - } - - /*! - @copydoc iterator_wrapper(reference) - */ - static iteration_proxy iterator_wrapper(const_reference cont) - { - return iteration_proxy(cont); - } - - /// @} - - - ////////////// - // capacity // - ////////////// - - /// @name capacity - /// @{ - - /*! - @brief checks whether the container is empty - - Checks if a JSON value has no elements. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `true` - boolean | `false` - string | `false` - number | `false` - object | result of function `object_t::empty()` - array | result of function `array_t::empty()` - - @note This function does not return whether a string stored as JSON value - is empty - it returns whether the JSON container itself is empty which is - false in the case of a string. - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their `empty()` functions have constant - complexity. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `begin() == end()`. - - @liveexample{The following code uses `empty()` to check if a JSON - object contains any elements.,empty} - - @sa @ref size() -- returns the number of elements - - @since version 1.0.0 - */ - bool empty() const noexcept - { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return true; - } - - case value_t::array: - { - // delegate call to array_t::empty() - return m_value.array->empty(); - } - - case value_t::object: - { - // delegate call to object_t::empty() - return m_value.object->empty(); - } - - default: - { - // all other types are nonempty - return false; - } - } - } - - /*! - @brief returns the number of elements - - Returns the number of elements in a JSON value. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `0` - boolean | `1` - string | `1` - number | `1` - object | result of function object_t::size() - array | result of function array_t::size() - - @note This function does not return the length of a string stored as JSON - value - it returns the number of elements in the JSON value which is 1 in - the case of a string. - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their size() functions have constant - complexity. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `std::distance(begin(), end())`. - - @liveexample{The following code calls `size()` on the different value - types.,size} - - @sa @ref empty() -- checks whether the container is empty - @sa @ref max_size() -- returns the maximal number of elements - - @since version 1.0.0 - */ - size_type size() const noexcept - { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return 0; - } - - case value_t::array: - { - // delegate call to array_t::size() - return m_value.array->size(); - } - - case value_t::object: - { - // delegate call to object_t::size() - return m_value.object->size(); - } - - default: - { - // all other types have size 1 - return 1; - } - } - } - - /*! - @brief returns the maximum possible number of elements - - Returns the maximum number of elements a JSON value is able to hold due to - system or library implementation limitations, i.e. `std::distance(begin(), - end())` for the JSON value. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `0` (same as `size()`) - boolean | `1` (same as `size()`) - string | `1` (same as `size()`) - number | `1` (same as `size()`) - object | result of function `object_t::max_size()` - array | result of function `array_t::max_size()` - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their `max_size()` functions have constant - complexity. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of returning `b.size()` where `b` is the largest - possible JSON value. - - @liveexample{The following code calls `max_size()` on the different value - types. Note the output is implementation specific.,max_size} - - @sa @ref size() -- returns the number of elements - - @since version 1.0.0 - */ - size_type max_size() const noexcept - { - switch (m_type) - { - case value_t::array: - { - // delegate call to array_t::max_size() - return m_value.array->max_size(); - } - - case value_t::object: - { - // delegate call to object_t::max_size() - return m_value.object->max_size(); - } - - default: - { - // all other types have max_size() == size() - return size(); - } - } - } - - /// @} - - - /////////////// - // modifiers // - /////////////// - - /// @name modifiers - /// @{ - - /*! - @brief clears the contents - - Clears the content of a JSON value and resets it to the default value as - if @ref basic_json(value_t) would have been called: - - Value type | initial value - ----------- | ------------- - null | `null` - boolean | `false` - string | `""` - number | `0` - object | `{}` - array | `[]` - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows the effect of `clear()` to different - JSON types.,clear} - - @since version 1.0.0 - */ - void clear() noexcept - { - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = 0; - break; - } - - case value_t::number_unsigned: - { - m_value.number_unsigned = 0; - break; - } - - case value_t::number_float: - { - m_value.number_float = 0.0; - break; - } - - case value_t::boolean: - { - m_value.boolean = false; - break; - } - - case value_t::string: - { - m_value.string->clear(); - break; - } - - case value_t::array: - { - m_value.array->clear(); - break; - } - - case value_t::object: - { - m_value.object->clear(); - break; - } - - default: - { - break; - } - } - } - - /*! - @brief add an object to an array - - Appends the given element @a val to the end of the JSON value. If the - function is called on a JSON null value, an empty array is created before - appending @a val. - - @param[in] val the value to add to the JSON array - - @throw std::domain_error when called on a type other than JSON array or - null; example: `"cannot use push_back() with number"` - - @complexity Amortized constant. - - @liveexample{The example shows how `push_back()` and `+=` can be used to - add elements to a JSON array. Note how the `null` value was silently - converted to a JSON array.,push_back} - - @since version 1.0.0 - */ - void push_back(basic_json&& val) - { - // push_back only works for null objects or arrays - if (not(is_null() or is_array())) - { - throw std::domain_error("cannot use push_back() with " + type_name()); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (move semantics) - m_value.array->push_back(std::move(val)); - // invalidate object - val.m_type = value_t::null; - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - reference operator+=(basic_json&& val) - { - push_back(std::move(val)); - return *this; - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - void push_back(const basic_json& val) - { - // push_back only works for null objects or arrays - if (not(is_null() or is_array())) - { - throw std::domain_error("cannot use push_back() with " + type_name()); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array - m_value.array->push_back(val); - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - reference operator+=(const basic_json& val) - { - push_back(val); - return *this; - } - - /*! - @brief add an object to an object - - Inserts the given element @a val to the JSON object. If the function is - called on a JSON null value, an empty object is created before inserting - @a val. - - @param[in] val the value to add to the JSON object - - @throw std::domain_error when called on a type other than JSON object or - null; example: `"cannot use push_back() with number"` - - @complexity Logarithmic in the size of the container, O(log(`size()`)). - - @liveexample{The example shows how `push_back()` and `+=` can be used to - add elements to a JSON object. Note how the `null` value was silently - converted to a JSON object.,push_back__object_t__value} - - @since version 1.0.0 - */ - void push_back(const typename object_t::value_type& val) - { - // push_back only works for null objects or objects - if (not(is_null() or is_object())) - { - throw std::domain_error("cannot use push_back() with " + type_name()); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to array - m_value.object->insert(val); - } - - /*! - @brief add an object to an object - @copydoc push_back(const typename object_t::value_type&) - */ - reference operator+=(const typename object_t::value_type& val) - { - push_back(val); - return *this; - } - - /*! - @brief add an object to an object - - This function allows to use `push_back` with an initializer list. In case - - 1. the current value is an object, - 2. the initializer list @a init contains only two elements, and - 3. the first element of @a init is a string, - - @a init is converted into an object element and added using - @ref push_back(const typename object_t::value_type&). Otherwise, @a init - is converted to a JSON value and added using @ref push_back(basic_json&&). - - @param init an initializer list - - @complexity Linear in the size of the initializer list @a init. - - @note This function is required to resolve an ambiguous overload error, - because pairs like `{"key", "value"}` can be both interpreted as - `object_t::value_type` or `std::initializer_list`, see - https://github.com/nlohmann/json/issues/235 for more information. - - @liveexample{The example shows how initializer lists are treated as - objects when possible.,push_back__initializer_list} - */ - void push_back(std::initializer_list init) - { - if (is_object() and init.size() == 2 and init.begin()->is_string()) - { - const string_t key = *init.begin(); - push_back(typename object_t::value_type(key, *(init.begin() + 1))); - } - else - { - push_back(basic_json(init)); - } - } - - /*! - @brief add an object to an object - @copydoc push_back(std::initializer_list) - */ - reference operator+=(std::initializer_list init) - { - push_back(init); - return *this; - } - - /*! - @brief add an object to an array - - Creates a JSON value from the passed parameters @a args to the end of the - JSON value. If the function is called on a JSON null value, an empty array - is created before appending the value created from @a args. - - @param[in] args arguments to forward to a constructor of @ref basic_json - @tparam Args compatible types to create a @ref basic_json object - - @throw std::domain_error when called on a type other than JSON array or - null; example: `"cannot use emplace_back() with number"` - - @complexity Amortized constant. - - @liveexample{The example shows how `push_back()` can be used to add - elements to a JSON array. Note how the `null` value was silently converted - to a JSON array.,emplace_back} - - @since version 2.0.8 - */ - template - void emplace_back(Args&& ... args) - { - // emplace_back only works for null objects or arrays - if (not(is_null() or is_array())) - { - throw std::domain_error("cannot use emplace_back() with " + type_name()); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (perfect forwarding) - m_value.array->emplace_back(std::forward(args)...); - } - - /*! - @brief add an object to an object if key does not exist - - Inserts a new element into a JSON object constructed in-place with the given - @a args if there is no element with the key in the container. If the - function is called on a JSON null value, an empty object is created before - appending the value created from @a args. - - @param[in] args arguments to forward to a constructor of @ref basic_json - @tparam Args compatible types to create a @ref basic_json object - - @return a pair consisting of an iterator to the inserted element, or the - already-existing element if no insertion happened, and a bool - denoting whether the insertion took place. - - @throw std::domain_error when called on a type other than JSON object or - null; example: `"cannot use emplace() with number"` - - @complexity Logarithmic in the size of the container, O(log(`size()`)). - - @liveexample{The example shows how `emplace()` can be used to add elements - to a JSON object. Note how the `null` value was silently converted to a - JSON object. Further note how no value is added if there was already one - value stored with the same key.,emplace} - - @since version 2.0.8 - */ - template - std::pair emplace(Args&& ... args) - { - // emplace only works for null objects or arrays - if (not(is_null() or is_object())) - { - throw std::domain_error("cannot use emplace() with " + type_name()); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to array (perfect forwarding) - auto res = m_value.object->emplace(std::forward(args)...); - // create result iterator and set iterator to the result of emplace - auto it = begin(); - it.m_it.object_iterator = res.first; - - // return pair of iterator and boolean - return {it, res.second}; - } - - /*! - @brief inserts element - - Inserts element @a val before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] val element to insert - @return iterator pointing to the inserted @a val. - - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` - - @complexity Constant plus linear in the distance between pos and end of the - container. - - @liveexample{The example shows how `insert()` is used.,insert} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, const basic_json& val) - { - // insert only works for arrays - if (is_array()) - { - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - throw std::domain_error("iterator does not fit current value"); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; - } - else - { - throw std::domain_error("cannot use insert() with " + type_name()); - } - } - - /*! - @brief inserts element - @copydoc insert(const_iterator, const basic_json&) - */ - iterator insert(const_iterator pos, basic_json&& val) - { - return insert(pos, val); - } - - /*! - @brief inserts elements - - Inserts @a cnt copies of @a val before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] cnt number of copies of @a val to insert - @param[in] val element to insert - @return iterator pointing to the first element inserted, or @a pos if - `cnt==0` - - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` - - @complexity Linear in @a cnt plus linear in the distance between @a pos - and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__count} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, size_type cnt, const basic_json& val) - { - // insert only works for arrays - if (is_array()) - { - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - throw std::domain_error("iterator does not fit current value"); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; - } - else - { - throw std::domain_error("cannot use insert() with " + type_name()); - } - } - - /*! - @brief inserts elements - - Inserts elements from range `[first, last)` before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] first begin of the range of elements to insert - @param[in] last end of the range of elements to insert - - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` - @throw std::domain_error if @a first and @a last do not belong to the same - JSON value; example: `"iterators do not fit"` - @throw std::domain_error if @a first or @a last are iterators into - container for which insert is called; example: `"passed iterators may not - belong to container"` - - @return iterator pointing to the first element inserted, or @a pos if - `first==last` - - @complexity Linear in `std::distance(first, last)` plus linear in the - distance between @a pos and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__range} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, const_iterator first, const_iterator last) - { - // insert only works for arrays - if (not is_array()) - { - throw std::domain_error("cannot use insert() with " + type_name()); - } - - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - throw std::domain_error("iterator does not fit current value"); - } - - // check if range iterators belong to the same JSON object - if (first.m_object != last.m_object) - { - throw std::domain_error("iterators do not fit"); - } - - if (first.m_object == this or last.m_object == this) - { - throw std::domain_error("passed iterators may not belong to container"); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; - } - - /*! - @brief inserts elements - - Inserts elements from initializer list @a ilist before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] ilist initializer list to insert the values from - - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` - - @return iterator pointing to the first element inserted, or @a pos if - `ilist` is empty - - @complexity Linear in `ilist.size()` plus linear in the distance between - @a pos and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__ilist} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, std::initializer_list ilist) - { - // insert only works for arrays - if (not is_array()) - { - throw std::domain_error("cannot use insert() with " + type_name()); - } - - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - throw std::domain_error("iterator does not fit current value"); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); - return result; - } - - /*! - @brief exchanges the values - - Exchanges the contents of the JSON value with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other JSON value to exchange the contents with - - @complexity Constant. - - @liveexample{The example below shows how JSON values can be swapped with - `swap()`.,swap__reference} - - @since version 1.0.0 - */ - void swap(reference other) noexcept ( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) - { - std::swap(m_type, other.m_type); - std::swap(m_value, other.m_value); - assert_invariant(); - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON array with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other array to exchange the contents with - - @throw std::domain_error when JSON value is not an array; example: `"cannot - use swap() with string"` - - @complexity Constant. - - @liveexample{The example below shows how arrays can be swapped with - `swap()`.,swap__array_t} - - @since version 1.0.0 - */ - void swap(array_t& other) - { - // swap only works for arrays - if (is_array()) - { - std::swap(*(m_value.array), other); - } - else - { - throw std::domain_error("cannot use swap() with " + type_name()); - } - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON object with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other object to exchange the contents with - - @throw std::domain_error when JSON value is not an object; example: - `"cannot use swap() with string"` - - @complexity Constant. - - @liveexample{The example below shows how objects can be swapped with - `swap()`.,swap__object_t} - - @since version 1.0.0 - */ - void swap(object_t& other) - { - // swap only works for objects - if (is_object()) - { - std::swap(*(m_value.object), other); - } - else - { - throw std::domain_error("cannot use swap() with " + type_name()); - } - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON string with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other string to exchange the contents with - - @throw std::domain_error when JSON value is not a string; example: `"cannot - use swap() with boolean"` - - @complexity Constant. - - @liveexample{The example below shows how strings can be swapped with - `swap()`.,swap__string_t} - - @since version 1.0.0 - */ - void swap(string_t& other) - { - // swap only works for strings - if (is_string()) - { - std::swap(*(m_value.string), other); - } - else - { - throw std::domain_error("cannot use swap() with " + type_name()); - } - } - - /// @} - - - ////////////////////////////////////////// - // lexicographical comparison operators // - ////////////////////////////////////////// - - /// @name lexicographical comparison operators - /// @{ - - private: - /*! - @brief comparison operator for JSON types - - Returns an ordering that is similar to Python: - - order: null < boolean < number < object < array < string - - furthermore, each type is not smaller than itself - - @since version 1.0.0 - */ - friend bool operator<(const value_t lhs, const value_t rhs) noexcept - { - static constexpr std::array order = {{ - 0, // null - 3, // object - 4, // array - 5, // string - 1, // boolean - 2, // integer - 2, // unsigned - 2, // float - } - }; - - // discarded values are not comparable - if (lhs == value_t::discarded or rhs == value_t::discarded) - { - return false; - } - - return order[static_cast(lhs)] < order[static_cast(rhs)]; - } - - public: - /*! - @brief comparison: equal - - Compares two JSON values for equality according to the following rules: - - Two JSON values are equal if (1) they are from the same type and (2) - their stored values are the same. - - Integer and floating-point numbers are automatically converted before - comparison. Floating-point numbers are compared indirectly: two - floating-point numbers `f1` and `f2` are considered equal if neither - `f1 > f2` nor `f2 > f1` holds. - - Two JSON null values are equal. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether the values @a lhs and @a rhs are equal - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__equal} - - @since version 1.0.0 - */ - friend bool operator==(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - { - return *lhs.m_value.array == *rhs.m_value.array; - } - case value_t::object: - { - return *lhs.m_value.object == *rhs.m_value.object; - } - case value_t::null: - { - return true; - } - case value_t::string: - { - return *lhs.m_value.string == *rhs.m_value.string; - } - case value_t::boolean: - { - return lhs.m_value.boolean == rhs.m_value.boolean; - } - case value_t::number_integer: - { - return lhs.m_value.number_integer == rhs.m_value.number_integer; - } - case value_t::number_unsigned: - { - return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; - } - case value_t::number_float: - { - return lhs.m_value.number_float == rhs.m_value.number_float; - } - default: - { - return false; - } - } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); - } - - return false; - } - - /*! - @brief comparison: equal - - The functions compares the given JSON value against a null pointer. As the - null pointer can be used to initialize a JSON value to null, a comparison - of JSON value @a v with a null pointer should be equivalent to call - `v.is_null()`. - - @param[in] v JSON value to consider - @return whether @a v is null - - @complexity Constant. - - @liveexample{The example compares several JSON types to the null pointer. - ,operator__equal__nullptr_t} - - @since version 1.0.0 - */ - friend bool operator==(const_reference v, std::nullptr_t) noexcept - { - return v.is_null(); - } - - /*! - @brief comparison: equal - @copydoc operator==(const_reference, std::nullptr_t) - */ - friend bool operator==(std::nullptr_t, const_reference v) noexcept - { - return v.is_null(); - } - - /*! - @brief comparison: not equal - - Compares two JSON values for inequality by calculating `not (lhs == rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether the values @a lhs and @a rhs are not equal - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__notequal} - - @since version 1.0.0 - */ - friend bool operator!=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs == rhs); - } - - /*! - @brief comparison: not equal - - The functions compares the given JSON value against a null pointer. As the - null pointer can be used to initialize a JSON value to null, a comparison - of JSON value @a v with a null pointer should be equivalent to call - `not v.is_null()`. - - @param[in] v JSON value to consider - @return whether @a v is not null - - @complexity Constant. - - @liveexample{The example compares several JSON types to the null pointer. - ,operator__notequal__nullptr_t} - - @since version 1.0.0 - */ - friend bool operator!=(const_reference v, std::nullptr_t) noexcept - { - return not v.is_null(); - } - - /*! - @brief comparison: not equal - @copydoc operator!=(const_reference, std::nullptr_t) - */ - friend bool operator!=(std::nullptr_t, const_reference v) noexcept - { - return not v.is_null(); - } - - /*! - @brief comparison: less than - - Compares whether one JSON value @a lhs is less than another JSON value @a - rhs according to the following rules: - - If @a lhs and @a rhs have the same type, the values are compared using - the default `<` operator. - - Integer and floating-point numbers are automatically converted before - comparison - - In case @a lhs and @a rhs have different types, the values are ignored - and the order of the types is considered, see - @ref operator<(const value_t, const value_t). - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is less than @a rhs - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__less} - - @since version 1.0.0 - */ - friend bool operator<(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - { - return *lhs.m_value.array < *rhs.m_value.array; - } - case value_t::object: - { - return *lhs.m_value.object < *rhs.m_value.object; - } - case value_t::null: - { - return false; - } - case value_t::string: - { - return *lhs.m_value.string < *rhs.m_value.string; - } - case value_t::boolean: - { - return lhs.m_value.boolean < rhs.m_value.boolean; - } - case value_t::number_integer: - { - return lhs.m_value.number_integer < rhs.m_value.number_integer; - } - case value_t::number_unsigned: - { - return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; - } - case value_t::number_float: - { - return lhs.m_value.number_float < rhs.m_value.number_float; - } - default: - { - return false; - } - } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; - } - - // We only reach this line if we cannot compare values. In that case, - // we compare types. Note we have to call the operator explicitly, - // because MSVC has problems otherwise. - return operator<(lhs_type, rhs_type); - } - - /*! - @brief comparison: less than or equal - - Compares whether one JSON value @a lhs is less than or equal to another - JSON value by calculating `not (rhs < lhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is less than or equal to @a rhs - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__greater} - - @since version 1.0.0 - */ - friend bool operator<=(const_reference lhs, const_reference rhs) noexcept - { - return not (rhs < lhs); - } - - /*! - @brief comparison: greater than - - Compares whether one JSON value @a lhs is greater than another - JSON value by calculating `not (lhs <= rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is greater than to @a rhs - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__lessequal} - - @since version 1.0.0 - */ - friend bool operator>(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs <= rhs); - } - - /*! - @brief comparison: greater than or equal - - Compares whether one JSON value @a lhs is greater than or equal to another - JSON value by calculating `not (lhs < rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is greater than or equal to @a rhs - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__greaterequal} - - @since version 1.0.0 - */ - friend bool operator>=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs < rhs); - } - - /// @} - - - /////////////////// - // serialization // - /////////////////// - - /// @name serialization - /// @{ - - /*! - @brief serialize to stream - - Serialize the given JSON value @a j to the output stream @a o. The JSON - value will be serialized using the @ref dump member function. The - indentation of the output can be controlled with the member variable - `width` of the output stream @a o. For instance, using the manipulator - `std::setw(4)` on @a o sets the indentation level to `4` and the - serialization result is the same as calling `dump(4)`. - - @note During serializaion, the locale and the precision of the output - stream @a o are changed. The original values are restored when the - function returns. - - @param[in,out] o stream to serialize to - @param[in] j JSON value to serialize - - @return the stream @a o - - @complexity Linear. - - @liveexample{The example below shows the serialization with different - parameters to `width` to adjust the indentation level.,operator_serialize} - - @since version 1.0.0 - */ - friend std::ostream& operator<<(std::ostream& o, const basic_json& j) - { - // read width member and use it as indentation parameter if nonzero - const bool pretty_print = (o.width() > 0); - const auto indentation = (pretty_print ? o.width() : 0); - - // reset width to 0 for subsequent calls to this stream - o.width(0); - - // fix locale problems - const auto old_locale = o.imbue(std::locale::classic()); - // set precision - - // 6, 15 or 16 digits of precision allows round-trip IEEE 754 - // string->float->string, string->double->string or string->long - // double->string; to be safe, we read this value from - // std::numeric_limits::digits10 - const auto old_precision = o.precision(std::numeric_limits::digits10); - - // do the actual serialization - j.dump(o, pretty_print, static_cast(indentation)); - - // reset locale and precision - o.imbue(old_locale); - o.precision(old_precision); - return o; - } - - /*! - @brief serialize to stream - @copydoc operator<<(std::ostream&, const basic_json&) - */ - friend std::ostream& operator>>(const basic_json& j, std::ostream& o) - { - return o << j; - } - - /// @} - - - ///////////////////// - // deserialization // - ///////////////////// - - /// @name deserialization - /// @{ - - /*! - @brief deserialize from an array - - This function reads from an array of 1-byte values. - - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @param[in] array array to read from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an array.,parse__array__parser_callback_t} - - @since version 2.0.3 - */ - template - static basic_json parse(T (&array)[N], - const parser_callback_t cb = nullptr) - { - // delegate the call to the iterator-range parse overload - return parse(std::begin(array), std::end(array), cb); - } - - /*! - @brief deserialize from string literal - - @tparam CharT character/literal type with size of 1 byte - @param[in] s string literal to read a serialized JSON value from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - @note String containers like `std::string` or @ref string_t can be parsed - with @ref parse(const ContiguousContainer&, const parser_callback_t) - - @liveexample{The example below demonstrates the `parse()` function with - and without callback function.,parse__string__parser_callback_t} - - @sa @ref parse(std::istream&, const parser_callback_t) for a version that - reads from an input stream - - @since version 1.0.0 (originally for @ref string_t) - */ - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> - static basic_json parse(const CharT s, - const parser_callback_t cb = nullptr) - { - return parser(reinterpret_cast(s), cb).parse(); - } - - /*! - @brief deserialize from stream - - @param[in,out] i stream to read a serialized JSON value from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function with - and without callback function.,parse__istream__parser_callback_t} - - @sa @ref parse(const CharT, const parser_callback_t) for a version - that reads from a string - - @since version 1.0.0 - */ - static basic_json parse(std::istream& i, - const parser_callback_t cb = nullptr) - { - return parser(i, cb).parse(); - } - - /*! - @copydoc parse(std::istream&, const parser_callback_t) - */ - static basic_json parse(std::istream&& i, - const parser_callback_t cb = nullptr) - { - return parser(i, cb).parse(); - } - - /*! - @brief deserialize from an iterator range with contiguous storage - - This function reads from an iterator range of a container with contiguous - storage of 1-byte values. Compatible container types include - `std::vector`, `std::string`, `std::array`, `std::valarray`, and - `std::initializer_list`. Furthermore, C-style arrays can be used with - `std::begin()`/`std::end()`. User-defined containers can be used as long - as they implement random-access iterators and a contiguous storage. - - @pre The iterator range is contiguous. Violating this precondition yields - undefined behavior. **This precondition is enforced with an assertion.** - @pre Each element in the range has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with noncompliant iterators and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @tparam IteratorType iterator of container with contiguous storage - @param[in] first begin of the range to parse (included) - @param[in] last end of the range to parse (excluded) - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an iterator range.,parse__iteratortype__parser_callback_t} - - @since version 2.0.3 - */ - template::iterator_category>::value, int>::type = 0> - static basic_json parse(IteratorType first, IteratorType last, - const parser_callback_t cb = nullptr) - { - // assertion to check that the iterator range is indeed contiguous, - // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate(first, last, std::make_pair(true, 0), - [&first](std::pair res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first); - - // assertion to check that each element is 1 byte long - static_assert(sizeof(typename std::iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - // if iterator range is empty, create a parser with an empty string - // to generate "unexpected EOF" error message - if (std::distance(first, last) <= 0) - { - return parser("").parse(); - } - - return parser(first, last, cb).parse(); - } - - /*! - @brief deserialize from a container with contiguous storage - - This function reads from a container with contiguous storage of 1-byte - values. Compatible container types include `std::vector`, `std::string`, - `std::array`, and `std::initializer_list`. User-defined containers can be - used as long as they implement random-access iterators and a contiguous - storage. - - @pre The container storage is contiguous. Violating this precondition - yields undefined behavior. **This precondition is enforced with an - assertion.** - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with a noncompliant container and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @tparam ContiguousContainer container type with contiguous storage - @param[in] c container to read from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from a contiguous container.,parse__contiguouscontainer__parser_callback_t} - - @since version 2.0.3 - */ - template::value and - std::is_base_of< - std::random_access_iterator_tag, - typename std::iterator_traits()))>::iterator_category>::value - , int>::type = 0> - static basic_json parse(const ContiguousContainer& c, - const parser_callback_t cb = nullptr) - { - // delegate the call to the iterator-range parse overload - return parse(std::begin(c), std::end(c), cb); - } - - /*! - @brief deserialize from stream - - Deserializes an input stream to a JSON value. - - @param[in,out] i input stream to read a serialized JSON value from - @param[in,out] j JSON value to write the deserialized input to - - @throw std::invalid_argument in case of parse errors - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below shows how a JSON value is constructed by - reading a serialization from a stream.,operator_deserialize} - - @sa parse(std::istream&, const parser_callback_t) for a variant with a - parser callback function to filter values while parsing - - @since version 1.0.0 - */ - friend std::istream& operator<<(basic_json& j, std::istream& i) - { - j = parser(i).parse(); - return i; - } - - /*! - @brief deserialize from stream - @copydoc operator<<(basic_json&, std::istream&) - */ - friend std::istream& operator>>(std::istream& i, basic_json& j) - { - j = parser(i).parse(); - return i; - } - - /// @} - - ////////////////////////////////////////// - // binary serialization/deserialization // - ////////////////////////////////////////// - - /// @name binary serialization/deserialization support - /// @{ - - private: - template - static void add_to_vector(std::vector& vec, size_t bytes, const T number) - { - assert(bytes == 1 or bytes == 2 or bytes == 4 or bytes == 8); - - switch (bytes) - { - case 8: - { - vec.push_back(static_cast((number >> 070) & 0xff)); - vec.push_back(static_cast((number >> 060) & 0xff)); - vec.push_back(static_cast((number >> 050) & 0xff)); - vec.push_back(static_cast((number >> 040) & 0xff)); - // intentional fall-through - } - - case 4: - { - vec.push_back(static_cast((number >> 030) & 0xff)); - vec.push_back(static_cast((number >> 020) & 0xff)); - // intentional fall-through - } - - case 2: - { - vec.push_back(static_cast((number >> 010) & 0xff)); - // intentional fall-through - } - - case 1: - { - vec.push_back(static_cast(number & 0xff)); - break; - } - } - } - - /*! - @brief take sufficient bytes from a vector to fill an integer variable - - In the context of binary serialization formats, we need to read several - bytes from a byte vector and combine them to multi-byte integral data - types. - - @param[in] vec byte vector to read from - @param[in] current_index the position in the vector after which to read - - @return the next sizeof(T) bytes from @a vec, in reverse order as T - - @tparam T the integral return type - - @throw std::out_of_range if there are less than sizeof(T)+1 bytes in the - vector @a vec to read - - In the for loop, the bytes from the vector are copied in reverse order into - the return value. In the figures below, let sizeof(T)=4 and `i` be the loop - variable. - - Precondition: - - vec: | | | a | b | c | d | T: | | | | | - ^ ^ ^ ^ - current_index i ptr sizeof(T) - - Postcondition: - - vec: | | | a | b | c | d | T: | d | c | b | a | - ^ ^ ^ - | i ptr - current_index - - @sa Code adapted from . - */ - template - static T get_from_vector(const std::vector& vec, const size_t current_index) - { - if (current_index + sizeof(T) + 1 > vec.size()) - { - throw std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector"); - } - - T result; - uint8_t* ptr = reinterpret_cast(&result); - for (size_t i = 0; i < sizeof(T); ++i) - { - *ptr++ = vec[current_index + sizeof(T) - i]; - } - return result; - } - - /*! - @brief create a MessagePack serialization of a given JSON value - - This is a straightforward implementation of the MessagePack specification. - - @param[in] j JSON value to serialize - @param[in,out] v byte vector to write the serialization to - - @sa https://github.com/msgpack/msgpack/blob/master/spec.md - */ - static void to_msgpack_internal(const basic_json& j, std::vector& v) - { - switch (j.type()) - { - case value_t::null: - { - // nil - v.push_back(0xc0); - break; - } - - case value_t::boolean: - { - // true and false - v.push_back(j.m_value.boolean ? 0xc3 : 0xc2); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // MessagePack does not differentiate between positive - // signed integers and unsigned integers. Therefore, we used - // the code from the value_t::number_unsigned case here. - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - add_to_vector(v, 1, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= UINT8_MAX) - { - // uint 8 - v.push_back(0xcc); - add_to_vector(v, 1, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= UINT16_MAX) - { - // uint 16 - v.push_back(0xcd); - add_to_vector(v, 2, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= UINT32_MAX) - { - // uint 32 - v.push_back(0xce); - add_to_vector(v, 4, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= UINT64_MAX) - { - // uint 64 - v.push_back(0xcf); - add_to_vector(v, 8, j.m_value.number_unsigned); - } - } - else - { - if (j.m_value.number_integer >= -32) - { - // negative fixnum - add_to_vector(v, 1, j.m_value.number_integer); - } - else if (j.m_value.number_integer >= INT8_MIN and j.m_value.number_integer <= INT8_MAX) - { - // int 8 - v.push_back(0xd0); - add_to_vector(v, 1, j.m_value.number_integer); - } - else if (j.m_value.number_integer >= INT16_MIN and j.m_value.number_integer <= INT16_MAX) - { - // int 16 - v.push_back(0xd1); - add_to_vector(v, 2, j.m_value.number_integer); - } - else if (j.m_value.number_integer >= INT32_MIN and j.m_value.number_integer <= INT32_MAX) - { - // int 32 - v.push_back(0xd2); - add_to_vector(v, 4, j.m_value.number_integer); - } - else if (j.m_value.number_integer >= INT64_MIN and j.m_value.number_integer <= INT64_MAX) - { - // int 64 - v.push_back(0xd3); - add_to_vector(v, 8, j.m_value.number_integer); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - add_to_vector(v, 1, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= UINT8_MAX) - { - // uint 8 - v.push_back(0xcc); - add_to_vector(v, 1, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= UINT16_MAX) - { - // uint 16 - v.push_back(0xcd); - add_to_vector(v, 2, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= UINT32_MAX) - { - // uint 32 - v.push_back(0xce); - add_to_vector(v, 4, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= UINT64_MAX) - { - // uint 64 - v.push_back(0xcf); - add_to_vector(v, 8, j.m_value.number_unsigned); - } - break; - } - - case value_t::number_float: - { - // float 64 - v.push_back(0xcb); - const uint8_t* helper = reinterpret_cast(&(j.m_value.number_float)); - for (size_t i = 0; i < 8; ++i) - { - v.push_back(helper[7 - i]); - } - break; - } - - case value_t::string: - { - const auto N = j.m_value.string->size(); - if (N <= 31) - { - // fixstr - v.push_back(static_cast(0xa0 | N)); - } - else if (N <= 255) - { - // str 8 - v.push_back(0xd9); - add_to_vector(v, 1, N); - } - else if (N <= 65535) - { - // str 16 - v.push_back(0xda); - add_to_vector(v, 2, N); - } - else if (N <= 4294967295) - { - // str 32 - v.push_back(0xdb); - add_to_vector(v, 4, N); - } - - // append string - std::copy(j.m_value.string->begin(), j.m_value.string->end(), - std::back_inserter(v)); - break; - } - - case value_t::array: - { - const auto N = j.m_value.array->size(); - if (N <= 15) - { - // fixarray - v.push_back(static_cast(0x90 | N)); - } - else if (N <= 0xffff) - { - // array 16 - v.push_back(0xdc); - add_to_vector(v, 2, N); - } - else if (N <= 0xffffffff) - { - // array 32 - v.push_back(0xdd); - add_to_vector(v, 4, N); - } - - // append each element - for (const auto& el : *j.m_value.array) - { - to_msgpack_internal(el, v); - } - break; - } - - case value_t::object: - { - const auto N = j.m_value.object->size(); - if (N <= 15) - { - // fixmap - v.push_back(static_cast(0x80 | (N & 0xf))); - } - else if (N <= 65535) - { - // map 16 - v.push_back(0xde); - add_to_vector(v, 2, N); - } - else if (N <= 4294967295) - { - // map 32 - v.push_back(0xdf); - add_to_vector(v, 4, N); - } - - // append each element - for (const auto& el : *j.m_value.object) - { - to_msgpack_internal(el.first, v); - to_msgpack_internal(el.second, v); - } - break; - } - - default: - { - break; - } - } - } - - /*! - @brief create a CBOR serialization of a given JSON value - - This is a straightforward implementation of the CBOR specification. - - @param[in] j JSON value to serialize - @param[in,out] v byte vector to write the serialization to - - @sa https://tools.ietf.org/html/rfc7049 - */ - static void to_cbor_internal(const basic_json& j, std::vector& v) - { - switch (j.type()) - { - case value_t::null: - { - v.push_back(0xf6); - break; - } - - case value_t::boolean: - { - v.push_back(j.m_value.boolean ? 0xf5 : 0xf4); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // CBOR does not differentiate between positive signed - // integers and unsigned integers. Therefore, we used the - // code from the value_t::number_unsigned case here. - if (j.m_value.number_integer <= 0x17) - { - add_to_vector(v, 1, j.m_value.number_integer); - } - else if (j.m_value.number_integer <= UINT8_MAX) - { - v.push_back(0x18); - // one-byte uint8_t - add_to_vector(v, 1, j.m_value.number_integer); - } - else if (j.m_value.number_integer <= UINT16_MAX) - { - v.push_back(0x19); - // two-byte uint16_t - add_to_vector(v, 2, j.m_value.number_integer); - } - else if (j.m_value.number_integer <= UINT32_MAX) - { - v.push_back(0x1a); - // four-byte uint32_t - add_to_vector(v, 4, j.m_value.number_integer); - } - else - { - v.push_back(0x1b); - // eight-byte uint64_t - add_to_vector(v, 8, j.m_value.number_integer); - } - } - else - { - // The conversions below encode the sign in the first byte, - // and the value is converted to a positive number. - const auto positive_number = -1 - j.m_value.number_integer; - if (j.m_value.number_integer >= -24) - { - v.push_back(static_cast(0x20 + positive_number)); - } - else if (positive_number <= UINT8_MAX) - { - // int 8 - v.push_back(0x38); - add_to_vector(v, 1, positive_number); - } - else if (positive_number <= UINT16_MAX) - { - // int 16 - v.push_back(0x39); - add_to_vector(v, 2, positive_number); - } - else if (positive_number <= UINT32_MAX) - { - // int 32 - v.push_back(0x3a); - add_to_vector(v, 4, positive_number); - } - else - { - // int 64 - v.push_back(0x3b); - add_to_vector(v, 8, positive_number); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned <= 0x17) - { - v.push_back(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= 0xff) - { - v.push_back(0x18); - // one-byte uint8_t - add_to_vector(v, 1, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= 0xffff) - { - v.push_back(0x19); - // two-byte uint16_t - add_to_vector(v, 2, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= 0xffffffff) - { - v.push_back(0x1a); - // four-byte uint32_t - add_to_vector(v, 4, j.m_value.number_unsigned); - } - else if (j.m_value.number_unsigned <= 0xffffffffffffffff) - { - v.push_back(0x1b); - // eight-byte uint64_t - add_to_vector(v, 8, j.m_value.number_unsigned); - } - break; - } - - case value_t::number_float: - { - // Double-Precision Float - v.push_back(0xfb); - const uint8_t* helper = reinterpret_cast(&(j.m_value.number_float)); - for (size_t i = 0; i < 8; ++i) - { - v.push_back(helper[7 - i]); - } - break; - } - - case value_t::string: - { - const auto N = j.m_value.string->size(); - if (N <= 0x17) - { - v.push_back(0x60 + N); // 1 byte for string + size - } - else if (N <= 0xff) - { - v.push_back(0x78); // one-byte uint8_t for N - add_to_vector(v, 1, N); - } - else if (N <= 0xffff) - { - v.push_back(0x79); // two-byte uint16_t for N - add_to_vector(v, 2, N); - } - else if (N <= 0xffffffff) - { - v.push_back(0x7a); // four-byte uint32_t for N - add_to_vector(v, 4, N); - } - // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) - { - v.push_back(0x7b); // eight-byte uint64_t for N - add_to_vector(v, 8, N); - } - // LCOV_EXCL_STOP - - // append string - std::copy(j.m_value.string->begin(), j.m_value.string->end(), - std::back_inserter(v)); - break; - } - - case value_t::array: - { - const auto N = j.m_value.array->size(); - if (N <= 0x17) - { - v.push_back(0x80 + N); // 1 byte for array + size - } - else if (N <= 0xff) - { - v.push_back(0x98); // one-byte uint8_t for N - add_to_vector(v, 1, N); - } - else if (N <= 0xffff) - { - v.push_back(0x99); // two-byte uint16_t for N - add_to_vector(v, 2, N); - } - else if (N <= 0xffffffff) - { - v.push_back(0x9a); // four-byte uint32_t for N - add_to_vector(v, 4, N); - } - // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) - { - v.push_back(0x9b); // eight-byte uint64_t for N - add_to_vector(v, 8, N); - } - // LCOV_EXCL_STOP - - // append each element - for (const auto& el : *j.m_value.array) - { - to_cbor_internal(el, v); - } - break; - } - - case value_t::object: - { - const auto N = j.m_value.object->size(); - if (N <= 0x17) - { - v.push_back(0xa0 + N); // 1 byte for object + size - } - else if (N <= 0xff) - { - v.push_back(0xb8); - add_to_vector(v, 1, N); // one-byte uint8_t for N - } - else if (N <= 0xffff) - { - v.push_back(0xb9); - add_to_vector(v, 2, N); // two-byte uint16_t for N - } - else if (N <= 0xffffffff) - { - v.push_back(0xba); - add_to_vector(v, 4, N); // four-byte uint32_t for N - } - // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) - { - v.push_back(0xbb); - add_to_vector(v, 8, N); // eight-byte uint64_t for N - } - // LCOV_EXCL_STOP - - // append each element - for (const auto& el : *j.m_value.object) - { - to_cbor_internal(el.first, v); - to_cbor_internal(el.second, v); - } - break; - } - - default: - { - break; - } - } - } - - - /* - @brief checks if given lengths do not exceed the size of a given vector - - To secure the access to the byte vector during CBOR/MessagePack - deserialization, bytes are copied from the vector into buffers. This - function checks if the number of bytes to copy (@a len) does not exceed the - size @s size of the vector. Additionally, an @a offset is given from where - to start reading the bytes. - - This function checks whether reading the bytes is safe; that is, offset is a - valid index in the vector, offset+len - - @param[in] size size of the byte vector - @param[in] len number of bytes to read - @param[in] offset offset where to start reading - - vec: x x x x x X X X X X - ^ ^ ^ - 0 offset len - - @throws out_of_range if `len > v.size()` - */ - static void check_length(const size_t size, const size_t len, const size_t offset) - { - // simple case: requested length is greater than the vector's length - if (len > size or offset > size) - { - throw std::out_of_range("len out of range"); - } - - // second case: adding offset would result in overflow - if ((size > (std::numeric_limits::max() - offset))) - { - throw std::out_of_range("len+offset out of range"); - } - - // last case: reading past the end of the vector - if (len + offset > size) - { - throw std::out_of_range("len+offset out of range"); - } - } - - /*! - @brief create a JSON value from a given MessagePack vector - - @param[in] v MessagePack serialization - @param[in] idx byte index to start reading from @a v - - @return deserialized JSON value - - @throw std::invalid_argument if unsupported features from MessagePack were - used in the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely - - @sa https://github.com/msgpack/msgpack/blob/master/spec.md - */ - static basic_json from_msgpack_internal(const std::vector& v, size_t& idx) - { - // make sure reading 1 byte is safe - check_length(v.size(), 1, idx); - - // store and increment index - const size_t current_idx = idx++; - - if (v[current_idx] <= 0xbf) - { - if (v[current_idx] <= 0x7f) // positive fixint - { - return v[current_idx]; - } - else if (v[current_idx] <= 0x8f) // fixmap - { - basic_json result = value_t::object; - const size_t len = v[current_idx] & 0x0f; - for (size_t i = 0; i < len; ++i) - { - std::string key = from_msgpack_internal(v, idx); - result[key] = from_msgpack_internal(v, idx); - } - return result; - } - else if (v[current_idx] <= 0x9f) // fixarray - { - basic_json result = value_t::array; - const size_t len = v[current_idx] & 0x0f; - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_msgpack_internal(v, idx)); - } - return result; - } - else // fixstr - { - const size_t len = v[current_idx] & 0x1f; - const size_t offset = current_idx + 1; - idx += len; // skip content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast(v.data()) + offset, len); - } - } - else if (v[current_idx] >= 0xe0) // negative fixint - { - return static_cast(v[current_idx]); - } - else - { - switch (v[current_idx]) - { - case 0xc0: // nil - { - return value_t::null; - } - - case 0xc2: // false - { - return false; - } - - case 0xc3: // true - { - return true; - } - - case 0xca: // float 32 - { - // copy bytes in reverse order into the double variable - check_length(v.size(), sizeof(float), 1); - float res; - for (size_t byte = 0; byte < sizeof(float); ++byte) - { - reinterpret_cast(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte]; - } - idx += sizeof(float); // skip content bytes - return res; - } - - case 0xcb: // float 64 - { - // copy bytes in reverse order into the double variable - check_length(v.size(), sizeof(double), 1); - double res; - for (size_t byte = 0; byte < sizeof(double); ++byte) - { - reinterpret_cast(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte]; - } - idx += sizeof(double); // skip content bytes - return res; - } - - case 0xcc: // uint 8 - { - idx += 1; // skip content byte - return get_from_vector(v, current_idx); - } - - case 0xcd: // uint 16 - { - idx += 2; // skip 2 content bytes - return get_from_vector(v, current_idx); - } - - case 0xce: // uint 32 - { - idx += 4; // skip 4 content bytes - return get_from_vector(v, current_idx); - } - - case 0xcf: // uint 64 - { - idx += 8; // skip 8 content bytes - return get_from_vector(v, current_idx); - } - - case 0xd0: // int 8 - { - idx += 1; // skip content byte - return get_from_vector(v, current_idx); - } - - case 0xd1: // int 16 - { - idx += 2; // skip 2 content bytes - return get_from_vector(v, current_idx); - } - - case 0xd2: // int 32 - { - idx += 4; // skip 4 content bytes - return get_from_vector(v, current_idx); - } - - case 0xd3: // int 64 - { - idx += 8; // skip 8 content bytes - return get_from_vector(v, current_idx); - } - - case 0xd9: // str 8 - { - const auto len = static_cast(get_from_vector(v, current_idx)); - const size_t offset = current_idx + 2; - idx += len + 1; // skip size byte + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast(v.data()) + offset, len); - } - - case 0xda: // str 16 - { - const auto len = static_cast(get_from_vector(v, current_idx)); - const size_t offset = current_idx + 3; - idx += len + 2; // skip 2 size bytes + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast(v.data()) + offset, len); - } - - case 0xdb: // str 32 - { - const auto len = static_cast(get_from_vector(v, current_idx)); - const size_t offset = current_idx + 5; - idx += len + 4; // skip 4 size bytes + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast(v.data()) + offset, len); - } - - case 0xdc: // array 16 - { - basic_json result = value_t::array; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 2; // skip 2 size bytes - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_msgpack_internal(v, idx)); - } - return result; - } - - case 0xdd: // array 32 - { - basic_json result = value_t::array; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 4; // skip 4 size bytes - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_msgpack_internal(v, idx)); - } - return result; - } - - case 0xde: // map 16 - { - basic_json result = value_t::object; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 2; // skip 2 size bytes - for (size_t i = 0; i < len; ++i) - { - std::string key = from_msgpack_internal(v, idx); - result[key] = from_msgpack_internal(v, idx); - } - return result; - } - - case 0xdf: // map 32 - { - basic_json result = value_t::object; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 4; // skip 4 size bytes - for (size_t i = 0; i < len; ++i) - { - std::string key = from_msgpack_internal(v, idx); - result[key] = from_msgpack_internal(v, idx); - } - return result; - } - - default: - { - throw std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx]))); - } - } - } - } - - /*! - @brief create a JSON value from a given CBOR vector - - @param[in] v CBOR serialization - @param[in] idx byte index to start reading from @a v - - @return deserialized JSON value - - @throw std::invalid_argument if unsupported features from CBOR were used in - the given vector @a v or if the input is not valid CBOR - @throw std::out_of_range if the given vector ends prematurely - - @sa https://tools.ietf.org/html/rfc7049 - */ - static basic_json from_cbor_internal(const std::vector& v, size_t& idx) - { - // store and increment index - const size_t current_idx = idx++; - - switch (v.at(current_idx)) - { - // Integer 0x00..0x17 (0..23) - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - { - return v[current_idx]; - } - - case 0x18: // Unsigned integer (one-byte uint8_t follows) - { - idx += 1; // skip content byte - return get_from_vector(v, current_idx); - } - - case 0x19: // Unsigned integer (two-byte uint16_t follows) - { - idx += 2; // skip 2 content bytes - return get_from_vector(v, current_idx); - } - - case 0x1a: // Unsigned integer (four-byte uint32_t follows) - { - idx += 4; // skip 4 content bytes - return get_from_vector(v, current_idx); - } - - case 0x1b: // Unsigned integer (eight-byte uint64_t follows) - { - idx += 8; // skip 8 content bytes - return get_from_vector(v, current_idx); - } - - // Negative integer -1-0x00..-1-0x17 (-1..-24) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2a: - case 0x2b: - case 0x2c: - case 0x2d: - case 0x2e: - case 0x2f: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - { - return static_cast(0x20 - 1 - v[current_idx]); - } - - case 0x38: // Negative integer (one-byte uint8_t follows) - { - idx += 1; // skip content byte - // must be uint8_t ! - return static_cast(-1) - get_from_vector(v, current_idx); - } - - case 0x39: // Negative integer -1-n (two-byte uint16_t follows) - { - idx += 2; // skip 2 content bytes - return static_cast(-1) - get_from_vector(v, current_idx); - } - - case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) - { - idx += 4; // skip 4 content bytes - return static_cast(-1) - get_from_vector(v, current_idx); - } - - case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) - { - idx += 8; // skip 8 content bytes - return static_cast(-1) - static_cast(get_from_vector(v, current_idx)); - } - - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - { - const auto len = static_cast(v[current_idx] - 0x60); - const size_t offset = current_idx + 1; - idx += len; // skip content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast(v.data()) + offset, len); - } - - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - { - const auto len = static_cast(get_from_vector(v, current_idx)); - const size_t offset = current_idx + 2; - idx += len + 1; // skip size byte + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast(v.data()) + offset, len); - } - - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - { - const auto len = static_cast(get_from_vector(v, current_idx)); - const size_t offset = current_idx + 3; - idx += len + 2; // skip 2 size bytes + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast(v.data()) + offset, len); - } - - case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) - { - const auto len = static_cast(get_from_vector(v, current_idx)); - const size_t offset = current_idx + 5; - idx += len + 4; // skip 4 size bytes + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast(v.data()) + offset, len); - } - - case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) - { - const auto len = static_cast(get_from_vector(v, current_idx)); - const size_t offset = current_idx + 9; - idx += len + 8; // skip 8 size bytes + content bytes - check_length(v.size(), len, offset); - return std::string(reinterpret_cast(v.data()) + offset, len); - } - - case 0x7f: // UTF-8 string (indefinite length) - { - std::string result; - while (v.at(idx) != 0xff) - { - string_t s = from_cbor_internal(v, idx); - result += s; - } - // skip break byte (0xFF) - idx += 1; - return result; - } - - // array (0x00..0x17 data items follow) - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8a: - case 0x8b: - case 0x8c: - case 0x8d: - case 0x8e: - case 0x8f: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - { - basic_json result = value_t::array; - const auto len = static_cast(v[current_idx] - 0x80); - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_cbor_internal(v, idx)); - } - return result; - } - - case 0x98: // array (one-byte uint8_t for n follows) - { - basic_json result = value_t::array; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 1; // skip 1 size byte - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_cbor_internal(v, idx)); - } - return result; - } - - case 0x99: // array (two-byte uint16_t for n follow) - { - basic_json result = value_t::array; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 2; // skip 4 size bytes - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_cbor_internal(v, idx)); - } - return result; - } - - case 0x9a: // array (four-byte uint32_t for n follow) - { - basic_json result = value_t::array; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 4; // skip 4 size bytes - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_cbor_internal(v, idx)); - } - return result; - } - - case 0x9b: // array (eight-byte uint64_t for n follow) - { - basic_json result = value_t::array; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 8; // skip 8 size bytes - for (size_t i = 0; i < len; ++i) - { - result.push_back(from_cbor_internal(v, idx)); - } - return result; - } - - case 0x9f: // array (indefinite length) - { - basic_json result = value_t::array; - while (v.at(idx) != 0xff) - { - result.push_back(from_cbor_internal(v, idx)); - } - // skip break byte (0xFF) - idx += 1; - return result; - } - - // map (0x00..0x17 pairs of data items follow) - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - case 0xa8: - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: - case 0xaf: - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - { - basic_json result = value_t::object; - const auto len = static_cast(v[current_idx] - 0xa0); - for (size_t i = 0; i < len; ++i) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - return result; - } - - case 0xb8: // map (one-byte uint8_t for n follows) - { - basic_json result = value_t::object; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 1; // skip 1 size byte - for (size_t i = 0; i < len; ++i) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - return result; - } - - case 0xb9: // map (two-byte uint16_t for n follow) - { - basic_json result = value_t::object; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 2; // skip 2 size bytes - for (size_t i = 0; i < len; ++i) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - return result; - } - - case 0xba: // map (four-byte uint32_t for n follow) - { - basic_json result = value_t::object; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 4; // skip 4 size bytes - for (size_t i = 0; i < len; ++i) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - return result; - } - - case 0xbb: // map (eight-byte uint64_t for n follow) - { - basic_json result = value_t::object; - const auto len = static_cast(get_from_vector(v, current_idx)); - idx += 8; // skip 8 size bytes - for (size_t i = 0; i < len; ++i) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - return result; - } - - case 0xbf: // map (indefinite length) - { - basic_json result = value_t::object; - while (v.at(idx) != 0xff) - { - std::string key = from_cbor_internal(v, idx); - result[key] = from_cbor_internal(v, idx); - } - // skip break byte (0xFF) - idx += 1; - return result; - } - - case 0xf4: // false - { - return false; - } - - case 0xf5: // true - { - return true; - } - - case 0xf6: // null - { - return value_t::null; - } - - case 0xf9: // Half-Precision Float (two-byte IEEE 754) - { - check_length(v.size(), 2, 1); - idx += 2; // skip two content bytes - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added to - // IEEE 754 in 2008, today's programming platforms often still - // only have limited support for them. It is very easy to - // include at least decoding support for them even without such - // support. An example of a small decoder for half-precision - // floating-point numbers in the C language is shown in Fig. 3. - const int half = (v[current_idx + 1] << 8) + v[current_idx + 2]; - const int exp = (half >> 10) & 0x1f; - const int mant = half & 0x3ff; - double val; - if (exp == 0) - { - val = std::ldexp(mant, -24); - } - else if (exp != 31) - { - val = std::ldexp(mant + 1024, exp - 25); - } - else - { - val = mant == 0 ? INFINITY : NAN; - } - return half & 0x8000 ? -val : val; - } - - case 0xfa: // Single-Precision Float (four-byte IEEE 754) - { - // copy bytes in reverse order into the float variable - check_length(v.size(), sizeof(float), 1); - float res; - for (size_t byte = 0; byte < sizeof(float); ++byte) - { - reinterpret_cast(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte]; - } - idx += sizeof(float); // skip content bytes - return res; - } - - case 0xfb: // Double-Precision Float (eight-byte IEEE 754) - { - check_length(v.size(), sizeof(double), 1); - // copy bytes in reverse order into the double variable - double res; - for (size_t byte = 0; byte < sizeof(double); ++byte) - { - reinterpret_cast(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte]; - } - idx += sizeof(double); // skip content bytes - return res; - } - - default: // anything else (0xFF is handled inside the other types) - { - throw std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx]))); - } - } - } - - public: - /*! - @brief create a MessagePack serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the MessagePack - serialization format. MessagePack is a binary serialization format which - aims to be more compact than JSON itself, yet more efficient to parse. - - @param[in] j JSON value to serialize - @return MessagePack serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in MessagePack format.,to_msgpack} - - @sa http://msgpack.org - @sa @ref from_msgpack(const std::vector&) for the analogous - deserialization - @sa @ref to_cbor(const basic_json& for the related CBOR format - */ - static std::vector to_msgpack(const basic_json& j) - { - std::vector result; - to_msgpack_internal(j, result); - return result; - } - - /*! - @brief create a JSON value from a byte vector in MessagePack format - - Deserializes a given byte vector @a v to a JSON value using the MessagePack - serialization format. - - @param[in] v a byte vector in MessagePack format - @return deserialized JSON value - - @throw std::invalid_argument if unsupported features from MessagePack were - used in the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely - - @complexity Linear in the size of the byte vector @a v. - - @liveexample{The example shows the deserialization of a byte vector in - MessagePack format to a JSON value.,from_msgpack} - - @sa http://msgpack.org - @sa @ref to_msgpack(const basic_json&) for the analogous serialization - @sa @ref from_cbor(const std::vector&) for the related CBOR format - */ - static basic_json from_msgpack(const std::vector& v) - { - size_t i = 0; - return from_msgpack_internal(v, i); - } - - /*! - @brief create a MessagePack serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the CBOR (Concise - Binary Object Representation) serialization format. CBOR is a binary - serialization format which aims to be more compact than JSON itself, yet - more efficient to parse. - - @param[in] j JSON value to serialize - @return MessagePack serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in CBOR format.,to_cbor} - - @sa http://cbor.io - @sa @ref from_cbor(const std::vector&) for the analogous - deserialization - @sa @ref to_msgpack(const basic_json& for the related MessagePack format - */ - static std::vector to_cbor(const basic_json& j) - { - std::vector result; - to_cbor_internal(j, result); - return result; - } - - /*! - @brief create a JSON value from a byte vector in CBOR format - - Deserializes a given byte vector @a v to a JSON value using the CBOR - (Concise Binary Object Representation) serialization format. - - @param[in] v a byte vector in CBOR format - @return deserialized JSON value - - @throw std::invalid_argument if unsupported features from CBOR were used in - the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely - - @complexity Linear in the size of the byte vector @a v. - - @liveexample{The example shows the deserialization of a byte vector in CBOR - format to a JSON value.,from_cbor} - - @sa http://cbor.io - @sa @ref to_cbor(const basic_json&) for the analogous serialization - @sa @ref from_msgpack(const std::vector&) for the related - MessagePack format - */ - static basic_json from_cbor(const std::vector& v) - { - size_t i = 0; - return from_cbor_internal(v, i); - } - - /// @} - - private: - /////////////////////////// - // convenience functions // - /////////////////////////// - - /*! - @brief return the type as string - - Returns the type name as string to be used in error messages - usually to - indicate that a function was called on a wrong JSON type. - - @return basically a string representation of a the @a m_type member - - @complexity Constant. - - @since version 1.0.0 - */ - std::string type_name() const - { - switch (m_type) - { - case value_t::null: - return "null"; - case value_t::object: - return "object"; - case value_t::array: - return "array"; - case value_t::string: - return "string"; - case value_t::boolean: - return "boolean"; - case value_t::discarded: - return "discarded"; - default: - return "number"; - } - } - - /*! - @brief calculates the extra space to escape a JSON string - - @param[in] s the string to escape - @return the number of characters required to escape string @a s - - @complexity Linear in the length of string @a s. - */ - static std::size_t extra_space(const string_t& s) noexcept - { - return std::accumulate(s.begin(), s.end(), size_t{}, - [](size_t res, typename string_t::value_type c) - { - switch (c) - { - case '"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - { - // from c (1 byte) to \x (2 bytes) - return res + 1; - } - - default: - { - if (c >= 0x00 and c <= 0x1f) - { - // from c (1 byte) to \uxxxx (6 bytes) - return res + 5; - } - else - { - return res; - } - } - } - }); - } - - /*! - @brief escape a string - - Escape a string by replacing certain special characters by a sequence of - an escape character (backslash) and another character and other control - characters by a sequence of "\u" followed by a four-digit hex - representation. - - @param[in] s the string to escape - @return the escaped string - - @complexity Linear in the length of string @a s. - */ - static string_t escape_string(const string_t& s) - { - const auto space = extra_space(s); - if (space == 0) - { - return s; - } - - // create a result string of necessary size - string_t result(s.size() + space, '\\'); - std::size_t pos = 0; - - for (const auto& c : s) - { - switch (c) - { - // quotation mark (0x22) - case '"': - { - result[pos + 1] = '"'; - pos += 2; - break; - } - - // reverse solidus (0x5c) - case '\\': - { - // nothing to change - pos += 2; - break; - } - - // backspace (0x08) - case '\b': - { - result[pos + 1] = 'b'; - pos += 2; - break; - } - - // formfeed (0x0c) - case '\f': - { - result[pos + 1] = 'f'; - pos += 2; - break; - } - - // newline (0x0a) - case '\n': - { - result[pos + 1] = 'n'; - pos += 2; - break; - } - - // carriage return (0x0d) - case '\r': - { - result[pos + 1] = 'r'; - pos += 2; - break; - } - - // horizontal tab (0x09) - case '\t': - { - result[pos + 1] = 't'; - pos += 2; - break; - } - - default: - { - if (c >= 0x00 and c <= 0x1f) - { - // convert a number 0..15 to its hex representation - // (0..f) - static const char hexify[16] = - { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - - // print character c as \uxxxx - for (const char m : - { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f] - }) - { - result[++pos] = m; - } - - ++pos; - } - else - { - // all other characters are added as-is - result[pos++] = c; - } - break; - } - } - } - - return result; - } - - /*! - @brief internal implementation of the serialization function - - This function is called by the public member function dump and organizes - the serialization internally. The indentation level is propagated as - additional parameter. In case of arrays and objects, the function is - called recursively. Note that - - - strings and object keys are escaped using `escape_string()` - - integer numbers are converted implicitly via `operator<<` - - floating-point numbers are converted to a string using `"%g"` format - - @param[out] o stream to write to - @param[in] pretty_print whether the output shall be pretty-printed - @param[in] indent_step the indent level - @param[in] current_indent the current indent level (only used internally) - */ - void dump(std::ostream& o, - const bool pretty_print, - const unsigned int indent_step, - const unsigned int current_indent = 0) const - { - // variable to hold indentation for recursive calls - unsigned int new_indent = current_indent; - - switch (m_type) - { - case value_t::object: - { - if (m_value.object->empty()) - { - o << "{}"; - return; - } - - o << "{"; - - // increase indentation - if (pretty_print) - { - new_indent += indent_step; - o << "\n"; - } - - for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) - { - if (i != m_value.object->cbegin()) - { - o << (pretty_print ? ",\n" : ","); - } - o << string_t(new_indent, ' ') << "\"" - << escape_string(i->first) << "\":" - << (pretty_print ? " " : ""); - i->second.dump(o, pretty_print, indent_step, new_indent); - } - - // decrease indentation - if (pretty_print) - { - new_indent -= indent_step; - o << "\n"; - } - - o << string_t(new_indent, ' ') + "}"; - return; - } - - case value_t::array: - { - if (m_value.array->empty()) - { - o << "[]"; - return; - } - - o << "["; - - // increase indentation - if (pretty_print) - { - new_indent += indent_step; - o << "\n"; - } - - for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) - { - if (i != m_value.array->cbegin()) - { - o << (pretty_print ? ",\n" : ","); - } - o << string_t(new_indent, ' '); - i->dump(o, pretty_print, indent_step, new_indent); - } - - // decrease indentation - if (pretty_print) - { - new_indent -= indent_step; - o << "\n"; - } - - o << string_t(new_indent, ' ') << "]"; - return; - } - - case value_t::string: - { - o << string_t("\"") << escape_string(*m_value.string) << "\""; - return; - } - - case value_t::boolean: - { - o << (m_value.boolean ? "true" : "false"); - return; - } - - case value_t::number_integer: - { - o << m_value.number_integer; - return; - } - - case value_t::number_unsigned: - { - o << m_value.number_unsigned; - return; - } - - case value_t::number_float: - { - if (m_value.number_float == 0) - { - // special case for zero to get "0.0"/"-0.0" - o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0"); - } - else - { - o << m_value.number_float; - } - return; - } - - case value_t::discarded: - { - o << ""; - return; - } - - case value_t::null: - { - o << "null"; - return; - } - } - } - - private: - ////////////////////// - // member variables // - ////////////////////// - - /// the type of the current element - value_t m_type = value_t::null; - - /// the value of the current element - json_value m_value = {}; - - - private: - /////////////// - // iterators // - /////////////// - - /*! - @brief an iterator for primitive JSON types - - This class models an iterator for primitive JSON types (boolean, number, - string). It's only purpose is to allow the iterator/const_iterator classes - to "iterate" over primitive values. Internally, the iterator is modeled by - a `difference_type` variable. Value begin_value (`0`) models the begin, - end_value (`1`) models past the end. - */ - class primitive_iterator_t - { - public: - /// set iterator to a defined beginning - void set_begin() noexcept - { - m_it = begin_value; - } - - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } - - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return (m_it == begin_value); - } - - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return (m_it == end_value); - } - - /// return reference to the value to change and compare - operator difference_type& () noexcept - { - return m_it; - } - - /// return value to compare - constexpr operator difference_type () const noexcept - { - return m_it; - } - - private: - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; - - /// iterator as signed integer type - difference_type m_it = std::numeric_limits::denorm_min(); - }; - - /*! - @brief an iterator value - - @note This structure could easily be a union, but MSVC currently does not - allow unions members with complex constructors, see - https://github.com/nlohmann/json/pull/105. - */ - struct internal_iterator - { - /// iterator for JSON objects - typename object_t::iterator object_iterator; - /// iterator for JSON arrays - typename array_t::iterator array_iterator; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator; - - /// create an uninitialized internal_iterator - internal_iterator() noexcept - : object_iterator(), array_iterator(), primitive_iterator() - {} - }; - - /// proxy class for the iterator_wrapper functions - template - class iteration_proxy - { - private: - /// helper class for iteration - class iteration_proxy_internal - { - private: - /// the iterator - IteratorType anchor; - /// an index for arrays (used to create key names) - size_t array_index = 0; - - public: - explicit iteration_proxy_internal(IteratorType it) noexcept - : anchor(it) - {} - - /// dereference operator (needed for range-based for) - iteration_proxy_internal& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_internal& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// inequality operator (needed for range-based for) - bool operator!= (const iteration_proxy_internal& o) const - { - return anchor != o.anchor; - } - - /// return key of the iterator - typename basic_json::string_t key() const - { - assert(anchor.m_object != nullptr); - - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - { - return std::to_string(array_index); - } - - // use key from the object - case value_t::object: - { - return anchor.key(); - } - - // use an empty key for all primitive types - default: - { - return ""; - } - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } - }; - - /// the container to iterate - typename IteratorType::reference container; - - public: - /// construct iteration proxy from a container - explicit iteration_proxy(typename IteratorType::reference cont) - : container(cont) - {} - - /// return iterator begin (needed for range-based for) - iteration_proxy_internal begin() noexcept - { - return iteration_proxy_internal(container.begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_internal end() noexcept - { - return iteration_proxy_internal(container.end()); - } - }; - - public: - /*! - @brief a template for a random access iterator for the @ref basic_json class - - This class implements a both iterators (iterator and const_iterator) for the - @ref basic_json class. - - @note An iterator is called *initialized* when a pointer to a JSON value - has been set (e.g., by a constructor or a copy assignment). If the - iterator is default-constructed, it is *uninitialized* and most - methods are undefined. **The library uses assertions to detect calls - on uninitialized iterators.** - - @requirement The class satisfies the following concept requirements: - - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): - The iterator that can be moved to point (forward and backward) to any - element in constant time. - - @since version 1.0.0, simplified in version 2.0.9 - */ - template - class iter_impl : public std::iterator - { - /// allow basic_json to access private members - friend class basic_json; - - // make sure U is basic_json or const basic_json - static_assert(std::is_same::value - or std::is_same::value, - "iter_impl only accepts (const) basic_json"); - - public: - /// the type of the values when the iterator is dereferenced - using value_type = typename basic_json::value_type; - /// a type to represent differences between iterators - using difference_type = typename basic_json::difference_type; - /// defines a pointer to the type iterated over (value_type) - using pointer = typename std::conditional::value, - typename basic_json::const_pointer, - typename basic_json::pointer>::type; - /// defines a reference to the type iterated over (value_type) - using reference = typename std::conditional::value, - typename basic_json::const_reference, - typename basic_json::reference>::type; - /// the category of the iterator - using iterator_category = std::bidirectional_iterator_tag; - - /// default constructor - iter_impl() = default; - - /*! - @brief constructor for a given JSON instance - @param[in] object pointer to a JSON object for this iterator - @pre object != nullptr - @post The iterator is initialized; i.e. `m_object != nullptr`. - */ - explicit iter_impl(pointer object) noexcept - : m_object(object) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - m_it.object_iterator = typename object_t::iterator(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = typename array_t::iterator(); - break; - } - - default: - { - m_it.primitive_iterator = primitive_iterator_t(); - break; - } - } - } - - /* - Use operator `const_iterator` instead of `const_iterator(const iterator& - other) noexcept` to avoid two class definitions for @ref iterator and - @ref const_iterator. - - This function is only called if this class is an @ref iterator. If this - class is a @ref const_iterator this function is not called. - */ - operator const_iterator() const - { - const_iterator ret; - - if (m_object) - { - ret.m_object = m_object; - ret.m_it = m_it; - } - - return ret; - } - - /*! - @brief copy constructor - @param[in] other iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl(const iter_impl& other) noexcept - : m_object(other.m_object), m_it(other.m_it) - {} - - /*! - @brief copy assignment - @param[in,out] other iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl& operator=(iter_impl other) noexcept( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) - { - std::swap(m_object, other.m_object); - std::swap(m_it, other.m_it); - return *this; - } - - private: - /*! - @brief set the iterator to the first value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_begin() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - m_it.object_iterator = m_object->m_value.object->begin(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = m_object->m_value.array->begin(); - break; - } - - case basic_json::value_t::null: - { - // set to end so begin()==end() is true: null is empty - m_it.primitive_iterator.set_end(); - break; - } - - default: - { - m_it.primitive_iterator.set_begin(); - break; - } - } - } - - /*! - @brief set the iterator past the last value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_end() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - m_it.object_iterator = m_object->m_value.object->end(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = m_object->m_value.array->end(); - break; - } - - default: - { - m_it.primitive_iterator.set_end(); - break; - } - } - } - - public: - /*! - @brief return a reference to the value pointed to by the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator*() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return m_it.object_iterator->second; - } - - case basic_json::value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return *m_it.array_iterator; - } - - case basic_json::value_t::null: - { - throw std::out_of_range("cannot get value"); - } - - default: - { - if (m_it.primitive_iterator.is_begin()) - { - return *m_object; - } - else - { - throw std::out_of_range("cannot get value"); - } - } - } - } - - /*! - @brief dereference the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - pointer operator->() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return &(m_it.object_iterator->second); - } - - case basic_json::value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return &*m_it.array_iterator; - } - - default: - { - if (m_it.primitive_iterator.is_begin()) - { - return m_object; - } - else - { - throw std::out_of_range("cannot get value"); - } - } - } - } - - /*! - @brief post-increment (it++) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator++(int) - { - auto result = *this; - ++(*this); - return result; - } - - /*! - @brief pre-increment (++it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator++() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - std::advance(m_it.object_iterator, 1); - break; - } - - case basic_json::value_t::array: - { - std::advance(m_it.array_iterator, 1); - break; - } - - default: - { - ++m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief post-decrement (it--) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator--(int) - { - auto result = *this; - --(*this); - return result; - } - - /*! - @brief pre-decrement (--it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator--() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - std::advance(m_it.object_iterator, -1); - break; - } - - case basic_json::value_t::array: - { - std::advance(m_it.array_iterator, -1); - break; - } - - default: - { - --m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator==(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (m_object != other.m_object) - { - throw std::domain_error("cannot compare iterators of different containers"); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - return (m_it.object_iterator == other.m_it.object_iterator); - } - - case basic_json::value_t::array: - { - return (m_it.array_iterator == other.m_it.array_iterator); - } - - default: - { - return (m_it.primitive_iterator == other.m_it.primitive_iterator); - } - } - } - - /*! - @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator!=(const iter_impl& other) const - { - return not operator==(other); - } - - /*! - @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (m_object != other.m_object) - { - throw std::domain_error("cannot compare iterators of different containers"); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - throw std::domain_error("cannot compare order of object iterators"); - } - - case basic_json::value_t::array: - { - return (m_it.array_iterator < other.m_it.array_iterator); - } - - default: - { - return (m_it.primitive_iterator < other.m_it.primitive_iterator); - } - } - } - - /*! - @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<=(const iter_impl& other) const - { - return not other.operator < (*this); - } - - /*! - @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>(const iter_impl& other) const - { - return not operator<=(other); - } - - /*! - @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>=(const iter_impl& other) const - { - return not operator<(other); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator+=(difference_type i) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - throw std::domain_error("cannot use offsets with object iterators"); - } - - case basic_json::value_t::array: - { - std::advance(m_it.array_iterator, i); - break; - } - - default: - { - m_it.primitive_iterator += i; - break; - } - } - - return *this; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator-=(difference_type i) - { - return operator+=(-i); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator-(difference_type i) - { - auto result = *this; - result -= i; - return result; - } - - /*! - @brief return difference - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - difference_type operator-(const iter_impl& other) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - throw std::domain_error("cannot use offsets with object iterators"); - } - - case basic_json::value_t::array: - { - return m_it.array_iterator - other.m_it.array_iterator; - } - - default: - { - return m_it.primitive_iterator - other.m_it.primitive_iterator; - } - } - } - - /*! - @brief access to successor - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator[](difference_type n) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - throw std::domain_error("cannot use operator[] for object iterators"); - } - - case basic_json::value_t::array: - { - return *std::next(m_it.array_iterator, n); - } - - case basic_json::value_t::null: - { - throw std::out_of_range("cannot get value"); - } - - default: - { - if (m_it.primitive_iterator == -n) - { - return *m_object; - } - else - { - throw std::out_of_range("cannot get value"); - } - } - } - } - - /*! - @brief return the key of an object iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - typename object_t::key_type key() const - { - assert(m_object != nullptr); - - if (m_object->is_object()) - { - return m_it.object_iterator->first; - } - else - { - throw std::domain_error("cannot use key() for non-object iterators"); - } - } - - /*! - @brief return the value of an iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference value() const - { - return operator*(); - } - - private: - /// associated JSON instance - pointer m_object = nullptr; - /// the actual iterator of the associated instance - internal_iterator m_it = internal_iterator(); - }; - - /*! - @brief a template for a reverse iterator class - - @tparam Base the base iterator type to reverse. Valid types are @ref - iterator (to create @ref reverse_iterator) and @ref const_iterator (to - create @ref const_reverse_iterator). - - @requirement The class satisfies the following concept requirements: - - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): - The iterator that can be moved to point (forward and backward) to any - element in constant time. - - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): - It is possible to write to the pointed-to element (only if @a Base is - @ref iterator). - - @since version 1.0.0 - */ - template - class json_reverse_iterator : public std::reverse_iterator - { - public: - /// shortcut to the reverse iterator adaptor - using base_iterator = std::reverse_iterator; - /// the reference type for the pointed-to element - using reference = typename Base::reference; - - /// create reverse iterator from iterator - json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept - : base_iterator(it) - {} - - /// create reverse iterator from base class - json_reverse_iterator(const base_iterator& it) noexcept - : base_iterator(it) - {} - - /// post-increment (it++) - json_reverse_iterator operator++(int) - { - return base_iterator::operator++(1); - } - - /// pre-increment (++it) - json_reverse_iterator& operator++() - { - base_iterator::operator++(); - return *this; - } - - /// post-decrement (it--) - json_reverse_iterator operator--(int) - { - return base_iterator::operator--(1); - } - - /// pre-decrement (--it) - json_reverse_iterator& operator--() - { - base_iterator::operator--(); - return *this; - } - - /// add to iterator - json_reverse_iterator& operator+=(difference_type i) - { - base_iterator::operator+=(i); - return *this; - } - - /// add to iterator - json_reverse_iterator operator+(difference_type i) const - { - auto result = *this; - result += i; - return result; - } - - /// subtract from iterator - json_reverse_iterator operator-(difference_type i) const - { - auto result = *this; - result -= i; - return result; - } - - /// return difference - difference_type operator-(const json_reverse_iterator& other) const - { - return this->base() - other.base(); - } - - /// access to successor - reference operator[](difference_type n) const - { - return *(this->operator+(n)); - } - - /// return the key of an object iterator - typename object_t::key_type key() const - { - auto it = --this->base(); - return it.key(); - } - - /// return the value of an iterator - reference value() const - { - auto it = --this->base(); - return it.operator * (); - } - }; - - - private: - ////////////////////// - // lexer and parser // - ////////////////////// - - /*! - @brief lexical analysis - - This class organizes the lexical analysis during JSON deserialization. The - core of it is a scanner generated by [re2c](http://re2c.org) that - processes a buffer and recognizes tokens according to RFC 7159. - */ - class lexer - { - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_number, ///< a number -- use get_number() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input ///< indicating the end of the input buffer - }; - - /// the char type to use in the lexer - using lexer_char_t = unsigned char; - - /// a lexer from a buffer with given length - lexer(const lexer_char_t* buff, const size_t len) noexcept - : m_content(buff) - { - assert(m_content != nullptr); - m_start = m_cursor = m_content; - m_limit = m_content + len; - } - - /// a lexer from an input stream - explicit lexer(std::istream& s) - : m_stream(&s), m_line_buffer() - { - // immediately abort if stream is erroneous - if (s.fail()) - { - throw std::invalid_argument("stream error"); - } - - // fill buffer - fill_line_buffer(); - - // skip UTF-8 byte-order mark - if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF") - { - m_line_buffer[0] = ' '; - m_line_buffer[1] = ' '; - m_line_buffer[2] = ' '; - } - } - - // switch off unwanted functions (due to pointer members) - lexer() = delete; - lexer(const lexer&) = delete; - lexer operator=(const lexer&) = delete; - - /*! - @brief create a string from one or two Unicode code points - - There are two cases: (1) @a codepoint1 is in the Basic Multilingual - Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2) - @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to - represent a code point above U+FFFF. - - @param[in] codepoint1 the code point (can be high surrogate) - @param[in] codepoint2 the code point (can be low surrogate or 0) - - @return string representation of the code point; the length of the - result string is between 1 and 4 characters. - - @throw std::out_of_range if code point is > 0x10ffff; example: `"code - points above 0x10FFFF are invalid"` - @throw std::invalid_argument if the low surrogate is invalid; example: - `""missing or wrong low surrogate""` - - @complexity Constant. - - @see - */ - static string_t to_unicode(const std::size_t codepoint1, - const std::size_t codepoint2 = 0) - { - // calculate the code point from the given code points - std::size_t codepoint = codepoint1; - - // check if codepoint1 is a high surrogate - if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) - { - // check if codepoint2 is a low surrogate - if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) - { - codepoint = - // high surrogate occupies the most significant 22 bits - (codepoint1 << 10) - // low surrogate occupies the least significant 15 bits - + codepoint2 - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00; - } - else - { - throw std::invalid_argument("missing or wrong low surrogate"); - } - } - - string_t result; - - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - result.append(1, static_cast(codepoint)); - } - else if (codepoint <= 0x7ff) - { - // 2-byte characters: 110xxxxx 10xxxxxx - result.append(1, static_cast(0xC0 | ((codepoint >> 6) & 0x1F))); - result.append(1, static_cast(0x80 | (codepoint & 0x3F))); - } - else if (codepoint <= 0xffff) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - result.append(1, static_cast(0xE0 | ((codepoint >> 12) & 0x0F))); - result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - result.append(1, static_cast(0x80 | (codepoint & 0x3F))); - } - else if (codepoint <= 0x10ffff) - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - result.append(1, static_cast(0xF0 | ((codepoint >> 18) & 0x07))); - result.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); - result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - result.append(1, static_cast(0x80 | (codepoint & 0x3F))); - } - else - { - throw std::out_of_range("code points above 0x10FFFF are invalid"); - } - - return result; - } - - /// return name of values of type token_type (only used for errors) - static std::string token_type_name(const token_type t) - { - switch (t) - { - case token_type::uninitialized: - return ""; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case token_type::value_number: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return ""; - case token_type::end_of_input: - return "end of input"; - default: - { - // catch non-enum values - return "unknown token"; // LCOV_EXCL_LINE - } - } - } - - /*! - This function implements a scanner for JSON. It is specified using - regular expressions that try to follow RFC 7159 as close as possible. - These regular expressions are then translated into a minimized - deterministic finite automaton (DFA) by the tool - [re2c](http://re2c.org). As a result, the translated code for this - function consists of a large block of code with `goto` jumps. - - @return the class of the next token read from the buffer - - @complexity Linear in the length of the input.\n - - Proposition: The loop below will always terminate for finite input.\n - - Proof (by contradiction): Assume a finite input. To loop forever, the - loop must never hit code with a `break` statement. The only code - snippets without a `break` statement are the continue statements for - whitespace and byte-order-marks. To loop forever, the input must be an - infinite sequence of whitespace or byte-order-marks. This contradicts - the assumption of finite input, q.e.d. - */ - token_type scan() - { - while (true) - { - // pointer for backtracking information - m_marker = nullptr; - - // remember the begin of the token - m_start = m_cursor; - assert(m_start != nullptr); - - - { - lexer_char_t yych; - unsigned int yyaccept = 0; - static const unsigned char yybm[] = - { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 32, 32, 0, 0, 32, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 160, 128, 0, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 0, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - }; - if ((m_limit - m_cursor) < 5) - { - fill_line_buffer(5); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yybm[0 + yych] & 32) - { - goto basic_json_parser_6; - } - if (yych <= '[') - { - if (yych <= '-') - { - if (yych <= '"') - { - if (yych <= 0x00) - { - goto basic_json_parser_2; - } - if (yych <= '!') - { - goto basic_json_parser_4; - } - goto basic_json_parser_9; - } - else - { - if (yych <= '+') - { - goto basic_json_parser_4; - } - if (yych <= ',') - { - goto basic_json_parser_10; - } - goto basic_json_parser_12; - } - } - else - { - if (yych <= '9') - { - if (yych <= '/') - { - goto basic_json_parser_4; - } - if (yych <= '0') - { - goto basic_json_parser_13; - } - goto basic_json_parser_15; - } - else - { - if (yych <= ':') - { - goto basic_json_parser_17; - } - if (yych <= 'Z') - { - goto basic_json_parser_4; - } - goto basic_json_parser_19; - } - } - } - else - { - if (yych <= 'n') - { - if (yych <= 'e') - { - if (yych == ']') - { - goto basic_json_parser_21; - } - goto basic_json_parser_4; - } - else - { - if (yych <= 'f') - { - goto basic_json_parser_23; - } - if (yych <= 'm') - { - goto basic_json_parser_4; - } - goto basic_json_parser_24; - } - } - else - { - if (yych <= 'z') - { - if (yych == 't') - { - goto basic_json_parser_25; - } - goto basic_json_parser_4; - } - else - { - if (yych <= '{') - { - goto basic_json_parser_26; - } - if (yych == '}') - { - goto basic_json_parser_28; - } - goto basic_json_parser_4; - } - } - } -basic_json_parser_2: - ++m_cursor; - { - last_token_type = token_type::end_of_input; - break; - } -basic_json_parser_4: - ++m_cursor; -basic_json_parser_5: - { - last_token_type = token_type::parse_error; - break; - } -basic_json_parser_6: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yybm[0 + yych] & 32) - { - goto basic_json_parser_6; - } - { - continue; - } -basic_json_parser_9: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych <= 0x1F) - { - goto basic_json_parser_5; - } - if (yych <= 0x7F) - { - goto basic_json_parser_31; - } - if (yych <= 0xC1) - { - goto basic_json_parser_5; - } - if (yych <= 0xF4) - { - goto basic_json_parser_31; - } - goto basic_json_parser_5; -basic_json_parser_10: - ++m_cursor; - { - last_token_type = token_type::value_separator; - break; - } -basic_json_parser_12: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_5; - } - if (yych <= '0') - { - goto basic_json_parser_13; - } - if (yych <= '9') - { - goto basic_json_parser_15; - } - goto basic_json_parser_5; -basic_json_parser_13: - yyaccept = 1; - yych = *(m_marker = ++m_cursor); - if (yych <= 'D') - { - if (yych == '.') - { - goto basic_json_parser_43; - } - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_44; - } - if (yych == 'e') - { - goto basic_json_parser_44; - } - } -basic_json_parser_14: - { - last_token_type = token_type::value_number; - break; - } -basic_json_parser_15: - yyaccept = 1; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - fill_line_buffer(3); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yybm[0 + yych] & 64) - { - goto basic_json_parser_15; - } - if (yych <= 'D') - { - if (yych == '.') - { - goto basic_json_parser_43; - } - goto basic_json_parser_14; - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_44; - } - if (yych == 'e') - { - goto basic_json_parser_44; - } - goto basic_json_parser_14; - } -basic_json_parser_17: - ++m_cursor; - { - last_token_type = token_type::name_separator; - break; - } -basic_json_parser_19: - ++m_cursor; - { - last_token_type = token_type::begin_array; - break; - } -basic_json_parser_21: - ++m_cursor; - { - last_token_type = token_type::end_array; - break; - } -basic_json_parser_23: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'a') - { - goto basic_json_parser_45; - } - goto basic_json_parser_5; -basic_json_parser_24: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'u') - { - goto basic_json_parser_46; - } - goto basic_json_parser_5; -basic_json_parser_25: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'r') - { - goto basic_json_parser_47; - } - goto basic_json_parser_5; -basic_json_parser_26: - ++m_cursor; - { - last_token_type = token_type::begin_object; - break; - } -basic_json_parser_28: - ++m_cursor; - { - last_token_type = token_type::end_object; - break; - } -basic_json_parser_30: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; -basic_json_parser_31: - if (yybm[0 + yych] & 128) - { - goto basic_json_parser_30; - } - if (yych <= 0xE0) - { - if (yych <= '\\') - { - if (yych <= 0x1F) - { - goto basic_json_parser_32; - } - if (yych <= '"') - { - goto basic_json_parser_33; - } - goto basic_json_parser_35; - } - else - { - if (yych <= 0xC1) - { - goto basic_json_parser_32; - } - if (yych <= 0xDF) - { - goto basic_json_parser_36; - } - goto basic_json_parser_37; - } - } - else - { - if (yych <= 0xEF) - { - if (yych == 0xED) - { - goto basic_json_parser_39; - } - goto basic_json_parser_38; - } - else - { - if (yych <= 0xF0) - { - goto basic_json_parser_40; - } - if (yych <= 0xF3) - { - goto basic_json_parser_41; - } - if (yych <= 0xF4) - { - goto basic_json_parser_42; - } - } - } -basic_json_parser_32: - m_cursor = m_marker; - if (yyaccept == 0) - { - goto basic_json_parser_5; - } - else - { - goto basic_json_parser_14; - } -basic_json_parser_33: - ++m_cursor; - { - last_token_type = token_type::value_string; - break; - } -basic_json_parser_35: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 'e') - { - if (yych <= '/') - { - if (yych == '"') - { - goto basic_json_parser_30; - } - if (yych <= '.') - { - goto basic_json_parser_32; - } - goto basic_json_parser_30; - } - else - { - if (yych <= '\\') - { - if (yych <= '[') - { - goto basic_json_parser_32; - } - goto basic_json_parser_30; - } - else - { - if (yych == 'b') - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; - } - } - } - else - { - if (yych <= 'q') - { - if (yych <= 'f') - { - goto basic_json_parser_30; - } - if (yych == 'n') - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 's') - { - if (yych <= 'r') - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 't') - { - goto basic_json_parser_30; - } - if (yych <= 'u') - { - goto basic_json_parser_48; - } - goto basic_json_parser_32; - } - } - } -basic_json_parser_36: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x7F) - { - goto basic_json_parser_32; - } - if (yych <= 0xBF) - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; -basic_json_parser_37: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x9F) - { - goto basic_json_parser_32; - } - if (yych <= 0xBF) - { - goto basic_json_parser_36; - } - goto basic_json_parser_32; -basic_json_parser_38: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x7F) - { - goto basic_json_parser_32; - } - if (yych <= 0xBF) - { - goto basic_json_parser_36; - } - goto basic_json_parser_32; -basic_json_parser_39: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x7F) - { - goto basic_json_parser_32; - } - if (yych <= 0x9F) - { - goto basic_json_parser_36; - } - goto basic_json_parser_32; -basic_json_parser_40: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x8F) - { - goto basic_json_parser_32; - } - if (yych <= 0xBF) - { - goto basic_json_parser_38; - } - goto basic_json_parser_32; -basic_json_parser_41: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x7F) - { - goto basic_json_parser_32; - } - if (yych <= 0xBF) - { - goto basic_json_parser_38; - } - goto basic_json_parser_32; -basic_json_parser_42: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 0x7F) - { - goto basic_json_parser_32; - } - if (yych <= 0x8F) - { - goto basic_json_parser_38; - } - goto basic_json_parser_32; -basic_json_parser_43: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_49; - } - goto basic_json_parser_32; -basic_json_parser_44: - yych = *++m_cursor; - if (yych <= ',') - { - if (yych == '+') - { - goto basic_json_parser_51; - } - goto basic_json_parser_32; - } - else - { - if (yych <= '-') - { - goto basic_json_parser_51; - } - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_52; - } - goto basic_json_parser_32; - } -basic_json_parser_45: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_54; - } - goto basic_json_parser_32; -basic_json_parser_46: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_55; - } - goto basic_json_parser_32; -basic_json_parser_47: - yych = *++m_cursor; - if (yych == 'u') - { - goto basic_json_parser_56; - } - goto basic_json_parser_32; -basic_json_parser_48: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_57; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_57; - } - if (yych <= '`') - { - goto basic_json_parser_32; - } - if (yych <= 'f') - { - goto basic_json_parser_57; - } - goto basic_json_parser_32; - } -basic_json_parser_49: - yyaccept = 1; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - fill_line_buffer(3); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= 'D') - { - if (yych <= '/') - { - goto basic_json_parser_14; - } - if (yych <= '9') - { - goto basic_json_parser_49; - } - goto basic_json_parser_14; - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_44; - } - if (yych == 'e') - { - goto basic_json_parser_44; - } - goto basic_json_parser_14; - } -basic_json_parser_51: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych >= ':') - { - goto basic_json_parser_32; - } -basic_json_parser_52: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '/') - { - goto basic_json_parser_14; - } - if (yych <= '9') - { - goto basic_json_parser_52; - } - goto basic_json_parser_14; -basic_json_parser_54: - yych = *++m_cursor; - if (yych == 's') - { - goto basic_json_parser_58; - } - goto basic_json_parser_32; -basic_json_parser_55: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_59; - } - goto basic_json_parser_32; -basic_json_parser_56: - yych = *++m_cursor; - if (yych == 'e') - { - goto basic_json_parser_61; - } - goto basic_json_parser_32; -basic_json_parser_57: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_63; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_63; - } - if (yych <= '`') - { - goto basic_json_parser_32; - } - if (yych <= 'f') - { - goto basic_json_parser_63; - } - goto basic_json_parser_32; - } -basic_json_parser_58: - yych = *++m_cursor; - if (yych == 'e') - { - goto basic_json_parser_64; - } - goto basic_json_parser_32; -basic_json_parser_59: - ++m_cursor; - { - last_token_type = token_type::literal_null; - break; - } -basic_json_parser_61: - ++m_cursor; - { - last_token_type = token_type::literal_true; - break; - } -basic_json_parser_63: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_66; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_66; - } - if (yych <= '`') - { - goto basic_json_parser_32; - } - if (yych <= 'f') - { - goto basic_json_parser_66; - } - goto basic_json_parser_32; - } -basic_json_parser_64: - ++m_cursor; - { - last_token_type = token_type::literal_false; - break; - } -basic_json_parser_66: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(1); // LCOV_EXCL_LINE - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych <= '9') - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_30; - } - if (yych <= '`') - { - goto basic_json_parser_32; - } - if (yych <= 'f') - { - goto basic_json_parser_30; - } - goto basic_json_parser_32; - } - } - - } - - return last_token_type; - } - - /*! - @brief append data from the stream to the line buffer - - This function is called by the scan() function when the end of the - buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be - incremented without leaving the limits of the line buffer. Note re2c - decides when to call this function. - - If the lexer reads from contiguous storage, there is no trailing null - byte. Therefore, this function must make sure to add these padding - null bytes. - - If the lexer reads from an input stream, this function reads the next - line of the input. - - @pre - p p p p p p u u u u u x . . . . . . - ^ ^ ^ ^ - m_content m_start | m_limit - m_cursor - - @post - u u u u u x x x x x x x . . . . . . - ^ ^ ^ - | m_cursor m_limit - m_start - m_content - */ - void fill_line_buffer(size_t n = 0) - { - // if line buffer is used, m_content points to its data - assert(m_line_buffer.empty() - or m_content == reinterpret_cast(m_line_buffer.data())); - - // if line buffer is used, m_limit is set past the end of its data - assert(m_line_buffer.empty() - or m_limit == m_content + m_line_buffer.size()); - - // pointer relationships - assert(m_content <= m_start); - assert(m_start <= m_cursor); - assert(m_cursor <= m_limit); - assert(m_marker == nullptr or m_marker <= m_limit); - - // number of processed characters (p) - const size_t num_processed_chars = static_cast(m_start - m_content); - // offset for m_marker wrt. to m_start - const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start; - // number of unprocessed characters (u) - const auto offset_cursor = m_cursor - m_start; - - // no stream is used or end of file is reached - if (m_stream == nullptr or m_stream->eof()) - { - // m_start may or may not be pointing into m_line_buffer at - // this point. We trust the standand library to do the right - // thing. See http://stackoverflow.com/q/28142011/266378 - m_line_buffer.assign(m_start, m_limit); - - // append n characters to make sure that there is sufficient - // space between m_cursor and m_limit - m_line_buffer.append(1, '\x00'); - if (n > 0) - { - m_line_buffer.append(n - 1, '\x01'); - } - } - else - { - // delete processed characters from line buffer - m_line_buffer.erase(0, num_processed_chars); - // read next line from input stream - m_line_buffer_tmp.clear(); - std::getline(*m_stream, m_line_buffer_tmp, '\n'); - - // add line with newline symbol to the line buffer - m_line_buffer += m_line_buffer_tmp; - m_line_buffer.push_back('\n'); - } - - // set pointers - m_content = reinterpret_cast(m_line_buffer.data()); - assert(m_content != nullptr); - m_start = m_content; - m_marker = m_start + offset_marker; - m_cursor = m_start + offset_cursor; - m_limit = m_start + m_line_buffer.size(); - } - - /// return string representation of last read token - string_t get_token_string() const - { - assert(m_start != nullptr); - return string_t(reinterpret_cast(m_start), - static_cast(m_cursor - m_start)); - } - - /*! - @brief return string value for string tokens - - The function iterates the characters between the opening and closing - quotes of the string value. The complete string is the range - [m_start,m_cursor). Consequently, we iterate from m_start+1 to - m_cursor-1. - - We differentiate two cases: - - 1. Escaped characters. In this case, a new character is constructed - according to the nature of the escape. Some escapes create new - characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied - as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape - `"\\uxxxx"` need special care. In this case, to_unicode takes care - of the construction of the values. - 2. Unescaped characters are copied as is. - - @pre `m_cursor - m_start >= 2`, meaning the length of the last token - is at least 2 bytes which is trivially true for any string (which - consists of at least two quotes). - - " c1 c2 c3 ... " - ^ ^ - m_start m_cursor - - @complexity Linear in the length of the string.\n - - Lemma: The loop body will always terminate.\n - - Proof (by contradiction): Assume the loop body does not terminate. As - the loop body does not contain another loop, one of the called - functions must never return. The called functions are `std::strtoul` - and to_unicode. Neither function can loop forever, so the loop body - will never loop forever which contradicts the assumption that the loop - body does not terminate, q.e.d.\n - - Lemma: The loop condition for the for loop is eventually false.\n - - Proof (by contradiction): Assume the loop does not terminate. Due to - the above lemma, this can only be due to a tautological loop - condition; that is, the loop condition i < m_cursor - 1 must always be - true. Let x be the change of i for any loop iteration. Then - m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This - can be rephrased to m_cursor - m_start - 2 > x. With the - precondition, we x <= 0, meaning that the loop condition holds - indefinitly if i is always decreased. However, observe that the value - of i is strictly increasing with each iteration, as it is incremented - by 1 in the iteration expression and never decremented inside the loop - body. Hence, the loop condition will eventually be false which - contradicts the assumption that the loop condition is a tautology, - q.e.d. - - @return string value of current token without opening and closing - quotes - @throw std::out_of_range if to_unicode fails - */ - string_t get_string() const - { - assert(m_cursor - m_start >= 2); - - string_t result; - result.reserve(static_cast(m_cursor - m_start - 2)); - - // iterate the result between the quotes - for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) - { - // find next escape character - auto e = std::find(i, m_cursor - 1, '\\'); - if (e != i) - { - // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705 - for (auto k = i; k < e; k++) - { - result.push_back(static_cast(*k)); - } - i = e - 1; // -1 because of ++i - } - else - { - // processing escaped character - // read next character - ++i; - - switch (*i) - { - // the default escapes - case 't': - { - result += "\t"; - break; - } - case 'b': - { - result += "\b"; - break; - } - case 'f': - { - result += "\f"; - break; - } - case 'n': - { - result += "\n"; - break; - } - case 'r': - { - result += "\r"; - break; - } - case '\\': - { - result += "\\"; - break; - } - case '/': - { - result += "/"; - break; - } - case '"': - { - result += "\""; - break; - } - - // unicode - case 'u': - { - // get code xxxx from uxxxx - auto codepoint = std::strtoul(std::string(reinterpret_cast(i + 1), - 4).c_str(), nullptr, 16); - - // check if codepoint is a high surrogate - if (codepoint >= 0xD800 and codepoint <= 0xDBFF) - { - // make sure there is a subsequent unicode - if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') - { - throw std::invalid_argument("missing low surrogate"); - } - - // get code yyyy from uxxxx\uyyyy - auto codepoint2 = std::strtoul(std::string(reinterpret_cast - (i + 7), 4).c_str(), nullptr, 16); - result += to_unicode(codepoint, codepoint2); - // skip the next 10 characters (xxxx\uyyyy) - i += 10; - } - else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF) - { - // we found a lone low surrogate - throw std::invalid_argument("missing high surrogate"); - } - else - { - // add unicode character(s) - result += to_unicode(codepoint); - // skip the next four characters (xxxx) - i += 4; - } - break; - } - } - } - } - - return result; - } - - /*! - @brief parse floating point number - - This function (and its overloads) serves to select the most approprate - standard floating point number parsing function based on the type - supplied via the first parameter. Set this to @a - static_cast(nullptr). - - @param[in,out] endptr recieves a pointer to the first character after - the number - - @return the floating point number - */ - long double str_to_float_t(long double* /* type */, char** endptr) const - { - return std::strtold(reinterpret_cast(m_start), endptr); - } - - /*! - @brief parse floating point number - - This function (and its overloads) serves to select the most approprate - standard floating point number parsing function based on the type - supplied via the first parameter. Set this to @a - static_cast(nullptr). - - @param[in,out] endptr recieves a pointer to the first character after - the number - - @return the floating point number - */ - double str_to_float_t(double* /* type */, char** endptr) const - { - return std::strtod(reinterpret_cast(m_start), endptr); - } - - /*! - @brief parse floating point number - - This function (and its overloads) serves to select the most approprate - standard floating point number parsing function based on the type - supplied via the first parameter. Set this to @a - static_cast(nullptr). - - @param[in,out] endptr recieves a pointer to the first character after - the number - - @return the floating point number - */ - float str_to_float_t(float* /* type */, char** endptr) const - { - return std::strtof(reinterpret_cast(m_start), endptr); - } - - /*! - @brief return number value for number tokens - - This function translates the last token into the most appropriate - number type (either integer, unsigned integer or floating point), - which is passed back to the caller via the result parameter. - - This function parses the integer component up to the radix point or - exponent while collecting information about the 'floating point - representation', which it stores in the result parameter. If there is - no radix point or exponent, and the number can fit into a @ref - number_integer_t or @ref number_unsigned_t then it sets the result - parameter accordingly. - - If the number is a floating point number the number is then parsed - using @a std:strtod (or @a std:strtof or @a std::strtold). - - @param[out] result @ref basic_json object to receive the number, or - NAN if the conversion read past the current token. The latter case - needs to be treated by the caller function. - */ - void get_number(basic_json& result) const - { - assert(m_start != nullptr); - - const lexer::lexer_char_t* curptr = m_start; - - // accumulate the integer conversion result (unsigned for now) - number_unsigned_t value = 0; - - // maximum absolute value of the relevant integer type - number_unsigned_t max; - - // temporarily store the type to avoid unecessary bitfield access - value_t type; - - // look for sign - if (*curptr == '-') - { - type = value_t::number_integer; - max = static_cast((std::numeric_limits::max)()) + 1; - curptr++; - } - else - { - type = value_t::number_unsigned; - max = static_cast((std::numeric_limits::max)()); - } - - // count the significant figures - for (; curptr < m_cursor; curptr++) - { - // quickly skip tests if a digit - if (*curptr < '0' || *curptr > '9') - { - if (*curptr == '.') - { - // don't count '.' but change to float - type = value_t::number_float; - continue; - } - // assume exponent (if not then will fail parse): change to - // float, stop counting and record exponent details - type = value_t::number_float; - break; - } - - // skip if definitely not an integer - if (type != value_t::number_float) - { - auto digit = static_cast(*curptr - '0'); - - // overflow if value * 10 + digit > max, move terms around - // to avoid overflow in intermediate values - if (value > (max - digit) / 10) - { - // overflow - type = value_t::number_float; - } - else - { - // no overflow - value = value * 10 + digit; - } - } - } - - // save the value (if not a float) - if (type == value_t::number_unsigned) - { - result.m_value.number_unsigned = value; - } - else if (type == value_t::number_integer) - { - // invariant: if we parsed a '-', the absolute value is between - // 0 (we allow -0) and max == -INT64_MIN - assert(value >= 0); - assert(value <= max); - - if (value == max) - { - // we cannot simply negate value (== max == -INT64_MIN), - // see https://github.com/nlohmann/json/issues/389 - result.m_value.number_integer = static_cast(INT64_MIN); - } - else - { - // all other values can be negated safely - result.m_value.number_integer = -static_cast(value); - } - } - else - { - // parse with strtod - result.m_value.number_float = str_to_float_t(static_cast(nullptr), NULL); - - // replace infinity and NAN by null - if (not std::isfinite(result.m_value.number_float)) - { - type = value_t::null; - result.m_value = basic_json::json_value(); - } - } - - // save the type - result.m_type = type; - } - - private: - /// optional input stream - std::istream* m_stream = nullptr; - /// line buffer buffer for m_stream - string_t m_line_buffer {}; - /// used for filling m_line_buffer - string_t m_line_buffer_tmp {}; - /// the buffer pointer - const lexer_char_t* m_content = nullptr; - /// pointer to the beginning of the current symbol - const lexer_char_t* m_start = nullptr; - /// pointer for backtracking information - const lexer_char_t* m_marker = nullptr; - /// pointer to the current symbol - const lexer_char_t* m_cursor = nullptr; - /// pointer to the end of the buffer - const lexer_char_t* m_limit = nullptr; - /// the last token type - token_type last_token_type = token_type::end_of_input; - }; - - /*! - @brief syntax analysis - - This class implements a recursive decent parser. - */ - class parser - { - public: - /// a parser reading from a string literal - parser(const char* buff, const parser_callback_t cb = nullptr) - : callback(cb), - m_lexer(reinterpret_cast(buff), std::strlen(buff)) - {} - - /// a parser reading from an input stream - parser(std::istream& is, const parser_callback_t cb = nullptr) - : callback(cb), m_lexer(is) - {} - - /// a parser reading from an iterator range with contiguous storage - template::iterator_category, std::random_access_iterator_tag>::value - , int>::type - = 0> - parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr) - : callback(cb), - m_lexer(reinterpret_cast(&(*first)), - static_cast(std::distance(first, last))) - {} - - /// public parser interface - basic_json parse() - { - // read first token - get_token(); - - basic_json result = parse_internal(true); - result.assert_invariant(); - - expect(lexer::token_type::end_of_input); - - // return parser result and replace it with null in case the - // top-level value was discarded by the callback function - return result.is_discarded() ? basic_json() : std::move(result); - } - - private: - /// the actual parser - basic_json parse_internal(bool keep) - { - auto result = basic_json(value_t::discarded); - - switch (last_token) - { - case lexer::token_type::begin_object: - { - if (keep and (not callback - or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0))) - { - // explicitly set result to object to cope with {} - result.m_type = value_t::object; - result.m_value = value_t::object; - } - - // read next token - get_token(); - - // closing } -> we are done - if (last_token == lexer::token_type::end_object) - { - get_token(); - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result = basic_json(value_t::discarded); - } - return result; - } - - // no comma is expected here - unexpect(lexer::token_type::value_separator); - - // otherwise: parse key-value pairs - do - { - // ugly, but could be fixed with loop reorganization - if (last_token == lexer::token_type::value_separator) - { - get_token(); - } - - // store key - expect(lexer::token_type::value_string); - const auto key = m_lexer.get_string(); - - bool keep_tag = false; - if (keep) - { - if (callback) - { - basic_json k(key); - keep_tag = callback(depth, parse_event_t::key, k); - } - else - { - keep_tag = true; - } - } - - // parse separator (:) - get_token(); - expect(lexer::token_type::name_separator); - - // parse and add value - get_token(); - auto value = parse_internal(keep); - if (keep and keep_tag and not value.is_discarded()) - { - result[key] = std::move(value); - } - } - while (last_token == lexer::token_type::value_separator); - - // closing } - expect(lexer::token_type::end_object); - get_token(); - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result = basic_json(value_t::discarded); - } - - return result; - } - - case lexer::token_type::begin_array: - { - if (keep and (not callback - or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0))) - { - // explicitly set result to object to cope with [] - result.m_type = value_t::array; - result.m_value = value_t::array; - } - - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == lexer::token_type::end_array) - { - get_token(); - if (callback and not callback(--depth, parse_event_t::array_end, result)) - { - result = basic_json(value_t::discarded); - } - return result; - } - - // no comma is expected here - unexpect(lexer::token_type::value_separator); - - // otherwise: parse values - do - { - // ugly, but could be fixed with loop reorganization - if (last_token == lexer::token_type::value_separator) - { - get_token(); - } - - // parse value - auto value = parse_internal(keep); - if (keep and not value.is_discarded()) - { - result.push_back(std::move(value)); - } - } - while (last_token == lexer::token_type::value_separator); - - // closing ] - expect(lexer::token_type::end_array); - get_token(); - if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) - { - result = basic_json(value_t::discarded); - } - - return result; - } - - case lexer::token_type::literal_null: - { - get_token(); - result.m_type = value_t::null; - break; - } - - case lexer::token_type::value_string: - { - const auto s = m_lexer.get_string(); - get_token(); - result = basic_json(s); - break; - } - - case lexer::token_type::literal_true: - { - get_token(); - result.m_type = value_t::boolean; - result.m_value = true; - break; - } - - case lexer::token_type::literal_false: - { - get_token(); - result.m_type = value_t::boolean; - result.m_value = false; - break; - } - - case lexer::token_type::value_number: - { - m_lexer.get_number(result); - get_token(); - break; - } - - default: - { - // the last token was unexpected - unexpect(last_token); - } - } - - if (keep and callback and not callback(depth, parse_event_t::value, result)) - { - result = basic_json(value_t::discarded); - } - return result; - } - - /// get next token from lexer - typename lexer::token_type get_token() - { - last_token = m_lexer.scan(); - return last_token; - } - - void expect(typename lexer::token_type t) const - { - if (t != last_token) - { - std::string error_msg = "parse error - unexpected "; - error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + - "'") : - lexer::token_type_name(last_token)); - error_msg += "; expected " + lexer::token_type_name(t); - throw std::invalid_argument(error_msg); - } - } - - void unexpect(typename lexer::token_type t) const - { - if (t == last_token) - { - std::string error_msg = "parse error - unexpected "; - error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + - "'") : - lexer::token_type_name(last_token)); - throw std::invalid_argument(error_msg); - } - } - - private: - /// current level of recursion - int depth = 0; - /// callback function - const parser_callback_t callback = nullptr; - /// the type of the last read token - typename lexer::token_type last_token = lexer::token_type::uninitialized; - /// the lexer - lexer m_lexer; - }; - - public: - /*! - @brief JSON Pointer - - A JSON pointer defines a string syntax for identifying a specific value - within a JSON document. It can be used with functions `at` and - `operator[]`. Furthermore, JSON pointers are the base for JSON patches. - - @sa [RFC 6901](https://tools.ietf.org/html/rfc6901) - - @since version 2.0.0 - */ - class json_pointer - { - /// allow basic_json to access private members - friend class basic_json; - - public: - /*! - @brief create JSON pointer - - Create a JSON pointer according to the syntax described in - [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). - - @param[in] s string representing the JSON pointer; if omitted, the - empty string is assumed which references the whole JSON - value - - @throw std::domain_error if reference token is nonempty and does not - begin with a slash (`/`); example: `"JSON pointer must be empty or - begin with /"` - @throw std::domain_error if a tilde (`~`) is not followed by `0` - (representing `~`) or `1` (representing `/`); example: `"escape error: - ~ must be followed with 0 or 1"` - - @liveexample{The example shows the construction several valid JSON - pointers as well as the exceptional behavior.,json_pointer} - - @since version 2.0.0 - */ - explicit json_pointer(const std::string& s = "") - : reference_tokens(split(s)) - {} - - /*! - @brief return a string representation of the JSON pointer - - @invariant For each JSON pointer `ptr`, it holds: - @code {.cpp} - ptr == json_pointer(ptr.to_string()); - @endcode - - @return a string representation of the JSON pointer - - @liveexample{The example shows the result of `to_string`., - json_pointer__to_string} - - @since version 2.0.0 - */ - std::string to_string() const noexcept - { - return std::accumulate(reference_tokens.begin(), - reference_tokens.end(), std::string{}, - [](const std::string & a, const std::string & b) - { - return a + "/" + escape(b); - }); - } - - /// @copydoc to_string() - operator std::string() const - { - return to_string(); - } - - private: - /// remove and return last reference pointer - std::string pop_back() - { - if (is_root()) - { - throw std::domain_error("JSON pointer has no parent"); - } - - auto last = reference_tokens.back(); - reference_tokens.pop_back(); - return last; - } - - /// return whether pointer points to the root document - bool is_root() const - { - return reference_tokens.empty(); - } - - json_pointer top() const - { - if (is_root()) - { - throw std::domain_error("JSON pointer has no parent"); - } - - json_pointer result = *this; - result.reference_tokens = {reference_tokens[0]}; - return result; - } - - /*! - @brief create and return a reference to the pointed to value - - @complexity Linear in the number of reference tokens. - */ - reference get_and_create(reference j) const - { - pointer result = &j; - - // in case no reference tokens exist, return a reference to the - // JSON value j which will be overwritten by a primitive value - for (const auto& reference_token : reference_tokens) - { - switch (result->m_type) - { - case value_t::null: - { - if (reference_token == "0") - { - // start a new array if reference token is 0 - result = &result->operator[](0); - } - else - { - // start a new object otherwise - result = &result->operator[](reference_token); - } - break; - } - - case value_t::object: - { - // create an entry in the object - result = &result->operator[](reference_token); - break; - } - - case value_t::array: - { - // create an entry in the array - result = &result->operator[](static_cast(std::stoi(reference_token))); - break; - } - - /* - The following code is only reached if there exists a - reference token _and_ the current value is primitive. In - this case, we have an error situation, because primitive - values may only occur as single value; that is, with an - empty list of reference tokens. - */ - default: - { - throw std::domain_error("invalid value to unflatten"); - } - } - } - - return *result; - } - - /*! - @brief return a reference to the pointed to value - - @note This version does not throw if a value is not present, but tries - to create nested values instead. For instance, calling this function - with pointer `"/this/that"` on a null value is equivalent to calling - `operator[]("this").operator[]("that")` on that value, effectively - changing the null value to an object. - - @param[in] ptr a JSON value - - @return reference to the JSON value pointed to by the JSON pointer - - @complexity Linear in the length of the JSON pointer. - - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number - */ - reference get_unchecked(pointer ptr) const - { - for (const auto& reference_token : reference_tokens) - { - // convert null values to arrays or objects before continuing - if (ptr->m_type == value_t::null) - { - // check if reference token is a number - const bool nums = std::all_of(reference_token.begin(), - reference_token.end(), - [](const char x) - { - return std::isdigit(x); - }); - - // change value to array for numbers or "-" or to object - // otherwise - if (nums or reference_token == "-") - { - *ptr = value_t::array; - } - else - { - *ptr = value_t::object; - } - } - - switch (ptr->m_type) - { - case value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case value_t::array: - { - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - throw std::domain_error("array index must not begin with '0'"); - } - - if (reference_token == "-") - { - // explicityly treat "-" as index beyond the end - ptr = &ptr->operator[](ptr->m_value.array->size()); - } - else - { - // convert array index to number; unchecked access - ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); - } - break; - } - - default: - { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); - } - } - } - - return *ptr; - } - - reference get_checked(pointer ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case value_t::array: - { - if (reference_token == "-") - { - // "-" always fails the range check - throw std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range"); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - throw std::domain_error("array index must not begin with '0'"); - } - - // note: at performs range check - ptr = &ptr->at(static_cast(std::stoi(reference_token))); - break; - } - - default: - { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); - } - } - } - - return *ptr; - } - - /*! - @brief return a const reference to the pointed to value - - @param[in] ptr a JSON value - - @return const reference to the JSON value pointed to by the JSON - pointer - */ - const_reference get_unchecked(const_pointer ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case value_t::array: - { - if (reference_token == "-") - { - // "-" cannot be used for const access - throw std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range"); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - throw std::domain_error("array index must not begin with '0'"); - } - - // use unchecked array access - ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); - break; - } - - default: - { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); - } - } - } - - return *ptr; - } - - const_reference get_checked(const_pointer ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case value_t::array: - { - if (reference_token == "-") - { - // "-" always fails the range check - throw std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range"); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - throw std::domain_error("array index must not begin with '0'"); - } - - // note: at performs range check - ptr = &ptr->at(static_cast(std::stoi(reference_token))); - break; - } - - default: - { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); - } - } - } - - return *ptr; - } - - /// split the string input to reference tokens - static std::vector split(const std::string& reference_string) - { - std::vector result; - - // special case: empty reference string -> no reference tokens - if (reference_string.empty()) - { - return result; - } - - // check if nonempty reference string begins with slash - if (reference_string[0] != '/') - { - throw std::domain_error("JSON pointer must be empty or begin with '/'"); - } - - // extract the reference tokens: - // - slash: position of the last read slash (or end of string) - // - start: position after the previous slash - for ( - // search for the first slash after the first character - size_t slash = reference_string.find_first_of("/", 1), - // set the beginning of the first reference token - start = 1; - // we can stop if start == string::npos+1 = 0 - start != 0; - // set the beginning of the next reference token - // (will eventually be 0 if slash == std::string::npos) - start = slash + 1, - // find next slash - slash = reference_string.find_first_of("/", start)) - { - // use the text between the beginning of the reference token - // (start) and the last slash (slash). - auto reference_token = reference_string.substr(start, slash - start); - - // check reference tokens are properly escaped - for (size_t pos = reference_token.find_first_of("~"); - pos != std::string::npos; - pos = reference_token.find_first_of("~", pos + 1)) - { - assert(reference_token[pos] == '~'); - - // ~ must be followed by 0 or 1 - if (pos == reference_token.size() - 1 or - (reference_token[pos + 1] != '0' and - reference_token[pos + 1] != '1')) - { - throw std::domain_error("escape error: '~' must be followed with '0' or '1'"); - } - } - - // finally, store the reference token - unescape(reference_token); - result.push_back(reference_token); - } - - return result; - } - - private: - /*! - @brief replace all occurrences of a substring by another string - - @param[in,out] s the string to manipulate; changed so that all - occurrences of @a f are replaced with @a t - @param[in] f the substring to replace with @a t - @param[in] t the string to replace @a f - - @pre The search string @a f must not be empty. - - @since version 2.0.0 - */ - static void replace_substring(std::string& s, - const std::string& f, - const std::string& t) - { - assert(not f.empty()); - - for ( - size_t pos = s.find(f); // find first occurrence of f - pos != std::string::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t - pos = s.find(f, pos + t.size()) // find next occurrence of f - ); - } - - /// escape tilde and slash - static std::string escape(std::string s) - { - // escape "~"" to "~0" and "/" to "~1" - replace_substring(s, "~", "~0"); - replace_substring(s, "/", "~1"); - return s; - } - - /// unescape tilde and slash - static void unescape(std::string& s) - { - // first transform any occurrence of the sequence '~1' to '/' - replace_substring(s, "~1", "/"); - // then transform any occurrence of the sequence '~0' to '~' - replace_substring(s, "~0", "~"); - } - - /*! - @param[in] reference_string the reference string to the current value - @param[in] value the value to consider - @param[in,out] result the result object to insert values to - - @note Empty objects or arrays are flattened to `null`. - */ - static void flatten(const std::string& reference_string, - const basic_json& value, - basic_json& result) - { - switch (value.m_type) - { - case value_t::array: - { - if (value.m_value.array->empty()) - { - // flatten empty array as null - result[reference_string] = nullptr; - } - else - { - // iterate array and use index as reference string - for (size_t i = 0; i < value.m_value.array->size(); ++i) - { - flatten(reference_string + "/" + std::to_string(i), - value.m_value.array->operator[](i), result); - } - } - break; - } - - case value_t::object: - { - if (value.m_value.object->empty()) - { - // flatten empty object as null - result[reference_string] = nullptr; - } - else - { - // iterate object and use keys as reference string - for (const auto& element : *value.m_value.object) - { - flatten(reference_string + "/" + escape(element.first), - element.second, result); - } - } - break; - } - - default: - { - // add primitive value with its reference string - result[reference_string] = value; - break; - } - } - } - - /*! - @param[in] value flattened JSON - - @return unflattened JSON - */ - static basic_json unflatten(const basic_json& value) - { - if (not value.is_object()) - { - throw std::domain_error("only objects can be unflattened"); - } - - basic_json result; - - // iterate the JSON object values - for (const auto& element : *value.m_value.object) - { - if (not element.second.is_primitive()) - { - throw std::domain_error("values in object must be primitive"); - } - - // assign value to reference pointed to by JSON pointer; Note - // that if the JSON pointer is "" (i.e., points to the whole - // value), function get_and_create returns a reference to - // result itself. An assignment will then create a primitive - // value. - json_pointer(element.first).get_and_create(result) = element.second; - } - - return result; - } - - private: - /// the reference tokens - std::vector reference_tokens {}; - }; - - ////////////////////////// - // JSON Pointer support // - ////////////////////////// - - /// @name JSON Pointer functions - /// @{ - - /*! - @brief access specified element via JSON Pointer - - Uses a JSON pointer to retrieve a reference to the respective JSON value. - No bound checking is performed. Similar to @ref operator[](const typename - object_t::key_type&), `null` values are created in arrays and objects if - necessary. - - In particular: - - If the JSON pointer points to an object key that does not exist, it - is created an filled with a `null` value before a reference to it - is returned. - - If the JSON pointer points to an array index that does not exist, it - is created an filled with a `null` value before a reference to it - is returned. All indices between the current maximum and the given - index are also filled with `null`. - - The special value `-` is treated as a synonym for the index past the - end. - - @param[in] ptr a JSON pointer - - @return reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number - - @liveexample{The behavior is shown in the example.,operatorjson_pointer} - - @since version 2.0.0 - */ - reference operator[](const json_pointer& ptr) - { - return ptr.get_unchecked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Uses a JSON pointer to retrieve a reference to the respective JSON value. - No bound checking is performed. The function does not change the JSON - value; no `null` values are created. In particular, the the special value - `-` yields an exception. - - @param[in] ptr JSON pointer to the desired element - - @return const reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number - - @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} - - @since version 2.0.0 - */ - const_reference operator[](const json_pointer& ptr) const - { - return ptr.get_unchecked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Returns a reference to the element at with specified JSON pointer @a ptr, - with bounds checking. - - @param[in] ptr JSON pointer to the desired element - - @return reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number - - @liveexample{The behavior is shown in the example.,at_json_pointer} - - @since version 2.0.0 - */ - reference at(const json_pointer& ptr) - { - return ptr.get_checked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Returns a const reference to the element at with specified JSON pointer @a - ptr, with bounds checking. - - @param[in] ptr JSON pointer to the desired element - - @return reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number - - @liveexample{The behavior is shown in the example.,at_json_pointer_const} - - @since version 2.0.0 - */ - const_reference at(const json_pointer& ptr) const - { - return ptr.get_checked(this); - } - - /*! - @brief return flattened JSON value - - The function creates a JSON object whose keys are JSON pointers (see [RFC - 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all - primitive. The original JSON value can be restored using the @ref - unflatten() function. - - @return an object that maps JSON pointers to primitve values - - @note Empty objects and arrays are flattened to `null` and will not be - reconstructed correctly by the @ref unflatten() function. - - @complexity Linear in the size the JSON value. - - @liveexample{The following code shows how a JSON object is flattened to an - object whose keys consist of JSON pointers.,flatten} - - @sa @ref unflatten() for the reverse function - - @since version 2.0.0 - */ - basic_json flatten() const - { - basic_json result(value_t::object); - json_pointer::flatten("", *this, result); - return result; - } - - /*! - @brief unflatten a previously flattened JSON value - - The function restores the arbitrary nesting of a JSON value that has been - flattened before using the @ref flatten() function. The JSON value must - meet certain constraints: - 1. The value must be an object. - 2. The keys must be JSON pointers (see - [RFC 6901](https://tools.ietf.org/html/rfc6901)) - 3. The mapped values must be primitive JSON types. - - @return the original JSON from a flattened version - - @note Empty objects and arrays are flattened by @ref flatten() to `null` - values and can not unflattened to their original type. Apart from - this example, for a JSON value `j`, the following is always true: - `j == j.flatten().unflatten()`. - - @complexity Linear in the size the JSON value. - - @liveexample{The following code shows how a flattened JSON object is - unflattened into the original nested JSON object.,unflatten} - - @sa @ref flatten() for the reverse function - - @since version 2.0.0 - */ - basic_json unflatten() const - { - return json_pointer::unflatten(*this); - } - - /// @} - - ////////////////////////// - // JSON Patch functions // - ////////////////////////// - - /// @name JSON Patch functions - /// @{ - - /*! - @brief applies a JSON patch - - [JSON Patch](http://jsonpatch.com) defines a JSON document structure for - expressing a sequence of operations to apply to a JSON) document. With - this funcion, a JSON Patch is applied to the current JSON value by - executing all operations from the patch. - - @param[in] json_patch JSON patch document - @return patched document - - @note The application of a patch is atomic: Either all operations succeed - and the patched document is returned or an exception is thrown. In - any case, the original value is not changed: the patch is applied - to a copy of the value. - - @throw std::out_of_range if a JSON pointer inside the patch could not - be resolved successfully in the current JSON value; example: `"key baz - not found"` - @throw invalid_argument if the JSON patch is malformed (e.g., mandatory - attributes are missing); example: `"operation add must have member path"` - - @complexity Linear in the size of the JSON value and the length of the - JSON patch. As usually only a fraction of the JSON value is affected by - the patch, the complexity can usually be neglected. - - @liveexample{The following code shows how a JSON patch is applied to a - value.,patch} - - @sa @ref diff -- create a JSON patch by comparing two JSON values - - @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) - @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) - - @since version 2.0.0 - */ - basic_json patch(const basic_json& json_patch) const - { - // make a working copy to apply the patch to - basic_json result = *this; - - // the valid JSON Patch operations - enum class patch_operations {add, remove, replace, move, copy, test, invalid}; - - const auto get_op = [](const std::string op) - { - if (op == "add") - { - return patch_operations::add; - } - if (op == "remove") - { - return patch_operations::remove; - } - if (op == "replace") - { - return patch_operations::replace; - } - if (op == "move") - { - return patch_operations::move; - } - if (op == "copy") - { - return patch_operations::copy; - } - if (op == "test") - { - return patch_operations::test; - } - - return patch_operations::invalid; - }; - - // wrapper for "add" operation; add value at ptr - const auto operation_add = [&result](json_pointer & ptr, basic_json val) - { - // adding to the root of the target document means replacing it - if (ptr.is_root()) - { - result = val; - } - else - { - // make sure the top element of the pointer exists - json_pointer top_pointer = ptr.top(); - if (top_pointer != ptr) - { - result.at(top_pointer); - } - - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result[ptr]; - - switch (parent.m_type) - { - case value_t::null: - case value_t::object: - { - // use operator[] to add value - parent[last_path] = val; - break; - } - - case value_t::array: - { - if (last_path == "-") - { - // special case: append to back - parent.push_back(val); - } - else - { - const auto idx = std::stoi(last_path); - if (static_cast(idx) > parent.size()) - { - // avoid undefined behavior - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); - } - else - { - // default case: insert add offset - parent.insert(parent.begin() + static_cast(idx), val); - } - } - break; - } - - default: - { - // if there exists a parent it cannot be primitive - assert(false); // LCOV_EXCL_LINE - } - } - } - }; - - // wrapper for "remove" operation; remove value at ptr - const auto operation_remove = [&result](json_pointer & ptr) - { - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result.at(ptr); - - // remove child - if (parent.is_object()) - { - // perform range check - auto it = parent.find(last_path); - if (it != parent.end()) - { - parent.erase(it); - } - else - { - throw std::out_of_range("key '" + last_path + "' not found"); - } - } - else if (parent.is_array()) - { - // note erase performs range check - parent.erase(static_cast(std::stoi(last_path))); - } - }; - - // type check - if (not json_patch.is_array()) - { - // a JSON patch must be an array of objects - throw std::invalid_argument("JSON patch must be an array of objects"); - } - - // iterate and apply th eoperations - for (const auto& val : json_patch) - { - // wrapper to get a value for an operation - const auto get_value = [&val](const std::string & op, - const std::string & member, - bool string_type) -> basic_json& - { - // find value - auto it = val.m_value.object->find(member); - - // context-sensitive error message - const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; - - // check if desired value is present - if (it == val.m_value.object->end()) - { - throw std::invalid_argument(error_msg + " must have member '" + member + "'"); - } - - // check if result is of type string - if (string_type and not it->second.is_string()) - { - throw std::invalid_argument(error_msg + " must have string member '" + member + "'"); - } - - // no error: return value - return it->second; - }; - - // type check - if (not val.is_object()) - { - throw std::invalid_argument("JSON patch must be an array of objects"); - } - - // collect mandatory members - const std::string op = get_value("op", "op", true); - const std::string path = get_value(op, "path", true); - json_pointer ptr(path); - - switch (get_op(op)) - { - case patch_operations::add: - { - operation_add(ptr, get_value("add", "value", false)); - break; - } - - case patch_operations::remove: - { - operation_remove(ptr); - break; - } - - case patch_operations::replace: - { - // the "path" location must exist - use at() - result.at(ptr) = get_value("replace", "value", false); - break; - } - - case patch_operations::move: - { - const std::string from_path = get_value("move", "from", true); - json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); - - // The move operation is functionally identical to a - // "remove" operation on the "from" location, followed - // immediately by an "add" operation at the target - // location with the value that was just removed. - operation_remove(from_ptr); - operation_add(ptr, v); - break; - } - - case patch_operations::copy: - { - const std::string from_path = get_value("copy", "from", true);; - const json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - result[ptr] = result.at(from_ptr); - break; - } - - case patch_operations::test: - { - bool success = false; - try - { - // check if "value" matches the one at "path" - // the "path" location must exist - use at() - success = (result.at(ptr) == get_value("test", "value", false)); - } - catch (std::out_of_range&) - { - // ignore out of range errors: success remains false - } - - // throw an exception if test fails - if (not success) - { - throw std::domain_error("unsuccessful: " + val.dump()); - } - - break; - } - - case patch_operations::invalid: - { - // op must be "add", "remove", "replace", "move", "copy", or - // "test" - throw std::invalid_argument("operation value '" + op + "' is invalid"); - } - } - } - - return result; - } - - /*! - @brief creates a diff as a JSON patch - - Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can - be changed into the value @a target by calling @ref patch function. - - @invariant For two JSON values @a source and @a target, the following code - yields always `true`: - @code {.cpp} - source.patch(diff(source, target)) == target; - @endcode - - @note Currently, only `remove`, `add`, and `replace` operations are - generated. - - @param[in] source JSON value to copare from - @param[in] target JSON value to copare against - @param[in] path helper value to create JSON pointers - - @return a JSON patch to convert the @a source to @a target - - @complexity Linear in the lengths of @a source and @a target. - - @liveexample{The following code shows how a JSON patch is created as a - diff for two JSON values.,diff} - - @sa @ref patch -- apply a JSON patch - - @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) - - @since version 2.0.0 - */ - static basic_json diff(const basic_json& source, - const basic_json& target, - const std::string& path = "") - { - // the patch - basic_json result(value_t::array); - - // if the values are the same, return empty patch - if (source == target) - { - return result; - } - - if (source.type() != target.type()) - { - // different types: replace value - result.push_back( - { - {"op", "replace"}, - {"path", path}, - {"value", target} - }); - } - else - { - switch (source.type()) - { - case value_t::array: - { - // first pass: traverse common elements - size_t i = 0; - while (i < source.size() and i < target.size()) - { - // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - ++i; - } - - // i now reached the end of at least one array - // in a second pass, traverse the remaining elements - - // remove my remaining elements - const auto end_index = static_cast(result.size()); - while (i < source.size()) - { - // add operations in reverse order to avoid invalid - // indices - result.insert(result.begin() + end_index, object( - { - {"op", "remove"}, - {"path", path + "/" + std::to_string(i)} - })); - ++i; - } - - // add other remaining elements - while (i < target.size()) - { - result.push_back( - { - {"op", "add"}, - {"path", path + "/" + std::to_string(i)}, - {"value", target[i]} - }); - ++i; - } - - break; - } - - case value_t::object: - { - // first pass: traverse this object's elements - for (auto it = source.begin(); it != source.end(); ++it) - { - // escape the key name to be used in a JSON patch - const auto key = json_pointer::escape(it.key()); - - if (target.find(it.key()) != target.end()) - { - // recursive call to compare object values at key it - auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - } - else - { - // found a key that is not in o -> remove it - result.push_back(object( - { - {"op", "remove"}, - {"path", path + "/" + key} - })); - } - } - - // second pass: traverse other object's elements - for (auto it = target.begin(); it != target.end(); ++it) - { - if (source.find(it.key()) == source.end()) - { - // found a key that is not in this -> add it - const auto key = json_pointer::escape(it.key()); - result.push_back( - { - {"op", "add"}, - {"path", path + "/" + key}, - {"value", it.value()} - }); - } - } - - break; - } - - default: - { - // both primitive type: replace value - result.push_back( - { - {"op", "replace"}, - {"path", path}, - {"value", target} - }); - break; - } - } - } - - return result; - } - - /// @} -}; - - -///////////// -// presets // -///////////// - -/*! -@brief default JSON class - -This type is the default specialization of the @ref basic_json class which -uses the standard template types. - -@since version 1.0.0 -*/ -using json = basic_json<>; -} - - -/////////////////////// -// nonmember support // -/////////////////////// - -// specialization of std::swap, and std::hash -namespace std -{ -/*! -@brief exchanges the values of two JSON objects - -@since version 1.0.0 -*/ -template<> -inline void swap(nlohmann::json& j1, - nlohmann::json& j2) noexcept( - is_nothrow_move_constructible::value and - is_nothrow_move_assignable::value - ) -{ - j1.swap(j2); -} - -/// hash value for JSON objects -template<> -struct hash -{ - /*! - @brief return a hash value for a JSON object - - @since version 1.0.0 - */ - std::size_t operator()(const nlohmann::json& j) const - { - // a naive hashing via the string representation - const auto& h = hash(); - return h(j.dump()); - } -}; -} - -/*! -@brief user-defined string literal for JSON values - -This operator implements a user-defined string literal for JSON objects. It -can be used by adding `"_json"` to a string literal and returns a JSON object -if no parse error occurred. - -@param[in] s a string representation of a JSON object -@param[in] n the length of string @a s -@return a JSON object - -@since version 1.0.0 -*/ -inline nlohmann::json operator "" _json(const char* s, std::size_t n) -{ - return nlohmann::json::parse(s, s + n); -} - -/*! -@brief user-defined string literal for JSON pointer - -This operator implements a user-defined string literal for JSON Pointers. It -can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer -object if no parse error occurred. - -@param[in] s a string representation of a JSON Pointer -@param[in] n the length of string @a s -@return a JSON pointer object - -@since version 2.0.0 -*/ -inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) -{ - return nlohmann::json::json_pointer(std::string(s, n)); -} - -// restore GCC/clang diagnostic settings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic pop -#endif - -#endif diff --git a/zto/ext/libnatpmp/Changelog.txt b/zto/ext/libnatpmp/Changelog.txt deleted file mode 100644 index be75a0b..0000000 --- a/zto/ext/libnatpmp/Changelog.txt +++ /dev/null @@ -1,98 +0,0 @@ -$Id: Changelog.txt,v 1.33 2013/11/26 08:47:36 nanard Exp $ - -2013/11/26: - enforce strict aliasing rules. - -2013/09/10: - small patch for MSVC >= 16 - rename win32 implementation of gettimeofday() to natpmp_gettimeofday() - -2012/08/21: - Little change in Makefile - removed warnings in testgetgateway.c - Fixed bugs in command line argumentparsing in natpmpc.c - -2011/08/07: - Patch to build on debian/kFreeBSD. - -2011/07/15: - Put 3 clauses BSD licence at the top of source files. - -2011/06/18: - --no-undefined => -Wl,--no-undefined - adding a natpmpc.1 man page - -2011/05/19: - Small fix in libnatpmpmodule.c thanks to Manuel Mausz - -2011/01/03: - Added an argument to initnatpmp() in order to force the gateway to be used - -2011/01/01: - fix in make install - -2010/05/21: - make install now working under MacOSX (and BSD) - -2010/04/12: - cplusplus stuff in natpmp.h - -2010/02/02: - Fixed compilation under Mac OS X - -2009/12/19: - improve and fix building under Windows. - Project files for MS Visual Studio 2008 - More simple (and working) code for Win32. - More checks in the /proc/net/route parsing. Add some comments. - -2009/08/04: - improving getgateway.c for windows - -2009/07/13: - Adding Haiku code in getgateway.c - -2009/06/04: - Adding Python module thanks to David Wu - -2009/03/10: - Trying to have windows get gateway working if not using DHCP - -2009/02/27: - dont include declspec.h if not under WIN32. - -2009/01/23: - Prefixed the libraries name with lib - -2008/10/06: - Fixed a memory leak in getdefaultgateway() (USE_SYSCTL_NET_ROUTE) - -2008/07/03: - Adding WIN32 code from Robbie Hanson - -2008/06/30: - added a Solaris implementation for getgateway(). - added a LICENCE file to the distribution - -2008/05/29: - Anonymous unions are forbidden in ANSI C. That was causing problems with - non-GCC compilers. - -2008/04/28: - introduced strnatpmperr() - improved natpmpc.c sample - make install now install the binary - -2007/12/13: - Fixed getgateway.c for working under OS X ;) - Fixed values for NATPMP_PROTOCOL_TCP and NATPMP_PROTOCOL_UDP - -2007/12/11: - Fixed getgateway.c for compilation under Mac OS X - -2007/12/01: - added some comments in .h - -2007/11/30: - implemented almost everything - diff --git a/zto/ext/libnatpmp/JavaTest.java b/zto/ext/libnatpmp/JavaTest.java deleted file mode 100644 index 0379c18..0000000 --- a/zto/ext/libnatpmp/JavaTest.java +++ /dev/null @@ -1,42 +0,0 @@ -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; - -import fr.free.miniupnp.libnatpmp.NatPmp; -import fr.free.miniupnp.libnatpmp.NatPmpResponse; - -class JavaTest { - public static void main(String[] args) { - NatPmp natpmp = new NatPmp(); - - natpmp.sendPublicAddressRequest(); - NatPmpResponse response = new NatPmpResponse(); - - int result = -1; - do{ - result = natpmp.readNatPmpResponseOrRetry(response); - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - //fallthrough - } - } while (result != 0); - - byte[] bytes = intToByteArray(response.addr); - - try { - InetAddress inetAddress = InetAddress.getByAddress(bytes); - System.out.println("Public address is " + inetAddress); - } catch (UnknownHostException e) { - throw new RuntimeException(e); - } - } - - public static final byte[] intToByteArray(int value) { - return new byte[] { - (byte)value, - (byte)(value >>> 8), - (byte)(value >>> 16), - (byte)(value >>> 24)}; - } -} diff --git a/zto/ext/libnatpmp/LICENSE b/zto/ext/libnatpmp/LICENSE deleted file mode 100644 index 7fff2c2..0000000 --- a/zto/ext/libnatpmp/LICENSE +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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. - diff --git a/zto/ext/libnatpmp/Makefile b/zto/ext/libnatpmp/Makefile deleted file mode 100644 index b67b3e8..0000000 --- a/zto/ext/libnatpmp/Makefile +++ /dev/null @@ -1,177 +0,0 @@ -# $Id: Makefile,v 1.23 2013/11/26 16:38:15 nanard Exp $ -# This Makefile is designed for use with GNU make -# libnatpmp -# (c) 2007-2013 Thomas Bernard -# http://miniupnp.free.fr/libnatpmp.html - -OS = $(shell uname -s) -CC = gcc -INSTALL = install -p -ARCH = $(shell uname -m | sed -e s/i.86/i686/) -VERSION = $(shell cat VERSION) - -ifeq ($(OS), Darwin) -JARSUFFIX=mac -endif -ifeq ($(OS), Linux) -JARSUFFIX=linux -endif -ifneq (,$(findstring WIN,$(OS))) -JARSUFFIX=win32 -endif - -# APIVERSION is used in soname -APIVERSION = 1 -#LDFLAGS = -Wl,--no-undefined -CFLAGS ?= -Os -#CFLAGS = -g -O0 -CFLAGS += -fPIC -CFLAGS += -Wall -#CFLAGS += -Wextra -CFLAGS += -DENABLE_STRNATPMPERR -#CFLAGS += -Wstrict-aliasing - -LIBOBJS = natpmp.o getgateway.o - -OBJS = $(LIBOBJS) testgetgateway.o natpmpc.o natpmp-jni.o - -STATICLIB = libnatpmp.a -ifeq ($(OS), Darwin) - SHAREDLIB = libnatpmp.dylib - JNISHAREDLIB = libjninatpmp.dylib - SONAME = $(basename $(SHAREDLIB)).$(APIVERSION).dylib - CFLAGS := -DMACOSX -D_DARWIN_C_SOURCE $(CFLAGS) - SONAMEFLAGS=-Wl,-install_name,$(JNISHAREDLIB) -dynamiclib -framework JavaVM -else -ifneq (,$(findstring WIN,$(OS))) - SHAREDLIB = natpmp.dll - JNISHAREDLIB = jninatpmp.dll - CC = i686-w64-mingw32-gcc - EXTRA_LD = -lws2_32 -lIphlpapi -Wl,--no-undefined -Wl,--enable-runtime-pseudo-reloc --Wl,kill-at -else - SHAREDLIB = libnatpmp.so - JNISHAREDLIB = libjninatpmp.so - SONAME = $(SHAREDLIB).$(APIVERSION) - SONAMEFLAGS=-Wl,-soname,$(JNISHAREDLIB) -endif -endif - -HEADERS = natpmp.h - -EXECUTABLES = testgetgateway natpmpc-shared natpmpc-static - -INSTALLPREFIX ?= $(PREFIX)/usr -INSTALLDIRINC = $(INSTALLPREFIX)/include -INSTALLDIRLIB = $(INSTALLPREFIX)/lib -INSTALLDIRBIN = $(INSTALLPREFIX)/bin - -JAVA ?= java -JAVAC ?= javac -JAVAH ?= javah -JAVAPACKAGE = fr/free/miniupnp/libnatpmp -JAVACLASSES = $(JAVAPACKAGE)/NatPmp.class $(JAVAPACKAGE)/NatPmpResponse.class $(JAVAPACKAGE)/LibraryExtractor.class $(JAVAPACKAGE)/URLUtils.class -JNIHEADERS = fr_free_miniupnp_libnatpmp_NatPmp.h - -.PHONY: all clean depend install cleaninstall installpythonmodule - -all: $(STATICLIB) $(SHAREDLIB) $(EXECUTABLES) - -pythonmodule: $(STATICLIB) libnatpmpmodule.c setup.py - python setup.py build - touch $@ - -installpythonmodule: pythonmodule - python setup.py install - -clean: - $(RM) $(OBJS) $(EXECUTABLES) $(STATICLIB) $(SHAREDLIB) $(JAVACLASSES) $(JNISHAREDLIB) - $(RM) pythonmodule - $(RM) -r build/ dist/ libraries/ - -depend: - makedepend -f$(MAKEFILE_LIST) -Y $(OBJS:.o=.c) 2>/dev/null - -install: $(HEADERS) $(STATICLIB) $(SHAREDLIB) natpmpc-shared - $(INSTALL) -d $(INSTALLDIRINC) - $(INSTALL) -m 644 $(HEADERS) $(INSTALLDIRINC) - $(INSTALL) -d $(INSTALLDIRLIB) - $(INSTALL) -m 644 $(STATICLIB) $(INSTALLDIRLIB) - $(INSTALL) -m 644 $(SHAREDLIB) $(INSTALLDIRLIB)/$(SONAME) - $(INSTALL) -d $(INSTALLDIRBIN) - $(INSTALL) -m 755 natpmpc-shared $(INSTALLDIRBIN)/natpmpc - ln -s -f $(SONAME) $(INSTALLDIRLIB)/$(SHAREDLIB) - -$(JNIHEADERS): fr/free/miniupnp/libnatpmp/NatPmp.class - $(JAVAH) -jni fr.free.miniupnp.libnatpmp.NatPmp - -%.class: %.java - $(JAVAC) -cp . $< - -$(JNISHAREDLIB): $(SHAREDLIB) $(JNIHEADERS) $(JAVACLASSES) -ifeq (,$(JAVA_HOME)) - @echo "Check your JAVA_HOME environement variable" && false -endif -ifneq (,$(findstring WIN,$(OS))) - $(CC) -m32 -D_JNI_Implementation_ -Wl,--kill-at \ - -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32" \ - natpmp-jni.c -shared \ - -o $(JNISHAREDLIB) -L. -lnatpmp -lws2_32 -lIphlpapi -else - $(CC) $(CFLAGS) -c -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32" natpmp-jni.c - $(CC) $(CFLAGS) -o $(JNISHAREDLIB) -shared $(SONAMEFLAGS) natpmp-jni.o -lc -L. -lnatpmp -endif - -jar: $(JNISHAREDLIB) - find fr -name '*.class' -print > classes.list - $(eval JNISHAREDLIBPATH := $(shell java fr.free.miniupnp.libnatpmp.LibraryExtractor)) - mkdir -p libraries/$(JNISHAREDLIBPATH) - mv $(JNISHAREDLIB) libraries/$(JNISHAREDLIBPATH)/$(JNISHAREDLIB) - jar cf natpmp_$(JARSUFFIX).jar @classes.list libraries/$(JNISHAREDLIBPATH)/$(JNISHAREDLIB) - $(RM) classes.list - -jnitest: $(JNISHAREDLIB) JavaTest.class - $(RM) libjninatpmp.so - $(JAVA) -Djna.nosys=true -cp . JavaTest - -mvn_install: - mvn install:install-file -Dfile=java/natpmp_$(JARSUFFIX).jar \ - -DgroupId=com.github \ - -DartifactId=natpmp \ - -Dversion=$(VERSION) \ - -Dpackaging=jar \ - -Dclassifier=$(JARSUFFIX) \ - -DgeneratePom=true \ - -DcreateChecksum=true - -cleaninstall: - $(RM) $(addprefix $(INSTALLDIRINC), $(HEADERS)) - $(RM) $(INSTALLDIRLIB)/$(SONAME) - $(RM) $(INSTALLDIRLIB)/$(SHAREDLIB) - $(RM) $(INSTALLDIRLIB)/$(STATICLIB) - -testgetgateway: testgetgateway.o getgateway.o - $(CC) $(LDFLAGS) -o $@ $^ $(EXTRA_LD) - -natpmpc-static: natpmpc.o $(STATICLIB) - $(CC) $(LDFLAGS) -o $@ $^ $(EXTRA_LD) - -natpmpc-shared: natpmpc.o $(SHAREDLIB) - $(CC) $(LDFLAGS) -o $@ $^ $(EXTRA_LD) - -$(STATICLIB): $(LIBOBJS) - $(AR) crs $@ $? - -$(SHAREDLIB): $(LIBOBJS) -ifeq ($(OS), Darwin) - $(CC) -dynamiclib -Wl,-install_name,$(SONAME) -o $@ $^ -else - $(CC) -shared -Wl,-soname,$(SONAME) -o $@ $^ $(EXTRA_LD) -endif - - -# DO NOT DELETE - -natpmp.o: natpmp.h getgateway.h declspec.h -getgateway.o: getgateway.h declspec.h -testgetgateway.o: getgateway.h declspec.h -natpmpc.o: natpmp.h diff --git a/zto/ext/libnatpmp/README b/zto/ext/libnatpmp/README deleted file mode 100644 index 269392d..0000000 --- a/zto/ext/libnatpmp/README +++ /dev/null @@ -1,7 +0,0 @@ -libnatpmp (c) 2007-2009 Thomas Bernard -contact : miniupnp@free.fr - -see http://miniupnp.free.fr/libnatpmp.html -or http://miniupnp.tuxfamily.org/libnatpmp.html -for some documentation and code samples. - diff --git a/zto/ext/libnatpmp/build.bat b/zto/ext/libnatpmp/build.bat deleted file mode 100644 index 2d2f27c..0000000 --- a/zto/ext/libnatpmp/build.bat +++ /dev/null @@ -1,30 +0,0 @@ -@echo Compiling with MinGW -@SET LIBS=-lws2_32 -liphlpapi - -@echo Compile getgateway -gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR getgateway.c -gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR testgetgateway.c -gcc -o testgetgateway getgateway.o testgetgateway.o %LIBS% -del testgetgateway.o - -@echo Compile natpmp-static: -gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR getgateway.c -gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR natpmp.c -gcc -c -Wall -Os -DWIN32 wingettimeofday.c -ar cr natpmp.a getgateway.o natpmp.o wingettimeofday.o -del getgateway.o natpmp.o -gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR natpmpc.c -gcc -o natpmpc-static natpmpc.o natpmp.a %LIBS% -upx --best natpmpc-static.exe -del natpmpc.o - -@echo Create natpmp.dll: -gcc -c -Wall -Os -DWIN32 -DENABLE_STRNATPMPERR -DNATPMP_EXPORTS getgateway.c -gcc -c -Wall -Os -DWIN32 -DENABLE_STRNATPMPERR -DNATPMP_EXPORTS natpmp.c -dllwrap -k --driver-name gcc --def natpmp.def --output-def natpmp.dll.def --implib natpmp.lib -o natpmp.dll getgateway.o natpmp.o wingettimeofday.o %LIBS% - -@echo Compile natpmp-shared: -gcc -c -Wall -Os -DWIN32 -DENABLE_STRNATPMPERR -DNATPMP_EXPORTS natpmpc.c -gcc -o natpmpc-shared natpmpc.o natpmp.lib -lws2_32 -upx --best natpmpc-shared.exe -del *.o diff --git a/zto/ext/libnatpmp/declspec.h b/zto/ext/libnatpmp/declspec.h deleted file mode 100644 index a76be02..0000000 --- a/zto/ext/libnatpmp/declspec.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef DECLSPEC_H_INCLUDED -#define DECLSPEC_H_INCLUDED - -#if defined(WIN32) && !defined(STATICLIB) - /* for windows dll */ - #ifdef NATPMP_EXPORTS - #define LIBSPEC __declspec(dllexport) - #else - #define LIBSPEC __declspec(dllimport) - #endif -#else - #if defined(__GNUC__) && __GNUC__ >= 4 - /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ - #define LIBSPEC __attribute__ ((visibility ("default"))) - #else - #define LIBSPEC - #endif -#endif - -#endif - diff --git a/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/LibraryExtractor.java b/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/LibraryExtractor.java deleted file mode 100644 index 5491d94..0000000 --- a/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/LibraryExtractor.java +++ /dev/null @@ -1,238 +0,0 @@ -package fr.free.miniupnp.libnatpmp; - -/** I (Leah X Schmidt) copied this code from jnaerator, because -JNAerator's extractor requires you to buy into the whole JNA -concept. - -JNAErator is -Copyright (c) 2009 Olivier Chafik, All Rights Reserved - -JNAerator is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -JNAerator is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with JNAerator. If not, see . - -*/ - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -public class LibraryExtractor { - - private static boolean libPathSet = false; - - public static String getLibraryPath(String libraryName, boolean extractAllLibraries, Class cl) { - try { - String customPath = System.getProperty("library." + libraryName); - if (customPath == null) - customPath = System.getenv(libraryName.toUpperCase() + "_LIBRARY"); - if (customPath != null) { - File f = new File(customPath); - if (!f.exists()) - System.err.println("Library file '" + customPath + "' does not exist !"); - else - return f.getAbsolutePath(); - } - //ClassLoader cl = LibraryExtractor.class.getClassLoader(); - String prefix = "(?i)" + (isWindows() ? "" : "lib") + libraryName + "[^A-Za-z_].*"; - String libsuffix = "(?i).*\\.(so|dll|dylib|jnilib)"; - //String othersuffix = "(?i).*\\.(pdb)"; - - URL sourceURL = null; - List otherURLs = new ArrayList(); - - - String arch = getCurrentOSAndArchString(); - //System.out.println("libURL = " + libURL); - List list = URLUtils.listFiles(URLUtils.getResource(cl, "libraries/" + arch)), - noArchList = URLUtils.listFiles(URLUtils.getResource(cl, "libraries/noarch")); - - Set names = new HashSet(); - for (URL url : list) { - String name = getFileName(url); - names.add(name); - } - for (URL url : noArchList) { - String name = getFileName(url); - if (names.add(name)) - list.add(url); - } - - for (File f : new File(".").listFiles()) - if (f.isFile()) - list.add(f.toURI().toURL()); - - for (URL url : list) { - String name = getFileName(url); - boolean pref = name.matches(prefix), suff = name.matches(libsuffix); - if (pref && suff) - sourceURL = url; - else //if (suff || fileName.matches(othersuffix)) - otherURLs.add(url); - } - List files = new ArrayList(); - if (extractAllLibraries) { - for (URL url : otherURLs) - files.add(extract(url)); - } - - if (System.getProperty("javawebstart.version") != null) { - if (isWindows()) { - //File f = new File("c:\\Windows\\" + (Platform.is64Bit() ? "SysWOW64\\" : "System32\\") + libraryName + ".dll"); - File f = new File("c:\\Windows\\" + "System32\\" + libraryName + ".dll"); - if (f.exists()) - return f.toString(); - } else if (isMac()) { - File f = new File("/System/Library/Frameworks/" + libraryName + ".framework/" + libraryName); - if (f.exists()) - return f.toString(); - } - } - - if (sourceURL == null) - return libraryName; - else { - File file = extract(sourceURL); - files.add(file); - - int lastSize; - do { - lastSize = files.size(); - for (Iterator it = files.iterator(); it.hasNext();) { - File f = it.next(); - if (!f.getName().matches(libsuffix)) - continue; - - try { - System.load(f.toString()); - it.remove(); - } catch (Throwable ex) { - System.err.println("Loading " + f.getName() + " failed (" + ex + ")"); - } - } - } while (files.size() < lastSize); - - return file.getCanonicalPath(); - } - } catch (Throwable ex) { - System.err.println("ERROR: Failed to extract library " + libraryName); - ex.printStackTrace(); - return libraryName; - } - } - - public static final boolean isWindows() { - String osName = System.getProperty("os.name"); - return osName.startsWith("Windows"); - } - - public static final boolean isMac() { - String osName = System.getProperty("os.name"); - return osName.startsWith("Mac") || osName.startsWith("Darwin"); - } - - //this code is from JNA, but JNA has a fallback to some native - //stuff in case this doesn't work. Since sun.arch.data.model is - //defined for Sun and IBM, this should work nearly everywhere. - public static final boolean is64Bit() { - String model = System.getProperty("sun.arch.data.model", - System.getProperty("com.ibm.vm.bitmode")); - if (model != null) { - return "64".equals(model); - } - String arch = System.getProperty("os.arch").toLowerCase(); - if ("x86_64".equals(arch) - || "ia64".equals(arch) - || "ppc64".equals(arch) - || "sparcv9".equals(arch) - || "amd64".equals(arch)) { - return true; - } - - return false; - } - - public static String getCurrentOSAndArchString() { - String os = System.getProperty("os.name"), arch = System.getProperty("os.arch"); - if (os.equals("Mac OS X")) { - os = "darwin"; - arch = "fat"; - } else if (os.startsWith("Windows")) { - return "win" + (is64Bit() ? "64" : "32"); - } else if (os.matches("SunOS|Solaris")) - os = "solaris"; - return os + "-" + arch; - } - - private static File extract(URL url) throws IOException { - File localFile; - if ("file".equals(url.getProtocol())) - localFile = new File(URLDecoder.decode(url.getFile(), "UTF-8")); - else { - File f = new File(System.getProperty("user.home")); - f = new File(f, ".jnaerator"); - f = new File(f, "extractedLibraries"); - if (!f.exists()) - f.mkdirs(); - - if (!libPathSet) { - String path = System.getProperty("java.library.path"); - if (path == null) { - System.setProperty("java.library.path", f.toString()); - } else { - System.setProperty("java.library.path", path + ":" + f); - } - - libPathSet = true; - } - localFile = new File(f, new File(url.getFile()).getName()); - URLConnection c = url.openConnection(); - if (localFile.exists() && localFile.lastModified() > c.getLastModified()) { - c.getInputStream().close(); - } else { - System.out.println("Extracting " + url); - InputStream in = c.getInputStream(); - OutputStream out = new FileOutputStream(localFile); - int len; - byte[] b = new byte[1024]; - while ((len = in.read(b)) > 0) - out.write(b, 0, len); - out.close(); - in.close(); - } - } - return localFile; - } - - private static String getFileName(URL url) { - return new File(url.getFile()).getName(); - } - - public static void main(String[] args) { - System.out.println(getCurrentOSAndArchString()); - } -} \ No newline at end of file diff --git a/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/NatPmp.java b/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/NatPmp.java deleted file mode 100644 index 2f1ddd3..0000000 --- a/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/NatPmp.java +++ /dev/null @@ -1,50 +0,0 @@ -package fr.free.miniupnp.libnatpmp; - -import java.nio.ByteBuffer; - - -public class NatPmp { - private static final String JNA_LIBRARY_NAME = LibraryExtractor.getLibraryPath("jninatpmp", true, NatPmp.class); - - static { - String s = JNA_LIBRARY_NAME; - startup(); - } - - public ByteBuffer natpmp; - - public NatPmp() { - init(0, 0); - } - - public NatPmp(int forcedgw) { - init(1, forcedgw); - } - - /** Cleans up the native resources used by this object. - Attempting to use the object after this has been called - will lead to crashes.*/ - public void dispose() { - free(); - } - - - protected void finalize() { - if (natpmp != null) - free(); - } - - private native void init(int forcegw, int forcedgw); - private native void free(); - - private static native void startup(); - - public native int sendPublicAddressRequest(); - public native int sendNewPortMappingRequest(int protocol, int privateport, int publicport, int lifetime); - - //returns a number of milliseconds, in accordance with Java convention - public native long getNatPmpRequestTimeout(); - - public native int readNatPmpResponseOrRetry(NatPmpResponse response); - -} diff --git a/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/NatPmpResponse.java b/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/NatPmpResponse.java deleted file mode 100644 index 35c87ea..0000000 --- a/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/NatPmpResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -package fr.free.miniupnp.libnatpmp; - -public class NatPmpResponse { - - public static final int TYPE_PUBLICADDRESS=0; - public static final int TYPE_UDPPORTMAPPING=1; - public static final int TYPE_TCPPORTMAPPING=2; - - /** see TYPE_* constants */ - public short type; - /** NAT-PMP response code */ - public short resultcode; - /** milliseconds since start of epoch */ - public long epoch; - - /** only defined if type == 0*/ - public int addr; - - /** only defined if type != 0 */ - public int privateport; - - /** only defined if type != 0 */ - public int mappedpublicport; - - /** only defined if type != 0 */ - public long lifetime; //milliseconds - -} \ No newline at end of file diff --git a/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/URLUtils.java b/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/URLUtils.java deleted file mode 100644 index 5b419ab..0000000 --- a/zto/ext/libnatpmp/fr/free/miniupnp/libnatpmp/URLUtils.java +++ /dev/null @@ -1,81 +0,0 @@ -package fr.free.miniupnp.libnatpmp; - -/** I (Leah X Schmidt) copied this code from jnaerator, because -JNAerator's extractor requires you to buy into the whole JNA -concept. - -JNAErator is -Copyright (c) 2009 Olivier Chafik, All Rights Reserved - -JNAerator is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -JNAerator is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with JNAerator. If not, see . - -*/ - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.jar.JarEntry; -import java.util.jar.JarInputStream; - -public class URLUtils { - - public static URL getResource(Class cl, String path) throws IOException { - String clp = cl.getName().replace('.', '/') + ".class"; - URL clu = cl.getClassLoader().getResource(clp); - String s = clu.toString(); - if (s.endsWith(clp)) - return new URL(s.substring(0, s.length() - clp.length()) + path); - - if (s.startsWith("jar:")) { - String[] ss = s.split("!"); - return new URL(ss[1] + "!/" + path); - } - return null; - } - - public static List listFiles(URL directory) throws IOException { - List ret = new ArrayList(); - String s = directory.toString(); - if (s.startsWith("jar:")) { - String[] ss = s.substring("jar:".length()).split("!"); - String path = ss[1]; - URL target = new URL(ss[0]); - InputStream tin = target.openStream(); - try { - JarInputStream jin = new JarInputStream(tin); - JarEntry je; - while ((je = jin.getNextJarEntry()) != null) { - String p = "/" + je.getName(); - if (p.startsWith(path) && p.indexOf('/', path.length() + 1) < 0) - - ret.add(new URL("jar:" + target + "!" + p)); - } - } finally { - tin.close(); - } - } else if (s.startsWith("file:")) { - File f = new File(directory.getFile()); - File[] ffs = f.listFiles(); - if (ffs != null) - for (File ff : ffs) - ret.add(ff.toURI().toURL()); - } else - throw new IOException("Cannot list contents of " + directory); - - return ret; - } -} \ No newline at end of file diff --git a/zto/ext/libnatpmp/getgateway.c b/zto/ext/libnatpmp/getgateway.c deleted file mode 100644 index f743a08..0000000 --- a/zto/ext/libnatpmp/getgateway.c +++ /dev/null @@ -1,573 +0,0 @@ -/* $Id: getgateway.c,v 1.25 2014/04/22 10:28:57 nanard Exp $ */ -/* libnatpmp - -Copyright (c) 2007-2014, Thomas BERNARD -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. - * The name of the author may not 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 -#include -#ifndef WIN32 -#include -#endif -#if !defined(_MSC_VER) -#include -#endif -/* There is no portable method to get the default route gateway. - * So below are four (or five ?) differents functions implementing this. - * Parsing /proc/net/route is for linux. - * sysctl is the way to access such informations on BSD systems. - * Many systems should provide route information through raw PF_ROUTE - * sockets. - * In MS Windows, default gateway is found by looking into the registry - * or by using GetBestRoute(). */ -#ifdef __linux__ -#define USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#endif - -#if defined(BSD) || defined(__FreeBSD_kernel__) -#undef USE_PROC_NET_ROUTE -#define USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#include -#endif - -#ifdef __APPLE__ -#undef USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#define USE_SYSCTL_NET_ROUTE -#endif - -#if (defined(sun) && defined(__SVR4)) -#undef USE_PROC_NET_ROUTE -#define USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#endif - -#ifdef WIN32 -#undef USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -//#define USE_WIN32_CODE -#define USE_WIN32_CODE_2 -#endif - -#ifdef __CYGWIN__ -#undef USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#define USE_WIN32_CODE -#include -#include -#include -#include -#endif - -#ifdef __HAIKU__ -#include -#include -#include -#include -#define USE_HAIKU_CODE -#endif - -#ifdef USE_SYSCTL_NET_ROUTE -#include -#include -#include -#endif -#ifdef USE_SOCKET_ROUTE -#include -#include -#include -#include -#include -#endif - -#ifdef USE_WIN32_CODE -#include -#include -#define MAX_KEY_LENGTH 255 -#define MAX_VALUE_LENGTH 16383 -#endif - -#ifdef USE_WIN32_CODE_2 -#include -#include -#endif - -#include "getgateway.h" - -#ifndef WIN32 -#define SUCCESS (0) -#define FAILED (-1) -#endif - -#ifdef USE_PROC_NET_ROUTE -/* - parse /proc/net/route which is as follow : - -Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -wlan0 0001A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 -eth0 0000FEA9 00000000 0001 0 0 0 0000FFFF 0 0 0 -wlan0 00000000 0101A8C0 0003 0 0 0 00000000 0 0 0 -eth0 00000000 00000000 0001 0 0 1000 00000000 0 0 0 - - One header line, and then one line by route by route table entry. -*/ -int getdefaultgateway(in_addr_t * addr) -{ - unsigned long d, g; - char buf[256]; - int line = 0; - FILE * f; - char * p; - f = fopen("/proc/net/route", "r"); - if(!f) - return FAILED; - while(fgets(buf, sizeof(buf), f)) { - if(line > 0) { /* skip the first line */ - p = buf; - /* skip the interface name */ - while(*p && !isspace(*p)) - p++; - while(*p && isspace(*p)) - p++; - if(sscanf(p, "%lx%lx", &d, &g)==2) { - if(d == 0 && g != 0) { /* default */ - *addr = g; - fclose(f); - return SUCCESS; - } - } - } - line++; - } - /* default route not found ! */ - if(f) - fclose(f); - return FAILED; -} -#endif /* #ifdef USE_PROC_NET_ROUTE */ - - -#ifdef USE_SYSCTL_NET_ROUTE - -#define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) - -int getdefaultgateway(in_addr_t * addr) -{ -#if 0 - /* net.route.0.inet.dump.0.0 ? */ - int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, - NET_RT_DUMP, 0, 0/*tableid*/}; -#endif - /* net.route.0.inet.flags.gateway */ - int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, - NET_RT_FLAGS, RTF_GATEWAY}; - size_t l; - char * buf, * p; - struct rt_msghdr * rt; - struct sockaddr * sa; - struct sockaddr * sa_tab[RTAX_MAX]; - int i; - int r = FAILED; - if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) { - return FAILED; - } - if(l>0) { - buf = malloc(l); - if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) { - free(buf); - return FAILED; - } - for(p=buf; prtm_msglen) { - rt = (struct rt_msghdr *)p; - sa = (struct sockaddr *)(rt + 1); - for(i=0; irtm_addrs & (1 << i)) { - sa_tab[i] = sa; - sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len)); - } else { - sa_tab[i] = NULL; - } - } - if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) - && sa_tab[RTAX_DST]->sa_family == AF_INET - && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) { - if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) { - *addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr; - r = SUCCESS; - } - } - } - free(buf); - } - return r; -} -#endif /* #ifdef USE_SYSCTL_NET_ROUTE */ - - -#ifdef USE_SOCKET_ROUTE -/* Thanks to Darren Kenny for this code */ -#define NEXTADDR(w, u) \ - if (rtm_addrs & (w)) {\ - l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\ - } - -#define rtm m_rtmsg.m_rtm - -struct { - struct rt_msghdr m_rtm; - char m_space[512]; -} m_rtmsg; - -int getdefaultgateway(in_addr_t *addr) -{ - int s, seq, l, rtm_addrs, i; - pid_t pid; - struct sockaddr so_dst, so_mask; - char *cp = m_rtmsg.m_space; - struct sockaddr *gate = NULL, *sa; - struct rt_msghdr *msg_hdr; - - pid = getpid(); - seq = 0; - rtm_addrs = RTA_DST | RTA_NETMASK; - - memset(&so_dst, 0, sizeof(so_dst)); - memset(&so_mask, 0, sizeof(so_mask)); - memset(&rtm, 0, sizeof(struct rt_msghdr)); - - rtm.rtm_type = RTM_GET; - rtm.rtm_flags = RTF_UP | RTF_GATEWAY; - rtm.rtm_version = RTM_VERSION; - rtm.rtm_seq = ++seq; - rtm.rtm_addrs = rtm_addrs; - - so_dst.sa_family = AF_INET; - so_mask.sa_family = AF_INET; - - NEXTADDR(RTA_DST, so_dst); - NEXTADDR(RTA_NETMASK, so_mask); - - rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; - - s = socket(PF_ROUTE, SOCK_RAW, 0); - - if (write(s, (char *)&m_rtmsg, l) < 0) { - close(s); - return FAILED; - } - - do { - l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); - } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); - - close(s); - - msg_hdr = &rtm; - - cp = ((char *)(msg_hdr + 1)); - if (msg_hdr->rtm_addrs) { - for (i = 1; i; i <<= 1) - if (i & msg_hdr->rtm_addrs) { - sa = (struct sockaddr *)cp; - if (i == RTA_GATEWAY ) - gate = sa; - - cp += sizeof(struct sockaddr); - } - } else { - return FAILED; - } - - - if (gate != NULL ) { - *addr = ((struct sockaddr_in *)gate)->sin_addr.s_addr; - return SUCCESS; - } else { - return FAILED; - } -} -#endif /* #ifdef USE_SOCKET_ROUTE */ - -#ifdef USE_WIN32_CODE -LIBSPEC int getdefaultgateway(in_addr_t * addr) -{ - HKEY networkCardsKey; - HKEY networkCardKey; - HKEY interfacesKey; - HKEY interfaceKey; - DWORD i = 0; - DWORD numSubKeys = 0; - TCHAR keyName[MAX_KEY_LENGTH]; - DWORD keyNameLength = MAX_KEY_LENGTH; - TCHAR keyValue[MAX_VALUE_LENGTH]; - DWORD keyValueLength = MAX_VALUE_LENGTH; - DWORD keyValueType = REG_SZ; - TCHAR gatewayValue[MAX_VALUE_LENGTH]; - DWORD gatewayValueLength = MAX_VALUE_LENGTH; - DWORD gatewayValueType = REG_MULTI_SZ; - int done = 0; - - //const char * networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; - //const char * interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; -#ifdef UNICODE - LPCTSTR networkCardsPath = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; - LPCTSTR interfacesPath = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; -#define STR_SERVICENAME L"ServiceName" -#define STR_DHCPDEFAULTGATEWAY L"DhcpDefaultGateway" -#define STR_DEFAULTGATEWAY L"DefaultGateway" -#else - LPCTSTR networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; - LPCTSTR interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; -#define STR_SERVICENAME "ServiceName" -#define STR_DHCPDEFAULTGATEWAY "DhcpDefaultGateway" -#define STR_DEFAULTGATEWAY "DefaultGateway" -#endif - // The windows registry lists its primary network devices in the following location: - // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards - // - // Each network device has its own subfolder, named with an index, with various properties: - // -NetworkCards - // -5 - // -Description = Broadcom 802.11n Network Adapter - // -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D} - // -8 - // -Description = Marvell Yukon 88E8058 PCI-E Gigabit Ethernet Controller - // -ServiceName = {86226414-5545-4335-A9D1-5BD7120119AD} - // - // The above service name is the name of a subfolder within: - // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces - // - // There may be more subfolders in this interfaces path than listed in the network cards path above: - // -Interfaces - // -{3a539854-6a70-11db-887c-806e6f6e6963} - // -DhcpIPAddress = 0.0.0.0 - // -[more] - // -{E35A72F8-5065-4097-8DFE-C7790774EE4D} - // -DhcpIPAddress = 10.0.1.4 - // -DhcpDefaultGateway = 10.0.1.1 - // -[more] - // -{86226414-5545-4335-A9D1-5BD7120119AD} - // -DhcpIpAddress = 10.0.1.5 - // -DhcpDefaultGateay = 10.0.1.1 - // -[more] - // - // In order to extract this information, we enumerate each network card, and extract the ServiceName value. - // This is then used to open the interface subfolder, and attempt to extract a DhcpDefaultGateway value. - // Once one is found, we're done. - // - // It may be possible to simply enumerate the interface folders until we find one with a DhcpDefaultGateway value. - // However, the technique used is the technique most cited on the web, and we assume it to be more correct. - - if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predifined key - networkCardsPath, // Name of registry subkey to open - 0, // Reserved - must be zero - KEY_READ, // Mask - desired access rights - &networkCardsKey)) // Pointer to output key - { - // Unable to open network cards keys - return -1; - } - - if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predefined key - interfacesPath, // Name of registry subkey to open - 0, // Reserved - must be zero - KEY_READ, // Mask - desired access rights - &interfacesKey)) // Pointer to output key - { - // Unable to open interfaces key - RegCloseKey(networkCardsKey); - return -1; - } - - // Figure out how many subfolders are within the NetworkCards folder - RegQueryInfoKey(networkCardsKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - - //printf( "Number of subkeys: %u\n", (unsigned int)numSubKeys); - - // Enumrate through each subfolder within the NetworkCards folder - for(i = 0; i < numSubKeys && !done; i++) - { - keyNameLength = MAX_KEY_LENGTH; - if(ERROR_SUCCESS == RegEnumKeyEx(networkCardsKey, // Open registry key - i, // Index of subkey to retrieve - keyName, // Buffer that receives the name of the subkey - &keyNameLength, // Variable that receives the size of the above buffer - NULL, // Reserved - must be NULL - NULL, // Buffer that receives the class string - NULL, // Variable that receives the size of the above buffer - NULL)) // Variable that receives the last write time of subkey - { - if(RegOpenKeyEx(networkCardsKey, keyName, 0, KEY_READ, &networkCardKey) == ERROR_SUCCESS) - { - keyValueLength = MAX_VALUE_LENGTH; - if(ERROR_SUCCESS == RegQueryValueEx(networkCardKey, // Open registry key - STR_SERVICENAME, // Name of key to query - NULL, // Reserved - must be NULL - &keyValueType, // Receives value type - (LPBYTE)keyValue, // Receives value - &keyValueLength)) // Receives value length in bytes - { -// printf("keyValue: %s\n", keyValue); - if(RegOpenKeyEx(interfacesKey, keyValue, 0, KEY_READ, &interfaceKey) == ERROR_SUCCESS) - { - gatewayValueLength = MAX_VALUE_LENGTH; - if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key - STR_DHCPDEFAULTGATEWAY, // Name of key to query - NULL, // Reserved - must be NULL - &gatewayValueType, // Receives value type - (LPBYTE)gatewayValue, // Receives value - &gatewayValueLength)) // Receives value length in bytes - { - // Check to make sure it's a string - if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1)) - { - //printf("gatewayValue: %s\n", gatewayValue); - done = 1; - } - } - else if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key - STR_DEFAULTGATEWAY, // Name of key to query - NULL, // Reserved - must be NULL - &gatewayValueType, // Receives value type - (LPBYTE)gatewayValue,// Receives value - &gatewayValueLength)) // Receives value length in bytes - { - // Check to make sure it's a string - if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1)) - { - //printf("gatewayValue: %s\n", gatewayValue); - done = 1; - } - } - RegCloseKey(interfaceKey); - } - } - RegCloseKey(networkCardKey); - } - } - } - - RegCloseKey(interfacesKey); - RegCloseKey(networkCardsKey); - - if(done) - { -#if UNICODE - char tmp[32]; - for(i = 0; i < 32; i++) { - tmp[i] = (char)gatewayValue[i]; - if(!tmp[i]) - break; - } - tmp[31] = '\0'; - *addr = inet_addr(tmp); -#else - *addr = inet_addr(gatewayValue); -#endif - return 0; - } - - return -1; -} -#endif /* #ifdef USE_WIN32_CODE */ - -#ifdef USE_WIN32_CODE_2 -int getdefaultgateway(in_addr_t *addr) -{ - MIB_IPFORWARDROW ip_forward; - memset(&ip_forward, 0, sizeof(ip_forward)); - if(GetBestRoute(inet_addr("0.0.0.0"), 0, &ip_forward) != NO_ERROR) - return -1; - *addr = ip_forward.dwForwardNextHop; - return 0; -} -#endif /* #ifdef USE_WIN32_CODE_2 */ - -#ifdef USE_HAIKU_CODE -int getdefaultgateway(in_addr_t *addr) -{ - int fd, ret = -1; - struct ifconf config; - void *buffer = NULL; - struct ifreq *interface; - - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - return -1; - } - if (ioctl(fd, SIOCGRTSIZE, &config, sizeof(config)) != 0) { - goto fail; - } - if (config.ifc_value < 1) { - goto fail; /* No routes */ - } - if ((buffer = malloc(config.ifc_value)) == NULL) { - goto fail; - } - config.ifc_len = config.ifc_value; - config.ifc_buf = buffer; - if (ioctl(fd, SIOCGRTTABLE, &config, sizeof(config)) != 0) { - goto fail; - } - for (interface = buffer; - (uint8_t *)interface < (uint8_t *)buffer + config.ifc_len; ) { - struct route_entry route = interface->ifr_route; - int intfSize; - if (route.flags & (RTF_GATEWAY | RTF_DEFAULT)) { - *addr = ((struct sockaddr_in *)route.gateway)->sin_addr.s_addr; - ret = 0; - break; - } - intfSize = sizeof(route) + IF_NAMESIZE; - if (route.destination != NULL) { - intfSize += route.destination->sa_len; - } - if (route.mask != NULL) { - intfSize += route.mask->sa_len; - } - if (route.gateway != NULL) { - intfSize += route.gateway->sa_len; - } - interface = (struct ifreq *)((uint8_t *)interface + intfSize); - } -fail: - free(buffer); - close(fd); - return ret; -} -#endif /* #ifdef USE_HAIKU_CODE */ - -#if !defined(USE_PROC_NET_ROUTE) && !defined(USE_SOCKET_ROUTE) && !defined(USE_SYSCTL_NET_ROUTE) && !defined(USE_WIN32_CODE) && !defined(USE_WIN32_CODE_2) && !defined(USE_HAIKU_CODE) -int getdefaultgateway(in_addr_t * addr) -{ - return -1; -} -#endif diff --git a/zto/ext/libnatpmp/getgateway.h b/zto/ext/libnatpmp/getgateway.h deleted file mode 100644 index 5d3df73..0000000 --- a/zto/ext/libnatpmp/getgateway.h +++ /dev/null @@ -1,49 +0,0 @@ -/* $Id: getgateway.h,v 1.8 2014/04/22 09:15:40 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2014, Thomas BERNARD -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. - * The name of the author may not 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. -*/ -#ifndef __GETGATEWAY_H__ -#define __GETGATEWAY_H__ - -#ifdef WIN32 -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -#include -#else -typedef unsigned long uint32_t; -typedef unsigned short uint16_t; -#endif -#define in_addr_t uint32_t -#endif -/* #include "declspec.h" */ - -/* getdefaultgateway() : - * return value : - * 0 : success - * -1 : failure */ -/* LIBSPEC */int getdefaultgateway(in_addr_t * addr); - -#endif diff --git a/zto/ext/libnatpmp/libnatpmpmodule.c b/zto/ext/libnatpmp/libnatpmpmodule.c deleted file mode 100644 index 0fd9914..0000000 --- a/zto/ext/libnatpmp/libnatpmpmodule.c +++ /dev/null @@ -1,281 +0,0 @@ -/* $Id: libnatpmpmodule.c,v 1.7 2012/03/05 19:38:37 nanard Exp $ */ -/* libnatpmp - * http://miniupnp.free.fr/libnatpmp.html -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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 -#ifdef WIN32 -#include -#else -#include -#include -#endif - -#define STATICLIB -#include "structmember.h" -#include "natpmp.h" - -/* for compatibility with Python < 2.4 */ -#ifndef Py_RETURN_NONE -#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None -#endif - -#ifndef Py_RETURN_TRUE -#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True -#endif - -#ifndef Py_RETURN_FALSE -#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False -#endif - -typedef struct { - PyObject_HEAD - - /* Type-specific fields go here. */ - unsigned int discoverdelay; - - natpmp_t natpmp; -} NATPMPObject; - -static PyMemberDef NATPMP_members[] = { - {"discoverdelay", T_UINT, offsetof(NATPMPObject, discoverdelay), - 0/*READWRITE*/, "value in ms used to wait for NATPMP responses" - }, - {NULL} -}; - -static PyObject * -NATPMPObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - NATPMPObject *self; - - self = (NATPMPObject *)type->tp_alloc(type, 0); - if (self) { - initnatpmp(&self->natpmp, 0, 0); - } - - return (PyObject *)self; -} - -static void -NATPMPObject_dealloc(NATPMPObject *self) -{ - closenatpmp(&self->natpmp); - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject * -NATPMP_externalipaddress(NATPMPObject *self) -{ - int r; - struct timeval timeout; - fd_set fds; - natpmpresp_t response; - - r = sendpublicaddressrequest(&self->natpmp); - - if (r < 0) { -#ifdef ENABLE_STRNATPMPERR - PyErr_SetString(PyExc_Exception, strnatpmperr(r)); -#endif - return NULL; - } - - do { - FD_ZERO(&fds); - FD_SET(self->natpmp.s, &fds); - getnatpmprequesttimeout(&self->natpmp, &timeout); - select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&self->natpmp, &response); - if (r < 0 && r != NATPMP_TRYAGAIN) { -#ifdef ENABLE_STRNATPMPERR - PyErr_SetString(PyExc_Exception, strnatpmperr(r)); -#endif - return NULL; - } - } while (r == NATPMP_TRYAGAIN); - - return Py_BuildValue("s", inet_ntoa(response.pnu.publicaddress.addr)); -} - -static PyObject * -NATPMP_domapping(natpmp_t *n, unsigned short eport, unsigned short iport, - const char *protocol, unsigned int lifetime) -{ - int proto; - struct timeval timeout; - fd_set fds; - natpmpresp_t response; - int r; - - if (!strncasecmp("tcp", protocol, 3)) { - proto = NATPMP_PROTOCOL_TCP; - } else if (!strncasecmp("udp", protocol, 3)) { - proto = NATPMP_PROTOCOL_UDP; - } else { - PyErr_SetString(PyExc_Exception, "Unknown protocol"); - return NULL; - } - - r = sendnewportmappingrequest(n, proto, iport, eport, - lifetime); - - if (r < 0) { -#ifdef ENABLE_STRNATPMPERR - PyErr_SetString(PyExc_Exception, strnatpmperr(r)); -#endif - return NULL; - } - - do { - FD_ZERO(&fds); - FD_SET(n->s, &fds); - getnatpmprequesttimeout(n, &timeout); - select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(n, &response); - if (r < 0 && r != NATPMP_TRYAGAIN) { -#ifdef ENABLE_STRNATPMPERR - PyErr_SetString(PyExc_Exception, strnatpmperr(r)); -#endif - return NULL; - } - } while (r == NATPMP_TRYAGAIN); - - return Py_BuildValue("H", response.pnu.newportmapping.mappedpublicport); -} - - -/* AddPortMapping(externalPort, protocol, internalPort, lifetime) - * protocol is 'UDP' or 'TCP' */ -static PyObject * -NATPMP_addportmapping(NATPMPObject *self, PyObject *args) -{ - unsigned short eport; - unsigned short iport; - unsigned int lifetime; - const char *protocol; - - if (!PyArg_ParseTuple(args, "HsHI", &eport, &protocol, &iport, &lifetime)) - return NULL; - - return NATPMP_domapping(&self->natpmp, eport, iport, protocol, lifetime); -} - -/* DeletePortMapping(externalPort, protocol, internalPort) - * protocol is 'UDP' or 'TCP' */ -static PyObject * -NATPMP_deleteportmapping(NATPMPObject *self, PyObject *args) -{ - unsigned short eport; - unsigned short iport; - const char *protocol; - - if (!PyArg_ParseTuple(args, "HsH", &eport, &protocol, &iport)) - return NULL; - - return NATPMP_domapping(&self->natpmp, eport, iport, protocol, 0); -} - -/* natpmp.NATPMP object Method Table */ -static PyMethodDef NATPMP_methods[] = { - {"externalipaddress", (PyCFunction)NATPMP_externalipaddress, METH_NOARGS, - "return external IP address" - }, - {"addportmapping", (PyCFunction)NATPMP_addportmapping, METH_VARARGS, - "add a port mapping" - }, - {"deleteportmapping", (PyCFunction)NATPMP_deleteportmapping, METH_VARARGS, - "delete a port mapping" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NATPMPType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "libnatpmp.NATPMP", /*tp_name*/ - sizeof(NATPMPObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)NATPMPObject_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "NATPMP objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NATPMP_methods, /* tp_methods */ - NATPMP_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - NATPMPObject_new, /* tp_new */ -}; - -/* module methods */ -static PyMethodDef libnatpmp_methods[] = { - {NULL} /* Sentinel */ -}; - -#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ -#define PyMODINIT_FUNC void -#endif -PyMODINIT_FUNC -initlibnatpmp(void) -{ - PyObject* m; - - if (PyType_Ready(&NATPMPType) < 0) - return; - - m = Py_InitModule3("libnatpmp", libnatpmp_methods, - "libnatpmp module."); - - Py_INCREF(&NATPMPType); - PyModule_AddObject(m, "NATPMP", (PyObject *)&NATPMPType); -} - diff --git a/zto/ext/libnatpmp/msvc/libnatpmp.sln b/zto/ext/libnatpmp/msvc/libnatpmp.sln deleted file mode 100644 index ac746d4..0000000 --- a/zto/ext/libnatpmp/msvc/libnatpmp.sln +++ /dev/null @@ -1,29 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnatpmp", "libnatpmp.vcproj", "{D59B6527-F3DE-4D26-A08D-52F1EE989301}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "natpmpc-static", "natpmpc-static.vcproj", "{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}" - ProjectSection(ProjectDependencies) = postProject - {D59B6527-F3DE-4D26-A08D-52F1EE989301} = {D59B6527-F3DE-4D26-A08D-52F1EE989301} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D59B6527-F3DE-4D26-A08D-52F1EE989301}.Debug|Win32.ActiveCfg = Debug|Win32 - {D59B6527-F3DE-4D26-A08D-52F1EE989301}.Debug|Win32.Build.0 = Debug|Win32 - {D59B6527-F3DE-4D26-A08D-52F1EE989301}.Release|Win32.ActiveCfg = Release|Win32 - {D59B6527-F3DE-4D26-A08D-52F1EE989301}.Release|Win32.Build.0 = Release|Win32 - {A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Debug|Win32.ActiveCfg = Debug|Win32 - {A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Debug|Win32.Build.0 = Debug|Win32 - {A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Release|Win32.ActiveCfg = Release|Win32 - {A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/zto/ext/libnatpmp/msvc/libnatpmp.vcproj b/zto/ext/libnatpmp/msvc/libnatpmp.vcproj deleted file mode 100644 index 9bae5c1..0000000 --- a/zto/ext/libnatpmp/msvc/libnatpmp.vcproj +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/zto/ext/libnatpmp/msvc/natpmpc-static.vcproj b/zto/ext/libnatpmp/msvc/natpmpc-static.vcproj deleted file mode 100644 index c2052d9..0000000 --- a/zto/ext/libnatpmp/msvc/natpmpc-static.vcproj +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/zto/ext/libnatpmp/natpmp-jni.c b/zto/ext/libnatpmp/natpmp-jni.c deleted file mode 100644 index feec1ce..0000000 --- a/zto/ext/libnatpmp/natpmp-jni.c +++ /dev/null @@ -1,157 +0,0 @@ -#ifdef __CYGWIN__ -#include -#define __int64 uint64_t -#endif - -#ifdef WIN32 -#include -#include -#include -#endif - -#include -#include "natpmp.h" - -#include "fr_free_miniupnp_libnatpmp_NatPmp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -JNIEXPORT void JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_init (JNIEnv *env, jobject obj, jint forcegw, jint forcedgw) { - natpmp_t *p = malloc (sizeof(natpmp_t)); - if (p == NULL) return; - - initnatpmp(p, forcegw, (in_addr_t) forcedgw); - - jobject wrapped = (*env)->NewDirectByteBuffer(env, p, sizeof(natpmp_t)); - if (wrapped == NULL) return; - - jclass thisClass = (*env)->GetObjectClass(env,obj); - if (thisClass == NULL) return; - - jfieldID fid = (*env)->GetFieldID(env, thisClass, "natpmp", "Ljava/nio/ByteBuffer;"); - if (fid == NULL) return; - (*env)->SetObjectField(env, obj, fid, wrapped); -} - -JNIEXPORT void JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_free (JNIEnv *env, jobject obj) { - - jclass thisClass = (*env)->GetObjectClass(env,obj); - if (thisClass == NULL) return; - - jfieldID fid = (*env)->GetFieldID(env, thisClass, "natpmp", "Ljava/nio/ByteBuffer;"); - - if (fid == NULL) return; - jobject wrapped = (*env)->GetObjectField(env, obj, fid); - if (wrapped == NULL) return; - - natpmp_t* natpmp = (natpmp_t*) (*env)->GetDirectBufferAddress(env, wrapped); - - closenatpmp(natpmp); - - if (natpmp == NULL) return; - free(natpmp); - - (*env)->SetObjectField(env, obj, fid, NULL); -} - -static natpmp_t* getNatPmp(JNIEnv* env, jobject obj) { - jclass thisClass = (*env)->GetObjectClass(env,obj); - if (thisClass == NULL) return NULL; - - jfieldID fid = (*env)->GetFieldID(env, thisClass, "natpmp", "Ljava/nio/ByteBuffer;"); - - if (fid == NULL) return NULL; - jobject wrapped = (*env)->GetObjectField(env, obj, fid); - if (wrapped == NULL) return NULL; - - natpmp_t* natpmp = (natpmp_t*) (*env)->GetDirectBufferAddress(env, wrapped); - - return natpmp; -} - -JNIEXPORT jint JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_sendPublicAddressRequest(JNIEnv* env, jobject obj) { - natpmp_t* natpmp = getNatPmp(env, obj); - if (natpmp == NULL) return -1; - - return sendpublicaddressrequest(natpmp); -} - - -JNIEXPORT void JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_startup(JNIEnv* env, jclass cls) { - (void)env; - (void)cls; -#ifdef WIN32 - WSADATA wsaData; - WORD wVersionRequested = MAKEWORD(2, 2); - WSAStartup(wVersionRequested, &wsaData); -#endif -} - - -JNIEXPORT jint JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_sendNewPortMappingRequest(JNIEnv* env, jobject obj, jint protocol, jint privateport, jint publicport, jint lifetime) { - natpmp_t* natpmp = getNatPmp(env, obj); - if (natpmp == NULL) return -1; - - return sendnewportmappingrequest(natpmp, protocol, privateport, publicport, lifetime); -} - -JNIEXPORT jlong JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_getNatPmpRequestTimeout(JNIEnv* env, jobject obj) { - natpmp_t* natpmp = getNatPmp(env, obj); - - struct timeval timeout; - - getnatpmprequesttimeout(natpmp, &timeout); - - return ((jlong) timeout.tv_sec) * 1000 + (timeout.tv_usec / 1000); - -} - -#define SET_FIELD(prefix, name, type, longtype) { \ - jfieldID fid = (*env)->GetFieldID(env, thisClass, #name, type); \ - if (fid == NULL) return -1; \ - (*env)->Set ## longtype ## Field(env, response, fid, resp. prefix name); \ -} - -JNIEXPORT jint JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_readNatPmpResponseOrRetry(JNIEnv* env, jobject obj, jobject response) { - - natpmp_t* natpmp = getNatPmp(env, obj); - natpmpresp_t resp; - int result = readnatpmpresponseorretry(natpmp, &resp); - - if (result != 0) { - return result; - } - - jclass thisClass = (*env)->GetObjectClass(env, response); - if (thisClass == NULL) return -1; - - SET_FIELD(,type, "S", Short); - SET_FIELD(,resultcode, "S", Short); - - jfieldID fid = (*env)->GetFieldID(env, thisClass, "epoch", "J"); - if (fid == NULL) return -1; - (*env)->SetLongField(env, response, fid, ((jlong)resp.epoch) * 1000); - - if (resp.type == 0) { - jfieldID fid = (*env)->GetFieldID(env, thisClass, "addr", "I"); - if (fid == NULL) return -1; - (*env)->SetIntField(env, response, fid, resp.pnu.publicaddress.addr.s_addr); - - - } else { - SET_FIELD(pnu.newportmapping., privateport, "I", Int); - SET_FIELD(pnu.newportmapping., mappedpublicport, "I", Int); - - jfieldID fid = (*env)->GetFieldID(env, thisClass, "lifetime", "J"); - if (fid == NULL) return -1; - (*env)->SetLongField(env, response, fid, ((jlong) resp.pnu.newportmapping.lifetime) * 1000 * 1000); - } - return result; -} - - -#ifdef __cplusplus -} -#endif diff --git a/zto/ext/libnatpmp/natpmp.c b/zto/ext/libnatpmp/natpmp.c deleted file mode 100644 index 9843c41..0000000 --- a/zto/ext/libnatpmp/natpmp.c +++ /dev/null @@ -1,383 +0,0 @@ -/* $Id: natpmp.c,v 1.20 2015/05/27 12:43:15 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2015, Thomas BERNARD -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. - * The name of the author may not 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. -*/ -#ifdef __linux__ -#define _BSD_SOURCE 1 -#endif -#include -#include -#if !defined(_MSC_VER) -#include -#endif -#ifdef WIN32 -#include -#include -#include -#include -#ifndef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#endif -#ifndef ECONNREFUSED -#define ECONNREFUSED WSAECONNREFUSED -#endif -#include "wingettimeofday.h" -#define gettimeofday natpmp_gettimeofday -#else -#include -#include -#include -#include -#include -#define closesocket close -#endif -#include "natpmp.h" -#include "getgateway.h" -#include - -LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw) -{ -#ifdef WIN32 - u_long ioctlArg = 1; -#else - int flags; -#endif - struct sockaddr_in addr; - if(!p) - return NATPMP_ERR_INVALIDARGS; - memset(p, 0, sizeof(natpmp_t)); - p->s = socket(PF_INET, SOCK_DGRAM, 0); - if(p->s < 0) - return NATPMP_ERR_SOCKETERROR; -#ifdef WIN32 - if(ioctlsocket(p->s, FIONBIO, &ioctlArg) == SOCKET_ERROR) - return NATPMP_ERR_FCNTLERROR; -#else - if((flags = fcntl(p->s, F_GETFL, 0)) < 0) - return NATPMP_ERR_FCNTLERROR; - if(fcntl(p->s, F_SETFL, flags | O_NONBLOCK) < 0) - return NATPMP_ERR_FCNTLERROR; -#endif - - if(forcegw) { - p->gateway = forcedgw; - } else { - if(getdefaultgateway(&(p->gateway)) < 0) - return NATPMP_ERR_CANNOTGETGATEWAY; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(NATPMP_PORT); - addr.sin_addr.s_addr = p->gateway; - if(connect(p->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) - return NATPMP_ERR_CONNECTERR; - return 0; -} - -LIBSPEC int closenatpmp(natpmp_t * p) -{ - if(!p) - return NATPMP_ERR_INVALIDARGS; - if(closesocket(p->s) < 0) - return NATPMP_ERR_CLOSEERR; - return 0; -} - -int sendpendingrequest(natpmp_t * p) -{ - int r; -/* struct sockaddr_in addr;*/ - if(!p) - return NATPMP_ERR_INVALIDARGS; -/* memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(NATPMP_PORT); - addr.sin_addr.s_addr = p->gateway; - r = (int)sendto(p->s, p->pending_request, p->pending_request_len, 0, - (struct sockaddr *)&addr, sizeof(addr));*/ - r = (int)send(p->s, (const char *)p->pending_request, p->pending_request_len, 0); - return (r<0) ? NATPMP_ERR_SENDERR : r; -} - -int sendnatpmprequest(natpmp_t * p) -{ - int n; - if(!p) - return NATPMP_ERR_INVALIDARGS; - /* TODO : check if no request is already pending */ - p->has_pending_request = 1; - p->try_number = 1; - n = sendpendingrequest(p); - gettimeofday(&p->retry_time, NULL); // check errors ! - p->retry_time.tv_usec += 250000; /* add 250ms */ - if(p->retry_time.tv_usec >= 1000000) { - p->retry_time.tv_usec -= 1000000; - p->retry_time.tv_sec++; - } - return n; -} - -LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout) -{ - struct timeval now; - if(!p || !timeout) - return NATPMP_ERR_INVALIDARGS; - if(!p->has_pending_request) - return NATPMP_ERR_NOPENDINGREQ; - if(gettimeofday(&now, NULL) < 0) - return NATPMP_ERR_GETTIMEOFDAYERR; - timeout->tv_sec = p->retry_time.tv_sec - now.tv_sec; - timeout->tv_usec = p->retry_time.tv_usec - now.tv_usec; - if(timeout->tv_usec < 0) { - timeout->tv_usec += 1000000; - timeout->tv_sec--; - } - return 0; -} - -LIBSPEC int sendpublicaddressrequest(natpmp_t * p) -{ - if(!p) - return NATPMP_ERR_INVALIDARGS; - //static const unsigned char request[] = { 0, 0 }; - p->pending_request[0] = 0; - p->pending_request[1] = 0; - p->pending_request_len = 2; - // TODO: return 0 instead of sizeof(request) ?? - return sendnatpmprequest(p); -} - -LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol, - uint16_t privateport, uint16_t publicport, - uint32_t lifetime) -{ - if(!p || (protocol!=NATPMP_PROTOCOL_TCP && protocol!=NATPMP_PROTOCOL_UDP)) - return NATPMP_ERR_INVALIDARGS; - p->pending_request[0] = 0; - p->pending_request[1] = protocol; - p->pending_request[2] = 0; - p->pending_request[3] = 0; - /* break strict-aliasing rules : - *((uint16_t *)(p->pending_request + 4)) = htons(privateport); */ - p->pending_request[4] = (privateport >> 8) & 0xff; - p->pending_request[5] = privateport & 0xff; - /* break stric-aliasing rules : - *((uint16_t *)(p->pending_request + 6)) = htons(publicport); */ - p->pending_request[6] = (publicport >> 8) & 0xff; - p->pending_request[7] = publicport & 0xff; - /* break stric-aliasing rules : - *((uint32_t *)(p->pending_request + 8)) = htonl(lifetime); */ - p->pending_request[8] = (lifetime >> 24) & 0xff; - p->pending_request[9] = (lifetime >> 16) & 0xff; - p->pending_request[10] = (lifetime >> 8) & 0xff; - p->pending_request[11] = lifetime & 0xff; - p->pending_request_len = 12; - return sendnatpmprequest(p); -} - -LIBSPEC int readnatpmpresponse(natpmp_t * p, natpmpresp_t * response) -{ - unsigned char buf[16]; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); - int n; - if(!p) - return NATPMP_ERR_INVALIDARGS; - n = recvfrom(p->s, (char *)buf, sizeof(buf), 0, - (struct sockaddr *)&addr, &addrlen); - if(n<0) -#ifdef WIN32 - switch(WSAGetLastError()) { -#else - switch(errno) { -#endif - /*case EAGAIN:*/ - case EWOULDBLOCK: - n = NATPMP_TRYAGAIN; - break; - case ECONNREFUSED: - n = NATPMP_ERR_NOGATEWAYSUPPORT; - break; - default: - n = NATPMP_ERR_RECVFROM; - } - /* check that addr is correct (= gateway) */ - else if(addr.sin_addr.s_addr != p->gateway) - n = NATPMP_ERR_WRONGPACKETSOURCE; - else { - response->resultcode = ntohs(*((uint16_t *)(buf + 2))); - response->epoch = ntohl(*((uint32_t *)(buf + 4))); - if(buf[0] != 0) - n = NATPMP_ERR_UNSUPPORTEDVERSION; - else if(buf[1] < 128 || buf[1] > 130) - n = NATPMP_ERR_UNSUPPORTEDOPCODE; - else if(response->resultcode != 0) { - switch(response->resultcode) { - case 1: - n = NATPMP_ERR_UNSUPPORTEDVERSION; - break; - case 2: - n = NATPMP_ERR_NOTAUTHORIZED; - break; - case 3: - n = NATPMP_ERR_NETWORKFAILURE; - break; - case 4: - n = NATPMP_ERR_OUTOFRESOURCES; - break; - case 5: - n = NATPMP_ERR_UNSUPPORTEDOPCODE; - break; - default: - n = NATPMP_ERR_UNDEFINEDERROR; - } - } else { - response->type = buf[1] & 0x7f; - if(buf[1] == 128) - //response->publicaddress.addr = *((uint32_t *)(buf + 8)); - response->pnu.publicaddress.addr.s_addr = *((uint32_t *)(buf + 8)); - else { - response->pnu.newportmapping.privateport = ntohs(*((uint16_t *)(buf + 8))); - response->pnu.newportmapping.mappedpublicport = ntohs(*((uint16_t *)(buf + 10))); - response->pnu.newportmapping.lifetime = ntohl(*((uint32_t *)(buf + 12))); - } - n = 0; - } - } - return n; -} - -int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response) -{ - int n; - if(!p || !response) - return NATPMP_ERR_INVALIDARGS; - if(!p->has_pending_request) - return NATPMP_ERR_NOPENDINGREQ; - n = readnatpmpresponse(p, response); - if(n<0) { - if(n==NATPMP_TRYAGAIN) { - struct timeval now; - gettimeofday(&now, NULL); // check errors ! - if(timercmp(&now, &p->retry_time, >=)) { - int delay, r; - if(p->try_number >= 9) { - return NATPMP_ERR_NOGATEWAYSUPPORT; - } - /*printf("retry! %d\n", p->try_number);*/ - delay = 250 * (1<try_number); // ms - /*for(i=0; itry_number; i++) - delay += delay;*/ - p->retry_time.tv_sec += (delay / 1000); - p->retry_time.tv_usec += (delay % 1000) * 1000; - if(p->retry_time.tv_usec >= 1000000) { - p->retry_time.tv_usec -= 1000000; - p->retry_time.tv_sec++; - } - p->try_number++; - r = sendpendingrequest(p); - if(r<0) - return r; - } - } - } else { - p->has_pending_request = 0; - } - return n; -} - -#ifdef ENABLE_STRNATPMPERR -LIBSPEC const char * strnatpmperr(int r) -{ - const char * s; - switch(r) { - case NATPMP_ERR_INVALIDARGS: - s = "invalid arguments"; - break; - case NATPMP_ERR_SOCKETERROR: - s = "socket() failed"; - break; - case NATPMP_ERR_CANNOTGETGATEWAY: - s = "cannot get default gateway ip address"; - break; - case NATPMP_ERR_CLOSEERR: -#ifdef WIN32 - s = "closesocket() failed"; -#else - s = "close() failed"; -#endif - break; - case NATPMP_ERR_RECVFROM: - s = "recvfrom() failed"; - break; - case NATPMP_ERR_NOPENDINGREQ: - s = "no pending request"; - break; - case NATPMP_ERR_NOGATEWAYSUPPORT: - s = "the gateway does not support nat-pmp"; - break; - case NATPMP_ERR_CONNECTERR: - s = "connect() failed"; - break; - case NATPMP_ERR_WRONGPACKETSOURCE: - s = "packet not received from the default gateway"; - break; - case NATPMP_ERR_SENDERR: - s = "send() failed"; - break; - case NATPMP_ERR_FCNTLERROR: - s = "fcntl() failed"; - break; - case NATPMP_ERR_GETTIMEOFDAYERR: - s = "gettimeofday() failed"; - break; - case NATPMP_ERR_UNSUPPORTEDVERSION: - s = "unsupported nat-pmp version error from server"; - break; - case NATPMP_ERR_UNSUPPORTEDOPCODE: - s = "unsupported nat-pmp opcode error from server"; - break; - case NATPMP_ERR_UNDEFINEDERROR: - s = "undefined nat-pmp server error"; - break; - case NATPMP_ERR_NOTAUTHORIZED: - s = "not authorized"; - break; - case NATPMP_ERR_NETWORKFAILURE: - s = "network failure"; - break; - case NATPMP_ERR_OUTOFRESOURCES: - s = "nat-pmp server out of resources"; - break; - default: - s = "Unknown libnatpmp error"; - } - return s; -} -#endif - diff --git a/zto/ext/libnatpmp/natpmp.def b/zto/ext/libnatpmp/natpmp.def deleted file mode 100644 index cd11003..0000000 --- a/zto/ext/libnatpmp/natpmp.def +++ /dev/null @@ -1,11 +0,0 @@ -LIBRARY -; libnatpmp library - -EXPORTS - initnatpmp - closenatpmp - sendpublicaddressrequest - sendnewportmappingrequest - getnatpmprequesttimeout - readnatpmpresponseorretry - strnatpmperr diff --git a/zto/ext/libnatpmp/natpmp.h b/zto/ext/libnatpmp/natpmp.h deleted file mode 100644 index 7889d20..0000000 --- a/zto/ext/libnatpmp/natpmp.h +++ /dev/null @@ -1,219 +0,0 @@ -/* $Id: natpmp.h,v 1.20 2014/04/22 09:15:40 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2014, Thomas BERNARD -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. - * The name of the author may not 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. -*/ -#ifndef __NATPMP_H__ -#define __NATPMP_H__ - -/* NAT-PMP Port as defined by the NAT-PMP draft */ -#define NATPMP_PORT (5351) - -#include -#if !defined(_MSC_VER) -#include -#endif /* !defined(_MSC_VER) */ - -#ifdef WIN32 -#include -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -#include -#else /* !defined(_MSC_VER) || _MSC_VER >= 1600 */ -typedef unsigned long uint32_t; -typedef unsigned short uint16_t; -#endif /* !defined(_MSC_VER) || _MSC_VER >= 1600 */ -#define in_addr_t uint32_t -#include "declspec.h" -#else /* WIN32 */ -#define LIBSPEC -#include -#endif /* WIN32 */ - -/* causes problem when installing. Maybe should it be inlined ? */ -/* #include "declspec.h" */ - -typedef struct { - int s; /* socket */ - in_addr_t gateway; /* default gateway (IPv4) */ - int has_pending_request; - unsigned char pending_request[12]; - int pending_request_len; - int try_number; - struct timeval retry_time; -} natpmp_t; - -typedef struct { - uint16_t type; /* NATPMP_RESPTYPE_* */ - uint16_t resultcode; /* NAT-PMP response code */ - uint32_t epoch; /* Seconds since start of epoch */ - union { - struct { - //in_addr_t addr; - struct in_addr addr; - } publicaddress; - struct { - uint16_t privateport; - uint16_t mappedpublicport; - uint32_t lifetime; - } newportmapping; - } pnu; -} natpmpresp_t; - -/* possible values for type field of natpmpresp_t */ -#define NATPMP_RESPTYPE_PUBLICADDRESS (0) -#define NATPMP_RESPTYPE_UDPPORTMAPPING (1) -#define NATPMP_RESPTYPE_TCPPORTMAPPING (2) - -/* Values to pass to sendnewportmappingrequest() */ -#define NATPMP_PROTOCOL_UDP (1) -#define NATPMP_PROTOCOL_TCP (2) - -/* return values */ -/* NATPMP_ERR_INVALIDARGS : invalid arguments passed to the function */ -#define NATPMP_ERR_INVALIDARGS (-1) -/* NATPMP_ERR_SOCKETERROR : socket() failed. check errno for details */ -#define NATPMP_ERR_SOCKETERROR (-2) -/* NATPMP_ERR_CANNOTGETGATEWAY : can't get default gateway IP */ -#define NATPMP_ERR_CANNOTGETGATEWAY (-3) -/* NATPMP_ERR_CLOSEERR : close() failed. check errno for details */ -#define NATPMP_ERR_CLOSEERR (-4) -/* NATPMP_ERR_RECVFROM : recvfrom() failed. check errno for details */ -#define NATPMP_ERR_RECVFROM (-5) -/* NATPMP_ERR_NOPENDINGREQ : readnatpmpresponseorretry() called while - * no NAT-PMP request was pending */ -#define NATPMP_ERR_NOPENDINGREQ (-6) -/* NATPMP_ERR_NOGATEWAYSUPPORT : the gateway does not support NAT-PMP */ -#define NATPMP_ERR_NOGATEWAYSUPPORT (-7) -/* NATPMP_ERR_CONNECTERR : connect() failed. check errno for details */ -#define NATPMP_ERR_CONNECTERR (-8) -/* NATPMP_ERR_WRONGPACKETSOURCE : packet not received from the network gateway */ -#define NATPMP_ERR_WRONGPACKETSOURCE (-9) -/* NATPMP_ERR_SENDERR : send() failed. check errno for details */ -#define NATPMP_ERR_SENDERR (-10) -/* NATPMP_ERR_FCNTLERROR : fcntl() failed. check errno for details */ -#define NATPMP_ERR_FCNTLERROR (-11) -/* NATPMP_ERR_GETTIMEOFDAYERR : gettimeofday() failed. check errno for details */ -#define NATPMP_ERR_GETTIMEOFDAYERR (-12) - -/* */ -#define NATPMP_ERR_UNSUPPORTEDVERSION (-14) -#define NATPMP_ERR_UNSUPPORTEDOPCODE (-15) - -/* Errors from the server : */ -#define NATPMP_ERR_UNDEFINEDERROR (-49) -#define NATPMP_ERR_NOTAUTHORIZED (-51) -#define NATPMP_ERR_NETWORKFAILURE (-52) -#define NATPMP_ERR_OUTOFRESOURCES (-53) - -/* NATPMP_TRYAGAIN : no data available for the moment. try again later */ -#define NATPMP_TRYAGAIN (-100) - -#ifdef __cplusplus -extern "C" { -#endif - -/* initnatpmp() - * initialize a natpmp_t object - * With forcegw=1 the gateway is not detected automaticaly. - * Return values : - * 0 = OK - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_SOCKETERROR - * NATPMP_ERR_FCNTLERROR - * NATPMP_ERR_CANNOTGETGATEWAY - * NATPMP_ERR_CONNECTERR */ -LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw); - -/* closenatpmp() - * close resources associated with a natpmp_t object - * Return values : - * 0 = OK - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_CLOSEERR */ -LIBSPEC int closenatpmp(natpmp_t * p); - -/* sendpublicaddressrequest() - * send a public address NAT-PMP request to the network gateway - * Return values : - * 2 = OK (size of the request) - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_SENDERR */ -LIBSPEC int sendpublicaddressrequest(natpmp_t * p); - -/* sendnewportmappingrequest() - * send a new port mapping NAT-PMP request to the network gateway - * Arguments : - * protocol is either NATPMP_PROTOCOL_TCP or NATPMP_PROTOCOL_UDP, - * lifetime is in seconds. - * To remove a port mapping, set lifetime to zero. - * To remove all port mappings to the host, set lifetime and both ports - * to zero. - * Return values : - * 12 = OK (size of the request) - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_SENDERR */ -LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol, - uint16_t privateport, uint16_t publicport, - uint32_t lifetime); - -/* getnatpmprequesttimeout() - * fills the timeval structure with the timeout duration of the - * currently pending NAT-PMP request. - * Return values : - * 0 = OK - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_GETTIMEOFDAYERR - * NATPMP_ERR_NOPENDINGREQ */ -LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout); - -/* readnatpmpresponseorretry() - * fills the natpmpresp_t structure if possible - * Return values : - * 0 = OK - * NATPMP_TRYAGAIN - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_NOPENDINGREQ - * NATPMP_ERR_NOGATEWAYSUPPORT - * NATPMP_ERR_RECVFROM - * NATPMP_ERR_WRONGPACKETSOURCE - * NATPMP_ERR_UNSUPPORTEDVERSION - * NATPMP_ERR_UNSUPPORTEDOPCODE - * NATPMP_ERR_NOTAUTHORIZED - * NATPMP_ERR_NETWORKFAILURE - * NATPMP_ERR_OUTOFRESOURCES - * NATPMP_ERR_UNSUPPORTEDOPCODE - * NATPMP_ERR_UNDEFINEDERROR */ -LIBSPEC int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response); - -#ifdef ENABLE_STRNATPMPERR -LIBSPEC const char * strnatpmperr(int t); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/zto/ext/libnatpmp/natpmpc.1 b/zto/ext/libnatpmp/natpmpc.1 deleted file mode 100644 index 5f0003d..0000000 --- a/zto/ext/libnatpmp/natpmpc.1 +++ /dev/null @@ -1,19 +0,0 @@ -.TH natpmpc 1 - -.SH NAME -natpmpc \- NAT\-PMP library test client and mapping setter. - -.SH "SYNOPSIS" -Display the public IP address: -.br -\fBnatpmpc\fP - -Add a port mapping: -.br -\fBnatpmpc\fP \-a [lifetime] - -.SH DESCRIPTION - -In order to remove a mapping, set it with a lifetime of 0 seconds. -To remove all mappings for your machine, use 0 as private port and -lifetime. diff --git a/zto/ext/libnatpmp/natpmpc.c b/zto/ext/libnatpmp/natpmpc.c deleted file mode 100644 index 611bd2d..0000000 --- a/zto/ext/libnatpmp/natpmpc.c +++ /dev/null @@ -1,244 +0,0 @@ -/* $Id: natpmpc.c,v 1.13 2012/08/21 17:23:38 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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 -#include -#include -#if defined(_MSC_VER) -#if _MSC_VER >= 1400 -#define strcasecmp _stricmp -#else -#define strcasecmp stricmp -#endif -#else -#include -#endif -#ifdef WIN32 -#include -#else -#include -#include -#endif -#include "natpmp.h" - -void usage(FILE * out, const char * argv0) -{ - fprintf(out, "Usage :\n"); - fprintf(out, " %s [options]\n", argv0); - fprintf(out, "\tdisplay the public IP address.\n"); - fprintf(out, " %s -h\n", argv0); - fprintf(out, "\tdisplay this help screen.\n"); - fprintf(out, " %s [options] -a [lifetime]\n", argv0); - fprintf(out, "\tadd a port mapping.\n"); - fprintf(out, "\nOption available :\n"); - fprintf(out, " -g ipv4address\n"); - fprintf(out, "\tforce the gateway to be used as destination for NAT-PMP commands.\n"); - fprintf(out, "\n In order to remove a mapping, set it with a lifetime of 0 seconds.\n"); - fprintf(out, " To remove all mappings for your machine, use 0 as private port and lifetime.\n"); -} - -/* sample code for using libnatpmp */ -int main(int argc, char * * argv) -{ - natpmp_t natpmp; - natpmpresp_t response; - int r; - int sav_errno; - struct timeval timeout; - fd_set fds; - int i; - int protocol = 0; - uint16_t privateport = 0; - uint16_t publicport = 0; - uint32_t lifetime = 3600; - int command = 0; - int forcegw = 0; - in_addr_t gateway = 0; - struct in_addr gateway_in_use; - -#ifdef WIN32 - WSADATA wsaData; - int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); - if(nResult != NO_ERROR) - { - fprintf(stderr, "WSAStartup() failed.\n"); - return -1; - } -#endif - - /* argument parsing */ - for(i=1; i i + 1) { - if(1 != sscanf(argv[i+1], "%u", &lifetime)) { - fprintf(stderr, "%s is not a correct 32bits unsigned integer\n", argv[i]); - } else { - i++; - } - } - break; - default: - fprintf(stderr, "Unknown option %s\n", argv[i]); - usage(stderr, argv[0]); - return 1; - } - } else { - fprintf(stderr, "Unknown option %s\n", argv[i]); - usage(stderr, argv[0]); - return 1; - } - } - - /* initnatpmp() */ - r = initnatpmp(&natpmp, forcegw, gateway); - printf("initnatpmp() returned %d (%s)\n", r, r?"FAILED":"SUCCESS"); - if(r<0) - return 1; - - gateway_in_use.s_addr = natpmp.gateway; - printf("using gateway : %s\n", inet_ntoa(gateway_in_use)); - - /* sendpublicaddressrequest() */ - r = sendpublicaddressrequest(&natpmp); - printf("sendpublicaddressrequest returned %d (%s)\n", - r, r==2?"SUCCESS":"FAILED"); - if(r<0) - return 1; - - do { - FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); - r = select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - if(r<0) { - fprintf(stderr, "select()"); - return 1; - } - r = readnatpmpresponseorretry(&natpmp, &response); - sav_errno = errno; - printf("readnatpmpresponseorretry returned %d (%s)\n", - r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED")); - if(r<0 && r!=NATPMP_TRYAGAIN) { -#ifdef ENABLE_STRNATPMPERR - fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n", - strnatpmperr(r)); -#endif - fprintf(stderr, " errno=%d '%s'\n", - sav_errno, strerror(sav_errno)); - } - } while(r==NATPMP_TRYAGAIN); - if(r<0) - return 1; - - /* TODO : check that response.type == 0 */ - printf("Public IP address : %s\n", inet_ntoa(response.pnu.publicaddress.addr)); - printf("epoch = %u\n", response.epoch); - - if(command == 'a') { - /* sendnewportmappingrequest() */ - r = sendnewportmappingrequest(&natpmp, protocol, - privateport, publicport, - lifetime); - printf("sendnewportmappingrequest returned %d (%s)\n", - r, r==12?"SUCCESS":"FAILED"); - if(r < 0) - return 1; - - do { - FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); - select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); - printf("readnatpmpresponseorretry returned %d (%s)\n", - r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED")); - } while(r==NATPMP_TRYAGAIN); - if(r<0) { -#ifdef ENABLE_STRNATPMPERR - fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n", - strnatpmperr(r)); -#endif - return 1; - } - - printf("Mapped public port %hu protocol %s to local port %hu " - "liftime %u\n", - response.pnu.newportmapping.mappedpublicport, - response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" : - (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : - "UNKNOWN"), - response.pnu.newportmapping.privateport, - response.pnu.newportmapping.lifetime); - printf("epoch = %u\n", response.epoch); - } - - r = closenatpmp(&natpmp); - printf("closenatpmp() returned %d (%s)\n", r, r==0?"SUCCESS":"FAILED"); - if(r<0) - return 1; - - return 0; -} - diff --git a/zto/ext/libnatpmp/setup.py b/zto/ext/libnatpmp/setup.py deleted file mode 100644 index aa774ee..0000000 --- a/zto/ext/libnatpmp/setup.py +++ /dev/null @@ -1,18 +0,0 @@ -#! /usr/bin/python -# $Id: setup.py,v 1.3 2012/03/05 04:54:01 nanard Exp $ -# -# python script to build the libnatpmp module under unix -# -# replace libnatpmp.a by libnatpmp.so for shared library usage -from distutils.core import setup, Extension -from distutils import sysconfig -sysconfig.get_config_vars()["OPT"] = '' -sysconfig.get_config_vars()["CFLAGS"] = '' -setup(name="libnatpmp", version="1.0", - ext_modules=[ - Extension(name="libnatpmp", sources=["libnatpmpmodule.c"], - extra_objects=["libnatpmp.a"], - define_macros=[('ENABLE_STRNATPMPERR', None)] - )] - ) - diff --git a/zto/ext/libnatpmp/setupmingw32.py b/zto/ext/libnatpmp/setupmingw32.py deleted file mode 100644 index d02fdfc..0000000 --- a/zto/ext/libnatpmp/setupmingw32.py +++ /dev/null @@ -1,17 +0,0 @@ -#! /usr/bin/python -# $Id: setupmingw32.py,v 1.3 2012/03/05 04:54:01 nanard Exp $ -# python script to build the miniupnpc module under windows -# -from distutils.core import setup, Extension -from distutils import sysconfig -sysconfig.get_config_vars()["OPT"] = '' -sysconfig.get_config_vars()["CFLAGS"] = '' -setup(name="libnatpmp", version="1.0", - ext_modules=[ - Extension(name="libnatpmp", sources=["libnatpmpmodule.c"], - libraries=["ws2_32"], - extra_objects=["libnatpmp.a"], - define_macros=[('ENABLE_STRNATPMPERR', None)] - )] - ) - diff --git a/zto/ext/libnatpmp/testgetgateway.c b/zto/ext/libnatpmp/testgetgateway.c deleted file mode 100644 index 24cbe7d..0000000 --- a/zto/ext/libnatpmp/testgetgateway.c +++ /dev/null @@ -1,57 +0,0 @@ -/* $Id: testgetgateway.c,v 1.7 2012/08/21 17:13:31 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2011, Thomas BERNARD -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. - * The name of the author may not 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 -#ifdef WIN32 -#include -#else -#include -#include -#endif -#include "getgateway.h" - -int main(int argc, char * * argv) -{ - (void)argc; - (void)argv; - struct in_addr gatewayaddr; - int r; -#ifdef WIN32 - uint32_t temp = 0; - r = getdefaultgateway(&temp); - gatewayaddr.S_un.S_addr = temp; -#else - r = getdefaultgateway(&(gatewayaddr.s_addr)); -#endif - if(r>=0) - printf("default gateway : %s\n", inet_ntoa(gatewayaddr)); - else - fprintf(stderr, "getdefaultgateway() failed\n"); - return 0; -} - diff --git a/zto/ext/libnatpmp/wingettimeofday.c b/zto/ext/libnatpmp/wingettimeofday.c deleted file mode 100644 index cb730e1..0000000 --- a/zto/ext/libnatpmp/wingettimeofday.c +++ /dev/null @@ -1,60 +0,0 @@ -/* $Id: wingettimeofday.c,v 1.6 2013/09/10 20:13:26 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2013, Thomas BERNARD -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. - * The name of the author may not 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. -*/ -#ifdef WIN32 -#if defined(_MSC_VER) -struct timeval { - long tv_sec; - long tv_usec; -}; -#else -#include -#endif - -typedef struct _FILETIME { - unsigned long dwLowDateTime; - unsigned long dwHighDateTime; -} FILETIME; - -void __stdcall GetSystemTimeAsFileTime(FILETIME*); - -int natpmp_gettimeofday(struct timeval* p, void* tz /* IGNORED */) { - union { - long long ns100; /*time since 1 Jan 1601 in 100ns units */ - FILETIME ft; - } _now; - - if(!p) - return -1; - GetSystemTimeAsFileTime( &(_now.ft) ); - p->tv_usec =(long)((_now.ns100 / 10LL) % 1000000LL ); - p->tv_sec = (long)((_now.ns100-(116444736000000000LL))/10000000LL); - return 0; -} -#endif - diff --git a/zto/ext/libnatpmp/wingettimeofday.h b/zto/ext/libnatpmp/wingettimeofday.h deleted file mode 100644 index 1d18d9f..0000000 --- a/zto/ext/libnatpmp/wingettimeofday.h +++ /dev/null @@ -1,39 +0,0 @@ -/* $Id: wingettimeofday.h,v 1.5 2013/09/11 07:22:25 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2013, Thomas BERNARD -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. - * The name of the author may not 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. -*/ -#ifndef __WINGETTIMEOFDAY_H__ -#define __WINGETTIMEOFDAY_H__ -#ifdef WIN32 -#if defined(_MSC_VER) -#include -#else -#include -#endif -int natpmp_gettimeofday(struct timeval* p, void* tz /* IGNORED */); -#endif -#endif diff --git a/zto/ext/miniupnpc/Changelog.txt b/zto/ext/miniupnpc/Changelog.txt deleted file mode 100644 index 078bebc..0000000 --- a/zto/ext/miniupnpc/Changelog.txt +++ /dev/null @@ -1,677 +0,0 @@ -$Id: Changelog.txt,v 1.223 2016/04/19 21:06:20 nanard Exp $ -miniUPnP client Changelog. - -VERSION 2.0 : released 2016/04/19 - -2016/01/24: - change miniwget to return HTTP status code - increments API_VERSION to 16 - -2016/01/22: - Improve UPNPIGD_IsConnected() to check if WAN address is not private. - parse HTTP response status line in miniwget.c - -2015/10/26: - snprintf() overflow check. check overflow in simpleUPnPcommand2() - -2015/10/25: - fix compilation with old macs - fix compilation with mingw32 (for Appveyor) - fix python module for python <= 2.3 - -2015/10/08: - Change sameport to localport - see https://github.com/miniupnp/miniupnp/pull/120 - increments API_VERSION to 15 - -2015/09/15: - Fix buffer overflow in igd_desc_parse.c/IGDstartelt() - Discovered by Aleksandar Nikolic of Cisco Talos - -2015/08/28: - move ssdpDiscoverDevices() to minissdpc.c - -2015/08/27: - avoid unix socket leak in getDevicesFromMiniSSDPD() - -2015/08/16: - Also accept "Up" as ConnectionStatus value - -2015/07/23: - split getDevicesFromMiniSSDPD - add ttl argument to upnpDiscover() functions - increments API_VERSION to 14 - -2015/07/22: - Read USN from SSDP messages. - -2015/07/15: - Check malloc/calloc - -2015/06/16: - update getDevicesFromMiniSSDPD() to process longer minissdpd - responses - -2015/05/22: - add searchalltypes param to upnpDiscoverDevices() - increments API_VERSION to 13 - -2015/04/30: - upnpc: output version on the terminal - -2015/04/27: - _BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE - fix CMakeLists.txt COMPILE_DEFINITIONS - fix getDevicesFromMiniSSDPD() not setting scope_id - improve -r command of upnpc command line tool - -2014/11/17: - search all : - upnpDiscoverDevices() / upnpDiscoverAll() functions - listdevices executable - increment API_VERSION to 12 - validate igd_desc_parse - -2014/11/13: - increment API_VERSION to 11 - -2014/11/05: - simplified function GetUPNPUrls() - -2014/09/11: - use remoteHost arg of DeletePortMapping - -2014/09/06: - Fix python3 build - -2014/07/01: - Fix parsing of IGD2 root descriptions - -2014/06/10: - rename LIBSPEC to MINIUPNP_LIBSPEC - -2014/05/15: - Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange - -2014/02/05: - handle EINPROGRESS after connect() - -2014/02/03: - minixml now handle XML comments - -VERSION 1.9 : released 2014/01/31 - -2014/01/31: - added argument remoteHost to UPNP_GetSpecificPortMappingEntry() - increment API_VERSION to 10 - -2013/12/09: - --help and -h arguments in upnpc.c - -2013/10/07: - fixed potential buffer overrun in miniwget.c - Modified UPNP_GetValidIGD() to check for ExternalIpAddress - -2013/08/01: - define MAXHOSTNAMELEN if not already done - -2013/06/06: - update upnpreplyparse to allow larger values (128 chars instead of 64) - -2013/05/14: - Update upnpreplyparse to take into account "empty" elements - validate upnpreplyparse.c code with "make check" - -2013/05/03: - Fix Solaris build thanks to Maciej Małecki - -2013/04/27: - Fix testminiwget.sh for BSD - -2013/03/23: - Fixed Makefile for *BSD - -2013/03/11: - Update Makefile to use JNAerator version 0.11 - -2013/02/11: - Fix testminiwget.sh for use with dash - Use $(DESTDIR) in Makefile - -VERSION 1.8 : released 2013/02/06 - -2012/10/16: - fix testminiwget with no IPv6 support - -2012/09/27: - Rename all include guards to not clash with C99 - (7.1.3 Reserved identifiers). - -2012/08/30: - Added -e option to upnpc program (set description for port mappings) - -2012/08/29: - Python 3 support (thanks to Christopher Foo) - -2012/08/11: - Fix a memory link in UPNP_GetValidIGD() - Try to handle scope id in link local IPv6 URL under MS Windows - -2012/07/20: - Disable HAS_IP_MREQN on DragonFly BSD - -2012/06/28: - GetUPNPUrls() now inserts scope into link-local IPv6 addresses - -2012/06/23: - More error return checks in upnpc.c - #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id - parseURL() now parses IPv6 addresses scope - new parameter for miniwget() : IPv6 address scope - increment API_VERSION to 9 - -2012/06/20: - fixed CMakeLists.txt - -2012/05/29 - Improvements in testminiwget.sh - -VERSION 1.7 : released 2012/05/24 - -2012/05/01: - Cleanup settings of CFLAGS in Makefile - Fix signed/unsigned integer comparaisons - -2012/04/20: - Allow to specify protocol with TCP or UDP for -A option - -2012/04/09: - Only try to fetch XML description once in UPNP_GetValidIGD() - Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments. - -2012/04/05: - minor improvements to minihttptestserver.c - -2012/03/15: - upnperrors.c returns valid error string for unrecognized error codes - -2012/03/08: - make minihttptestserver listen on loopback interface instead of 0.0.0.0 - -2012/01/25: - Maven installation thanks to Alexey Kuznetsov - -2012/01/21: - Replace WIN32 macro by _WIN32 - -2012/01/19: - Fixes in java wrappers thanks to Alexey Kuznetsov : - https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc - Make and install .deb packages (python) thanks to Alexey Kuznetsov : - https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc - -2012/01/07: - The multicast interface can now be specified by name with IPv4. - -2012/01/02: - Install man page - -2011/11/25: - added header to Port Mappings list in upnpc.c - -2011/10/09: - Makefile : make clean now removes jnaerator generated files. - MINIUPNPC_VERSION in miniupnpc.h (updated by make) - -2011/09/12: - added rootdescURL to UPNPUrls structure. - -VERSION 1.6 : released 2011/07/25 - -2011/07/25: - Update doc for version 1.6 release - -2011/06/18: - Fix for windows in miniwget.c - -2011/06/04: - display remote host in port mapping listing - -2011/06/03: - Fix in make install : there were missing headers - -2011/05/26: - Fix the socket leak in miniwget thanks to Richard Marsh. - Permit to add leaseduration in -a command. Display lease duration. - -2011/05/15: - Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6 - -2011/05/09: - add a test in testminiwget.sh. - more error checking in miniwget.c - -2011/05/06: - Adding some tool to test and validate miniwget.c - simplified and debugged miniwget.c - -2011/04/11: - moving ReceiveData() to a receivedata.c file. - parsing presentation url - adding IGD v2 WANIPv6FirewallControl commands - -2011/04/10: - update of miniupnpcmodule.c - comments in miniwget.c, update in testminiwget - Adding errors codes from IGD v2 - new functions in upnpc.c for IGD v2 - -2011/04/09: - Support for litteral ip v6 address in miniwget - -2011/04/08: - Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 - Updating APIVERSION - Supporting IPV6 in upnpDiscover() - Adding a -6 option to upnpc command line tool - -2011/03/18: - miniwget/parseURL() : return an error when url param is null. - fixing GetListOfPortMappings() - -2011/03/14: - upnpDiscover() now reporting an error code. - improvements in comments. - -2011/03/11: - adding miniupnpcstrings.h.cmake and CMakeLists.txt files. - -2011/02/15: - Implementation of GetListOfPortMappings() - -2011/02/07: - updates to minixml to support character data starting with spaces - minixml now support CDATA - upnpreplyparse treats specificaly - change in simpleUPnPcommand to return the buffer (simplification) - -2011/02/06: - Added leaseDuration argument to AddPortMapping() - Starting to implement GetListOfPortMappings() - -2011/01/11: - updating wingenminiupnpcstrings.c - -2011/01/04: - improving updateminiupnpcstrings.sh - -VERSION 1.5 : released 2011/01/01 - -2010/12/21: - use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo - -2010/12/11: - Improvements on getHTTPResponse() code. - -2010/12/09: - new code for miniwget that handle Chunked transfer encoding - using getHTTPResponse() in SOAP call code - Adding MANIFEST.in for 'python setup.py bdist_rpm' - -2010/11/25: - changes to minissdpc.c to compile under Win32. - see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729 - -2010/09/17: - Various improvement to Makefile from Michał Górny - -2010/08/05: - Adding the script "external-ip.sh" from Reuben Hawkins - -2010/06/09: - update to python module to match modification made on 2010/04/05 - update to Java test code to match modification made on 2010/04/05 - all UPNP_* function now return an error if the SOAP request failed - at HTTP level. - -2010/04/17: - Using GetBestRoute() under win32 in order to find the - right interface to use. - -2010/04/12: - Retrying with HTTP/1.1 if HTTP/1.0 failed. see - http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703 - -2010/04/07: - avoid returning duplicates in upnpDiscover() - -2010/04/05: - Create a connecthostport.h/.c with connecthostport() function - and use it in miniwget and miniupnpc. - Use getnameinfo() instead of inet_ntop or inet_ntoa - Work to make miniupnpc IPV6 compatible... - Add java test code. - Big changes in order to support device having both WANIPConnection - and WANPPPConnection. - -2010/04/04: - Use getaddrinfo() instead of gethostbyname() in miniwget. - -2010/01/06: - #define _DARWIN_C_SOURCE for Mac OS X - -2009/12/19: - Improve MinGW32 build - -2009/12/11: - adding a MSVC9 project to build the static library and executable - -2009/12/10: - Fixing some compilation stuff for Windows/MinGW - -2009/12/07: - adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS - some fixes for Windows when using virtual ethernet adapters (it is the - case with VMWare installed). - -2009/12/04: - some fixes for AmigaOS compilation - Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked - transfer encoding) - -2009/12/03: - updating printIDG and testigddescparse.c for debug. - modifications to compile under AmigaOS - adding a testminiwget program - Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked - transfer encoding - -2009/11/26: - fixing updateminiupnpcstrings.sh to take into account - which command that does not return an error code. - -VERSION 1.4 : released 2009/10/30 - -2009/10/16: - using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module. - -2009/10/10: - Some fixes for compilation under Solaris - compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464 - -2009/09/21: - fixing the code to ignore EINTR during connect() calls. - -2009/08/07: - Set socket timeout for connect() - Some cleanup in miniwget.c - -2009/08/04: - remove multiple redirections with -d in upnpc.c - Print textual error code in upnpc.c - Ignore EINTR during the connect() and poll() calls. - -2009/07/29: - fix in updateminiupnpcstrings.sh if OS name contains "/" - Sending a correct value for MX: field in SSDP request - -2009/07/20: - Change the Makefile to compile under Mac OS X - Fixed a stackoverflow in getDevicesFromMiniSSDPD() - -2009/07/09: - Compile under Haiku - generate miniupnpcstrings.h.in from miniupnpcstrings.h - -2009/06/04: - patching to compile under CygWin and cross compile for minGW - -VERSION 1.3 : - -2009/04/17: - updating python module - Use strtoull() when using C99 - -2009/02/28: - Fixed miniwget.c for compiling under sun - -2008/12/18: - cleanup in Makefile (thanks to Paul de Weerd) - minissdpc.c : win32 compatibility - miniupnpc.c : changed xmlns prefix from 'm' to 'u' - Removed NDEBUG (using DEBUG) - -2008/10/14: - Added the ExternalHost argument to DeletePortMapping() - -2008/10/11: - Added the ExternalHost argument to AddPortMapping() - Put a correct User-Agent: header in HTTP requests. - -VERSION 1.2 : - -2008/10/07: - Update docs - -2008/09/25: - Integrated sameport patch from Dario Meloni : Added a "sameport" - argument to upnpDiscover(). - -2008/07/18: - small modif to make Clang happy :) - -2008/07/17: - #define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV... - -2008/07/14: - include declspec.h in installation (to /usr/include/miniupnpc) - -VERSION 1.1 : - -2008/07/04: - standard options for install/ln instead of gnu-specific stuff. - -2008/07/03: - now builds a .dll and .lib with win32. (mingw32) - -2008/04/28: - make install now install the binary of the upnpc tool - -2008/04/27: - added testupnpigd.py - added error strings for miniupnpc "internal" errors - improved python module error/exception reporting. - -2008/04/23: - Completely rewrite igd_desc_parse.c in order to be compatible with - Linksys WAG200G - Added testigddescparse - updated python module - -VERSION 1.0 : - -2008/02/21: - put some #ifdef DEBUG around DisplayNameValueList() - -2008/02/18: - Improved error reporting in upnpcommands.c - UPNP_GetStatusInfo() returns LastConnectionError - -2008/02/16: - better error handling in minisoap.c - improving display of "valid IGD found" in upnpc.c - -2008/02/03: - Fixing UPNP_GetValidIGD() - improved make install :) - -2007/12/22: - Adding upnperrors.c/h to provide a strupnperror() function - used to translate UPnP error codes to string. - -2007/12/19: - Fixing getDevicesFromMiniSSDPD() - improved error reporting of UPnP functions - -2007/12/18: - It is now possible to specify a different location for MiniSSDPd socket. - working with MiniSSDPd is now more efficient. - python module improved. - -2007/12/16: - improving error reporting - -2007/12/13: - Try to improve compatibility by using HTTP/1.0 instead of 1.1 and - XML a bit different for SOAP. - -2007/11/25: - fixed select() call for linux - -2007/11/15: - Added -fPIC to CFLAG for better shared library code. - -2007/11/02: - Fixed a potential socket leak in miniwget2() - -2007/10/16: - added a parameter to upnpDiscover() in order to allow the use of another - interface than the default multicast interface. - -2007/10/12: - Fixed the creation of symbolic link in Makefile - -2007/10/08: - Added man page - -2007/10/02: - fixed memory bug in GetUPNPUrls() - -2007/10/01: - fixes in the Makefile - Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly. - Added SONAME in the shared library to please debian :) - fixed MS Windows compilation (minissdpd is not available under MS Windows). - -2007/09/25: - small change to Makefile to be able to install in a different location - (default is /usr) - -2007/09/24: - now compiling both shared and static library - -2007/09/19: - Cosmetic changes on upnpc.c - -2007/09/02: - adapting to new miniSSDPd (release version ?) - -2007/08/31: - Usage of miniSSDPd to skip discovery process. - -2007/08/27: - fixed python module to allow compilation with Python older than Python 2.4 - -2007/06/12: - Added a python module. - -2007/05/19: - Fixed compilation under MinGW - -2007/05/15: - fixed a memory leak in AddPortMapping() - Added testupnpreplyparse executable to check the parsing of - upnp soap messages - minixml now ignore namespace prefixes. - -2007/04/26: - upnpc now displays external ip address with -s or -l - -2007/04/11: - changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210" - -2007/03/19: - cleanup in miniwget.c - -2007/03/01: - Small typo fix... - -2007/01/30: - Now parsing the HTTP header from SOAP responses in order to - get content-length value. - -2007/01/29: - Fixed the Soap Query to speedup the HTTP request. - added some Win32 DLL stuff... - -2007/01/27: - Fixed some WIN32 compatibility issues - -2006/12/14: - Added UPNPIGD_IsConnected() function in miniupnp.c/.h - Added UPNP_GetValidIGD() in miniupnp.c/.h - cleaned upnpc.c main(). now using UPNP_GetValidIGD() - -2006/12/07: - Version 1.0-RC1 released - -2006/12/03: - Minor changes to compile under SunOS/Solaris - -2006/11/30: - made a minixml parser validator program - updated minixml to handle attributes correctly - -2006/11/22: - Added a -r option to the upnpc sample thanks to Alexander Hubmann. - -2006/11/19: - Cleanup code to make it more ANSI C compliant - -2006/11/10: - detect and display local lan address. - -2006/11/04: - Packets and Bytes Sent/Received are now unsigned int. - -2006/11/01: - Bug fix thanks to Giuseppe D'Angelo - -2006/10/31: - C++ compatibility for .h files. - Added a way to get ip Address on the LAN used to reach the IGD. - -2006/10/25: - Added M-SEARCH to the services in the discovery process. - -2006/10/22: - updated the Makefile to use makedepend, added a "make install" - update Makefile - -2006/10/20: - fixing the description url parsing thanks to patch sent by - Wayne Dawe. - Fixed/translated some comments. - Implemented a better discover process, first looking - for IGD then for root devices (as some devices only reply to - M-SEARCH for root devices). - -2006/09/02: - added freeUPNPDevlist() function. - -2006/08/04: - More command line arguments checking - -2006/08/01: - Added the .bat file to compile under Win32 with minGW32 - -2006/07/31: - Fixed the rootdesc parser (igd_desc_parse.c) - -2006/07/20: - parseMSEARCHReply() is now returning the ST: line as well - starting changes to detect several UPnP devices on the network - -2006/07/19: - using GetCommonLinkProperties to get down/upload bitrate - diff --git a/zto/ext/miniupnpc/LICENSE b/zto/ext/miniupnpc/LICENSE deleted file mode 100644 index cb5a060..0000000 --- a/zto/ext/miniupnpc/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -MiniUPnPc -Copyright (c) 2005-2015, Thomas BERNARD -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. - * The name of the author may not 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. - diff --git a/zto/ext/miniupnpc/MANIFEST.in b/zto/ext/miniupnpc/MANIFEST.in deleted file mode 100644 index 54b86f9..0000000 --- a/zto/ext/miniupnpc/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include README -include miniupnpcmodule.c -include setup.py -include *.h -include libminiupnpc.a diff --git a/zto/ext/miniupnpc/README b/zto/ext/miniupnpc/README deleted file mode 100644 index 91535db..0000000 --- a/zto/ext/miniupnpc/README +++ /dev/null @@ -1,64 +0,0 @@ -Project: miniupnp -Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ -github: https://github.com/miniupnp/miniupnp -freecode: http://freecode.com/projects/miniupnp -Author: Thomas Bernard -Copyright (c) 2005-2016 Thomas Bernard -This software is subject to the conditions detailed in the -LICENSE file provided within this distribution. - - -* miniUPnP Client - miniUPnPc * - -To compile, simply run 'gmake' (could be 'make' on your system). -Under win32, to compile with MinGW, type "mingw32make.bat". -MS Visual C solution and project files are supplied in the msvc/ subdirectory. - -The compilation is known to work under linux, FreeBSD, -OpenBSD, MacOS X, AmigaOS and cygwin. -The official AmigaOS4.1 SDK was used for AmigaOS4 and GeekGadgets for AmigaOS3. -upx (http://upx.sourceforge.net) is used to compress the win32 .exe files. - -To install the library and headers on the system use : -> su -> make install -> exit - -alternatively, to install into a specific location, use : -> INSTALLPREFIX=/usr/local make install - -upnpc.c is a sample client using the libminiupnpc. -To use the libminiupnpc in your application, link it with -libminiupnpc.a (or .so) and use the following functions found in miniupnpc.h, -upnpcommands.h and miniwget.h : -- upnpDiscover() -- UPNP_GetValidIGD() -- miniwget() -- parserootdesc() -- GetUPNPUrls() -- UPNP_* (calling UPNP methods) - -Note : use #include etc... for the includes -and -lminiupnpc for the link - -Discovery process is speeded up when MiniSSDPd is running on the machine. - - -* Python module * - -you can build a python module with 'make pythonmodule' -and install it with 'make installpythonmodule'. -setup.py (and setupmingw32.py) are included in the distribution. - - -Feel free to contact me if you have any problem : -e-mail : miniupnp@free.fr - -If you are using libminiupnpc in your application, please -send me an email ! - -For any question, you can use the web forum : -http://miniupnp.tuxfamily.org/forum/ - -Bugs should be reported on github : -https://github.com/miniupnp/miniupnp/issues diff --git a/zto/ext/miniupnpc/VERSION b/zto/ext/miniupnpc/VERSION deleted file mode 100644 index cd5ac03..0000000 --- a/zto/ext/miniupnpc/VERSION +++ /dev/null @@ -1 +0,0 @@ -2.0 diff --git a/zto/ext/miniupnpc/apiversions.txt b/zto/ext/miniupnpc/apiversions.txt deleted file mode 100644 index 9464a86..0000000 --- a/zto/ext/miniupnpc/apiversions.txt +++ /dev/null @@ -1,172 +0,0 @@ -$Id: apiversions.txt,v 1.9 2016/01/24 17:24:36 nanard Exp $ - -Differences in API between miniUPnPc versions - -API version 16 - added "status_code" argument to getHTTPResponse(), miniwget() and miniwget_getaddr() - updated macro : - #define MINIUPNPC_API_VERSION 16 - -API version 15 - changed "sameport" argument of upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice() - to "localport". When 0 or 1, behaviour is not changed, but it can take - any other value between 2 and 65535 - Existing programs should be compatible - updated macro : - #define MINIUPNPC_API_VERSION 15 - -API version 14 -miniupnpc.h - add ttl argument to upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice() - upnpDiscoverDevices() - getDevicesFromMiniSSDPD() : - connectToMiniSSDPD() / disconnectFromMiniSSDPD() - requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD() - updated macro : - #define MINIUPNPC_API_VERSION 14 - -API version 13 -miniupnpc.h: - add searchalltype param to upnpDiscoverDevices() function - updated macro : - #define MINIUPNPC_API_VERSION 13 - -API version 12 -miniupnpc.h : - add upnpDiscoverAll() / upnpDiscoverDevice() / upnpDiscoverDevices() - functions - updated macros : - #define MINIUPNPC_API_VERSION 12 - -API version 11 - -upnpreplyparse.h / portlistingparse.h : - removed usage of sys/queue.h / bsdqueue.h - -miniupnpc.h: - updated macros : - #define MINIUPNPC_API_VERSION 11 - -====================== miniUPnPc version 1.9 ====================== -API version 10 - -upnpcommands.h: - added argument remoteHost to UPNP_GetSpecificPortMappingEntry() - -miniupnpc.h: - updated macros : - #define MINIUPNPC_VERSION "1.9" - #define MINIUPNPC_API_VERSION 10 - -====================== miniUPnPc version 1.8 ====================== -API version 9 - -miniupnpc.h: - updated macros : - #define MINIUPNPC_VERSION "1.8" - #define MINIUPNPC_API_VERSION 9 - added "unsigned int scope_id;" to struct UPNPDev - added scope_id argument to GetUPNPUrls() - - - -====================== miniUPnPc version 1.7 ====================== -API version 8 - -miniupnpc.h : - add new macros : - #define MINIUPNPC_VERSION "1.7" - #define MINIUPNPC_API_VERSION 8 - add rootdescURL to struct UPNPUrls - - - -====================== miniUPnPc version 1.6 ====================== -API version 8 - -Adding support for IPv6. -igd_desc_parse.h : - struct IGDdatas_service : - add char presentationurl[MINIUPNPC_URL_MAXSIZE]; - struct IGDdatas : - add struct IGDdatas_service IPv6FC; -miniupnpc.h : - new macros : - #define UPNPDISCOVER_SUCCESS (0) - #define UPNPDISCOVER_UNKNOWN_ERROR (-1) - #define UPNPDISCOVER_SOCKET_ERROR (-101) - #define UPNPDISCOVER_MEMORY_ERROR (-102) - simpleUPnPcommand() prototype changed (but is normaly not used by API users) - add arguments ipv6 and error to upnpDiscover() : - struct UPNPDev * - upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock, int sameport, - int ipv6, - int * error); - add controlURL_6FC member to struct UPNPUrls : - struct UPNPUrls { - char * controlURL; - char * ipcondescURL; - char * controlURL_CIF; - char * controlURL_6FC; - }; - -upnpcommands.h : - add leaseDuration argument to UPNP_AddPortMapping() - add desc, enabled and leaseDuration arguments to UPNP_GetSpecificPortMappingEntry() - add UPNP_GetListOfPortMappings() function (IGDv2) - add IGDv2 IPv6 related functions : - UPNP_GetFirewallStatus() - UPNP_GetOutboundPinholeTimeout() - UPNP_AddPinhole() - UPNP_UpdatePinhole() - UPNP_DeletePinhole() - UPNP_CheckPinholeWorking() - UPNP_GetPinholePackets() - - - -====================== miniUPnPc version 1.5 ====================== -API version 5 - -new function : -int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); -new macro in upnpcommands.h : -#define UPNPCOMMAND_HTTP_ERROR - -====================== miniUPnPc version 1.4 ====================== -Same API as version 1.3 - -====================== miniUPnPc version 1.3 ====================== -API version 4 - -Use UNSIGNED_INTEGER type for -UPNP_GetTotalBytesSent(), UPNP_GetTotalBytesReceived(), -UPNP_GetTotalPacketsSent(), UPNP_GetTotalPacketsReceived() -Add remoteHost argument to UPNP_AddPortMapping() and UPNP_DeletePortMapping() - -====================== miniUPnPc version 1.2 ====================== -API version 3 - -added sameport argument to upnpDiscover() -struct UPNPDev * -upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock, int sameport); - -====================== miniUPnPc Version 1.1 ====================== -Same API as 1.0 - - -====================== miniUPnPc Version 1.0 ====================== -API version 2 - - -struct UPNPDev { - struct UPNPDev * pNext; - char * descURL; - char * st; - char buffer[2]; -}; -struct UPNPDev * upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock); - diff --git a/zto/ext/miniupnpc/codelength.h b/zto/ext/miniupnpc/codelength.h deleted file mode 100644 index f5f8e30..0000000 --- a/zto/ext/miniupnpc/codelength.h +++ /dev/null @@ -1,54 +0,0 @@ -/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas BERNARD - * copyright (c) 2005-2015 Thomas Bernard - * This software is subjet to the conditions detailed in the - * provided LICENCE file. */ -#ifndef CODELENGTH_H_INCLUDED -#define CODELENGTH_H_INCLUDED - -/* Encode length by using 7bit per Byte : - * Most significant bit of each byte specifies that the - * following byte is part of the code */ - -/* n : unsigned - * p : unsigned char * - */ -#define DECODELENGTH(n, p) n = 0; \ - do { n = (n << 7) | (*p & 0x7f); } \ - while((*(p++)&0x80) && (n<(1<<25))); - -/* n : unsigned - * READ : function/macro to read one byte (unsigned char) - */ -#define DECODELENGTH_READ(n, READ) \ - n = 0; \ - do { \ - unsigned char c; \ - READ(c); \ - n = (n << 7) | (c & 0x07f); \ - if(!(c&0x80)) break; \ - } while(n<(1<<25)); - -/* n : unsigned - * p : unsigned char * - * p_limit : unsigned char * - */ -#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ - n = 0; \ - do { \ - if((p) >= (p_limit)) break; \ - n = (n << 7) | (*(p) & 0x7f); \ - } while((*((p)++)&0x80) && (n<(1<<25))); - - -/* n : unsigned - * p : unsigned char * - */ -#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ - if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ - if(n>=16384) *(p++) = (n >> 14) | 0x80; \ - if(n>=128) *(p++) = (n >> 7) | 0x80; \ - *(p++) = n & 0x7f; - -#endif /* CODELENGTH_H_INCLUDED */ diff --git a/zto/ext/miniupnpc/connecthostport.c b/zto/ext/miniupnpc/connecthostport.c deleted file mode 100644 index c12d7bd..0000000 --- a/zto/ext/miniupnpc/connecthostport.c +++ /dev/null @@ -1,264 +0,0 @@ -/* $Id: connecthostport.c,v 1.16 2016/12/16 08:57:53 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2010-2016 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ - -/* use getaddrinfo() or gethostbyname() - * uncomment the following line in order to use gethostbyname() */ -#ifdef NO_GETADDRINFO -#define USE_GETHOSTBYNAME -#endif - -#include -#include -#ifdef _WIN32 -#include -#include -#include -#define MAXHOSTNAMELEN 64 -#define snprintf _snprintf -#define herror -#define socklen_t int -#else /* #ifdef _WIN32 */ -#include -#include -#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT -#include -#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ -#include -#include -#include -#define closesocket close -#include -#include -/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions - * during the connect() call */ -#define MINIUPNPC_IGNORE_EINTR -#ifndef USE_GETHOSTBYNAME -#include -#include -#endif /* #ifndef USE_GETHOSTBYNAME */ -#endif /* #else _WIN32 */ - -/* definition of PRINT_SOCKET_ERROR */ -#ifdef _WIN32 -#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); -#else -#define PRINT_SOCKET_ERROR(x) perror(x) -#endif - -#if defined(__amigaos__) || defined(__amigaos4__) -#define herror(A) printf("%s\n", A) -#endif - -#include "connecthostport.h" - -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -/* connecthostport() - * return a socket connected (TCP) to the host and port - * or -1 in case of error */ -int connecthostport(const char * host, unsigned short port, - unsigned int scope_id) -{ - int s, n; -#ifdef USE_GETHOSTBYNAME - struct sockaddr_in dest; - struct hostent *hp; -#else /* #ifdef USE_GETHOSTBYNAME */ - char tmp_host[MAXHOSTNAMELEN+1]; - char port_str[8]; - struct addrinfo *ai, *p; - struct addrinfo hints; -#endif /* #ifdef USE_GETHOSTBYNAME */ -#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT - struct timeval timeout; -#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ - -#ifdef USE_GETHOSTBYNAME - hp = gethostbyname(host); - if(hp == NULL) - { - herror(host); - return -1; - } - memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); - memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); - s = socket(PF_INET, SOCK_STREAM, 0); - if(s < 0) - { - PRINT_SOCKET_ERROR("socket"); - return -1; - } -#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT - /* setting a 3 seconds timeout for the connect() call */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt SO_RCVTIMEO"); - } - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt SO_SNDTIMEO"); - } -#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ - dest.sin_family = AF_INET; - dest.sin_port = htons(port); - n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); -#ifdef MINIUPNPC_IGNORE_EINTR - /* EINTR The system call was interrupted by a signal that was caught - * EINPROGRESS The socket is nonblocking and the connection cannot - * be completed immediately. */ - while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) - { - socklen_t len; - fd_set wset; - int err; - FD_ZERO(&wset); - FD_SET(s, &wset); - if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) - continue; - /*len = 0;*/ - /*n = getpeername(s, NULL, &len);*/ - len = sizeof(err); - if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { - PRINT_SOCKET_ERROR("getsockopt"); - closesocket(s); - return -1; - } - if(err != 0) { - errno = err; - n = -1; - } - } -#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ - if(n<0) - { - PRINT_SOCKET_ERROR("connect"); - closesocket(s); - return -1; - } -#else /* #ifdef USE_GETHOSTBYNAME */ - /* use getaddrinfo() instead of gethostbyname() */ - memset(&hints, 0, sizeof(hints)); - /* hints.ai_flags = AI_ADDRCONFIG; */ -#ifdef AI_NUMERICSERV - hints.ai_flags = AI_NUMERICSERV; -#endif - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */ - /* hints.ai_protocol = IPPROTO_TCP; */ - snprintf(port_str, sizeof(port_str), "%hu", port); - if(host[0] == '[') - { - /* literal ip v6 address */ - int i, j; - for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++) - { - tmp_host[i] = host[j]; - if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */ - j+=2; /* skip "25" */ - } - tmp_host[i] = '\0'; - } - else - { - strncpy(tmp_host, host, MAXHOSTNAMELEN); - } - tmp_host[MAXHOSTNAMELEN] = '\0'; - n = getaddrinfo(tmp_host, port_str, &hints, &ai); - if(n != 0) - { -#ifdef _WIN32 - fprintf(stderr, "getaddrinfo() error : %d\n", n); -#else - fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); -#endif - return -1; - } - s = -1; - for(p = ai; p; p = p->ai_next) - { - s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if(s < 0) - continue; - if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) { - struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr; - addr6->sin6_scope_id = scope_id; - } -#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT - /* setting a 3 seconds timeout for the connect() call */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt"); - } - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt"); - } -#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ - n = connect(s, p->ai_addr, p->ai_addrlen); -#ifdef MINIUPNPC_IGNORE_EINTR - /* EINTR The system call was interrupted by a signal that was caught - * EINPROGRESS The socket is nonblocking and the connection cannot - * be completed immediately. */ - while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) - { - socklen_t len; - fd_set wset; - int err; - FD_ZERO(&wset); - FD_SET(s, &wset); - if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) - continue; - /*len = 0;*/ - /*n = getpeername(s, NULL, &len);*/ - len = sizeof(err); - if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { - PRINT_SOCKET_ERROR("getsockopt"); - closesocket(s); - freeaddrinfo(ai); - return -1; - } - if(err != 0) { - errno = err; - n = -1; - } - } -#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ - if(n < 0) - { - closesocket(s); - continue; - } - else - { - break; - } - } - freeaddrinfo(ai); - if(s < 0) - { - PRINT_SOCKET_ERROR("socket"); - return -1; - } - if(n < 0) - { - PRINT_SOCKET_ERROR("connect"); - return -1; - } -#endif /* #ifdef USE_GETHOSTBYNAME */ - return s; -} - diff --git a/zto/ext/miniupnpc/connecthostport.h b/zto/ext/miniupnpc/connecthostport.h deleted file mode 100644 index 56941d6..0000000 --- a/zto/ext/miniupnpc/connecthostport.h +++ /dev/null @@ -1,18 +0,0 @@ -/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ - * Author: Thomas Bernard - * Copyright (c) 2010-2012 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef CONNECTHOSTPORT_H_INCLUDED -#define CONNECTHOSTPORT_H_INCLUDED - -/* connecthostport() - * return a socket connected (TCP) to the host and port - * or -1 in case of error */ -int connecthostport(const char * host, unsigned short port, - unsigned int scope_id); - -#endif - diff --git a/zto/ext/miniupnpc/external-ip.sh b/zto/ext/miniupnpc/external-ip.sh deleted file mode 100755 index 965d86b..0000000 --- a/zto/ext/miniupnpc/external-ip.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# $Id: external-ip.sh,v 1.1 2010/08/05 12:57:41 nanard Exp $ -# (c) 2010 Reuben Hawkins -upnpc -s | grep ExternalIPAddress | sed 's/[^0-9\.]//g' diff --git a/zto/ext/miniupnpc/igd_desc_parse.c b/zto/ext/miniupnpc/igd_desc_parse.c deleted file mode 100644 index d2999ad..0000000 --- a/zto/ext/miniupnpc/igd_desc_parse.c +++ /dev/null @@ -1,123 +0,0 @@ -/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */ -/* Project : miniupnp - * http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005-2015 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ - -#include "igd_desc_parse.h" -#include -#include - -/* Start element handler : - * update nesting level counter and copy element name */ -void IGDstartelt(void * d, const char * name, int l) -{ - struct IGDdatas * datas = (struct IGDdatas *)d; - if(l >= MINIUPNPC_URL_MAXSIZE) - l = MINIUPNPC_URL_MAXSIZE-1; - memcpy(datas->cureltname, name, l); - datas->cureltname[l] = '\0'; - datas->level++; - if( (l==7) && !memcmp(name, "service", l) ) { - datas->tmp.controlurl[0] = '\0'; - datas->tmp.eventsuburl[0] = '\0'; - datas->tmp.scpdurl[0] = '\0'; - datas->tmp.servicetype[0] = '\0'; - } -} - -#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) - -/* End element handler : - * update nesting level counter and update parser state if - * service element is parsed */ -void IGDendelt(void * d, const char * name, int l) -{ - struct IGDdatas * datas = (struct IGDdatas *)d; - datas->level--; - /*printf("endelt %2d %.*s\n", datas->level, l, name);*/ - if( (l==7) && !memcmp(name, "service", l) ) - { - if(COMPARE(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { - memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service)); - } else if(COMPARE(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) { - memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service)); - } else if(COMPARE(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANIPConnection:") - || COMPARE(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANPPPConnection:") ) { - if(datas->first.servicetype[0] == '\0') { - memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service)); - } else { - memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service)); - } - } - } -} - -/* Data handler : - * copy data depending on the current element name and state */ -void IGDdata(void * d, const char * data, int l) -{ - struct IGDdatas * datas = (struct IGDdatas *)d; - char * dstmember = 0; - /*printf("%2d %s : %.*s\n", - datas->level, datas->cureltname, l, data); */ - if( !strcmp(datas->cureltname, "URLBase") ) - dstmember = datas->urlbase; - else if( !strcmp(datas->cureltname, "presentationURL") ) - dstmember = datas->presentationurl; - else if( !strcmp(datas->cureltname, "serviceType") ) - dstmember = datas->tmp.servicetype; - else if( !strcmp(datas->cureltname, "controlURL") ) - dstmember = datas->tmp.controlurl; - else if( !strcmp(datas->cureltname, "eventSubURL") ) - dstmember = datas->tmp.eventsuburl; - else if( !strcmp(datas->cureltname, "SCPDURL") ) - dstmember = datas->tmp.scpdurl; -/* else if( !strcmp(datas->cureltname, "deviceType") ) - dstmember = datas->devicetype_tmp;*/ - if(dstmember) - { - if(l>=MINIUPNPC_URL_MAXSIZE) - l = MINIUPNPC_URL_MAXSIZE-1; - memcpy(dstmember, data, l); - dstmember[l] = '\0'; - } -} - -#ifdef DEBUG -void printIGD(struct IGDdatas * d) -{ - printf("urlbase = '%s'\n", d->urlbase); - printf("WAN Device (Common interface config) :\n"); - /*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/ - printf(" serviceType = '%s'\n", d->CIF.servicetype); - printf(" controlURL = '%s'\n", d->CIF.controlurl); - printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl); - printf(" SCPDURL = '%s'\n", d->CIF.scpdurl); - printf("primary WAN Connection Device (IP or PPP Connection):\n"); - /*printf(" deviceType = '%s'\n", d->first.devicetype);*/ - printf(" servicetype = '%s'\n", d->first.servicetype); - printf(" controlURL = '%s'\n", d->first.controlurl); - printf(" eventSubURL = '%s'\n", d->first.eventsuburl); - printf(" SCPDURL = '%s'\n", d->first.scpdurl); - printf("secondary WAN Connection Device (IP or PPP Connection):\n"); - /*printf(" deviceType = '%s'\n", d->second.devicetype);*/ - printf(" servicetype = '%s'\n", d->second.servicetype); - printf(" controlURL = '%s'\n", d->second.controlurl); - printf(" eventSubURL = '%s'\n", d->second.eventsuburl); - printf(" SCPDURL = '%s'\n", d->second.scpdurl); - printf("WAN IPv6 Firewall Control :\n"); - /*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/ - printf(" servicetype = '%s'\n", d->IPv6FC.servicetype); - printf(" controlURL = '%s'\n", d->IPv6FC.controlurl); - printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); - printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); -} -#endif /* DEBUG */ - diff --git a/zto/ext/miniupnpc/igd_desc_parse.h b/zto/ext/miniupnpc/igd_desc_parse.h deleted file mode 100644 index 0de546b..0000000 --- a/zto/ext/miniupnpc/igd_desc_parse.h +++ /dev/null @@ -1,49 +0,0 @@ -/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */ -/* Project : miniupnp - * http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005-2014 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#ifndef IGD_DESC_PARSE_H_INCLUDED -#define IGD_DESC_PARSE_H_INCLUDED - -/* Structure to store the result of the parsing of UPnP - * descriptions of Internet Gateway Devices */ -#define MINIUPNPC_URL_MAXSIZE (128) -struct IGDdatas_service { - char controlurl[MINIUPNPC_URL_MAXSIZE]; - char eventsuburl[MINIUPNPC_URL_MAXSIZE]; - char scpdurl[MINIUPNPC_URL_MAXSIZE]; - char servicetype[MINIUPNPC_URL_MAXSIZE]; - /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ -}; - -struct IGDdatas { - char cureltname[MINIUPNPC_URL_MAXSIZE]; - char urlbase[MINIUPNPC_URL_MAXSIZE]; - char presentationurl[MINIUPNPC_URL_MAXSIZE]; - int level; - /*int state;*/ - /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ - struct IGDdatas_service CIF; - /* "urn:schemas-upnp-org:service:WANIPConnection:1" - * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ - struct IGDdatas_service first; - /* if both WANIPConnection and WANPPPConnection are present */ - struct IGDdatas_service second; - /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ - struct IGDdatas_service IPv6FC; - /* tmp */ - struct IGDdatas_service tmp; -}; - -void IGDstartelt(void *, const char *, int); -void IGDendelt(void *, const char *, int); -void IGDdata(void *, const char *, int); -#ifdef DEBUG -void printIGD(struct IGDdatas *); -#endif /* DEBUG */ - -#endif /* IGD_DESC_PARSE_H_INCLUDED */ diff --git a/zto/ext/miniupnpc/listdevices.c b/zto/ext/miniupnpc/listdevices.c deleted file mode 100644 index a93c29f..0000000 --- a/zto/ext/miniupnpc/listdevices.c +++ /dev/null @@ -1,110 +0,0 @@ -/* $Id: listdevices.c,v 1.7 2015/10/08 16:15:47 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2013-2015 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ - -#include -#include -#include -#ifdef _WIN32 -#include -#endif /* _WIN32 */ -#include "miniupnpc.h" - -int main(int argc, char * * argv) -{ - const char * searched_device = NULL; - const char * * searched_devices = NULL; - const char * multicastif = 0; - const char * minissdpdpath = 0; - int ipv6 = 0; - unsigned char ttl = 2; - int error = 0; - struct UPNPDev * devlist = 0; - struct UPNPDev * dev; - int i; - -#ifdef _WIN32 - WSADATA wsaData; - int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); - if(nResult != NO_ERROR) - { - fprintf(stderr, "WSAStartup() failed.\n"); - return -1; - } -#endif - - for(i = 1; i < argc; i++) { - if(strcmp(argv[i], "-6") == 0) - ipv6 = 1; - else if(strcmp(argv[i], "-d") == 0) { - if(++i >= argc) { - fprintf(stderr, "%s option needs one argument\n", "-d"); - return 1; - } - searched_device = argv[i]; - } else if(strcmp(argv[i], "-t") == 0) { - if(++i >= argc) { - fprintf(stderr, "%s option needs one argument\n", "-t"); - return 1; - } - ttl = (unsigned char)atoi(argv[i]); - } else if(strcmp(argv[i], "-l") == 0) { - if(++i >= argc) { - fprintf(stderr, "-l option needs at least one argument\n"); - return 1; - } - searched_devices = (const char * *)(argv + i); - break; - } else if(strcmp(argv[i], "-m") == 0) { - if(++i >= argc) { - fprintf(stderr, "-m option needs one argument\n"); - return 1; - } - multicastif = argv[i]; - } else { - printf("usage : %s [options] [-l ...]\n", argv[0]); - printf("options :\n"); - printf(" -6 : use IPv6\n"); - printf(" -m address/ifname : network interface to use for multicast\n"); - printf(" -d : search only for this type of device\n"); - printf(" -l ... : search only for theses types of device\n"); - printf(" -t ttl : set multicast TTL. Default value is 2.\n"); - printf(" -h : this help\n"); - return 1; - } - } - - if(searched_device) { - printf("searching UPnP device type %s\n", searched_device); - devlist = upnpDiscoverDevice(searched_device, - 2000, multicastif, minissdpdpath, - 0/*localport*/, ipv6, ttl, &error); - } else if(searched_devices) { - printf("searching UPnP device types :\n"); - for(i = 0; searched_devices[i]; i++) - printf("\t%s\n", searched_devices[i]); - devlist = upnpDiscoverDevices(searched_devices, - 2000, multicastif, minissdpdpath, - 0/*localport*/, ipv6, ttl, &error, 1); - } else { - printf("searching all UPnP devices\n"); - devlist = upnpDiscoverAll(2000, multicastif, minissdpdpath, - 0/*localport*/, ipv6, ttl, &error); - } - if(devlist) { - for(dev = devlist, i = 1; dev != NULL; dev = dev->pNext, i++) { - printf("%3d: %-48s\n", i, dev->st); - printf(" %s\n", dev->descURL); - printf(" %s\n", dev->usn); - } - freeUPNPDevlist(devlist); - } else { - printf("no device found.\n"); - } - - return 0; -} - diff --git a/zto/ext/miniupnpc/mingw32make.bat b/zto/ext/miniupnpc/mingw32make.bat deleted file mode 100644 index c5d3cc4..0000000 --- a/zto/ext/miniupnpc/mingw32make.bat +++ /dev/null @@ -1,8 +0,0 @@ -@mingw32-make -f Makefile.mingw %1 -@if errorlevel 1 goto end -@if not exist upnpc-static.exe goto end -@strip upnpc-static.exe -@upx --best upnpc-static.exe -@strip upnpc-shared.exe -@upx --best upnpc-shared.exe -:end diff --git a/zto/ext/miniupnpc/minihttptestserver.c b/zto/ext/miniupnpc/minihttptestserver.c deleted file mode 100644 index d95dd7c..0000000 --- a/zto/ext/miniupnpc/minihttptestserver.c +++ /dev/null @@ -1,659 +0,0 @@ -/* $Id: minihttptestserver.c,v 1.20 2016/12/16 08:54:55 nanard Exp $ */ -/* Project : miniUPnP - * Author : Thomas Bernard - * Copyright (c) 2011-2016 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef INADDR_LOOPBACK -#define INADDR_LOOPBACK 0x7f000001 -#endif - -#define CRAP_LENGTH (2048) - -volatile sig_atomic_t quit = 0; -volatile sig_atomic_t child_to_wait_for = 0; - -/** - * signal handler for SIGCHLD (child status has changed) - */ -void handle_signal_chld(int sig) -{ - (void)sig; - /* printf("handle_signal_chld(%d)\n", sig); */ - ++child_to_wait_for; -} - -/** - * signal handler for SIGINT (CRTL C) - */ -void handle_signal_int(int sig) -{ - (void)sig; - /* printf("handle_signal_int(%d)\n", sig); */ - quit = 1; -} - -/** - * build a text/plain content of the specified length - */ -void build_content(char * p, int n) -{ - char line_buffer[80]; - int k; - int i = 0; - - while(n > 0) { - k = snprintf(line_buffer, sizeof(line_buffer), - "%04d_ABCDEFGHIJKL_This_line_is_64_bytes_long_ABCDEFGHIJKL_%04d\r\n", - i, i); - if(k != 64) { - fprintf(stderr, "snprintf() returned %d in build_content()\n", k); - } - ++i; - if(n >= 64) { - memcpy(p, line_buffer, 64); - p += 64; - n -= 64; - } else { - memcpy(p, line_buffer, n); - p += n; - n = 0; - } - } -} - -/** - * build crappy content - */ -void build_crap(char * p, int n) -{ - static const char crap[] = "_CRAP_\r\n"; - int i; - - while(n > 0) { - i = sizeof(crap) - 1; - if(i > n) - i = n; - memcpy(p, crap, i); - p += i; - n -= i; - } -} - -/** - * build chunked response. - * return a malloc'ed buffer - */ -char * build_chunked_response(int content_length, int * response_len) -{ - char * response_buffer; - char * content_buffer; - int buffer_length; - int i, n; - - /* allocate to have some margin */ - buffer_length = 256 + content_length + (content_length >> 4); - response_buffer = malloc(buffer_length); - if(response_buffer == NULL) - return NULL; - *response_len = snprintf(response_buffer, buffer_length, - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/plain\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n"); - - /* build the content */ - content_buffer = malloc(content_length); - if(content_buffer == NULL) { - free(response_buffer); - return NULL; - } - build_content(content_buffer, content_length); - - /* chunk it */ - i = 0; - while(i < content_length) { - n = (rand() % 199) + 1; - if(i + n > content_length) { - n = content_length - i; - } - /* TODO : check buffer size ! */ - *response_len += snprintf(response_buffer + *response_len, - buffer_length - *response_len, - "%x\r\n", n); - memcpy(response_buffer + *response_len, content_buffer + i, n); - *response_len += n; - i += n; - response_buffer[(*response_len)++] = '\r'; - response_buffer[(*response_len)++] = '\n'; - } - /* the last chunk : "0\r\n" a empty body and then - * the final "\r\n" */ - memcpy(response_buffer + *response_len, "0\r\n\r\n", 5); - *response_len += 5; - free(content_buffer); - - printf("resp_length=%d buffer_length=%d content_length=%d\n", - *response_len, buffer_length, content_length); - return response_buffer; -} - -/* favicon.ico generator */ -#ifdef OLD_HEADER -#define FAVICON_LENGTH (6 + 16 + 12 + 8 + 32 * 4) -#else -#define FAVICON_LENGTH (6 + 16 + 40 + 8 + 32 * 4) -#endif -void build_favicon_content(char * p, int n) -{ - int i; - if(n < FAVICON_LENGTH) - return; - /* header : 6 bytes */ - *p++ = 0; - *p++ = 0; - *p++ = 1; /* type : ICO */ - *p++ = 0; - *p++ = 1; /* number of images in file */ - *p++ = 0; - /* image directory (1 entry) : 16 bytes */ - *p++ = 16; /* width */ - *p++ = 16; /* height */ - *p++ = 2; /* number of colors in the palette. 0 = no palette */ - *p++ = 0; /* reserved */ - *p++ = 1; /* color planes */ - *p++ = 0; /* " */ - *p++ = 1; /* bpp */ - *p++ = 0; /* " */ -#ifdef OLD_HEADER - *p++ = 12 + 8 + 32 * 4; /* bmp size */ -#else - *p++ = 40 + 8 + 32 * 4; /* bmp size */ -#endif - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 6 + 16; /* bmp offset */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - /* BMP */ -#ifdef OLD_HEADER - /* BITMAPCOREHEADER */ - *p++ = 12; /* size of this header */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 16; /* width */ - *p++ = 0; /* " */ - *p++ = 16 * 2; /* height x 2 ! */ - *p++ = 0; /* " */ - *p++ = 1; /* color planes */ - *p++ = 0; /* " */ - *p++ = 1; /* bpp */ - *p++ = 0; /* " */ -#else - /* BITMAPINFOHEADER */ - *p++ = 40; /* size of this header */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 16; /* width */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 16 * 2; /* height x 2 ! */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 0; /* " */ - *p++ = 1; /* color planes */ - *p++ = 0; /* " */ - *p++ = 1; /* bpp */ - *p++ = 0; /* " */ - /* compression method, image size, ppm x, ppm y */ - /* colors in the palette ? */ - /* important colors */ - for(i = 4 * 6; i > 0; --i) - *p++ = 0; -#endif - /* palette */ - *p++ = 0; /* b */ - *p++ = 0; /* g */ - *p++ = 0; /* r */ - *p++ = 0; /* reserved */ - *p++ = 255; /* b */ - *p++ = 255; /* g */ - *p++ = 255; /* r */ - *p++ = 0; /* reserved */ - /* pixel data */ - for(i = 16; i > 0; --i) { - if(i & 1) { - *p++ = 0125; - *p++ = 0125; - } else { - *p++ = 0252; - *p++ = 0252; - } - *p++ = 0; - *p++ = 0; - } - /* Opacity MASK */ - for(i = 16 * 4; i > 0; --i) { - *p++ = 0; - } -} - -enum modes { - MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL, MODE_FAVICON -}; - -const struct { - const enum modes mode; - const char * text; -} modes_array[] = { - {MODE_CHUNKED, "chunked"}, - {MODE_ADDCRAP, "addcrap"}, - {MODE_NORMAL, "normal"}, - {MODE_FAVICON, "favicon.ico"}, - {MODE_INVALID, NULL} -}; - -/** - * write the response with random behaviour ! - */ -void send_response(int c, const char * buffer, int len) -{ - int n; - while(len > 0) { - n = (rand() % 99) + 1; - if(n > len) - n = len; - n = write(c, buffer, n); - if(n < 0) { - if(errno != EINTR) { - perror("write"); - return; - } - /* if errno == EINTR, try again */ - } else { - len -= n; - buffer += n; - } - usleep(10000); /* 10ms */ - } -} - -/** - * handle the HTTP connection - */ -void handle_http_connection(int c) -{ - char request_buffer[2048]; - int request_len = 0; - int headers_found = 0; - int n, i; - char request_method[16]; - char request_uri[256]; - char http_version[16]; - char * p; - char * response_buffer; - int response_len; - enum modes mode; - int content_length = 16*1024; - - /* read the request */ - while(request_len < (int)sizeof(request_buffer) && !headers_found) { - n = read(c, - request_buffer + request_len, - sizeof(request_buffer) - request_len); - if(n < 0) { - if(errno == EINTR) - continue; - perror("read"); - return; - } else if(n==0) { - /* remote host closed the connection */ - break; - } else { - request_len += n; - for(i = 0; i < request_len - 3; i++) { - if(0 == memcmp(request_buffer + i, "\r\n\r\n", 4)) { - /* found the end of headers */ - headers_found = 1; - break; - } - } - } - } - if(!headers_found) { - /* error */ - printf("no HTTP header found in the request\n"); - return; - } - printf("headers :\n%.*s", request_len, request_buffer); - /* the request have been received, now parse the request line */ - p = request_buffer; - for(i = 0; i < (int)sizeof(request_method) - 1; i++) { - if(*p == ' ' || *p == '\r') - break; - request_method[i] = *p; - ++p; - } - request_method[i] = '\0'; - while(*p == ' ') - p++; - for(i = 0; i < (int)sizeof(request_uri) - 1; i++) { - if(*p == ' ' || *p == '\r') - break; - request_uri[i] = *p; - ++p; - } - request_uri[i] = '\0'; - while(*p == ' ') - p++; - for(i = 0; i < (int)sizeof(http_version) - 1; i++) { - if(*p == ' ' || *p == '\r') - break; - http_version[i] = *p; - ++p; - } - http_version[i] = '\0'; - printf("Method = %s, URI = %s, %s\n", - request_method, request_uri, http_version); - /* check if the request method is allowed */ - if(0 != strcmp(request_method, "GET")) { - const char response405[] = "HTTP/1.1 405 Method Not Allowed\r\n" - "Allow: GET\r\n\r\n"; - const char * pc; - /* 405 Method Not Allowed */ - /* The response MUST include an Allow header containing a list - * of valid methods for the requested resource. */ - n = sizeof(response405) - 1; - pc = response405; - while(n > 0) { - i = write(c, pc, n); - if(i<0) { - if(errno != EINTR) { - perror("write"); - return; - } - } else { - n -= i; - pc += i; - } - } - return; - } - - mode = MODE_INVALID; - /* use the request URI to know what to do */ - for(i = 0; modes_array[i].mode != MODE_INVALID; i++) { - if(strstr(request_uri, modes_array[i].text)) { - mode = modes_array[i].mode; /* found */ - break; - } - } - - switch(mode) { - case MODE_CHUNKED: - response_buffer = build_chunked_response(content_length, &response_len); - break; - case MODE_ADDCRAP: - response_len = content_length+256; - response_buffer = malloc(response_len); - if(!response_buffer) - break; - n = snprintf(response_buffer, response_len, - "HTTP/1.1 200 OK\r\n" - "Server: minihttptestserver\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: %d\r\n" - "\r\n", content_length); - response_len = content_length+n+CRAP_LENGTH; - p = realloc(response_buffer, response_len); - if(p == NULL) { - /* error 500 */ - free(response_buffer); - response_buffer = NULL; - break; - } - response_buffer = p; - build_content(response_buffer + n, content_length); - build_crap(response_buffer + n + content_length, CRAP_LENGTH); - break; - case MODE_FAVICON: - content_length = FAVICON_LENGTH; - response_len = content_length + 256; - response_buffer = malloc(response_len); - if(!response_buffer) - break; - n = snprintf(response_buffer, response_len, - "HTTP/1.1 200 OK\r\n" - "Server: minihttptestserver\r\n" - "Content-Type: image/vnd.microsoft.icon\r\n" - "Content-Length: %d\r\n" - "\r\n", content_length); - /* image/x-icon */ - build_favicon_content(response_buffer + n, content_length); - response_len = content_length + n; - break; - default: - response_len = content_length+256; - response_buffer = malloc(response_len); - if(!response_buffer) - break; - n = snprintf(response_buffer, response_len, - "HTTP/1.1 200 OK\r\n" - "Server: minihttptestserver\r\n" - "Content-Type: text/plain\r\n" - "\r\n"); - response_len = content_length+n; - p = realloc(response_buffer, response_len); - if(p == NULL) { - /* Error 500 */ - free(response_buffer); - response_buffer = NULL; - break; - } - response_buffer = p; - build_content(response_buffer + n, response_len - n); - } - - if(response_buffer) { - send_response(c, response_buffer, response_len); - free(response_buffer); - } else { - /* Error 500 */ - } -} - -/** - */ -int main(int argc, char * * argv) { - int ipv6 = 0; - int s, c, i; - unsigned short port = 0; - struct sockaddr_storage server_addr; - socklen_t server_addrlen; - struct sockaddr_storage client_addr; - socklen_t client_addrlen; - pid_t pid; - int child = 0; - int status; - const char * expected_file_name = NULL; - struct sigaction sa; - - for(i = 1; i < argc; i++) { - if(argv[i][0] == '-') { - switch(argv[i][1]) { - case '6': - ipv6 = 1; - break; - case 'e': - /* write expected file ! */ - expected_file_name = argv[++i]; - break; - case 'p': - /* port */ - if(++i < argc) { - port = (unsigned short)atoi(argv[i]); - } - break; - default: - fprintf(stderr, "unknown command line switch '%s'\n", argv[i]); - } - } else { - fprintf(stderr, "unkown command line argument '%s'\n", argv[i]); - } - } - - srand(time(NULL)); - - memset(&sa, 0, sizeof(struct sigaction)); - - /*signal(SIGCHLD, handle_signal_chld);*/ - sa.sa_handler = handle_signal_chld; - if(sigaction(SIGCHLD, &sa, NULL) < 0) { - perror("sigaction"); - return 1; - } - /*signal(SIGINT, handle_signal_int);*/ - sa.sa_handler = handle_signal_int; - if(sigaction(SIGINT, &sa, NULL) < 0) { - perror("sigaction"); - return 1; - } - - s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0); - if(s < 0) { - perror("socket"); - return 1; - } - memset(&server_addr, 0, sizeof(struct sockaddr_storage)); - memset(&client_addr, 0, sizeof(struct sockaddr_storage)); - if(ipv6) { - struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr; - addr->sin6_family = AF_INET6; - addr->sin6_port = htons(port); - addr->sin6_addr = in6addr_loopback; - } else { - struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr; - addr->sin_family = AF_INET; - addr->sin_port = htons(port); - addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - } - if(bind(s, (struct sockaddr *)&server_addr, - ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) < 0) { - perror("bind"); - return 1; - } - if(listen(s, 5) < 0) { - perror("listen"); - } - if(port == 0) { - server_addrlen = sizeof(struct sockaddr_storage); - if(getsockname(s, (struct sockaddr *)&server_addr, &server_addrlen) < 0) { - perror("getsockname"); - return 1; - } - if(ipv6) { - struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr; - port = ntohs(addr->sin6_port); - } else { - struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr; - port = ntohs(addr->sin_port); - } - printf("Listening on port %hu\n", port); - fflush(stdout); - } - - /* write expected file */ - if(expected_file_name) { - FILE * f; - f = fopen(expected_file_name, "wb"); - if(f) { - char * buffer; - buffer = malloc(16*1024); - if(buffer == NULL) { - fprintf(stderr, "memory allocation error\n"); - } else { - build_content(buffer, 16*1024); - i = fwrite(buffer, 1, 16*1024, f); - if(i != 16*1024) { - fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024); - } - free(buffer); - } - fclose(f); - } else { - fprintf(stderr, "error opening file %s for writing\n", expected_file_name); - } - } - - /* fork() loop */ - while(!child && !quit) { - while(child_to_wait_for > 0) { - pid = wait(&status); - if(pid < 0) { - perror("wait"); - } else { - printf("child(%d) terminated with status %d\n", (int)pid, status); - } - --child_to_wait_for; - } - client_addrlen = sizeof(struct sockaddr_storage); - c = accept(s, (struct sockaddr *)&client_addr, - &client_addrlen); - if(c < 0) { - if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - continue; - perror("accept"); - return 1; - } - printf("accept...\n"); - pid = fork(); - if(pid < 0) { - perror("fork"); - return 1; - } else if(pid == 0) { - /* child */ - child = 1; - close(s); - s = -1; - handle_http_connection(c); - } - close(c); - } - if(s >= 0) { - close(s); - s = -1; - } - if(!child) { - while(child_to_wait_for > 0) { - pid = wait(&status); - if(pid < 0) { - perror("wait"); - } else { - printf("child(%d) terminated with status %d\n", (int)pid, status); - } - --child_to_wait_for; - } - printf("Bye...\n"); - } - return 0; -} - diff --git a/zto/ext/miniupnpc/minisoap.c b/zto/ext/miniupnpc/minisoap.c deleted file mode 100644 index 7aa0213..0000000 --- a/zto/ext/miniupnpc/minisoap.c +++ /dev/null @@ -1,128 +0,0 @@ -/* $Id: minisoap.c,v 1.24 2015/10/26 17:05:07 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005-2015 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * - * Minimal SOAP implementation for UPnP protocol. - */ -#include -#include -#ifdef _WIN32 -#include -#include -#define snprintf _snprintf -#else -#include -#include -#include -#endif -#include "minisoap.h" - -#ifdef _WIN32 -#define OS_STRING "Win32" -#define MINIUPNPC_VERSION_STRING "2.0" -#define UPNP_VERSION_STRING "UPnP/1.1" -#endif - -/* only for malloc */ -#include - -#ifdef _WIN32 -#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); -#else -#define PRINT_SOCKET_ERROR(x) perror(x) -#endif - -/* httpWrite sends the headers and the body to the socket - * and returns the number of bytes sent */ -static int -httpWrite(int fd, const char * body, int bodysize, - const char * headers, int headerssize) -{ - int n = 0; - /*n = write(fd, headers, headerssize);*/ - /*if(bodysize>0) - n += write(fd, body, bodysize);*/ - /* Note : my old linksys router only took into account - * soap request that are sent into only one packet */ - char * p; - /* TODO: AVOID MALLOC, we could use writev() for that */ - p = malloc(headerssize+bodysize); - if(!p) - return -1; - memcpy(p, headers, headerssize); - memcpy(p+headerssize, body, bodysize); - /*n = write(fd, p, headerssize+bodysize);*/ - n = send(fd, p, headerssize+bodysize, 0); - if(n<0) { - PRINT_SOCKET_ERROR("send"); - } - /* disable send on the socket */ - /* draytek routers dont seems to like that... */ -#if 0 -#ifdef _WIN32 - if(shutdown(fd, SD_SEND)<0) { -#else - if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ -#endif - PRINT_SOCKET_ERROR("shutdown"); - } -#endif - free(p); - return n; -} - -/* self explanatory */ -int soapPostSubmit(int fd, - const char * url, - const char * host, - unsigned short port, - const char * action, - const char * body, - const char * httpversion) -{ - int bodysize; - char headerbuf[512]; - int headerssize; - char portstr[8]; - bodysize = (int)strlen(body); - /* We are not using keep-alive HTTP connections. - * HTTP/1.1 needs the header Connection: close to do that. - * This is the default with HTTP/1.0 - * Using HTTP/1.1 means we need to support chunked transfer-encoding : - * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked - * transfer encoding. */ - /* Connection: Close is normally there only in HTTP/1.1 but who knows */ - portstr[0] = '\0'; - if(port != 80) - snprintf(portstr, sizeof(portstr), ":%hu", port); - headerssize = snprintf(headerbuf, sizeof(headerbuf), - "POST %s HTTP/%s\r\n" - "Host: %s%s\r\n" - "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" - "Content-Length: %d\r\n" - "Content-Type: text/xml\r\n" - "SOAPAction: \"%s\"\r\n" - "Connection: Close\r\n" - "Cache-Control: no-cache\r\n" /* ??? */ - "Pragma: no-cache\r\n" - "\r\n", - url, httpversion, host, portstr, bodysize, action); - if ((unsigned int)headerssize >= sizeof(headerbuf)) - return -1; -#ifdef DEBUG - /*printf("SOAP request : headersize=%d bodysize=%d\n", - headerssize, bodysize); - */ - printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n", - url, httpversion, host, portstr); - printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize); - printf("Headers :\n%s", headerbuf); - printf("Body :\n%s\n", body); -#endif - return httpWrite(fd, body, bodysize, headerbuf, headerssize); -} - - diff --git a/zto/ext/miniupnpc/minisoap.h b/zto/ext/miniupnpc/minisoap.h deleted file mode 100644 index 14c859d..0000000 --- a/zto/ext/miniupnpc/minisoap.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ -#ifndef MINISOAP_H_INCLUDED -#define MINISOAP_H_INCLUDED - -/*int httpWrite(int, const char *, int, const char *);*/ -int soapPostSubmit(int, const char *, const char *, unsigned short, - const char *, const char *, const char *); - -#endif - diff --git a/zto/ext/miniupnpc/minissdpc.c b/zto/ext/miniupnpc/minissdpc.c deleted file mode 100644 index 06b11e8..0000000 --- a/zto/ext/miniupnpc/minissdpc.c +++ /dev/null @@ -1,875 +0,0 @@ -/* $Id: minissdpc.c,v 1.33 2016/12/16 08:57:20 nanard Exp $ */ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * Project : miniupnp - * Web : http://miniupnp.free.fr/ - * Author : Thomas BERNARD - * copyright (c) 2005-2016 Thomas Bernard - * This software is subjet to the conditions detailed in the - * provided LICENCE file. */ -/*#include */ -#include -#include -#include -#include -#if defined (__NetBSD__) -#include -#endif -#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) -#ifdef _WIN32 -#include -#include -#include -#include -#include -#define snprintf _snprintf -#if !defined(_MSC_VER) -#include -#else /* !defined(_MSC_VER) */ -typedef unsigned short uint16_t; -#endif /* !defined(_MSC_VER) */ -#ifndef strncasecmp -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define strncasecmp _memicmp -#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ -#define strncasecmp memicmp -#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ -#endif /* #ifndef strncasecmp */ -#endif /* _WIN32 */ -#if defined(__amigaos__) || defined(__amigaos4__) -#include -#endif /* defined(__amigaos__) || defined(__amigaos4__) */ -#if defined(__amigaos__) -#define uint16_t unsigned short -#endif /* defined(__amigaos__) */ -/* Hack */ -#define UNIX_PATH_LEN 108 -struct sockaddr_un { - uint16_t sun_family; - char sun_path[UNIX_PATH_LEN]; -}; -#else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define closesocket close -#endif - -#ifdef _WIN32 -#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); -#else -#define PRINT_SOCKET_ERROR(x) perror(x) -#endif - -#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__) -#define HAS_IP_MREQN -#endif - -#if !defined(HAS_IP_MREQN) && !defined(_WIN32) -#include -#if defined(__sun) -#include -#endif -#endif - -#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN) -/* Several versions of glibc don't define this structure, - * define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */ -struct ip_mreqn -{ - struct in_addr imr_multiaddr; /* IP multicast address of group */ - struct in_addr imr_address; /* local IP address of interface */ - int imr_ifindex; /* Interface index */ -}; -#endif - -#if defined(__amigaos__) || defined(__amigaos4__) -/* Amiga OS specific stuff */ -#define TIMEVAL struct timeval -#endif - -#include "minissdpc.h" -#include "miniupnpc.h" -#include "receivedata.h" - -#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) - -#include "codelength.h" - -struct UPNPDev * -getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error) -{ - struct UPNPDev * devlist = NULL; - int s; - int res; - - s = connectToMiniSSDPD(socketpath); - if (s < 0) { - if (error) - *error = s; - return NULL; - } - res = requestDevicesFromMiniSSDPD(s, devtype); - if (res < 0) { - if (error) - *error = res; - } else { - devlist = receiveDevicesFromMiniSSDPD(s, error); - } - disconnectFromMiniSSDPD(s); - return devlist; -} - -/* macros used to read from unix socket */ -#define READ_BYTE_BUFFER(c) \ - if((int)bufferindex >= n) { \ - n = read(s, buffer, sizeof(buffer)); \ - if(n<=0) break; \ - bufferindex = 0; \ - } \ - c = buffer[bufferindex++]; - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif /* MIN */ - -#define READ_COPY_BUFFER(dst, len) \ - for(l = len, p = (unsigned char *)dst; l > 0; ) { \ - unsigned int lcopy; \ - if((int)bufferindex >= n) { \ - n = read(s, buffer, sizeof(buffer)); \ - if(n<=0) break; \ - bufferindex = 0; \ - } \ - lcopy = MIN(l, (n - bufferindex)); \ - memcpy(p, buffer + bufferindex, lcopy); \ - l -= lcopy; \ - p += lcopy; \ - bufferindex += lcopy; \ - } - -#define READ_DISCARD_BUFFER(len) \ - for(l = len; l > 0; ) { \ - unsigned int lcopy; \ - if(bufferindex >= n) { \ - n = read(s, buffer, sizeof(buffer)); \ - if(n<=0) break; \ - bufferindex = 0; \ - } \ - lcopy = MIN(l, (n - bufferindex)); \ - l -= lcopy; \ - bufferindex += lcopy; \ - } - -int -connectToMiniSSDPD(const char * socketpath) -{ - int s; - struct sockaddr_un addr; -#if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun) - struct timeval timeout; -#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ - - s = socket(AF_UNIX, SOCK_STREAM, 0); - if(s < 0) - { - /*syslog(LOG_ERR, "socket(unix): %m");*/ - perror("socket(unix)"); - return MINISSDPC_SOCKET_ERROR; - } -#if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun) - /* setting a 3 seconds timeout */ - /* not supported for AF_UNIX sockets under Solaris */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - perror("setsockopt SO_RCVTIMEO unix"); - } - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - perror("setsockopt SO_SNDTIMEO unix"); - } -#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ - if(!socketpath) - socketpath = "/var/run/minissdpd.sock"; - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); - /* TODO : check if we need to handle the EINTR */ - if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) - { - /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ - close(s); - return MINISSDPC_SOCKET_ERROR; - } - return s; -} - -int -disconnectFromMiniSSDPD(int s) -{ - if (close(s) < 0) - return MINISSDPC_SOCKET_ERROR; - return MINISSDPC_SUCCESS; -} - -int -requestDevicesFromMiniSSDPD(int s, const char * devtype) -{ - unsigned char buffer[256]; - unsigned char * p; - unsigned int stsize, l; - - stsize = strlen(devtype); - if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8)) - { - buffer[0] = 3; /* request type 3 : everything */ - } - else - { - buffer[0] = 1; /* request type 1 : request devices/services by type */ - } - p = buffer + 1; - l = stsize; CODELENGTH(l, p); - if(p + stsize > buffer + sizeof(buffer)) - { - /* devtype is too long ! */ -#ifdef DEBUG - fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n", - stsize, (unsigned)sizeof(buffer)); -#endif /* DEBUG */ - return MINISSDPC_INVALID_INPUT; - } - memcpy(p, devtype, stsize); - p += stsize; - if(write(s, buffer, p - buffer) < 0) - { - /*syslog(LOG_ERR, "write(): %m");*/ - perror("minissdpc.c: write()"); - return MINISSDPC_SOCKET_ERROR; - } - return MINISSDPC_SUCCESS; -} - -struct UPNPDev * -receiveDevicesFromMiniSSDPD(int s, int * error) -{ - struct UPNPDev * tmp; - struct UPNPDev * devlist = NULL; - unsigned char buffer[256]; - ssize_t n; - unsigned char * p; - unsigned char * url; - unsigned char * st; - unsigned int bufferindex; - unsigned int i, ndev; - unsigned int urlsize, stsize, usnsize, l; - - n = read(s, buffer, sizeof(buffer)); - if(n<=0) - { - perror("minissdpc.c: read()"); - if (error) - *error = MINISSDPC_SOCKET_ERROR; - return NULL; - } - ndev = buffer[0]; - bufferindex = 1; - for(i = 0; i < ndev; i++) - { - DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER); - if(n<=0) { - if (error) - *error = MINISSDPC_INVALID_SERVER_REPLY; - return devlist; - } -#ifdef DEBUG - printf(" urlsize=%u", urlsize); -#endif /* DEBUG */ - url = malloc(urlsize); - if(url == NULL) { - if (error) - *error = MINISSDPC_MEMORY_ERROR; - return devlist; - } - READ_COPY_BUFFER(url, urlsize); - if(n<=0) { - if (error) - *error = MINISSDPC_INVALID_SERVER_REPLY; - goto free_url_and_return; - } - DECODELENGTH_READ(stsize, READ_BYTE_BUFFER); - if(n<=0) { - if (error) - *error = MINISSDPC_INVALID_SERVER_REPLY; - goto free_url_and_return; - } -#ifdef DEBUG - printf(" stsize=%u", stsize); -#endif /* DEBUG */ - st = malloc(stsize); - if (st == NULL) { - if (error) - *error = MINISSDPC_MEMORY_ERROR; - goto free_url_and_return; - } - READ_COPY_BUFFER(st, stsize); - if(n<=0) { - if (error) - *error = MINISSDPC_INVALID_SERVER_REPLY; - goto free_url_and_st_and_return; - } - DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER); - if(n<=0) { - if (error) - *error = MINISSDPC_INVALID_SERVER_REPLY; - goto free_url_and_st_and_return; - } -#ifdef DEBUG - printf(" usnsize=%u\n", usnsize); -#endif /* DEBUG */ - tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize); - if(tmp == NULL) { - if (error) - *error = MINISSDPC_MEMORY_ERROR; - goto free_url_and_st_and_return; - } - tmp->pNext = devlist; - tmp->descURL = tmp->buffer; - tmp->st = tmp->buffer + 1 + urlsize; - memcpy(tmp->buffer, url, urlsize); - tmp->buffer[urlsize] = '\0'; - memcpy(tmp->st, st, stsize); - tmp->buffer[urlsize+1+stsize] = '\0'; - free(url); - free(st); - url = NULL; - st = NULL; - tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize; - READ_COPY_BUFFER(tmp->usn, usnsize); - if(n<=0) { - if (error) - *error = MINISSDPC_INVALID_SERVER_REPLY; - goto free_tmp_and_return; - } - tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0'; - tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */ - devlist = tmp; - } - if (error) - *error = MINISSDPC_SUCCESS; - return devlist; - -free_url_and_st_and_return: - free(st); -free_url_and_return: - free(url); - return devlist; - -free_tmp_and_return: - free(tmp); - return devlist; -} - -#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */ - -/* parseMSEARCHReply() - * the last 4 arguments are filled during the parsing : - * - location/locationsize : "location:" field of the SSDP reply packet - * - st/stsize : "st:" field of the SSDP reply packet. - * The strings are NOT null terminated */ -static void -parseMSEARCHReply(const char * reply, int size, - const char * * location, int * locationsize, - const char * * st, int * stsize, - const char * * usn, int * usnsize) -{ - int a, b, i; - i = 0; - a = i; /* start of the line */ - b = 0; /* end of the "header" (position of the colon) */ - while(isin6_family = AF_INET6; - if(localport > 0 && localport < 65536) - p->sin6_port = htons((unsigned short)localport); - p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ - } else { - struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; - p->sin_family = AF_INET; - if(localport > 0 && localport < 65536) - p->sin_port = htons((unsigned short)localport); - p->sin_addr.s_addr = INADDR_ANY; - } -#ifdef _WIN32 -/* This code could help us to use the right Network interface for - * SSDP multicast traffic */ -/* Get IP associated with the index given in the ip_forward struct - * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ - if(!ipv6 - && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { - DWORD dwRetVal = 0; - PMIB_IPADDRTABLE pIPAddrTable; - DWORD dwSize = 0; -#ifdef DEBUG - IN_ADDR IPAddr; -#endif - int i; -#ifdef DEBUG - printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); -#endif - pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); - if(pIPAddrTable) { - if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { - free(pIPAddrTable); - pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); - } - } - if(pIPAddrTable) { - dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); - if (dwRetVal == NO_ERROR) { -#ifdef DEBUG - printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); -#endif - for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { -#ifdef DEBUG - printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); - IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; - printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); - IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; - printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); - IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; - printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); - printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); - printf("\tType and State[%d]:", i); - printf("\n"); -#endif - if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { - /* Set the address of this interface to be used */ - struct in_addr mc_if; - memset(&mc_if, 0, sizeof(mc_if)); - mc_if.s_addr = pIPAddrTable->table[i].dwAddr; - if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { - PRINT_SOCKET_ERROR("setsockopt"); - } - ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; -#ifndef DEBUG - break; -#endif - } - } - } - free(pIPAddrTable); - pIPAddrTable = NULL; - } - } -#endif /* _WIN32 */ - -#ifdef _WIN32 - if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) -#else - if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) -#endif - { - if(error) - *error = MINISSDPC_SOCKET_ERROR; - PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)"); - return NULL; - } - -#ifdef _WIN32 - if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0) -#else /* _WIN32 */ - if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) -#endif /* _WIN32 */ - { - /* not a fatal error */ - PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)"); - } - - if(multicastif) - { - if(ipv6) { -#if !defined(_WIN32) - /* according to MSDN, if_nametoindex() is supported since - * MS Windows Vista and MS Windows Server 2008. - * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ - unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ - if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt IPV6_MULTICAST_IF"); - } -#else -#ifdef DEBUG - printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); -#endif -#endif - } else { - struct in_addr mc_if; - mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ - if(mc_if.s_addr != INADDR_NONE) - { - ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; - if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); - } - } else { -#ifdef HAS_IP_MREQN - /* was not an ip address, try with an interface name */ - struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ - memset(&reqn, 0, sizeof(struct ip_mreqn)); - reqn.imr_ifindex = if_nametoindex(multicastif); - if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); - } -#elif !defined(_WIN32) - struct ifreq ifr; - int ifrlen = sizeof(ifr); - strncpy(ifr.ifr_name, multicastif, IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ-1] = '\0'; - if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0) - { - PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)"); - } - mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; - if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) - { - PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); - } -#else /* _WIN32 */ -#ifdef DEBUG - printf("Setting of multicast interface not supported with interface name.\n"); -#endif -#endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */ - } - } - } - - /* Before sending the packed, we first "bind" in order to be able - * to receive the response */ - if (bind(sudp, (const struct sockaddr *)&sockudp_r, - ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) - { - if(error) - *error = MINISSDPC_SOCKET_ERROR; - PRINT_SOCKET_ERROR("bind"); - closesocket(sudp); - return NULL; - } - - if(error) - *error = MINISSDPC_SUCCESS; - /* Calculating maximum response time in seconds */ - mx = ((unsigned int)delay) / 1000u; - if(mx == 0) { - mx = 1; - delay = 1000; - } - /* receiving SSDP response packet */ - for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { - /* sending the SSDP M-SEARCH packet */ - n = snprintf(bufr, sizeof(bufr), - MSearchMsgFmt, - ipv6 ? - (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") - : UPNP_MCAST_ADDR, - deviceTypes[deviceIndex], mx); - if ((unsigned int)n >= sizeof(bufr)) { - if(error) - *error = MINISSDPC_MEMORY_ERROR; - goto error; - } -#ifdef DEBUG - /*printf("Sending %s", bufr);*/ - printf("Sending M-SEARCH request to %s with ST: %s\n", - ipv6 ? - (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") - : UPNP_MCAST_ADDR, - deviceTypes[deviceIndex]); -#endif -#ifdef NO_GETADDRINFO - /* the following code is not using getaddrinfo */ - /* emission */ - memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); - if(ipv6) { - struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; - p->sin6_family = AF_INET6; - p->sin6_port = htons(SSDP_PORT); - inet_pton(AF_INET6, - linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, - &(p->sin6_addr)); - } else { - struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; - p->sin_family = AF_INET; - p->sin_port = htons(SSDP_PORT); - p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); - } - n = sendto(sudp, bufr, n, 0, &sockudp_w, - ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); - if (n < 0) { - if(error) - *error = MINISSDPC_SOCKET_ERROR; - PRINT_SOCKET_ERROR("sendto"); - break; - } -#else /* #ifdef NO_GETADDRINFO */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ - hints.ai_socktype = SOCK_DGRAM; - /*hints.ai_flags = */ - if ((rv = getaddrinfo(ipv6 - ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) - : UPNP_MCAST_ADDR, - XSTR(SSDP_PORT), &hints, &servinfo)) != 0) { - if(error) - *error = MINISSDPC_SOCKET_ERROR; -#ifdef _WIN32 - fprintf(stderr, "getaddrinfo() failed: %d\n", rv); -#else - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); -#endif - break; - } - for(p = servinfo; p; p = p->ai_next) { - n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); - if (n < 0) { -#ifdef DEBUG - char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; - if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, - sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { - fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); - } -#endif - PRINT_SOCKET_ERROR("sendto"); - continue; - } - } - freeaddrinfo(servinfo); - if(n < 0) { - if(error) - *error = MINISSDPC_SOCKET_ERROR; - break; - } -#endif /* #ifdef NO_GETADDRINFO */ - /* Waiting for SSDP REPLY packet to M-SEARCH - * if searchalltypes is set, enter the loop only - * when the last deviceType is reached */ - if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do { - n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); - if (n < 0) { - /* error */ - if(error) - *error = MINISSDPC_SOCKET_ERROR; - goto error; - } else if (n == 0) { - /* no data or Time Out */ -#ifdef DEBUG - printf("NODATA or TIMEOUT\n"); -#endif /* DEBUG */ - if (devlist && !searchalltypes) { - /* found some devices, stop now*/ - if(error) - *error = MINISSDPC_SUCCESS; - goto error; - } - } else { - const char * descURL=NULL; - int urlsize=0; - const char * st=NULL; - int stsize=0; - const char * usn=NULL; - int usnsize=0; - parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize); - if(st&&descURL) { -#ifdef DEBUG - printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n", - stsize, st, usnsize, (usn?usn:""), urlsize, descURL); -#endif /* DEBUG */ - for(tmp=devlist; tmp; tmp = tmp->pNext) { - if(memcmp(tmp->descURL, descURL, urlsize) == 0 && - tmp->descURL[urlsize] == '\0' && - memcmp(tmp->st, st, stsize) == 0 && - tmp->st[stsize] == '\0' && - (usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) && - tmp->usn[usnsize] == '\0') - break; - } - /* at the exit of the loop above, tmp is null if - * no duplicate device was found */ - if(tmp) - continue; - tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize); - if(!tmp) { - /* memory allocation error */ - if(error) - *error = MINISSDPC_MEMORY_ERROR; - goto error; - } - tmp->pNext = devlist; - tmp->descURL = tmp->buffer; - tmp->st = tmp->buffer + 1 + urlsize; - tmp->usn = tmp->st + 1 + stsize; - memcpy(tmp->buffer, descURL, urlsize); - tmp->buffer[urlsize] = '\0'; - memcpy(tmp->st, st, stsize); - tmp->buffer[urlsize+1+stsize] = '\0'; - if(usn != NULL) - memcpy(tmp->usn, usn, usnsize); - tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0'; - tmp->scope_id = scope_id; - devlist = tmp; - } - } - } while(n > 0); - if(ipv6) { - /* switch linklocal flag */ - if(linklocal) { - linklocal = 0; - --deviceIndex; - } else { - linklocal = 1; - } - } - } -error: - closesocket(sudp); - return devlist; -} - diff --git a/zto/ext/miniupnpc/minissdpc.h b/zto/ext/miniupnpc/minissdpc.h deleted file mode 100644 index a5c622b..0000000 --- a/zto/ext/miniupnpc/minissdpc.h +++ /dev/null @@ -1,58 +0,0 @@ -/* $Id: minissdpc.h,v 1.7 2015/10/08 16:15:47 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author: Thomas Bernard - * Copyright (c) 2005-2015 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef MINISSDPC_H_INCLUDED -#define MINISSDPC_H_INCLUDED - -#include "miniupnpc_declspec.h" -#include "upnpdev.h" - -/* error codes : */ -#define MINISSDPC_SUCCESS (0) -#define MINISSDPC_UNKNOWN_ERROR (-1) -#define MINISSDPC_SOCKET_ERROR (-101) -#define MINISSDPC_MEMORY_ERROR (-102) -#define MINISSDPC_INVALID_INPUT (-103) -#define MINISSDPC_INVALID_SERVER_REPLY (-104) - -#ifdef __cplusplus -extern "C" { -#endif - -#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) - -MINIUPNP_LIBSPEC struct UPNPDev * -getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error); - -MINIUPNP_LIBSPEC int -connectToMiniSSDPD(const char * socketpath); - -MINIUPNP_LIBSPEC int -disconnectFromMiniSSDPD(int fd); - -MINIUPNP_LIBSPEC int -requestDevicesFromMiniSSDPD(int fd, const char * devtype); - -MINIUPNP_LIBSPEC struct UPNPDev * -receiveDevicesFromMiniSSDPD(int fd, int * error); - -#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */ - -MINIUPNP_LIBSPEC struct UPNPDev * -ssdpDiscoverDevices(const char * const deviceTypes[], - int delay, const char * multicastif, - int localport, - int ipv6, unsigned char ttl, - int * error, - int searchalltypes); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/zto/ext/miniupnpc/miniupnpc.c b/zto/ext/miniupnpc/miniupnpc.c deleted file mode 100644 index 2dc5c95..0000000 --- a/zto/ext/miniupnpc/miniupnpc.c +++ /dev/null @@ -1,722 +0,0 @@ -/* $Id: miniupnpc.c,v 1.149 2016/02/09 09:50:46 nanard Exp $ */ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * Project : miniupnp - * Web : http://miniupnp.free.fr/ - * Author : Thomas BERNARD - * copyright (c) 2005-2016 Thomas Bernard - * This software is subjet to the conditions detailed in the - * provided LICENSE file. */ -#include -#include -#include -#ifdef _WIN32 -/* Win32 Specific includes and defines */ -#include -#include -#include -#include -#define snprintf _snprintf -#define strdup _strdup -#ifndef strncasecmp -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define strncasecmp _memicmp -#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ -#define strncasecmp memicmp -#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ -#endif /* #ifndef strncasecmp */ -#define MAXHOSTNAMELEN 64 -#else /* #ifdef _WIN32 */ -/* Standard POSIX includes */ -#include -#if defined(__amigaos__) && !defined(__amigaos4__) -/* Amiga OS 3 specific stuff */ -#define socklen_t int -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#if !defined(__amigaos__) && !defined(__amigaos4__) -#include -#endif -#include -#include -#define closesocket close -#endif /* #else _WIN32 */ -#ifdef __GNU__ -#define MAXHOSTNAMELEN 64 -#endif - - -#include "miniupnpc.h" -#include "minissdpc.h" -#include "miniwget.h" -#include "minisoap.h" -#include "minixml.h" -#include "upnpcommands.h" -#include "connecthostport.h" - -/* compare the begining of a string with a constant string */ -#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) - -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -#define SOAPPREFIX "s" -#define SERVICEPREFIX "u" -#define SERVICEPREFIX2 'u' - -/* check if an ip address is a private (LAN) address - * see https://tools.ietf.org/html/rfc1918 */ -static int is_rfc1918addr(const char * addr) -{ - /* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */ - if(COMPARE(addr, "192.168.")) - return 1; - /* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */ - if(COMPARE(addr, "10.")) - return 1; - /* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */ - if(COMPARE(addr, "172.")) { - int i = atoi(addr + 4); - if((16 <= i) && (i <= 31)) - return 1; - } - return 0; -} - -/* root description parsing */ -MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data) -{ - struct xmlparser parser; - /* xmlparser object */ - parser.xmlstart = buffer; - parser.xmlsize = bufsize; - parser.data = data; - parser.starteltfunc = IGDstartelt; - parser.endeltfunc = IGDendelt; - parser.datafunc = IGDdata; - parser.attfunc = 0; - parsexml(&parser); -#ifdef DEBUG - printIGD(data); -#endif -} - -/* simpleUPnPcommand2 : - * not so simple ! - * return values : - * pointer - OK - * NULL - error */ -char * simpleUPnPcommand2(int s, const char * url, const char * service, - const char * action, struct UPNParg * args, - int * bufsize, const char * httpversion) -{ - char hostname[MAXHOSTNAMELEN+1]; - unsigned short port = 0; - char * path; - char soapact[128]; - char soapbody[2048]; - int soapbodylen; - char * buf; - int n; - int status_code; - - *bufsize = 0; - snprintf(soapact, sizeof(soapact), "%s#%s", service, action); - if(args==NULL) - { - soapbodylen = snprintf(soapbody, sizeof(soapbody), - "\r\n" - "<" SOAPPREFIX ":Envelope " - "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " - SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" - "<" SOAPPREFIX ":Body>" - "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" - "" - "" - "\r\n", action, service, action); - if ((unsigned int)soapbodylen >= sizeof(soapbody)) - return NULL; - } - else - { - char * p; - const char * pe, * pv; - const char * const pend = soapbody + sizeof(soapbody); - soapbodylen = snprintf(soapbody, sizeof(soapbody), - "\r\n" - "<" SOAPPREFIX ":Envelope " - "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " - SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" - "<" SOAPPREFIX ":Body>" - "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", - action, service); - if ((unsigned int)soapbodylen >= sizeof(soapbody)) - return NULL; - p = soapbody + soapbodylen; - while(args->elt) - { - if(p >= pend) /* check for space to write next byte */ - return NULL; - *(p++) = '<'; - - pe = args->elt; - while(p < pend && *pe) - *(p++) = *(pe++); - - if(p >= pend) /* check for space to write next byte */ - return NULL; - *(p++) = '>'; - - if((pv = args->val)) - { - while(p < pend && *pv) - *(p++) = *(pv++); - } - - if((p+2) > pend) /* check for space to write next 2 bytes */ - return NULL; - *(p++) = '<'; - *(p++) = '/'; - - pe = args->elt; - while(p < pend && *pe) - *(p++) = *(pe++); - - if(p >= pend) /* check for space to write next byte */ - return NULL; - *(p++) = '>'; - - args++; - } - if((p+4) > pend) /* check for space to write next 4 bytes */ - return NULL; - *(p++) = '<'; - *(p++) = '/'; - *(p++) = SERVICEPREFIX2; - *(p++) = ':'; - - pe = action; - while(p < pend && *pe) - *(p++) = *(pe++); - - strncpy(p, ">\r\n", - pend - p); - if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */ - return NULL; - } - if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; - if(s < 0) { - s = connecthostport(hostname, port, 0); - if(s < 0) { - /* failed to connect */ - return NULL; - } - } - - n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); - if(n<=0) { -#ifdef DEBUG - printf("Error sending SOAP request\n"); -#endif - closesocket(s); - return NULL; - } - - buf = getHTTPResponse(s, bufsize, &status_code); -#ifdef DEBUG - if(*bufsize > 0 && buf) - { - printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf); - } - else - { - printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize); - } -#endif - closesocket(s); - return buf; -} - -/* simpleUPnPcommand : - * not so simple ! - * return values : - * pointer - OK - * NULL - error */ -char * simpleUPnPcommand(int s, const char * url, const char * service, - const char * action, struct UPNParg * args, - int * bufsize) -{ - char * buf; - -#if 1 - buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); -#else - buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0"); - if (!buf || *bufsize == 0) - { -#if DEBUG - printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); -#endif - buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); - } -#endif - return buf; -} - -/* upnpDiscoverDevices() : - * return a chained list of all devices found or NULL if - * no devices was found. - * It is up to the caller to free the chained list - * delay is in millisecond (poll). - * UDA v1.1 says : - * The TTL for the IP packet SHOULD default to 2 and - * SHOULD be configurable. */ -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverDevices(const char * const deviceTypes[], - int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error, - int searchalltypes) -{ - struct UPNPDev * tmp; - struct UPNPDev * devlist = 0; -#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) - int deviceIndex; -#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ - - if(error) - *error = UPNPDISCOVER_UNKNOWN_ERROR; -#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) - /* first try to get infos from minissdpd ! */ - if(!minissdpdsock) - minissdpdsock = "/var/run/minissdpd.sock"; - for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { - struct UPNPDev * minissdpd_devlist; - int only_rootdevice = 1; - minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex], - minissdpdsock, 0); - if(minissdpd_devlist) { -#ifdef DEBUG - printf("returned by MiniSSDPD: %s\t%s\n", - minissdpd_devlist->st, minissdpd_devlist->descURL); -#endif /* DEBUG */ - if(!strstr(minissdpd_devlist->st, "rootdevice")) - only_rootdevice = 0; - for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) { -#ifdef DEBUG - printf("returned by MiniSSDPD: %s\t%s\n", - tmp->pNext->st, tmp->pNext->descURL); -#endif /* DEBUG */ - if(!strstr(tmp->st, "rootdevice")) - only_rootdevice = 0; - } - tmp->pNext = devlist; - devlist = minissdpd_devlist; - if(!searchalltypes && !only_rootdevice) - break; - } - } - for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) { - /* We return what we have found if it was not only a rootdevice */ - if(!strstr(tmp->st, "rootdevice")) { - if(error) - *error = UPNPDISCOVER_SUCCESS; - return devlist; - } - } -#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ - - /* direct discovery if minissdpd responses are not sufficient */ - { - struct UPNPDev * discovered_devlist; - discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport, - ipv6, ttl, error, searchalltypes); - if(devlist == NULL) - devlist = discovered_devlist; - else { - for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext); - tmp->pNext = discovered_devlist; - } - } - return devlist; -} - -/* upnpDiscover() Discover IGD device */ -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error) -{ - static const char * const deviceList[] = { -#if 0 - "urn:schemas-upnp-org:device:InternetGatewayDevice:2", - "urn:schemas-upnp-org:service:WANIPConnection:2", -#endif - "urn:schemas-upnp-org:device:InternetGatewayDevice:1", - "urn:schemas-upnp-org:service:WANIPConnection:1", - "urn:schemas-upnp-org:service:WANPPPConnection:1", - "upnp:rootdevice", - /*"ssdp:all",*/ - 0 - }; - return upnpDiscoverDevices(deviceList, - delay, multicastif, minissdpdsock, localport, - ipv6, ttl, error, 0); -} - -/* upnpDiscoverAll() Discover all UPnP devices */ -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverAll(int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error) -{ - static const char * const deviceList[] = { - /*"upnp:rootdevice",*/ - "ssdp:all", - 0 - }; - return upnpDiscoverDevices(deviceList, - delay, multicastif, minissdpdsock, localport, - ipv6, ttl, error, 0); -} - -/* upnpDiscoverDevice() Discover a specific device */ -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverDevice(const char * device, int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error) -{ - const char * const deviceList[] = { - device, - 0 - }; - return upnpDiscoverDevices(deviceList, - delay, multicastif, minissdpdsock, localport, - ipv6, ttl, error, 0); -} - -static char * -build_absolute_url(const char * baseurl, const char * descURL, - const char * url, unsigned int scope_id) -{ - int l, n; - char * s; - const char * base; - char * p; -#if defined(IF_NAMESIZE) && !defined(_WIN32) - char ifname[IF_NAMESIZE]; -#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ - char scope_str[8]; -#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ - - if( (url[0] == 'h') - &&(url[1] == 't') - &&(url[2] == 't') - &&(url[3] == 'p') - &&(url[4] == ':') - &&(url[5] == '/') - &&(url[6] == '/')) - return strdup(url); - base = (baseurl[0] == '\0') ? descURL : baseurl; - n = strlen(base); - if(n > 7) { - p = strchr(base + 7, '/'); - if(p) - n = p - base; - } - l = n + strlen(url) + 1; - if(url[0] != '/') - l++; - if(scope_id != 0) { -#if defined(IF_NAMESIZE) && !defined(_WIN32) - if(if_indextoname(scope_id, ifname)) { - l += 3 + strlen(ifname); /* 3 == strlen(%25) */ - } -#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ - /* under windows, scope is numerical */ - l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id); -#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ - } - s = malloc(l); - if(s == NULL) return NULL; - memcpy(s, base, n); - if(scope_id != 0) { - s[n] = '\0'; - if(0 == memcmp(s, "http://[fe80:", 13)) { - /* this is a linklocal IPv6 address */ - p = strchr(s, ']'); - if(p) { - /* insert %25 into URL */ -#if defined(IF_NAMESIZE) && !defined(_WIN32) - memmove(p + 3 + strlen(ifname), p, strlen(p) + 1); - memcpy(p, "%25", 3); - memcpy(p + 3, ifname, strlen(ifname)); - n += 3 + strlen(ifname); -#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ - memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1); - memcpy(p, "%25", 3); - memcpy(p + 3, scope_str, strlen(scope_str)); - n += 3 + strlen(scope_str); -#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ - } - } - } - if(url[0] != '/') - s[n++] = '/'; - memcpy(s + n, url, l - n); - return s; -} - -/* Prepare the Urls for usage... - */ -MINIUPNP_LIBSPEC void -GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, - const char * descURL, unsigned int scope_id) -{ - /* strdup descURL */ - urls->rootdescURL = strdup(descURL); - - /* get description of WANIPConnection */ - urls->ipcondescURL = build_absolute_url(data->urlbase, descURL, - data->first.scpdurl, scope_id); - urls->controlURL = build_absolute_url(data->urlbase, descURL, - data->first.controlurl, scope_id); - urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL, - data->CIF.controlurl, scope_id); - urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL, - data->IPv6FC.controlurl, scope_id); - -#ifdef DEBUG - printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL); - printf("urls->controlURL='%s'\n", urls->controlURL); - printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF); - printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC); -#endif -} - -MINIUPNP_LIBSPEC void -FreeUPNPUrls(struct UPNPUrls * urls) -{ - if(!urls) - return; - free(urls->controlURL); - urls->controlURL = 0; - free(urls->ipcondescURL); - urls->ipcondescURL = 0; - free(urls->controlURL_CIF); - urls->controlURL_CIF = 0; - free(urls->controlURL_6FC); - urls->controlURL_6FC = 0; - free(urls->rootdescURL); - urls->rootdescURL = 0; -} - -int -UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) -{ - char status[64]; - unsigned int uptime; - status[0] = '\0'; - UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, - status, &uptime, NULL); - if(0 == strcmp("Connected", status)) - return 1; - else if(0 == strcmp("Up", status)) /* Also accept "Up" */ - return 1; - else - return 0; -} - - -/* UPNP_GetValidIGD() : - * return values : - * -1 = Internal error - * 0 = NO IGD found - * 1 = A valid connected IGD has been found - * 2 = A valid IGD has been found but it reported as - * not connected - * 3 = an UPnP device has been found but was not recognized as an IGD - * - * In any positive non zero return case, the urls and data structures - * passed as parameters are set. Dont forget to call FreeUPNPUrls(urls) to - * free allocated memory. - */ -MINIUPNP_LIBSPEC int -UPNP_GetValidIGD(struct UPNPDev * devlist, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen) -{ - struct xml_desc { - char * xml; - int size; - int is_igd; - } * desc = NULL; - struct UPNPDev * dev; - int ndev = 0; - int i; - int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ - int n_igd = 0; - char extIpAddr[16]; - char myLanAddr[40]; - int status_code = -1; - - if(!devlist) - { -#ifdef DEBUG - printf("Empty devlist\n"); -#endif - return 0; - } - /* counting total number of devices in the list */ - for(dev = devlist; dev; dev = dev->pNext) - ndev++; - if(ndev > 0) - { - desc = calloc(ndev, sizeof(struct xml_desc)); - if(!desc) - return -1; /* memory allocation error */ - } - /* Step 1 : downloading descriptions and testing type */ - for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) - { - /* we should choose an internet gateway device. - * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ - desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), - myLanAddr, sizeof(myLanAddr), - dev->scope_id, &status_code); -#ifdef DEBUG - if(!desc[i].xml) - { - printf("error getting XML description %s\n", dev->descURL); - } -#endif - if(desc[i].xml) - { - memset(data, 0, sizeof(struct IGDdatas)); - memset(urls, 0, sizeof(struct UPNPUrls)); - parserootdesc(desc[i].xml, desc[i].size, data); - if(COMPARE(data->CIF.servicetype, - "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) - { - desc[i].is_igd = 1; - n_igd++; - if(lanaddr) - strncpy(lanaddr, myLanAddr, lanaddrlen); - } - } - } - /* iterate the list to find a device depending on state */ - for(state = 1; state <= 3; state++) - { - for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) - { - if(desc[i].xml) - { - memset(data, 0, sizeof(struct IGDdatas)); - memset(urls, 0, sizeof(struct UPNPUrls)); - parserootdesc(desc[i].xml, desc[i].size, data); - if(desc[i].is_igd || state >= 3 ) - { - int is_connected; - - GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); - - /* in state 2 and 3 we dont test if device is connected ! */ - if(state >= 2) - goto free_and_return; - is_connected = UPNPIGD_IsConnected(urls, data); -#ifdef DEBUG - printf("UPNPIGD_IsConnected(%s) = %d\n", - urls->controlURL, is_connected); -#endif - /* checks that status is connected AND there is a external IP address assigned */ - if(is_connected && - (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { - if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0') - && (0 != strcmp(extIpAddr, "0.0.0.0"))) - goto free_and_return; - } - FreeUPNPUrls(urls); - if(data->second.servicetype[0] != '\0') { -#ifdef DEBUG - printf("We tried %s, now we try %s !\n", - data->first.servicetype, data->second.servicetype); -#endif - /* swaping WANPPPConnection and WANIPConnection ! */ - memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); - memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); - memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); - GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); - is_connected = UPNPIGD_IsConnected(urls, data); -#ifdef DEBUG - printf("UPNPIGD_IsConnected(%s) = %d\n", - urls->controlURL, is_connected); -#endif - if(is_connected && - (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { - if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0') - && (0 != strcmp(extIpAddr, "0.0.0.0"))) - goto free_and_return; - } - FreeUPNPUrls(urls); - } - } - memset(data, 0, sizeof(struct IGDdatas)); - } - } - } - state = 0; -free_and_return: - if(desc) { - for(i = 0; i < ndev; i++) { - if(desc[i].xml) { - free(desc[i].xml); - } - } - free(desc); - } - return state; -} - -/* UPNP_GetIGDFromUrl() - * Used when skipping the discovery process. - * return value : - * 0 - Not ok - * 1 - OK */ -int -UPNP_GetIGDFromUrl(const char * rootdescurl, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen) -{ - char * descXML; - int descXMLsize = 0; - - descXML = miniwget_getaddr(rootdescurl, &descXMLsize, - lanaddr, lanaddrlen, 0, NULL); - if(descXML) { - memset(data, 0, sizeof(struct IGDdatas)); - memset(urls, 0, sizeof(struct UPNPUrls)); - parserootdesc(descXML, descXMLsize, data); - free(descXML); - descXML = NULL; - GetUPNPUrls(urls, data, rootdescurl, 0); - return 1; - } else { - return 0; - } -} - diff --git a/zto/ext/miniupnpc/miniupnpc.def b/zto/ext/miniupnpc/miniupnpc.def deleted file mode 100644 index 60e0bbe..0000000 --- a/zto/ext/miniupnpc/miniupnpc.def +++ /dev/null @@ -1,45 +0,0 @@ -LIBRARY -; miniupnpc library - miniupnpc - -EXPORTS -; miniupnpc - upnpDiscover - freeUPNPDevlist - parserootdesc - UPNP_GetValidIGD - UPNP_GetIGDFromUrl - GetUPNPUrls - FreeUPNPUrls -; miniwget - miniwget - miniwget_getaddr -; upnpcommands - UPNP_GetTotalBytesSent - UPNP_GetTotalBytesReceived - UPNP_GetTotalPacketsSent - UPNP_GetTotalPacketsReceived - UPNP_GetStatusInfo - UPNP_GetConnectionTypeInfo - UPNP_GetExternalIPAddress - UPNP_GetLinkLayerMaxBitRates - UPNP_AddPortMapping - UPNP_AddAnyPortMapping - UPNP_DeletePortMapping - UPNP_DeletePortMappingRange - UPNP_GetPortMappingNumberOfEntries - UPNP_GetSpecificPortMappingEntry - UPNP_GetGenericPortMappingEntry - UPNP_GetListOfPortMappings - UPNP_AddPinhole - UPNP_CheckPinholeWorking - UPNP_UpdatePinhole - UPNP_GetPinholePackets - UPNP_DeletePinhole - UPNP_GetFirewallStatus - UPNP_GetOutboundPinholeTimeout -; upnperrors - strupnperror -; portlistingparse - ParsePortListing - FreePortListing diff --git a/zto/ext/miniupnpc/miniupnpc.h b/zto/ext/miniupnpc/miniupnpc.h deleted file mode 100644 index 4cc45f7..0000000 --- a/zto/ext/miniupnpc/miniupnpc.h +++ /dev/null @@ -1,152 +0,0 @@ -/* $Id: miniupnpc.h,v 1.50 2016/04/19 21:06:21 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ - * Author: Thomas Bernard - * Copyright (c) 2005-2016 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef MINIUPNPC_H_INCLUDED -#define MINIUPNPC_H_INCLUDED - -#include "miniupnpc_declspec.h" -#include "igd_desc_parse.h" -#include "upnpdev.h" - -/* error codes : */ -#define UPNPDISCOVER_SUCCESS (0) -#define UPNPDISCOVER_UNKNOWN_ERROR (-1) -#define UPNPDISCOVER_SOCKET_ERROR (-101) -#define UPNPDISCOVER_MEMORY_ERROR (-102) - -/* versions : */ -#define MINIUPNPC_VERSION "2.0.20161216" -#define MINIUPNPC_API_VERSION 16 - -/* Source port: - Using "1" as an alias for 1900 for backwards compatability - (presuming one would have used that for the "sameport" parameter) */ -#define UPNP_LOCAL_PORT_ANY 0 -#define UPNP_LOCAL_PORT_SAME 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structures definitions : */ -struct UPNParg { const char * elt; const char * val; }; - -char * -simpleUPnPcommand(int, const char *, const char *, - const char *, struct UPNParg *, - int *); - -/* upnpDiscover() - * discover UPnP devices on the network. - * The discovered devices are returned as a chained list. - * It is up to the caller to free the list with freeUPNPDevlist(). - * delay (in millisecond) is the maximum time for waiting any device - * response. - * If available, device list will be obtained from MiniSSDPd. - * Default path for minissdpd socket will be used if minissdpdsock argument - * is NULL. - * If multicastif is not NULL, it will be used instead of the default - * multicast interface for sending SSDP discover packets. - * If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent - * from the source port 1900 (same as destination port), if set to - * UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will - * be attempted as the source port. - * "searchalltypes" parameter is useful when searching several types, - * if 0, the discovery will stop with the first type returning results. - * TTL should default to 2. */ -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error); - -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverAll(int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error); - -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverDevice(const char * device, int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error); - -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverDevices(const char * const deviceTypes[], - int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error, - int searchalltypes); - -/* parserootdesc() : - * parse root XML description of a UPnP device and fill the IGDdatas - * structure. */ -MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); - -/* structure used to get fast access to urls - * controlURL: controlURL of the WANIPConnection - * ipcondescURL: url of the description of the WANIPConnection - * controlURL_CIF: controlURL of the WANCommonInterfaceConfig - * controlURL_6FC: controlURL of the WANIPv6FirewallControl - */ -struct UPNPUrls { - char * controlURL; - char * ipcondescURL; - char * controlURL_CIF; - char * controlURL_6FC; - char * rootdescURL; -}; - -/* UPNP_GetValidIGD() : - * return values : - * 0 = NO IGD found - * 1 = A valid connected IGD has been found - * 2 = A valid IGD has been found but it reported as - * not connected - * 3 = an UPnP device has been found but was not recognized as an IGD - * - * In any non zero return case, the urls and data structures - * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to - * free allocated memory. - */ -MINIUPNP_LIBSPEC int -UPNP_GetValidIGD(struct UPNPDev * devlist, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen); - -/* UPNP_GetIGDFromUrl() - * Used when skipping the discovery process. - * When succeding, urls, data, and lanaddr arguments are set. - * return value : - * 0 - Not ok - * 1 - OK */ -MINIUPNP_LIBSPEC int -UPNP_GetIGDFromUrl(const char * rootdescurl, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen); - -MINIUPNP_LIBSPEC void -GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, - const char *, unsigned int); - -MINIUPNP_LIBSPEC void -FreeUPNPUrls(struct UPNPUrls *); - -/* return 0 or 1 */ -MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/zto/ext/miniupnpc/miniupnpc_declspec.h b/zto/ext/miniupnpc/miniupnpc_declspec.h deleted file mode 100644 index 40adb92..0000000 --- a/zto/ext/miniupnpc/miniupnpc_declspec.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED -#define MINIUPNPC_DECLSPEC_H_INCLUDED - -#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB) - /* for windows dll */ - #ifdef MINIUPNP_EXPORTS - #define MINIUPNP_LIBSPEC __declspec(dllexport) - #else - #define MINIUPNP_LIBSPEC __declspec(dllimport) - #endif -#else - #if defined(__GNUC__) && __GNUC__ >= 4 - /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ - #define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default"))) - #else - #define MINIUPNP_LIBSPEC - #endif -#endif - -#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */ - diff --git a/zto/ext/miniupnpc/miniupnpcmodule.c b/zto/ext/miniupnpc/miniupnpcmodule.c deleted file mode 100644 index a5bdce4..0000000 --- a/zto/ext/miniupnpc/miniupnpcmodule.c +++ /dev/null @@ -1,695 +0,0 @@ -/* $Id: miniupnpcmodule.c,v 1.29 2015/10/26 17:01:30 nanard Exp $*/ -/* Project : miniupnp - * Author : Thomas BERNARD - * website : http://miniupnp.tuxfamily.org/ - * copyright (c) 2007-2014 Thomas Bernard - * This software is subjet to the conditions detailed in the - * provided LICENCE file. */ -#include -#define MINIUPNP_STATICLIB -#include "structmember.h" -#include "miniupnpc.h" -#include "upnpcommands.h" -#include "upnperrors.h" - -/* for compatibility with Python < 2.4 */ -#ifndef Py_RETURN_NONE -#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None -#endif - -#ifndef Py_RETURN_TRUE -#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True -#endif - -#ifndef Py_RETURN_FALSE -#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False -#endif - -/* for compatibility with Python < 3.0 */ -#ifndef PyVarObject_HEAD_INIT -#define PyVarObject_HEAD_INIT(type, size) \ - PyObject_HEAD_INIT(type) size, -#endif - -#ifndef Py_TYPE -#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) -#endif - -typedef struct { - PyObject_HEAD - /* Type-specific fields go here. */ - struct UPNPDev * devlist; - struct UPNPUrls urls; - struct IGDdatas data; - unsigned int discoverdelay; /* value passed to upnpDiscover() */ - unsigned int localport; /* value passed to upnpDiscover() */ - char lanaddr[40]; /* our ip address on the LAN */ - char * multicastif; - char * minissdpdsocket; -} UPnPObject; - -static PyMemberDef UPnP_members[] = { - {"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr), - READONLY, "ip address on the LAN" - }, - {"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay), - 0/*READWRITE*/, "value in ms used to wait for SSDP responses" - }, - {"localport", T_UINT, offsetof(UPnPObject, localport), - 0/*READWRITE*/, - "If localport is set to UPNP_LOCAL_PORT_SAME(1) " - "SSDP packets will be sent from the source port " - "1900 (same as destination port), if set to " - "UPNP_LOCAL_PORT_ANY(0) system assign a source " - "port, any other value will be attempted as the " - "source port" - }, - /* T_STRING is allways readonly :( */ - {"multicastif", T_STRING, offsetof(UPnPObject, multicastif), - 0, "IP of the network interface to be used for multicast operations" - }, - {"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket), - 0, "path of the MiniSSDPd unix socket" - }, - {NULL} -}; - - -static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds) -{ - char* multicastif = NULL; - char* minissdpdsocket = NULL; - static char *kwlist[] = { - "multicastif", "minissdpdsocket", "discoverdelay", - "localport", NULL - }; - - if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist, - &multicastif, - &minissdpdsocket, - &self->discoverdelay, - &self->localport)) - return -1; - - if(self->localport>1 && - (self->localport>65534||self->localport<1024)) { - PyErr_SetString(PyExc_Exception, "Invalid localport value"); - return -1; - } - if(multicastif) - self->multicastif = strdup(multicastif); - if(minissdpdsocket) - self->minissdpdsocket = strdup(minissdpdsocket); - - return 0; -} - -static void -UPnPObject_dealloc(UPnPObject *self) -{ - freeUPNPDevlist(self->devlist); - FreeUPNPUrls(&self->urls); - free(self->multicastif); - free(self->minissdpdsocket); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject * -UPnP_discover(UPnPObject *self) -{ - struct UPNPDev * dev; - int i; - PyObject *res = NULL; - if(self->devlist) - { - freeUPNPDevlist(self->devlist); - self->devlist = 0; - } - Py_BEGIN_ALLOW_THREADS - self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/, - self->multicastif, - self->minissdpdsocket, - (int)self->localport, - 0/*ip v6*/, - 2/* TTL */, - 0/*error */); - Py_END_ALLOW_THREADS - /* Py_RETURN_NONE ??? */ - for(dev = self->devlist, i = 0; dev; dev = dev->pNext) - i++; - res = Py_BuildValue("i", i); - return res; -} - -static PyObject * -UPnP_selectigd(UPnPObject *self) -{ - int r; -Py_BEGIN_ALLOW_THREADS - r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data, - self->lanaddr, sizeof(self->lanaddr)); -Py_END_ALLOW_THREADS - if(r) - { - return Py_BuildValue("s", self->urls.controlURL); - } - else - { - /* TODO: have our own exception type ! */ - PyErr_SetString(PyExc_Exception, "No UPnP device discovered"); - return NULL; - } -} - -static PyObject * -UPnP_totalbytesent(UPnPObject *self) -{ - UNSIGNED_INTEGER i; -Py_BEGIN_ALLOW_THREADS - i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF, - self->data.CIF.servicetype); -Py_END_ALLOW_THREADS -#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) - return Py_BuildValue("I", i); -#else - return Py_BuildValue("i", (int)i); -#endif -} - -static PyObject * -UPnP_totalbytereceived(UPnPObject *self) -{ - UNSIGNED_INTEGER i; -Py_BEGIN_ALLOW_THREADS - i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF, - self->data.CIF.servicetype); -Py_END_ALLOW_THREADS -#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) - return Py_BuildValue("I", i); -#else - return Py_BuildValue("i", (int)i); -#endif -} - -static PyObject * -UPnP_totalpacketsent(UPnPObject *self) -{ - UNSIGNED_INTEGER i; -Py_BEGIN_ALLOW_THREADS - i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF, - self->data.CIF.servicetype); -Py_END_ALLOW_THREADS -#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) - return Py_BuildValue("I", i); -#else - return Py_BuildValue("i", (int)i); -#endif -} - -static PyObject * -UPnP_totalpacketreceived(UPnPObject *self) -{ - UNSIGNED_INTEGER i; -Py_BEGIN_ALLOW_THREADS - i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF, - self->data.CIF.servicetype); -Py_END_ALLOW_THREADS -#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) - return Py_BuildValue("I", i); -#else - return Py_BuildValue("i", (int)i); -#endif -} - -static PyObject * -UPnP_statusinfo(UPnPObject *self) -{ - char status[64]; - char lastconnerror[64]; - unsigned int uptime = 0; - int r; - status[0] = '\0'; - lastconnerror[0] = '\0'; -Py_BEGIN_ALLOW_THREADS - r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype, - status, &uptime, lastconnerror); -Py_END_ALLOW_THREADS - if(r==UPNPCOMMAND_SUCCESS) { -#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) - return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror); -#else - return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror); -#endif - } else { - /* TODO: have our own exception type ! */ - PyErr_SetString(PyExc_Exception, strupnperror(r)); - return NULL; - } -} - -static PyObject * -UPnP_connectiontype(UPnPObject *self) -{ - char connectionType[64]; - int r; - connectionType[0] = '\0'; -Py_BEGIN_ALLOW_THREADS - r = UPNP_GetConnectionTypeInfo(self->urls.controlURL, - self->data.first.servicetype, - connectionType); -Py_END_ALLOW_THREADS - if(r==UPNPCOMMAND_SUCCESS) { - return Py_BuildValue("s", connectionType); - } else { - /* TODO: have our own exception type ! */ - PyErr_SetString(PyExc_Exception, strupnperror(r)); - return NULL; - } -} - -static PyObject * -UPnP_externalipaddress(UPnPObject *self) -{ - char externalIPAddress[40]; - int r; - externalIPAddress[0] = '\0'; -Py_BEGIN_ALLOW_THREADS - r = UPNP_GetExternalIPAddress(self->urls.controlURL, - self->data.first.servicetype, - externalIPAddress); -Py_END_ALLOW_THREADS - if(r==UPNPCOMMAND_SUCCESS) { - return Py_BuildValue("s", externalIPAddress); - } else { - /* TODO: have our own exception type ! */ - PyErr_SetString(PyExc_Exception, strupnperror(r)); - return NULL; - } -} - -/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc, - * remoteHost) - * protocol is 'UDP' or 'TCP' */ -static PyObject * -UPnP_addportmapping(UPnPObject *self, PyObject *args) -{ - char extPort[6]; - unsigned short ePort; - char inPort[6]; - unsigned short iPort; - const char * proto; - const char * host; - const char * desc; - const char * remoteHost; - const char * leaseDuration = "0"; - int r; - if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto, - &host, &iPort, &desc, &remoteHost)) - return NULL; -Py_BEGIN_ALLOW_THREADS - sprintf(extPort, "%hu", ePort); - sprintf(inPort, "%hu", iPort); - r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype, - extPort, inPort, host, desc, proto, - remoteHost, leaseDuration); -Py_END_ALLOW_THREADS - if(r==UPNPCOMMAND_SUCCESS) - { - Py_RETURN_TRUE; - } - else - { - // TODO: RAISE an Exception. See upnpcommands.h for errors codes. - // upnperrors.c - //Py_RETURN_FALSE; - /* TODO: have our own exception type ! */ - PyErr_SetString(PyExc_Exception, strupnperror(r)); - return NULL; - } -} - -/* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc, - * remoteHost) - * protocol is 'UDP' or 'TCP' */ -static PyObject * -UPnP_addanyportmapping(UPnPObject *self, PyObject *args) -{ - char extPort[6]; - unsigned short ePort; - char inPort[6]; - unsigned short iPort; - char reservedPort[6]; - const char * proto; - const char * host; - const char * desc; - const char * remoteHost; - const char * leaseDuration = "0"; - int r; - if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto, &host, &iPort, &desc, &remoteHost)) - return NULL; -Py_BEGIN_ALLOW_THREADS - sprintf(extPort, "%hu", ePort); - sprintf(inPort, "%hu", iPort); - r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype, - extPort, inPort, host, desc, proto, - remoteHost, leaseDuration, reservedPort); -Py_END_ALLOW_THREADS - if(r==UPNPCOMMAND_SUCCESS) { - return Py_BuildValue("i", atoi(reservedPort)); - } else { - /* TODO: have our own exception type ! */ - PyErr_SetString(PyExc_Exception, strupnperror(r)); - return NULL; - } -} - - -/* DeletePortMapping(extPort, proto, removeHost='') - * proto = 'UDP', 'TCP' */ -static PyObject * -UPnP_deleteportmapping(UPnPObject *self, PyObject *args) -{ - char extPort[6]; - unsigned short ePort; - const char * proto; - const char * remoteHost = ""; - int r; - if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost)) - return NULL; -Py_BEGIN_ALLOW_THREADS - sprintf(extPort, "%hu", ePort); - r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype, - extPort, proto, remoteHost); -Py_END_ALLOW_THREADS - if(r==UPNPCOMMAND_SUCCESS) { - Py_RETURN_TRUE; - } else { - /* TODO: have our own exception type ! */ - PyErr_SetString(PyExc_Exception, strupnperror(r)); - return NULL; - } -} - -/* DeletePortMappingRange(extPort, proto, removeHost='') - * proto = 'UDP', 'TCP' */ -static PyObject * -UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args) -{ - char extPortStart[6]; - unsigned short ePortStart; - char extPortEnd[6]; - unsigned short ePortEnd; - const char * proto; - unsigned char manage; - char manageStr[1]; - int r; - if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage)) - return NULL; -Py_BEGIN_ALLOW_THREADS - sprintf(extPortStart, "%hu", ePortStart); - sprintf(extPortEnd, "%hu", ePortEnd); - sprintf(manageStr, "%hhu", manage); - r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype, - extPortStart, extPortEnd, proto, manageStr); -Py_END_ALLOW_THREADS - if(r==UPNPCOMMAND_SUCCESS) { - Py_RETURN_TRUE; - } else { - /* TODO: have our own exception type ! */ - PyErr_SetString(PyExc_Exception, strupnperror(r)); - return NULL; - } -} - -static PyObject * -UPnP_getportmappingnumberofentries(UPnPObject *self) -{ - unsigned int n = 0; - int r; -Py_BEGIN_ALLOW_THREADS - r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL, - self->data.first.servicetype, - &n); -Py_END_ALLOW_THREADS - if(r==UPNPCOMMAND_SUCCESS) { -#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) - return Py_BuildValue("I", n); -#else - return Py_BuildValue("i", (int)n); -#endif - } else { - /* TODO: have our own exception type ! */ - PyErr_SetString(PyExc_Exception, strupnperror(r)); - return NULL; - } -} - -/* GetSpecificPortMapping(ePort, proto, remoteHost='') - * proto = 'UDP' or 'TCP' */ -static PyObject * -UPnP_getspecificportmapping(UPnPObject *self, PyObject *args) -{ - char extPort[6]; - unsigned short ePort; - const char * proto; - const char * remoteHost = ""; - char intClient[40]; - char intPort[6]; - unsigned short iPort; - char desc[80]; - char enabled[4]; - char leaseDuration[16]; - if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost)) - return NULL; - extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0'; - desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0'; -Py_BEGIN_ALLOW_THREADS - sprintf(extPort, "%hu", ePort); - UPNP_GetSpecificPortMappingEntry(self->urls.controlURL, - self->data.first.servicetype, - extPort, proto, remoteHost, - intClient, intPort, - desc, enabled, leaseDuration); -Py_END_ALLOW_THREADS - if(intClient[0]) - { - iPort = (unsigned short)atoi(intPort); - return Py_BuildValue("(s,H,s,O,i)", - intClient, iPort, desc, - PyBool_FromLong(atoi(enabled)), - atoi(leaseDuration)); - } - else - { - Py_RETURN_NONE; - } -} - -/* GetGenericPortMapping(index) */ -static PyObject * -UPnP_getgenericportmapping(UPnPObject *self, PyObject *args) -{ - int i, r; - char index[8]; - char intClient[40]; - char intPort[6]; - unsigned short iPort; - char extPort[6]; - unsigned short ePort; - char protocol[4]; - char desc[80]; - char enabled[6]; - char rHost[64]; - char duration[16]; /* lease duration */ - unsigned int dur; - if(!PyArg_ParseTuple(args, "i", &i)) - return NULL; -Py_BEGIN_ALLOW_THREADS - snprintf(index, sizeof(index), "%d", i); - rHost[0] = '\0'; enabled[0] = '\0'; - duration[0] = '\0'; desc[0] = '\0'; - extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; - r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL, - self->data.first.servicetype, - index, - extPort, intClient, intPort, - protocol, desc, enabled, rHost, - duration); -Py_END_ALLOW_THREADS - if(r==UPNPCOMMAND_SUCCESS) - { - ePort = (unsigned short)atoi(extPort); - iPort = (unsigned short)atoi(intPort); - dur = (unsigned int)strtoul(duration, 0, 0); -#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) - return Py_BuildValue("(H,s,(s,H),s,s,s,I)", - ePort, protocol, intClient, iPort, - desc, enabled, rHost, dur); -#else - return Py_BuildValue("(i,s,(s,i),s,s,s,i)", - (int)ePort, protocol, intClient, (int)iPort, - desc, enabled, rHost, (int)dur); -#endif - } - else - { - Py_RETURN_NONE; - } -} - -/* miniupnpc.UPnP object Method Table */ -static PyMethodDef UPnP_methods[] = { - {"discover", (PyCFunction)UPnP_discover, METH_NOARGS, - "discover UPnP IGD devices on the network" - }, - {"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS, - "select a valid UPnP IGD among discovered devices" - }, - {"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS, - "return the total number of bytes sent by UPnP IGD" - }, - {"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS, - "return the total number of bytes received by UPnP IGD" - }, - {"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS, - "return the total number of packets sent by UPnP IGD" - }, - {"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS, - "return the total number of packets received by UPnP IGD" - }, - {"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS, - "return status and uptime" - }, - {"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS, - "return IGD WAN connection type" - }, - {"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS, - "return external IP address" - }, - {"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS, - "add a port mapping" - }, - {"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS, - "add a port mapping, IGD to select alternative if necessary" - }, - {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS, - "delete a port mapping" - }, - {"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS, - "delete a range of port mappings" - }, - {"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS, - "-- non standard --" - }, - {"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS, - "get details about a specific port mapping entry" - }, - {"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS, - "get all details about the port mapping at index" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject UPnPType = { - PyVarObject_HEAD_INIT(NULL, - 0) /*ob_size*/ - "miniupnpc.UPnP", /*tp_name*/ - sizeof(UPnPObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)UPnPObject_dealloc,/*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "UPnP objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - UPnP_methods, /* tp_methods */ - UPnP_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)UPnP_init, /* tp_init */ - 0, /* tp_alloc */ -#ifndef _WIN32 - PyType_GenericNew,/*UPnP_new,*/ /* tp_new */ -#else - 0, -#endif -}; - -/* module methods */ -static PyMethodDef miniupnpc_methods[] = { - {NULL} /* Sentinel */ -}; - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "miniupnpc", /* m_name */ - "miniupnpc module.", /* m_doc */ - -1, /* m_size */ - miniupnpc_methods, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ -}; -#endif - -#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ -#define PyMODINIT_FUNC void -#endif - -PyMODINIT_FUNC -#if PY_MAJOR_VERSION >= 3 -PyInit_miniupnpc(void) -#else -initminiupnpc(void) -#endif -{ - PyObject* m; - -#ifdef _WIN32 - UPnPType.tp_new = PyType_GenericNew; -#endif - if (PyType_Ready(&UPnPType) < 0) -#if PY_MAJOR_VERSION >= 3 - return 0; -#else - return; -#endif - -#if PY_MAJOR_VERSION >= 3 - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("miniupnpc", miniupnpc_methods, - "miniupnpc module."); -#endif - - Py_INCREF(&UPnPType); - PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType); - -#if PY_MAJOR_VERSION >= 3 - return m; -#endif -} - diff --git a/zto/ext/miniupnpc/miniupnpcstrings.h.in b/zto/ext/miniupnpc/miniupnpcstrings.h.in deleted file mode 100644 index 68bf429..0000000 --- a/zto/ext/miniupnpc/miniupnpcstrings.h.in +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author: Thomas Bernard - * Copyright (c) 2005-2014 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef MINIUPNPCSTRINGS_H_INCLUDED -#define MINIUPNPCSTRINGS_H_INCLUDED - -#define OS_STRING "OS/version" -#define MINIUPNPC_VERSION_STRING "version" - -#if 0 -/* according to "UPnP Device Architecture 1.0" */ -#define UPNP_VERSION_STRING "UPnP/1.0" -#else -/* according to "UPnP Device Architecture 1.1" */ -#define UPNP_VERSION_STRING "UPnP/1.1" -#endif - -#endif - diff --git a/zto/ext/miniupnpc/miniupnpctypes.h b/zto/ext/miniupnpc/miniupnpctypes.h deleted file mode 100644 index 591c32f..0000000 --- a/zto/ext/miniupnpc/miniupnpctypes.h +++ /dev/null @@ -1,19 +0,0 @@ -/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ -/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org - * Author : Thomas Bernard - * Copyright (c) 2011 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided within this distribution */ -#ifndef MINIUPNPCTYPES_H_INCLUDED -#define MINIUPNPCTYPES_H_INCLUDED - -#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) -#define UNSIGNED_INTEGER unsigned long long -#define STRTOUI strtoull -#else -#define UNSIGNED_INTEGER unsigned int -#define STRTOUI strtoul -#endif - -#endif - diff --git a/zto/ext/miniupnpc/miniwget.c b/zto/ext/miniupnpc/miniwget.c deleted file mode 100644 index 93c8aa6..0000000 --- a/zto/ext/miniupnpc/miniwget.c +++ /dev/null @@ -1,666 +0,0 @@ -/* $Id: miniwget.c,v 1.76 2016/12/16 08:54:04 nanard Exp $ */ -/* Project : miniupnp - * Website : http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005-2016 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ - -#include -#include -#include -#include -#ifdef _WIN32 -#include -#include -#include -#define MAXHOSTNAMELEN 64 -#define snprintf _snprintf -#define socklen_t int -#ifndef strncasecmp -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define strncasecmp _memicmp -#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ -#define strncasecmp memicmp -#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ -#endif /* #ifndef strncasecmp */ -#else /* #ifdef _WIN32 */ -#include -#include -#if defined(__amigaos__) && !defined(__amigaos4__) -#define socklen_t int -#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ -#include -#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ -#include -#include -#include -#include -#include -#define closesocket close -#include -#endif /* #else _WIN32 */ -#ifdef __GNU__ -#define MAXHOSTNAMELEN 64 -#endif /* __GNU__ */ - -#ifndef MIN -#define MIN(x,y) (((x)<(y))?(x):(y)) -#endif /* MIN */ - - -#ifdef _WIN32 -#define OS_STRING "Win32" -#define MINIUPNPC_VERSION_STRING "2.0" -#define UPNP_VERSION_STRING "UPnP/1.1" -#endif - -#include "miniwget.h" -#include "connecthostport.h" -#include "receivedata.h" - -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -/* - * Read a HTTP response from a socket. - * Process Content-Length and Transfer-encoding headers. - * return a pointer to the content buffer, which length is saved - * to the length parameter. - */ -void * -getHTTPResponse(int s, int * size, int * status_code) -{ - char buf[2048]; - int n; - int endofheaders = 0; - int chunked = 0; - int content_length = -1; - unsigned int chunksize = 0; - unsigned int bytestocopy = 0; - /* buffers : */ - char * header_buf; - unsigned int header_buf_len = 2048; - unsigned int header_buf_used = 0; - char * content_buf; - unsigned int content_buf_len = 2048; - unsigned int content_buf_used = 0; - char chunksize_buf[32]; - unsigned int chunksize_buf_index; -#ifdef DEBUG - char * reason_phrase = NULL; - int reason_phrase_len = 0; -#endif - - if(status_code) *status_code = -1; - header_buf = malloc(header_buf_len); - if(header_buf == NULL) - { -#ifdef DEBUG - fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse"); -#endif /* DEBUG */ - *size = -1; - return NULL; - } - content_buf = malloc(content_buf_len); - if(content_buf == NULL) - { - free(header_buf); -#ifdef DEBUG - fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse"); -#endif /* DEBUG */ - *size = -1; - return NULL; - } - chunksize_buf[0] = '\0'; - chunksize_buf_index = 0; - - while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0) - { - if(endofheaders == 0) - { - int i; - int linestart=0; - int colon=0; - int valuestart=0; - if(header_buf_used + n > header_buf_len) { - char * tmp = realloc(header_buf, header_buf_used + n); - if(tmp == NULL) { - /* memory allocation error */ - free(header_buf); - free(content_buf); - *size = -1; - return NULL; - } - header_buf = tmp; - header_buf_len = header_buf_used + n; - } - memcpy(header_buf + header_buf_used, buf, n); - header_buf_used += n; - /* search for CR LF CR LF (end of headers) - * recognize also LF LF */ - i = 0; - while(i < ((int)header_buf_used-1) && (endofheaders == 0)) { - if(header_buf[i] == '\r') { - i++; - if(header_buf[i] == '\n') { - i++; - if(i < (int)header_buf_used && header_buf[i] == '\r') { - i++; - if(i < (int)header_buf_used && header_buf[i] == '\n') { - endofheaders = i+1; - } - } - } - } else if(header_buf[i] == '\n') { - i++; - if(header_buf[i] == '\n') { - endofheaders = i+1; - } - } - i++; - } - if(endofheaders == 0) - continue; - /* parse header lines */ - for(i = 0; i < endofheaders - 1; i++) { - if(linestart > 0 && colon <= linestart && header_buf[i]==':') - { - colon = i; - while(i < (endofheaders-1) - && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t')) - i++; - valuestart = i + 1; - } - /* detecting end of line */ - else if(header_buf[i]=='\r' || header_buf[i]=='\n') - { - if(linestart == 0 && status_code) - { - /* Status line - * HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ - int sp; - for(sp = 0; sp < i; sp++) - if(header_buf[sp] == ' ') - { - if(*status_code < 0) - *status_code = atoi(header_buf + sp + 1); - else - { -#ifdef DEBUG - reason_phrase = header_buf + sp + 1; - reason_phrase_len = i - sp - 1; -#endif - break; - } - } -#ifdef DEBUG - printf("HTTP status code = %d, Reason phrase = %.*s\n", - *status_code, reason_phrase_len, reason_phrase); -#endif - } - else if(colon > linestart && valuestart > colon) - { -#ifdef DEBUG - printf("header='%.*s', value='%.*s'\n", - colon-linestart, header_buf+linestart, - i-valuestart, header_buf+valuestart); -#endif - if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart)) - { - content_length = atoi(header_buf+valuestart); -#ifdef DEBUG - printf("Content-Length: %d\n", content_length); -#endif - } - else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart) - && 0==strncasecmp(header_buf+valuestart, "chunked", 7)) - { -#ifdef DEBUG - printf("chunked transfer-encoding!\n"); -#endif - chunked = 1; - } - } - while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n')) - i++; - linestart = i; - colon = linestart; - valuestart = 0; - } - } - /* copy the remaining of the received data back to buf */ - n = header_buf_used - endofheaders; - memcpy(buf, header_buf + endofheaders, n); - /* if(headers) */ - } - if(endofheaders) - { - /* content */ - if(chunked) - { - int i = 0; - while(i < n) - { - if(chunksize == 0) - { - /* reading chunk size */ - if(chunksize_buf_index == 0) { - /* skipping any leading CR LF */ - if(i= '0' - && chunksize_buf[j] <= '9') - chunksize = (chunksize << 4) + (chunksize_buf[j] - '0'); - else - chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10); - } - chunksize_buf[0] = '\0'; - chunksize_buf_index = 0; - i++; - } else { - /* not finished to get chunksize */ - continue; - } -#ifdef DEBUG - printf("chunksize = %u (%x)\n", chunksize, chunksize); -#endif - if(chunksize == 0) - { -#ifdef DEBUG - printf("end of HTTP content - %d %d\n", i, n); - /*printf("'%.*s'\n", n-i, buf+i);*/ -#endif - goto end_of_stream; - } - } - bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); - if((content_buf_used + bytestocopy) > content_buf_len) - { - char * tmp; - if(content_length >= (int)(content_buf_used + bytestocopy)) { - content_buf_len = content_length; - } else { - content_buf_len = content_buf_used + bytestocopy; - } - tmp = realloc(content_buf, content_buf_len); - if(tmp == NULL) { - /* memory allocation error */ - free(content_buf); - free(header_buf); - *size = -1; - return NULL; - } - content_buf = tmp; - } - memcpy(content_buf + content_buf_used, buf + i, bytestocopy); - content_buf_used += bytestocopy; - i += bytestocopy; - chunksize -= bytestocopy; - } - } - else - { - /* not chunked */ - if(content_length > 0 - && (int)(content_buf_used + n) > content_length) { - /* skipping additional bytes */ - n = content_length - content_buf_used; - } - if(content_buf_used + n > content_buf_len) - { - char * tmp; - if(content_length >= (int)(content_buf_used + n)) { - content_buf_len = content_length; - } else { - content_buf_len = content_buf_used + n; - } - tmp = realloc(content_buf, content_buf_len); - if(tmp == NULL) { - /* memory allocation error */ - free(content_buf); - free(header_buf); - *size = -1; - return NULL; - } - content_buf = tmp; - } - memcpy(content_buf + content_buf_used, buf, n); - content_buf_used += n; - } - } - /* use the Content-Length header value if available */ - if(content_length > 0 && (int)content_buf_used >= content_length) - { -#ifdef DEBUG - printf("End of HTTP content\n"); -#endif - break; - } - } -end_of_stream: - free(header_buf); header_buf = NULL; - *size = content_buf_used; - if(content_buf_used == 0) - { - free(content_buf); - content_buf = NULL; - } - return content_buf; -} - -/* miniwget3() : - * do all the work. - * Return NULL if something failed. */ -static void * -miniwget3(const char * host, - unsigned short port, const char * path, - int * size, char * addr_str, int addr_str_len, - const char * httpversion, unsigned int scope_id, - int * status_code) -{ - char buf[2048]; - int s; - int n; - int len; - int sent; - void * content; - - *size = 0; - s = connecthostport(host, port, scope_id); - if(s < 0) - return NULL; - - /* get address for caller ! */ - if(addr_str) - { - struct sockaddr_storage saddr; - socklen_t saddrlen; - - saddrlen = sizeof(saddr); - if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) - { - perror("getsockname"); - } - else - { -#if defined(__amigaos__) && !defined(__amigaos4__) - /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD); - * But his function make a string with the port : nn.nn.nn.nn:port */ -/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr), - NULL, addr_str, (DWORD *)&addr_str_len)) - { - printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError()); - }*/ - /* the following code is only compatible with ip v4 addresses */ - strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len); -#else -#if 0 - if(saddr.sa_family == AF_INET6) { - inet_ntop(AF_INET6, - &(((struct sockaddr_in6 *)&saddr)->sin6_addr), - addr_str, addr_str_len); - } else { - inet_ntop(AF_INET, - &(((struct sockaddr_in *)&saddr)->sin_addr), - addr_str, addr_str_len); - } -#endif - /* getnameinfo return ip v6 address with the scope identifier - * such as : 2a01:e35:8b2b:7330::%4281128194 */ - n = getnameinfo((const struct sockaddr *)&saddr, saddrlen, - addr_str, addr_str_len, - NULL, 0, - NI_NUMERICHOST | NI_NUMERICSERV); - if(n != 0) { -#ifdef _WIN32 - fprintf(stderr, "getnameinfo() failed : %d\n", n); -#else - fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); -#endif - } -#endif - } -#ifdef DEBUG - printf("address miniwget : %s\n", addr_str); -#endif - } - - len = snprintf(buf, sizeof(buf), - "GET %s HTTP/%s\r\n" - "Host: %s:%d\r\n" - "Connection: Close\r\n" - "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" - - "\r\n", - path, httpversion, host, port); - if ((unsigned int)len >= sizeof(buf)) - { - closesocket(s); - return NULL; - } - sent = 0; - /* sending the HTTP request */ - while(sent < len) - { - n = send(s, buf+sent, len-sent, 0); - if(n < 0) - { - perror("send"); - closesocket(s); - return NULL; - } - else - { - sent += n; - } - } - content = getHTTPResponse(s, size, status_code); - closesocket(s); - return content; -} - -/* miniwget2() : - * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ -static void * -miniwget2(const char * host, - unsigned short port, const char * path, - int * size, char * addr_str, int addr_str_len, - unsigned int scope_id, int * status_code) -{ - char * respbuffer; - -#if 1 - respbuffer = miniwget3(host, port, path, size, - addr_str, addr_str_len, "1.1", - scope_id, status_code); -#else - respbuffer = miniwget3(host, port, path, size, - addr_str, addr_str_len, "1.0", - scope_id, status_code); - if (*size == 0) - { -#ifdef DEBUG - printf("Retrying with HTTP/1.1\n"); -#endif - free(respbuffer); - respbuffer = miniwget3(host, port, path, size, - addr_str, addr_str_len, "1.1", - scope_id, status_code); - } -#endif - return respbuffer; -} - - - - -/* parseURL() - * arguments : - * url : source string not modified - * hostname : hostname destination string (size of MAXHOSTNAMELEN+1) - * port : port (destination) - * path : pointer to the path part of the URL - * - * Return values : - * 0 - Failure - * 1 - Success */ -int -parseURL(const char * url, - char * hostname, unsigned short * port, - char * * path, unsigned int * scope_id) -{ - char * p1, *p2, *p3; - if(!url) - return 0; - p1 = strstr(url, "://"); - if(!p1) - return 0; - p1 += 3; - if( (url[0]!='h') || (url[1]!='t') - ||(url[2]!='t') || (url[3]!='p')) - return 0; - memset(hostname, 0, MAXHOSTNAMELEN + 1); - if(*p1 == '[') - { - /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ - char * scope; - scope = strchr(p1, '%'); - p2 = strchr(p1, ']'); - if(p2 && scope && scope < p2 && scope_id) { - /* parse scope */ -#ifdef IF_NAMESIZE - char tmp[IF_NAMESIZE]; - int l; - scope++; - /* "%25" is just '%' in URL encoding */ - if(scope[0] == '2' && scope[1] == '5') - scope += 2; /* skip "25" */ - l = p2 - scope; - if(l >= IF_NAMESIZE) - l = IF_NAMESIZE - 1; - memcpy(tmp, scope, l); - tmp[l] = '\0'; - *scope_id = if_nametoindex(tmp); - if(*scope_id == 0) { - *scope_id = (unsigned int)strtoul(tmp, NULL, 10); - } -#else - /* under windows, scope is numerical */ - char tmp[8]; - int l; - scope++; - /* "%25" is just '%' in URL encoding */ - if(scope[0] == '2' && scope[1] == '5') - scope += 2; /* skip "25" */ - l = p2 - scope; - if(l >= sizeof(tmp)) - l = sizeof(tmp) - 1; - memcpy(tmp, scope, l); - tmp[l] = '\0'; - *scope_id = (unsigned int)strtoul(tmp, NULL, 10); -#endif - } - p3 = strchr(p1, '/'); - if(p2 && p3) - { - p2++; - strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); - if(*p2 == ':') - { - *port = 0; - p2++; - while( (*p2 >= '0') && (*p2 <= '9')) - { - *port *= 10; - *port += (unsigned short)(*p2 - '0'); - p2++; - } - } - else - { - *port = 80; - } - *path = p3; - return 1; - } - } - p2 = strchr(p1, ':'); - p3 = strchr(p1, '/'); - if(!p3) - return 0; - if(!p2 || (p2>p3)) - { - strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1))); - *port = 80; - } - else - { - strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); - *port = 0; - p2++; - while( (*p2 >= '0') && (*p2 <= '9')) - { - *port *= 10; - *port += (unsigned short)(*p2 - '0'); - p2++; - } - } - *path = p3; - return 1; -} - -void * -miniwget(const char * url, int * size, - unsigned int scope_id, int * status_code) -{ - unsigned short port; - char * path; - /* protocol://host:port/chemin */ - char hostname[MAXHOSTNAMELEN+1]; - *size = 0; - if(!parseURL(url, hostname, &port, &path, &scope_id)) - return NULL; -#ifdef DEBUG - printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", - hostname, port, path, scope_id); -#endif - return miniwget2(hostname, port, path, size, 0, 0, scope_id, status_code); -} - -void * -miniwget_getaddr(const char * url, int * size, - char * addr, int addrlen, unsigned int scope_id, - int * status_code) -{ - unsigned short port; - char * path; - /* protocol://host:port/path */ - char hostname[MAXHOSTNAMELEN+1]; - *size = 0; - if(addr) - addr[0] = '\0'; - if(!parseURL(url, hostname, &port, &path, &scope_id)) - return NULL; -#ifdef DEBUG - printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", - hostname, port, path, scope_id); -#endif - return miniwget2(hostname, port, path, size, addr, addrlen, scope_id, status_code); -} - diff --git a/zto/ext/miniupnpc/miniwget.h b/zto/ext/miniupnpc/miniwget.h deleted file mode 100644 index 0701494..0000000 --- a/zto/ext/miniupnpc/miniwget.h +++ /dev/null @@ -1,30 +0,0 @@ -/* $Id: miniwget.h,v 1.12 2016/01/24 17:24:36 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005-2016 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#ifndef MINIWGET_H_INCLUDED -#define MINIWGET_H_INCLUDED - -#include "miniupnpc_declspec.h" - -#ifdef __cplusplus -extern "C" { -#endif - -MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size, int * status_code); - -MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int, int *); - -MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int, int *); - -int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/zto/ext/miniupnpc/minixml.c b/zto/ext/miniupnpc/minixml.c deleted file mode 100644 index 3e201ec..0000000 --- a/zto/ext/miniupnpc/minixml.c +++ /dev/null @@ -1,229 +0,0 @@ -/* $Id: minixml.c,v 1.11 2014/02/03 15:54:12 nanard Exp $ */ -/* minixml.c : the minimum size a xml parser can be ! */ -/* Project : miniupnp - * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author : Thomas Bernard - -Copyright (c) 2005-2014, Thomas BERNARD -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. - * The name of the author may not 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 -#include "minixml.h" - -/* parseatt : used to parse the argument list - * return 0 (false) in case of success and -1 (true) if the end - * of the xmlbuffer is reached. */ -static int parseatt(struct xmlparser * p) -{ - const char * attname; - int attnamelen; - const char * attvalue; - int attvaluelen; - while(p->xml < p->xmlend) - { - if(*p->xml=='/' || *p->xml=='>') - return 0; - if( !IS_WHITE_SPACE(*p->xml) ) - { - char sep; - attname = p->xml; - attnamelen = 0; - while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) ) - { - attnamelen++; p->xml++; - if(p->xml >= p->xmlend) - return -1; - } - while(*(p->xml++) != '=') - { - if(p->xml >= p->xmlend) - return -1; - } - while(IS_WHITE_SPACE(*p->xml)) - { - p->xml++; - if(p->xml >= p->xmlend) - return -1; - } - sep = *p->xml; - if(sep=='\'' || sep=='\"') - { - p->xml++; - if(p->xml >= p->xmlend) - return -1; - attvalue = p->xml; - attvaluelen = 0; - while(*p->xml != sep) - { - attvaluelen++; p->xml++; - if(p->xml >= p->xmlend) - return -1; - } - } - else - { - attvalue = p->xml; - attvaluelen = 0; - while( !IS_WHITE_SPACE(*p->xml) - && *p->xml != '>' && *p->xml != '/') - { - attvaluelen++; p->xml++; - if(p->xml >= p->xmlend) - return -1; - } - } - /*printf("%.*s='%.*s'\n", - attnamelen, attname, attvaluelen, attvalue);*/ - if(p->attfunc) - p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen); - } - p->xml++; - } - return -1; -} - -/* parseelt parse the xml stream and - * call the callback functions when needed... */ -static void parseelt(struct xmlparser * p) -{ - int i; - const char * elementname; - while(p->xml < (p->xmlend - 1)) - { - if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "", 3) != 0); - p->xml += 3; - } - else if((p->xml)[0]=='<' && (p->xml)[1]!='?') - { - i = 0; elementname = ++p->xml; - while( !IS_WHITE_SPACE(*p->xml) - && (*p->xml!='>') && (*p->xml!='/') - ) - { - i++; p->xml++; - if (p->xml >= p->xmlend) - return; - /* to ignore namespace : */ - if(*p->xml==':') - { - i = 0; - elementname = ++p->xml; - } - } - if(i>0) - { - if(p->starteltfunc) - p->starteltfunc(p->data, elementname, i); - if(parseatt(p)) - return; - if(*p->xml!='/') - { - const char * data; - i = 0; data = ++p->xml; - if (p->xml >= p->xmlend) - return; - while( IS_WHITE_SPACE(*p->xml) ) - { - i++; p->xml++; - if (p->xml >= p->xmlend) - return; - } - if(memcmp(p->xml, "xml += 9; - data = p->xml; - i = 0; - while(memcmp(p->xml, "]]>", 3) != 0) - { - i++; p->xml++; - if ((p->xml + 3) >= p->xmlend) - return; - } - if(i>0 && p->datafunc) - p->datafunc(p->data, data, i); - while(*p->xml!='<') - { - p->xml++; - if (p->xml >= p->xmlend) - return; - } - } - else - { - while(*p->xml!='<') - { - i++; p->xml++; - if ((p->xml + 1) >= p->xmlend) - return; - } - if(i>0 && p->datafunc && *(p->xml + 1) == '/') - p->datafunc(p->data, data, i); - } - } - } - else if(*p->xml == '/') - { - i = 0; elementname = ++p->xml; - if (p->xml >= p->xmlend) - return; - while((*p->xml != '>')) - { - i++; p->xml++; - if (p->xml >= p->xmlend) - return; - } - if(p->endeltfunc) - p->endeltfunc(p->data, elementname, i); - p->xml++; - } - } - else - { - p->xml++; - } - } -} - -/* the parser must be initialized before calling this function */ -void parsexml(struct xmlparser * parser) -{ - parser->xml = parser->xmlstart; - parser->xmlend = parser->xmlstart + parser->xmlsize; - parseelt(parser); -} - - diff --git a/zto/ext/miniupnpc/minixml.h b/zto/ext/miniupnpc/minixml.h deleted file mode 100644 index 9f43aa4..0000000 --- a/zto/ext/miniupnpc/minixml.h +++ /dev/null @@ -1,37 +0,0 @@ -/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ -/* minimal xml parser - * - * Project : miniupnp - * Website : http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#ifndef MINIXML_H_INCLUDED -#define MINIXML_H_INCLUDED -#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) - -/* if a callback function pointer is set to NULL, - * the function is not called */ -struct xmlparser { - const char *xmlstart; - const char *xmlend; - const char *xml; /* pointer to current character */ - int xmlsize; - void * data; - void (*starteltfunc) (void *, const char *, int); - void (*endeltfunc) (void *, const char *, int); - void (*datafunc) (void *, const char *, int); - void (*attfunc) (void *, const char *, int, const char *, int); -}; - -/* parsexml() - * the xmlparser structure must be initialized before the call - * the following structure members have to be initialized : - * xmlstart, xmlsize, data, *func - * xml is for internal usage, xmlend is computed automatically */ -void parsexml(struct xmlparser *); - -#endif - diff --git a/zto/ext/miniupnpc/minixmlvalid.c b/zto/ext/miniupnpc/minixmlvalid.c deleted file mode 100644 index dad1488..0000000 --- a/zto/ext/miniupnpc/minixmlvalid.c +++ /dev/null @@ -1,163 +0,0 @@ -/* $Id: minixmlvalid.c,v 1.7 2015/07/15 12:41:15 nanard Exp $ */ -/* MiniUPnP Project - * http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ - * minixmlvalid.c : - * validation program for the minixml parser - * - * (c) 2006-2011 Thomas Bernard */ - -#include -#include -#include -#include "minixml.h" - -/* xml event structure */ -struct event { - enum { ELTSTART, ELTEND, ATT, CHARDATA } type; - const char * data; - int len; -}; - -struct eventlist { - int n; - struct event * events; -}; - -/* compare 2 xml event lists - * return 0 if the two lists are equals */ -int evtlistcmp(struct eventlist * a, struct eventlist * b) -{ - int i; - struct event * ae, * be; - if(a->n != b->n) - { - printf("event number not matching : %d != %d\n", a->n, b->n); - /*return 1;*/ - } - for(i=0; in; i++) - { - ae = a->events + i; - be = b->events + i; - if( (ae->type != be->type) - ||(ae->len != be->len) - ||memcmp(ae->data, be->data, ae->len)) - { - printf("Found a difference : %d '%.*s' != %d '%.*s'\n", - ae->type, ae->len, ae->data, - be->type, be->len, be->data); - return 1; - } - } - return 0; -} - -/* Test data */ -static const char xmldata[] = -"\n" -" " -"character data" -" \n \t" -"" -"\nstuff !\n ]]> \n\n" -" \tchardata1 chardata2 " -""; - -static const struct event evtref[] = -{ - {ELTSTART, "xmlroot", 7}, - {ELTSTART, "elt1", 4}, - /* attributes */ - {CHARDATA, "character data", 14}, - {ELTEND, "elt1", 4}, - {ELTSTART, "elt1b", 5}, - {ELTSTART, "elt1", 4}, - {CHARDATA, " stuff !\n ", 16}, - {ELTEND, "elt1", 4}, - {ELTSTART, "elt2a", 5}, - {ELTSTART, "elt2b", 5}, - {CHARDATA, "chardata1", 9}, - {ELTEND, "elt2b", 5}, - {ELTSTART, "elt2b", 5}, - {CHARDATA, " chardata2 ", 11}, - {ELTEND, "elt2b", 5}, - {ELTEND, "elt2a", 5}, - {ELTEND, "xmlroot", 7} -}; - -void startelt(void * data, const char * p, int l) -{ - struct eventlist * evtlist = data; - struct event * evt; - evt = evtlist->events + evtlist->n; - /*printf("startelt : %.*s\n", l, p);*/ - evt->type = ELTSTART; - evt->data = p; - evt->len = l; - evtlist->n++; -} - -void endelt(void * data, const char * p, int l) -{ - struct eventlist * evtlist = data; - struct event * evt; - evt = evtlist->events + evtlist->n; - /*printf("endelt : %.*s\n", l, p);*/ - evt->type = ELTEND; - evt->data = p; - evt->len = l; - evtlist->n++; -} - -void chardata(void * data, const char * p, int l) -{ - struct eventlist * evtlist = data; - struct event * evt; - evt = evtlist->events + evtlist->n; - /*printf("chardata : '%.*s'\n", l, p);*/ - evt->type = CHARDATA; - evt->data = p; - evt->len = l; - evtlist->n++; -} - -int testxmlparser(const char * xml, int size) -{ - int r; - struct eventlist evtlist; - struct eventlist evtlistref; - struct xmlparser parser; - evtlist.n = 0; - evtlist.events = malloc(sizeof(struct event)*100); - if(evtlist.events == NULL) - { - fprintf(stderr, "Memory allocation error.\n"); - return -1; - } - memset(&parser, 0, sizeof(parser)); - parser.xmlstart = xml; - parser.xmlsize = size; - parser.data = &evtlist; - parser.starteltfunc = startelt; - parser.endeltfunc = endelt; - parser.datafunc = chardata; - parsexml(&parser); - printf("%d events\n", evtlist.n); - /* compare */ - evtlistref.n = sizeof(evtref)/sizeof(struct event); - evtlistref.events = (struct event *)evtref; - r = evtlistcmp(&evtlistref, &evtlist); - free(evtlist.events); - return r; -} - -int main(int argc, char * * argv) -{ - int r; - (void)argc; (void)argv; - - r = testxmlparser(xmldata, sizeof(xmldata)-1); - if(r) - printf("minixml validation test failed\n"); - return r; -} - diff --git a/zto/ext/miniupnpc/portlistingparse.c b/zto/ext/miniupnpc/portlistingparse.c deleted file mode 100644 index d1954f5..0000000 --- a/zto/ext/miniupnpc/portlistingparse.c +++ /dev/null @@ -1,172 +0,0 @@ -/* $Id: portlistingparse.c,v 1.10 2016/12/16 08:53:21 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2011-2016 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ -#include -#include -#ifdef DEBUG -#include -#endif /* DEBUG */ -#include "portlistingparse.h" -#include "minixml.h" - -/* list of the elements */ -static const struct { - const portMappingElt code; - const char * const str; -} elements[] = { - { PortMappingEntry, "PortMappingEntry"}, - { NewRemoteHost, "NewRemoteHost"}, - { NewExternalPort, "NewExternalPort"}, - { NewProtocol, "NewProtocol"}, - { NewInternalPort, "NewInternalPort"}, - { NewInternalClient, "NewInternalClient"}, - { NewEnabled, "NewEnabled"}, - { NewDescription, "NewDescription"}, - { NewLeaseTime, "NewLeaseTime"}, - { PortMappingEltNone, NULL} -}; - -/* Helper function */ -static UNSIGNED_INTEGER -atoui(const char * p, int l) -{ - UNSIGNED_INTEGER r = 0; - while(l > 0 && *p) - { - if(*p >= '0' && *p <= '9') - r = r*10 + (*p - '0'); - else - break; - p++; - l--; - } - return r; -} - -/* Start element handler */ -static void -startelt(void * d, const char * name, int l) -{ - int i; - struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; - pdata->curelt = PortMappingEltNone; - for(i = 0; elements[i].str; i++) - { - if(strlen(elements[i].str) == (size_t)l && memcmp(name, elements[i].str, l) == 0) - { - pdata->curelt = elements[i].code; - break; - } - } - if(pdata->curelt == PortMappingEntry) - { - struct PortMapping * pm; - pm = calloc(1, sizeof(struct PortMapping)); - if(pm == NULL) - { - /* malloc error */ -#ifdef DEBUG - fprintf(stderr, "%s: error allocating memory", - "startelt"); -#endif /* DEBUG */ - return; - } - pm->l_next = pdata->l_head; /* insert in list */ - pdata->l_head = pm; - } -} - -/* End element handler */ -static void -endelt(void * d, const char * name, int l) -{ - struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; - (void)name; - (void)l; - pdata->curelt = PortMappingEltNone; -} - -/* Data handler */ -static void -data(void * d, const char * data, int l) -{ - struct PortMapping * pm; - struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; - pm = pdata->l_head; - if(!pm) - return; - if(l > 63) - l = 63; - switch(pdata->curelt) - { - case NewRemoteHost: - memcpy(pm->remoteHost, data, l); - pm->remoteHost[l] = '\0'; - break; - case NewExternalPort: - pm->externalPort = (unsigned short)atoui(data, l); - break; - case NewProtocol: - if(l > 3) - l = 3; - memcpy(pm->protocol, data, l); - pm->protocol[l] = '\0'; - break; - case NewInternalPort: - pm->internalPort = (unsigned short)atoui(data, l); - break; - case NewInternalClient: - memcpy(pm->internalClient, data, l); - pm->internalClient[l] = '\0'; - break; - case NewEnabled: - pm->enabled = (unsigned char)atoui(data, l); - break; - case NewDescription: - memcpy(pm->description, data, l); - pm->description[l] = '\0'; - break; - case NewLeaseTime: - pm->leaseTime = atoui(data, l); - break; - default: - break; - } -} - - -/* Parse the PortMappingList XML document for IGD version 2 - */ -void -ParsePortListing(const char * buffer, int bufsize, - struct PortMappingParserData * pdata) -{ - struct xmlparser parser; - - memset(pdata, 0, sizeof(struct PortMappingParserData)); - /* init xmlparser */ - parser.xmlstart = buffer; - parser.xmlsize = bufsize; - parser.data = pdata; - parser.starteltfunc = startelt; - parser.endeltfunc = endelt; - parser.datafunc = data; - parser.attfunc = 0; - parsexml(&parser); -} - -void -FreePortListing(struct PortMappingParserData * pdata) -{ - struct PortMapping * pm; - while((pm = pdata->l_head) != NULL) - { - /* remove from list */ - pdata->l_head = pm->l_next; - free(pm); - } -} - diff --git a/zto/ext/miniupnpc/portlistingparse.h b/zto/ext/miniupnpc/portlistingparse.h deleted file mode 100644 index 661ad1f..0000000 --- a/zto/ext/miniupnpc/portlistingparse.h +++ /dev/null @@ -1,65 +0,0 @@ -/* $Id: portlistingparse.h,v 1.11 2015/07/21 13:16:55 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2011-2015 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ -#ifndef PORTLISTINGPARSE_H_INCLUDED -#define PORTLISTINGPARSE_H_INCLUDED - -#include "miniupnpc_declspec.h" -/* for the definition of UNSIGNED_INTEGER */ -#include "miniupnpctypes.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* sample of PortMappingEntry : - - 202.233.2.1 - 2345 - TCP - 2345 - 192.168.1.137 - 1 - dooom - 345 - - */ -typedef enum { PortMappingEltNone, - PortMappingEntry, NewRemoteHost, - NewExternalPort, NewProtocol, - NewInternalPort, NewInternalClient, - NewEnabled, NewDescription, - NewLeaseTime } portMappingElt; - -struct PortMapping { - struct PortMapping * l_next; /* list next element */ - UNSIGNED_INTEGER leaseTime; - unsigned short externalPort; - unsigned short internalPort; - char remoteHost[64]; - char internalClient[64]; - char description[64]; - char protocol[4]; - unsigned char enabled; -}; - -struct PortMappingParserData { - struct PortMapping * l_head; /* list head */ - portMappingElt curelt; -}; - -MINIUPNP_LIBSPEC void -ParsePortListing(const char * buffer, int bufsize, - struct PortMappingParserData * pdata); - -MINIUPNP_LIBSPEC void -FreePortListing(struct PortMappingParserData * pdata); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/zto/ext/miniupnpc/pymoduletest.py b/zto/ext/miniupnpc/pymoduletest.py deleted file mode 100644 index 9fddd9c..0000000 --- a/zto/ext/miniupnpc/pymoduletest.py +++ /dev/null @@ -1,88 +0,0 @@ -#! /usr/bin/python -# vim: tabstop=2 shiftwidth=2 expandtab -# MiniUPnP project -# Author : Thomas Bernard -# This Sample code is public domain. -# website : http://miniupnp.tuxfamily.org/ - -# import the python miniupnpc module -import miniupnpc -import sys - -try: - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('-m', '--multicastif') - parser.add_argument('-p', '--minissdpdsocket') - parser.add_argument('-d', '--discoverdelay', type=int, default=200) - parser.add_argument('-z', '--localport', type=int, default=0) - # create the object - u = miniupnpc.UPnP(**vars(parser.parse_args())) -except: - print 'argparse not available' - i = 1 - multicastif = None - minissdpdsocket = None - discoverdelay = 200 - localport = 0 - while i < len(sys.argv): - print sys.argv[i] - if sys.argv[i] == '-m' or sys.argv[i] == '--multicastif': - multicastif = sys.argv[i+1] - elif sys.argv[i] == '-p' or sys.argv[i] == '--minissdpdsocket': - minissdpdsocket = sys.argv[i+1] - elif sys.argv[i] == '-d' or sys.argv[i] == '--discoverdelay': - discoverdelay = int(sys.argv[i+1]) - elif sys.argv[i] == '-z' or sys.argv[i] == '--localport': - localport = int(sys.argv[i+1]) - else: - raise Exception('invalid argument %s' % sys.argv[i]) - i += 2 - # create the object - u = miniupnpc.UPnP(multicastif, minissdpdsocket, discoverdelay, localport) - -print 'inital(default) values :' -print ' discoverdelay', u.discoverdelay -print ' lanaddr', u.lanaddr -print ' multicastif', u.multicastif -print ' minissdpdsocket', u.minissdpdsocket -#u.minissdpdsocket = '../minissdpd/minissdpd.sock' -# discovery process, it usualy takes several seconds (2 seconds or more) -print 'Discovering... delay=%ums' % u.discoverdelay -print u.discover(), 'device(s) detected' -# select an igd -try: - u.selectigd() -except Exception, e: - print 'Exception :', e - sys.exit(1) -# display information about the IGD and the internet connection -print 'local ip address :', u.lanaddr -print 'external ip address :', u.externalipaddress() -print u.statusinfo(), u.connectiontype() -print 'total bytes : sent', u.totalbytesent(), 'received', u.totalbytereceived() -print 'total packets : sent', u.totalpacketsent(), 'received', u.totalpacketreceived() - -#print u.addportmapping(64000, 'TCP', -# '192.168.1.166', 63000, 'port mapping test', '') -#print u.deleteportmapping(64000, 'TCP') - -port = 0 -proto = 'UDP' -# list the redirections : -i = 0 -while True: - p = u.getgenericportmapping(i) - if p==None: - break - print i, p - (port, proto, (ihost,iport), desc, c, d, e) = p - #print port, desc - i = i + 1 - -print u.getspecificportmapping(port, proto) -try: - print u.getportmappingnumberofentries() -except Exception, e: - print 'GetPortMappingNumberOfEntries() is not supported :', e - diff --git a/zto/ext/miniupnpc/receivedata.c b/zto/ext/miniupnpc/receivedata.c deleted file mode 100644 index ef85a3d..0000000 --- a/zto/ext/miniupnpc/receivedata.c +++ /dev/null @@ -1,105 +0,0 @@ -/* $Id: receivedata.c,v 1.7 2015/11/09 21:51:41 nanard Exp $ */ -/* Project : miniupnp - * Website : http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2011-2014 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ - -#include -#include -#ifdef _WIN32 -#include -#include -#else /* _WIN32 */ -#include -#if defined(__amigaos__) && !defined(__amigaos4__) -#define socklen_t int -#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ -#include -#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ -#include -#include -#if !defined(__amigaos__) && !defined(__amigaos4__) -#include -#endif /* !defined(__amigaos__) && !defined(__amigaos4__) */ -#include -#define MINIUPNPC_IGNORE_EINTR -#endif /* _WIN32 */ - -#ifdef _WIN32 -#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); -#else -#define PRINT_SOCKET_ERROR(x) perror(x) -#endif - -#include "receivedata.h" - -int -receivedata(int socket, - char * data, int length, - int timeout, unsigned int * scope_id) -{ -#ifdef MINIUPNPC_GET_SRC_ADDR - struct sockaddr_storage src_addr; - socklen_t src_addr_len = sizeof(src_addr); -#endif /* MINIUPNPC_GET_SRC_ADDR */ - int n; -#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) - /* using poll */ - struct pollfd fds[1]; /* for the poll */ -#ifdef MINIUPNPC_IGNORE_EINTR - do { -#endif /* MINIUPNPC_IGNORE_EINTR */ - fds[0].fd = socket; - fds[0].events = POLLIN; - n = poll(fds, 1, timeout); -#ifdef MINIUPNPC_IGNORE_EINTR - } while(n < 0 && errno == EINTR); -#endif /* MINIUPNPC_IGNORE_EINTR */ - if(n < 0) { - PRINT_SOCKET_ERROR("poll"); - return -1; - } else if(n == 0) { - /* timeout */ - return 0; - } -#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ - /* using select under _WIN32 and amigaos */ - fd_set socketSet; - TIMEVAL timeval; - FD_ZERO(&socketSet); - FD_SET(socket, &socketSet); - timeval.tv_sec = timeout / 1000; - timeval.tv_usec = (timeout % 1000) * 1000; - n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval); - if(n < 0) { - PRINT_SOCKET_ERROR("select"); - return -1; - } else if(n == 0) { - return 0; - } -#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ -#ifdef MINIUPNPC_GET_SRC_ADDR - memset(&src_addr, 0, sizeof(src_addr)); - n = recvfrom(socket, data, length, 0, - (struct sockaddr *)&src_addr, &src_addr_len); -#else /* MINIUPNPC_GET_SRC_ADDR */ - n = recv(socket, data, length, 0); -#endif /* MINIUPNPC_GET_SRC_ADDR */ - if(n<0) { - PRINT_SOCKET_ERROR("recv"); - } -#ifdef MINIUPNPC_GET_SRC_ADDR - if (src_addr.ss_family == AF_INET6) { - const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr; -#ifdef DEBUG - printf("scope_id=%u\n", src_addr6->sin6_scope_id); -#endif /* DEBUG */ - if(scope_id) - *scope_id = src_addr6->sin6_scope_id; - } -#endif /* MINIUPNPC_GET_SRC_ADDR */ - return n; -} - diff --git a/zto/ext/miniupnpc/receivedata.h b/zto/ext/miniupnpc/receivedata.h deleted file mode 100644 index 0520a11..0000000 --- a/zto/ext/miniupnpc/receivedata.h +++ /dev/null @@ -1,19 +0,0 @@ -/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author: Thomas Bernard - * Copyright (c) 2011-2012 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef RECEIVEDATA_H_INCLUDED -#define RECEIVEDATA_H_INCLUDED - -/* Reads data from the specified socket. - * Returns the number of bytes read if successful, zero if no bytes were - * read or if we timed out. Returns negative if there was an error. */ -int receivedata(int socket, - char * data, int length, - int timeout, unsigned int * scope_id); - -#endif - diff --git a/zto/ext/miniupnpc/setup.py b/zto/ext/miniupnpc/setup.py deleted file mode 100644 index 97e42bf..0000000 --- a/zto/ext/miniupnpc/setup.py +++ /dev/null @@ -1,28 +0,0 @@ -#! /usr/bin/python -# vim: tabstop=8 shiftwidth=8 expandtab -# $Id: setup.py,v 1.12 2015/10/26 17:03:17 nanard Exp $ -# the MiniUPnP Project (c) 2007-2014 Thomas Bernard -# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ -# -# python script to build the miniupnpc module under unix -# -# replace libminiupnpc.a by libminiupnpc.so for shared library usage -try: - from setuptools import setup, Extension -except ImportError: - from distutils.core import setup, Extension -from distutils import sysconfig -sysconfig.get_config_vars()["OPT"] = '' -sysconfig.get_config_vars()["CFLAGS"] = '' -setup(name="miniupnpc", - version=open('VERSION').read().strip(), - author='Thomas BERNARD', - author_email='miniupnp@free.fr', - license=open('LICENSE').read(), - url='http://miniupnp.free.fr/', - description='miniUPnP client', - ext_modules=[ - Extension(name="miniupnpc", sources=["miniupnpcmodule.c"], - extra_objects=["libminiupnpc.a"]) - ]) - diff --git a/zto/ext/miniupnpc/setupmingw32.py b/zto/ext/miniupnpc/setupmingw32.py deleted file mode 100644 index 43dfb46..0000000 --- a/zto/ext/miniupnpc/setupmingw32.py +++ /dev/null @@ -1,28 +0,0 @@ -#! /usr/bin/python -# vim: tabstop=8 shiftwidth=8 expandtab -# $Id: setupmingw32.py,v 1.10 2015/10/26 17:03:17 nanard Exp $ -# the MiniUPnP Project (c) 2007-2014 Thomas Bernard -# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ -# -# python script to build the miniupnpc module under windows (using mingw32) -# -try: - from setuptools import setup, Extension -except ImportError: - from distutils.core import setup, Extension -from distutils import sysconfig -sysconfig.get_config_vars()["OPT"] = '' -sysconfig.get_config_vars()["CFLAGS"] = '' -setup(name="miniupnpc", - version=open('VERSION').read().strip(), - author='Thomas BERNARD', - author_email='miniupnp@free.fr', - license=open('LICENSE').read(), - url='http://miniupnp.free.fr/', - description='miniUPnP client', - ext_modules=[ - Extension(name="miniupnpc", sources=["miniupnpcmodule.c"], - libraries=["ws2_32", "iphlpapi"], - extra_objects=["libminiupnpc.a"]) - ]) - diff --git a/zto/ext/miniupnpc/testdesc/linksys_WAG200G_desc.values b/zto/ext/miniupnpc/testdesc/linksys_WAG200G_desc.values deleted file mode 100644 index cf42221..0000000 --- a/zto/ext/miniupnpc/testdesc/linksys_WAG200G_desc.values +++ /dev/null @@ -1,14 +0,0 @@ -# values for linksys_WAG200G_desc.xml - -CIF: - servicetype = urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 - controlurl = /upnp/control/WANCommonIFC1 - eventsuburl = /upnp/event/WANCommonIFC1 - scpdurl = /cmnicfg.xml - -first: - servicetype = urn:schemas-upnp-org:service:WANPPPConnection:1 - controlurl = /upnp/control/WANPPPConn1 - eventsuburl = /upnp/event/WANPPPConn1 - scpdurl = /pppcfg.xml - diff --git a/zto/ext/miniupnpc/testdesc/linksys_WAG200G_desc.xml b/zto/ext/miniupnpc/testdesc/linksys_WAG200G_desc.xml deleted file mode 100644 index d428d73..0000000 --- a/zto/ext/miniupnpc/testdesc/linksys_WAG200G_desc.xml +++ /dev/null @@ -1,110 +0,0 @@ - - - -1 -0 - -http://192.168.1.1:49152 - -urn:schemas-upnp-org:device:InternetGatewayDevice:1 -LINKSYS WAG200G Gateway -LINKSYS -http://www.linksys.com -LINKSYS WAG200G Gateway -Wireless-G ADSL Home Gateway -WAG200G -http://www.linksys.com -123456789 -uuid:8ca2eb37-1dd2-11b2-86f1-001a709b5aa8 -WAG200G - - -urn:schemas-upnp-org:service:Layer3Forwarding:1 -urn:upnp-org:serviceId:L3Forwarding1 -/upnp/control/L3Forwarding1 -/upnp/event/L3Forwarding1 -/l3frwd.xml - - - - -urn:schemas-upnp-org:device:WANDevice:1 -WANDevice -LINKSYS -http://www.linksys.com/ -Residential Gateway -Internet Connection Sharing -1 -http://www.linksys.com/ -0000001 -uuid:8ca2eb36-1dd2-11b2-86f1-001a709b5aa8 -WAG200G - - -urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 -urn:upnp-org:serviceId:WANCommonIFC1 -/upnp/control/WANCommonIFC1 -/upnp/event/WANCommonIFC1 -/cmnicfg.xml - - - - -urn:schemas-upnp-org:device:WANConnectionDevice:1 -WANConnectionDevice -LINKSYS -http://www.linksys.com/ -Residential Gateway -Internet Connection Sharing -1 -http://www.linksys.com/ -0000001 -uuid:8ca2eb37-1dd2-11b2-86f0-001a709b5aa8 -WAG200G - - -urn:schemas-upnp-org:service:WANEthernetLinkConfig:1 -urn:upnp-org:serviceId:WANEthLinkC1 -/upnp/control/WANEthLinkC1 -/upnp/event/WANEthLinkC1 -/wanelcfg.xml - - -urn:schemas-upnp-org:service:WANPPPConnection:1 -urn:upnp-org:serviceId:WANPPPConn1 -/upnp/control/WANPPPConn1 -/upnp/event/WANPPPConn1 -/pppcfg.xml - - - - - - -urn:schemas-upnp-org:device:LANDevice:1 -LANDevice -LINKSYS -http://www.linksys.com/ -Residential Gateway -Residential Gateway -1 -http://www.linksys.com/ -0000001 -uuid:8ca2eb36-1dd2-11b2-86f0-001a709b5aa -8 -WAG200G - - -urn:schemas-upnp-org:service:LANHostConfigManagement:1 -urn:upnp-org:serviceId:LANHostCfg1 -/upnp/control/LANHostCfg1 -/upnp/event/LANHostCfg1 -/lanhostc.xml - - - - -http://192.168.1.1/index.htm - - - diff --git a/zto/ext/miniupnpc/testdesc/new_LiveBox_desc.values b/zto/ext/miniupnpc/testdesc/new_LiveBox_desc.values deleted file mode 100644 index c55552e..0000000 --- a/zto/ext/miniupnpc/testdesc/new_LiveBox_desc.values +++ /dev/null @@ -1,20 +0,0 @@ -# values for new_LiveBox_desc.xml - -CIF: - servicetype = urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 - controlurl = /87895a19/upnp/control/WANCommonIFC1 - eventsuburl = /87895a19/upnp/control/WANCommonIFC1 - scpdurl = /87895a19/gateicfgSCPD.xml - -first: - servicetype = urn:schemas-upnp-org:service:WANPPPConnection:2 - controlurl = /87895a19/upnp/control/WANIPConn1 - eventsuburl = /87895a19/upnp/control/WANIPConn1 - scpdurl = /87895a19/gateconnSCPD_PPP.xml - -IPv6FC: - servicetype = urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 - controlurl = /87895a19/upnp/control/WANIPv6FwCtrl1 - eventsuburl = /87895a19/upnp/control/WANIPv6FwCtrl1 - scpdurl = /87895a19/wanipv6fwctrlSCPD.xml - diff --git a/zto/ext/miniupnpc/testdesc/new_LiveBox_desc.xml b/zto/ext/miniupnpc/testdesc/new_LiveBox_desc.xml deleted file mode 100644 index 620eb55..0000000 --- a/zto/ext/miniupnpc/testdesc/new_LiveBox_desc.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - 1 - 0 - - - VEN_0129&DEV_0000&SUBSYS_03&REV_250417 - GenericUmPass - NetworkInfrastructure.Gateway - Network.Gateway - urn:schemas-upnp-org:device:InternetGatewayDevice:2 - Orange Livebox - Sagemcom - http://www.sagemcom.com/ - Residential Livebox,(DSL,WAN Ethernet) - uuid:87895a19-50f9-3736-a87f-115c230155f8 - Sagemcom,fr,SG30_sip-fr-4.28.35.1 - 3 - LK14129DP441489 - http://192.168.1.1 - - - - image/png - 16 - 16 - 8 - /87895a19/ligd.png - - - - - urn:schemas-upnp-org:device:WANDevice:2 - WANDevice - Sagemcom - http://www.sagemcom.com/ - WAN Device on Sagemcom,fr,SG30_sip-fr-4.28.35.1 - Residential Livebox,(DSL,WAN Ethernet) - 3 - http://www.sagemcom.com/ - LK14129DP441489 - http://192.168.1.1 - uuid:e2397374-53d8-3fc6-8306-593ba1a34625 - - - - urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 - urn:upnp-org:serviceId:WANCommonIFC1 - /87895a19/upnp/control/WANCommonIFC1 - /87895a19/upnp/control/WANCommonIFC1 - /87895a19/gateicfgSCPD.xml - - - - - urn:schemas-upnp-org:device:WANConnectionDevice:2 - WANConnectionDevice - Sagemcom - http://www.sagemcom.com/ - WanConnectionDevice on Sagemcom,fr,SG30_sip-fr-4.28.35.1 - Residential Livebox,(DSL,WAN Ethernet) - 3 - http://www.sagemcom.com/ - LK14129DP441489 - http://192.168.1.1 - uuid:44598a08-288e-32c9-8a4d-d3c008ede331 - - - - urn:schemas-upnp-org:service:WANPPPConnection:2 - urn:upnp-org:serviceId:WANIPConn1 - /87895a19/upnp/control/WANIPConn1 - /87895a19/upnp/control/WANIPConn1 - /87895a19/gateconnSCPD_PPP.xml - - - urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 - urn:upnp-org:serviceId:WANIPv6FwCtrl1 - /87895a19/upnp/control/WANIPv6FwCtrl1 - /87895a19/upnp/control/WANIPv6FwCtrl1 - /87895a19/wanipv6fwctrlSCPD.xml - - - - - - - - \ No newline at end of file diff --git a/zto/ext/miniupnpc/testigddescparse.c b/zto/ext/miniupnpc/testigddescparse.c deleted file mode 100644 index c1907fd..0000000 --- a/zto/ext/miniupnpc/testigddescparse.c +++ /dev/null @@ -1,187 +0,0 @@ -/* $Id: testigddescparse.c,v 1.10 2015/08/06 09:55:24 nanard Exp $ */ -/* Project : miniupnp - * http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2008-2015 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#include -#include -#include -#include "igd_desc_parse.h" -#include "minixml.h" -#include "miniupnpc.h" - -/* count number of differences */ -int compare_service(struct IGDdatas_service * s, FILE * f) -{ - int n = 0; - char line[1024]; - - while(fgets(line, sizeof(line), f)) { - char * value; - char * equal; - char * name; - char * parsedvalue; - int l; - l = strlen(line); - while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n') || (line[l-1] == ' '))) - line[--l] = '\0'; - if(l == 0) - break; /* end on blank line */ - if(line[0] == '#') - continue; /* skip comments */ - equal = strchr(line, '='); - if(equal == NULL) { - fprintf(stderr, "Warning, line does not contain '=' : %s\n", line); - continue; - } - *equal = '\0'; - name = line; - while(*name == ' ' || *name == '\t') - name++; - l = strlen(name); - while((l > 0) && (name[l-1] == ' ' || name[l-1] == '\t')) - name[--l] = '\0'; - value = equal + 1; - while(*value == ' ' || *value == '\t') - value++; - if(strcmp(name, "controlurl") == 0) - parsedvalue = s->controlurl; - else if(strcmp(name, "eventsuburl") == 0) - parsedvalue = s->eventsuburl; - else if(strcmp(name, "scpdurl") == 0) - parsedvalue = s->scpdurl; - else if(strcmp(name, "servicetype") == 0) - parsedvalue = s->servicetype; - else { - fprintf(stderr, "unknown field '%s'\n", name); - continue; - } - if(0 != strcmp(parsedvalue, value)) { - fprintf(stderr, "difference : '%s' != '%s'\n", parsedvalue, value); - n++; - } - } - return n; -} - -int compare_igd(struct IGDdatas * p, FILE * f) -{ - int n = 0; - char line[1024]; - struct IGDdatas_service * s; - - while(fgets(line, sizeof(line), f)) { - char * colon; - int l = (int)strlen(line); - while((l > 0) && (line[l-1] == '\r' || (line[l-1] == '\n'))) - line[--l] = '\0'; - if(l == 0 || line[0] == '#') - continue; /* skip blank lines and comments */ - colon = strchr(line, ':'); - if(colon == NULL) { - fprintf(stderr, "Warning, no ':' : %s\n", line); - continue; - } - s = NULL; - *colon = '\0'; - if(strcmp(line, "CIF") == 0) - s = &p->CIF; - else if(strcmp(line, "first") == 0) - s = &p->first; - else if(strcmp(line, "second") == 0) - s = &p->second; - else if(strcmp(line, "IPv6FC") == 0) - s = &p->IPv6FC; - else { - s = NULL; - fprintf(stderr, "*** unknown service '%s' ***\n", line); - n++; - continue; - } - n += compare_service(s, f); - } - if(n > 0) - fprintf(stderr, "*** %d difference%s ***\n", n, (n > 1) ? "s" : ""); - return n; -} - -int test_igd_desc_parse(char * buffer, int len, FILE * f) -{ - int n; - struct IGDdatas igd; - struct xmlparser parser; - struct UPNPUrls urls; - - memset(&igd, 0, sizeof(struct IGDdatas)); - memset(&parser, 0, sizeof(struct xmlparser)); - parser.xmlstart = buffer; - parser.xmlsize = len; - parser.data = &igd; - parser.starteltfunc = IGDstartelt; - parser.endeltfunc = IGDendelt; - parser.datafunc = IGDdata; - parsexml(&parser); -#ifdef DEBUG - printIGD(&igd); -#endif /* DEBUG */ - GetUPNPUrls(&urls, &igd, "http://fake/desc/url/file.xml", 0); - printf("ipcondescURL='%s'\n", urls.ipcondescURL); - printf("controlURL='%s'\n", urls.controlURL); - printf("controlURL_CIF='%s'\n", urls.controlURL_CIF); - n = f ? compare_igd(&igd, f) : 0; - FreeUPNPUrls(&urls); - return n; -} - -int main(int argc, char * * argv) -{ - FILE * f; - char * buffer; - int len; - int r; - if(argc<2) { - fprintf(stderr, "Usage: %s file.xml [file.values]\n", argv[0]); - return 1; - } - f = fopen(argv[1], "r"); - if(!f) { - fprintf(stderr, "Cannot open %s for reading.\n", argv[1]); - return 1; - } - fseek(f, 0, SEEK_END); - len = ftell(f); - fseek(f, 0, SEEK_SET); - buffer = malloc(len); - if(!buffer) { - fprintf(stderr, "Memory allocation error.\n"); - fclose(f); - return 1; - } - r = (int)fread(buffer, 1, len, f); - if(r != len) { - fprintf(stderr, "Failed to read file %s. %d out of %d bytes.\n", - argv[1], r, len); - fclose(f); - free(buffer); - return 1; - } - fclose(f); - f = NULL; - if(argc > 2) { - f = fopen(argv[2], "r"); - if(!f) { - fprintf(stderr, "Cannot open %s for reading.\n", argv[2]); - free(buffer); - return 1; - } - } - r = test_igd_desc_parse(buffer, len, f); - free(buffer); - if(f) - fclose(f); - return r; -} - diff --git a/zto/ext/miniupnpc/testminiwget.c b/zto/ext/miniupnpc/testminiwget.c deleted file mode 100644 index 5eb49ec..0000000 --- a/zto/ext/miniupnpc/testminiwget.c +++ /dev/null @@ -1,55 +0,0 @@ -/* $Id: testminiwget.c,v 1.5 2016/01/24 17:24:36 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005-2016 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#include -#include -#include "miniwget.h" - -/** - * This program uses the miniwget / miniwget_getaddr function - * from miniwget.c in order to retreive a web ressource using - * a GET HTTP method, and store it in a file. - */ -int main(int argc, char * * argv) -{ - void * data; - int size, writtensize; - FILE *f; - char addr[64]; - int status_code = -1; - - if(argc < 3) { - fprintf(stderr, "Usage:\t%s url file\n", argv[0]); - fprintf(stderr, "Example:\t%s http://www.google.com/ out.html\n", argv[0]); - return 1; - } - data = miniwget_getaddr(argv[1], &size, addr, sizeof(addr), 0, &status_code); - if(!data || (status_code != 200)) { - if(data) free(data); - fprintf(stderr, "Error %d fetching %s\n", status_code, argv[1]); - return 1; - } - printf("local address : %s\n", addr); - printf("got %d bytes\n", size); - f = fopen(argv[2], "wb"); - if(!f) { - fprintf(stderr, "Cannot open file %s for writing\n", argv[2]); - free(data); - return 1; - } - writtensize = fwrite(data, 1, size, f); - if(writtensize != size) { - fprintf(stderr, "Could only write %d bytes out of %d to %s\n", - writtensize, size, argv[2]); - } else { - printf("%d bytes written to %s\n", writtensize, argv[2]); - } - fclose(f); - free(data); - return 0; -} - diff --git a/zto/ext/miniupnpc/testminiwget.sh b/zto/ext/miniupnpc/testminiwget.sh deleted file mode 100755 index 690b405..0000000 --- a/zto/ext/miniupnpc/testminiwget.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/bin/sh -# $Id: testminiwget.sh,v 1.13 2015/09/03 17:57:44 nanard Exp $ -# project miniupnp : http://miniupnp.free.fr/ -# (c) 2011-2015 Thomas Bernard -# -# test program for miniwget.c -# is usually invoked by "make check" -# -# This test program : -# 1 - launches a local HTTP server (minihttptestserver) -# 2 - uses testminiwget to retreive data from this server -# 3 - compares served and received data -# 4 - kills the local HTTP server and exits -# -# The script was tested and works with ksh, bash -# it should now also run with dash - -TMPD=`mktemp -d -t miniwgetXXXXXXXXXX` -HTTPSERVEROUT="${TMPD}/httpserverout" -EXPECTEDFILE="${TMPD}/expectedfile" -DOWNLOADEDFILE="${TMPD}/downloadedfile" -PORT= -RET=0 - -case "$HAVE_IPV6" in - n|no|0) - ADDR=localhost - SERVERARGS="" - ;; - *) - ADDR="[::1]" - SERVERARGS="-6" - ;; - -esac - -#make minihttptestserver -#make testminiwget - -# launching the test HTTP server -./minihttptestserver $SERVERARGS -e $EXPECTEDFILE > $HTTPSERVEROUT & -SERVERPID=$! -while [ -z "$PORT" ]; do - sleep 1 - PORT=`cat $HTTPSERVEROUT | sed 's/Listening on port \([0-9]*\)/\1/' ` -done -echo "Test HTTP server is listening on $PORT" - -URL1="http://$ADDR:$PORT/index.html" -URL2="http://$ADDR:$PORT/chunked" -URL3="http://$ADDR:$PORT/addcrap" - -echo "standard test ..." -./testminiwget $URL1 "${DOWNLOADEDFILE}.1" -if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.1" ; then - echo "ok" -else - echo "standard test FAILED" - RET=1 -fi - -echo "chunked transfert encoding test ..." -./testminiwget $URL2 "${DOWNLOADEDFILE}.2" -if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.2" ; then - echo "ok" -else - echo "chunked transfert encoding test FAILED" - RET=1 -fi - -echo "response too long test ..." -./testminiwget $URL3 "${DOWNLOADEDFILE}.3" -if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.3" ; then - echo "ok" -else - echo "response too long test FAILED" - RET=1 -fi - -# kill the test HTTP server -kill $SERVERPID -wait $SERVERPID - -# remove temporary files (for success cases) -if [ $RET -eq 0 ]; then - rm -f "${DOWNLOADEDFILE}.1" - rm -f "${DOWNLOADEDFILE}.2" - rm -f "${DOWNLOADEDFILE}.3" - rm -f $EXPECTEDFILE $HTTPSERVEROUT - rmdir ${TMPD} -else - echo "at least one of the test FAILED" - echo "directory ${TMPD} is left intact" -fi -exit $RET - diff --git a/zto/ext/miniupnpc/testminixml.c b/zto/ext/miniupnpc/testminixml.c deleted file mode 100644 index 57c4a85..0000000 --- a/zto/ext/miniupnpc/testminixml.c +++ /dev/null @@ -1,89 +0,0 @@ -/* $Id: testminixml.c,v 1.10 2014/11/17 17:19:13 nanard Exp $ - * MiniUPnP project - * Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author : Thomas Bernard. - * Copyright (c) 2005-2014 Thomas Bernard - * - * testminixml.c - * test program for the "minixml" functions. - */ -#include -#include -#include -#include "minixml.h" -#include "igd_desc_parse.h" - -/* ---------------------------------------------------------------------- */ -void printeltname1(void * d, const char * name, int l) -{ - int i; - (void)d; - printf("element "); - for(i=0;i -#include -#include "portlistingparse.h" - -struct port_mapping { - unsigned int leasetime; - unsigned short externalport; - unsigned short internalport; - const char * remotehost; - const char * client; - const char * proto; - const char * desc; - unsigned char enabled; -}; - -/* return the number of differences */ -int test(const char * portListingXml, int portListingXmlLen, - const struct port_mapping * ref, int count) -{ - int i; - int r = 0; - struct PortMappingParserData data; - struct PortMapping * pm; - - memset(&data, 0, sizeof(data)); - ParsePortListing(portListingXml, portListingXmlLen, &data); - for(i = 0, pm = data.l_head; - (pm != NULL) && (i < count); - i++, pm = pm->l_next) { - printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", - i, pm->protocol, pm->externalPort, pm->internalClient, - pm->internalPort, - pm->description, pm->remoteHost, - (unsigned)pm->leaseTime); - if(0 != strcmp(pm->protocol, ref[i].proto)) { - printf("protocol : '%s' != '%s'\n", pm->protocol, ref[i].proto); - r++; - } - if(pm->externalPort != ref[i].externalport) { - printf("externalPort : %hu != %hu\n", - pm->externalPort, ref[i].externalport); - r++; - } - if(0 != strcmp(pm->internalClient, ref[i].client)) { - printf("client : '%s' != '%s'\n", - pm->internalClient, ref[i].client); - r++; - } - if(pm->internalPort != ref[i].internalport) { - printf("internalPort : %hu != %hu\n", - pm->internalPort, ref[i].internalport); - r++; - } - if(0 != strcmp(pm->description, ref[i].desc)) { - printf("description : '%s' != '%s'\n", - pm->description, ref[i].desc); - r++; - } - if(0 != strcmp(pm->remoteHost, ref[i].remotehost)) { - printf("remoteHost : '%s' != '%s'\n", - pm->remoteHost, ref[i].remotehost); - r++; - } - if((unsigned)pm->leaseTime != ref[i].leasetime) { - printf("leaseTime : %u != %u\n", - (unsigned)pm->leaseTime, ref[i].leasetime); - r++; - } - if(pm->enabled != ref[i].enabled) { - printf("enabled : %d != %d\n", - (int)pm->enabled, (int)ref[i].enabled); - r++; - } - } - if((i != count) || (pm != NULL)) { - printf("count mismatch : i=%d count=%d pm=%p\n", i, count, pm); - r++; - } - FreePortListing(&data); - return r; -} - -const char test_document[] = -"\n" -"\n" -" \n" -" \n" -" 5002\n" -" UDP\n" -" 4001\n" -" 192.168.1.123\n" -" 1\n" -" xxx\n" -" 0\n" -" \n" -" \n" -" 202.233.2.1\n" -" 2345\n" -" TCP\n" -" 2349\n" -" 192.168.1.137\n" -" 1\n" -" dooom\n" -" 346\n" -" \n" -" \n" -" 134.231.2.11\n" -" 12345\n" -" TCP\n" -" 12345\n" -" 192.168.1.137\n" -" 1\n" -" dooom A\n" -" 347\n" -" \n" -""; - -#define PORT_MAPPINGS_COUNT 3 -const struct port_mapping port_mappings[PORT_MAPPINGS_COUNT] = { -{347, 12345, 12345, "134.231.2.11", "192.168.1.137", "TCP", "dooom A", 1}, -{346, 2345, 2349, "202.233.2.1", "192.168.1.137", "TCP", "dooom", 1}, -{0, 5002, 4001, "", "192.168.1.123", "UDP", "xxx", 1} -}; - -/* --- main --- */ -int main(void) -{ - int r; - r = test(test_document, sizeof(test_document) - 1, - port_mappings, PORT_MAPPINGS_COUNT); - if(r == 0) { - printf("test of portlistingparse OK\n"); - return 0; - } else { - printf("test FAILED (%d differences counted)\n", r); - return 1; - } -} - diff --git a/zto/ext/miniupnpc/testreplyparse/DeletePortMapping.namevalue b/zto/ext/miniupnpc/testreplyparse/DeletePortMapping.namevalue deleted file mode 100644 index 48ca0cc..0000000 --- a/zto/ext/miniupnpc/testreplyparse/DeletePortMapping.namevalue +++ /dev/null @@ -1,3 +0,0 @@ -NewRemoteHost= -NewExternalPort=123 -NewProtocol=TCP diff --git a/zto/ext/miniupnpc/testreplyparse/DeletePortMapping.xml b/zto/ext/miniupnpc/testreplyparse/DeletePortMapping.xml deleted file mode 100644 index a955c53..0000000 --- a/zto/ext/miniupnpc/testreplyparse/DeletePortMapping.xml +++ /dev/null @@ -1,6 +0,0 @@ - -123 -TCP - - - diff --git a/zto/ext/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue b/zto/ext/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue deleted file mode 100644 index 5aa75f8..0000000 --- a/zto/ext/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue +++ /dev/null @@ -1,2 +0,0 @@ -NewExternalIPAddress=1.2.3.4 - diff --git a/zto/ext/miniupnpc/testreplyparse/GetExternalIPAddress.xml b/zto/ext/miniupnpc/testreplyparse/GetExternalIPAddress.xml deleted file mode 100644 index db7ec1f..0000000 --- a/zto/ext/miniupnpc/testreplyparse/GetExternalIPAddress.xml +++ /dev/null @@ -1,2 +0,0 @@ -1.2.3.4 - diff --git a/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue b/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue deleted file mode 100644 index 26b169c..0000000 --- a/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue +++ /dev/null @@ -1,3 +0,0 @@ -NewProtocol=UDP -NewExternalPort=12345 -NewRemoteHost= diff --git a/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml b/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml deleted file mode 100644 index bbb540e..0000000 --- a/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml +++ /dev/null @@ -1,3 +0,0 @@ - -12345UDP - diff --git a/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue b/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue deleted file mode 100644 index 2189789..0000000 --- a/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue +++ /dev/null @@ -1,5 +0,0 @@ -NewInternalPort=12345 -NewInternalClient=192.168.10.110 -NewEnabled=1 -NewPortMappingDescription=libminiupnpc -NewLeaseDuration=0 diff --git a/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml b/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml deleted file mode 100644 index 77e8d9c..0000000 --- a/zto/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml +++ /dev/null @@ -1,2 +0,0 @@ -12345192.168.10.1101libminiupnpc0 - diff --git a/zto/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue b/zto/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue deleted file mode 100644 index f78c7e2..0000000 --- a/zto/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue +++ /dev/null @@ -1 +0,0 @@ -NewDefaultConnectionService=uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID diff --git a/zto/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.xml b/zto/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.xml deleted file mode 100644 index ac04c07..0000000 --- a/zto/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.xml +++ /dev/null @@ -1 +0,0 @@ -uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID diff --git a/zto/ext/miniupnpc/testreplyparse/readme.txt b/zto/ext/miniupnpc/testreplyparse/readme.txt deleted file mode 100644 index 3eb1f01..0000000 --- a/zto/ext/miniupnpc/testreplyparse/readme.txt +++ /dev/null @@ -1,7 +0,0 @@ -This directory contains files used for validation of upnpreplyparse.c code. - -Each .xml file to parse should give the results which are in the .namevalue -file. - -A .namevalue file contain name=value lines. - diff --git a/zto/ext/miniupnpc/testupnpigd.py b/zto/ext/miniupnpc/testupnpigd.py deleted file mode 100755 index 6d167a4..0000000 --- a/zto/ext/miniupnpc/testupnpigd.py +++ /dev/null @@ -1,84 +0,0 @@ -#! /usr/bin/python -# $Id: testupnpigd.py,v 1.4 2008/10/11 10:27:20 nanard Exp $ -# MiniUPnP project -# Author : Thomas Bernard -# This Sample code is public domain. -# website : http://miniupnp.tuxfamily.org/ - -# import the python miniupnpc module -import miniupnpc -import socket -import BaseHTTPServer - -# function definition -def list_redirections(): - i = 0 - while True: - p = u.getgenericportmapping(i) - if p==None: - break - print i, p - i = i + 1 - -#define the handler class for HTTP connections -class handler_class(BaseHTTPServer.BaseHTTPRequestHandler): - def do_GET(self): - self.send_response(200) - self.end_headers() - self.wfile.write("OK MON GARS") - -# create the object -u = miniupnpc.UPnP() -#print 'inital(default) values :' -#print ' discoverdelay', u.discoverdelay -#print ' lanaddr', u.lanaddr -#print ' multicastif', u.multicastif -#print ' minissdpdsocket', u.minissdpdsocket -u.discoverdelay = 200; - -try: - print 'Discovering... delay=%ums' % u.discoverdelay - ndevices = u.discover() - print ndevices, 'device(s) detected' - - # select an igd - u.selectigd() - # display information about the IGD and the internet connection - print 'local ip address :', u.lanaddr - externalipaddress = u.externalipaddress() - print 'external ip address :', externalipaddress - print u.statusinfo(), u.connectiontype() - - #instanciate a HTTPd object. The port is assigned by the system. - httpd = BaseHTTPServer.HTTPServer((u.lanaddr, 0), handler_class) - eport = httpd.server_port - - # find a free port for the redirection - r = u.getspecificportmapping(eport, 'TCP') - while r != None and eport < 65536: - eport = eport + 1 - r = u.getspecificportmapping(eport, 'TCP') - - print 'trying to redirect %s port %u TCP => %s port %u TCP' % (externalipaddress, eport, u.lanaddr, httpd.server_port) - - b = u.addportmapping(eport, 'TCP', u.lanaddr, httpd.server_port, - 'UPnP IGD Tester port %u' % eport, '') - if b: - print 'Success. Now waiting for some HTTP request on http://%s:%u' % (externalipaddress ,eport) - try: - httpd.handle_request() - httpd.server_close() - except KeyboardInterrupt, details: - print "CTRL-C exception!", details - b = u.deleteportmapping(eport, 'TCP') - if b: - print 'Successfully deleted port mapping' - else: - print 'Failed to remove port mapping' - else: - print 'Failed' - - httpd.server_close() - -except Exception, e: - print 'Exception :', e diff --git a/zto/ext/miniupnpc/testupnpreplyparse.c b/zto/ext/miniupnpc/testupnpreplyparse.c deleted file mode 100644 index 7ba7131..0000000 --- a/zto/ext/miniupnpc/testupnpreplyparse.c +++ /dev/null @@ -1,96 +0,0 @@ -/* $Id: testupnpreplyparse.c,v 1.4 2014/01/27 11:45:19 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2014 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ -#include -#include -#include -#include "upnpreplyparse.h" - -int -test_parsing(const char * buf, int len, FILE * f) -{ - char line[1024]; - struct NameValueParserData pdata; - int ok = 1; - ParseNameValue(buf, len, &pdata); - /* check result */ - if(f != NULL) - { - while(fgets(line, sizeof(line), f)) - { - char * value; - char * equal; - char * parsedvalue; - int l; - l = strlen(line); - while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n'))) - line[--l] = '\0'; - /* skip empty lines */ - if(l == 0) - continue; - equal = strchr(line, '='); - if(equal == NULL) - { - fprintf(stderr, "Warning, line does not contain '=' : %s\n", line); - continue; - } - *equal = '\0'; - value = equal + 1; - parsedvalue = GetValueFromNameValueList(&pdata, line); - if((parsedvalue == NULL) || (strcmp(parsedvalue, value) != 0)) - { - fprintf(stderr, "Element <%s> : expecting value '%s', got '%s'\n", - line, value, parsedvalue ? parsedvalue : ""); - ok = 0; - } - } - } - ClearNameValueList(&pdata); - return ok; -} - -int main(int argc, char * * argv) -{ - FILE * f; - char buffer[4096]; - int l; - int ok; - - if(argc<2) - { - fprintf(stderr, "Usage: %s file.xml [file.namevalues]\n", argv[0]); - return 1; - } - f = fopen(argv[1], "r"); - if(!f) - { - fprintf(stderr, "Error : can not open file %s\n", argv[1]); - return 2; - } - l = fread(buffer, 1, sizeof(buffer)-1, f); - fclose(f); - f = NULL; - buffer[l] = '\0'; - if(argc > 2) - { - f = fopen(argv[2], "r"); - if(!f) - { - fprintf(stderr, "Error : can not open file %s\n", argv[2]); - return 2; - } - } -#ifdef DEBUG - DisplayNameValueList(buffer, l); -#endif - ok = test_parsing(buffer, l, f); - if(f) - { - fclose(f); - } - return ok ? 0 : 3; -} - diff --git a/zto/ext/miniupnpc/testupnpreplyparse.sh b/zto/ext/miniupnpc/testupnpreplyparse.sh deleted file mode 100755 index 992930b..0000000 --- a/zto/ext/miniupnpc/testupnpreplyparse.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -for f in testreplyparse/*.xml ; do - bf="`dirname $f`/`basename $f .xml`" - if ./testupnpreplyparse $f $bf.namevalue ; then - echo "$f : passed" - else - echo "$f : FAILED" - exit 1 - fi -done - -exit 0 - diff --git a/zto/ext/miniupnpc/updateminiupnpcstrings.sh b/zto/ext/miniupnpc/updateminiupnpcstrings.sh deleted file mode 100755 index dde4354..0000000 --- a/zto/ext/miniupnpc/updateminiupnpcstrings.sh +++ /dev/null @@ -1,53 +0,0 @@ -#! /bin/sh -# $Id: updateminiupnpcstrings.sh,v 1.7 2011/01/04 11:41:53 nanard Exp $ -# project miniupnp : http://miniupnp.free.fr/ -# (c) 2009 Thomas Bernard - -FILE=miniupnpcstrings.h -TMPFILE=miniupnpcstrings.h.tmp -TEMPLATE_FILE=${FILE}.in - -# detecting the OS name and version -OS_NAME=`uname -s` -OS_VERSION=`uname -r` -if [ -f /etc/debian_version ]; then - OS_NAME=Debian - OS_VERSION=`cat /etc/debian_version` -fi -# use lsb_release (Linux Standard Base) when available -LSB_RELEASE=`which lsb_release` -if [ 0 -eq $? -a -x "${LSB_RELEASE}" ]; then - OS_NAME=`${LSB_RELEASE} -i -s` - OS_VERSION=`${LSB_RELEASE} -r -s` - case $OS_NAME in - Debian) - #OS_VERSION=`${LSB_RELEASE} -c -s` - ;; - Ubuntu) - #OS_VERSION=`${LSB_RELEASE} -c -s` - ;; - esac -fi - -# on AmigaOS 3, uname -r returns "unknown", so we use uname -v -if [ "$OS_NAME" = "AmigaOS" ]; then - if [ "$OS_VERSION" = "unknown" ]; then - OS_VERSION=`uname -v` - fi -fi - -echo "Detected OS [$OS_NAME] version [$OS_VERSION]" -MINIUPNPC_VERSION=`cat VERSION` -echo "MiniUPnPc version [${MINIUPNPC_VERSION}]" - -EXPR="s|OS_STRING \".*\"|OS_STRING \"${OS_NAME}/${OS_VERSION}\"|" -#echo $EXPR -test -f ${FILE}.in -echo "setting OS_STRING macro value to ${OS_NAME}/${OS_VERSION} in $FILE." -sed -e "$EXPR" < $TEMPLATE_FILE > $TMPFILE - -EXPR="s|MINIUPNPC_VERSION_STRING \".*\"|MINIUPNPC_VERSION_STRING \"${MINIUPNPC_VERSION}\"|" -echo "setting MINIUPNPC_VERSION_STRING macro value to ${MINIUPNPC_VERSION} in $FILE." -sed -e "$EXPR" < $TMPFILE > $FILE -rm $TMPFILE - diff --git a/zto/ext/miniupnpc/upnpc.c b/zto/ext/miniupnpc/upnpc.c deleted file mode 100644 index 8e7edad..0000000 --- a/zto/ext/miniupnpc/upnpc.c +++ /dev/null @@ -1,855 +0,0 @@ -/* $Id: upnpc.c,v 1.115 2016/10/07 09:04:01 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005-2016 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ - -#include -#include -#include -#include -#ifdef _WIN32 -#include -#define snprintf _snprintf -#else -/* for IPPROTO_TCP / IPPROTO_UDP */ -#include -#endif -#include -#include "miniwget.h" -#include "miniupnpc.h" -#include "upnpcommands.h" -#include "upnperrors.h" -#include "miniupnpcstrings.h" - -/* protofix() checks if protocol is "UDP" or "TCP" - * returns NULL if not */ -const char * protofix(const char * proto) -{ - static const char proto_tcp[4] = { 'T', 'C', 'P', 0}; - static const char proto_udp[4] = { 'U', 'D', 'P', 0}; - int i, b; - for(i=0, b=1; i<4; i++) - b = b && ( (proto[i] == proto_tcp[i]) - || (proto[i] == (proto_tcp[i] | 32)) ); - if(b) - return proto_tcp; - for(i=0, b=1; i<4; i++) - b = b && ( (proto[i] == proto_udp[i]) - || (proto[i] == (proto_udp[i] | 32)) ); - if(b) - return proto_udp; - return 0; -} - -/* is_int() checks if parameter is an integer or not - * 1 for integer - * 0 for not an integer */ -int is_int(char const* s) -{ - if(s == NULL) - return 0; - while(*s) { - /* #define isdigit(c) ((c) >= '0' && (c) <= '9') */ - if(!isdigit(*s)) - return 0; - s++; - } - return 1; -} - -static void DisplayInfos(struct UPNPUrls * urls, - struct IGDdatas * data) -{ - char externalIPAddress[40]; - char connectionType[64]; - char status[64]; - char lastconnerr[64]; - unsigned int uptime = 0; - unsigned int brUp, brDown; - time_t timenow, timestarted; - int r; - if(UPNP_GetConnectionTypeInfo(urls->controlURL, - data->first.servicetype, - connectionType) != UPNPCOMMAND_SUCCESS) - printf("GetConnectionTypeInfo failed.\n"); - else - printf("Connection Type : %s\n", connectionType); - if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, - status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS) - printf("GetStatusInfo failed.\n"); - else - printf("Status : %s, uptime=%us, LastConnectionError : %s\n", - status, uptime, lastconnerr); - if(uptime > 0) { - timenow = time(NULL); - timestarted = timenow - uptime; - printf(" Time started : %s", ctime(×tarted)); - } - if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, - &brDown, &brUp) != UPNPCOMMAND_SUCCESS) { - printf("GetLinkLayerMaxBitRates failed.\n"); - } else { - printf("MaxBitRateDown : %u bps", brDown); - if(brDown >= 1000000) { - printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10); - } else if(brDown >= 1000) { - printf(" (%u Kbps)", brDown / 1000); - } - printf(" MaxBitRateUp %u bps", brUp); - if(brUp >= 1000000) { - printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10); - } else if(brUp >= 1000) { - printf(" (%u Kbps)", brUp / 1000); - } - printf("\n"); - } - r = UPNP_GetExternalIPAddress(urls->controlURL, - data->first.servicetype, - externalIPAddress); - if(r != UPNPCOMMAND_SUCCESS) { - printf("GetExternalIPAddress failed. (errorcode=%d)\n", r); - } else { - printf("ExternalIPAddress = %s\n", externalIPAddress); - } -} - -static void GetConnectionStatus(struct UPNPUrls * urls, - struct IGDdatas * data) -{ - unsigned int bytessent, bytesreceived, packetsreceived, packetssent; - DisplayInfos(urls, data); - bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); - bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); - packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); - packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); - printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); - printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); -} - -static void ListRedirections(struct UPNPUrls * urls, - struct IGDdatas * data) -{ - int r; - int i = 0; - char index[6]; - char intClient[40]; - char intPort[6]; - char extPort[6]; - char protocol[4]; - char desc[80]; - char enabled[6]; - char rHost[64]; - char duration[16]; - /*unsigned int num=0; - UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num); - printf("PortMappingNumberOfEntries : %u\n", num);*/ - printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); - do { - snprintf(index, 6, "%d", i); - rHost[0] = '\0'; enabled[0] = '\0'; - duration[0] = '\0'; desc[0] = '\0'; - extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; - r = UPNP_GetGenericPortMappingEntry(urls->controlURL, - data->first.servicetype, - index, - extPort, intClient, intPort, - protocol, desc, enabled, - rHost, duration); - if(r==0) - /* - printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n" - " desc='%s' rHost='%s'\n", - i, protocol, extPort, intClient, intPort, - enabled, duration, - desc, rHost); - */ - printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n", - i, protocol, extPort, intClient, intPort, - desc, rHost, duration); - else - printf("GetGenericPortMappingEntry() returned %d (%s)\n", - r, strupnperror(r)); - i++; - } while(r==0); -} - -static void NewListRedirections(struct UPNPUrls * urls, - struct IGDdatas * data) -{ - int r; - int i = 0; - struct PortMappingParserData pdata; - struct PortMapping * pm; - - memset(&pdata, 0, sizeof(struct PortMappingParserData)); - r = UPNP_GetListOfPortMappings(urls->controlURL, - data->first.servicetype, - "0", - "65535", - "TCP", - "1000", - &pdata); - if(r == UPNPCOMMAND_SUCCESS) - { - printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); - for(pm = pdata.l_head; pm != NULL; pm = pm->l_next) - { - printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", - i, pm->protocol, pm->externalPort, pm->internalClient, - pm->internalPort, - pm->description, pm->remoteHost, - (unsigned)pm->leaseTime); - i++; - } - FreePortListing(&pdata); - } - else - { - printf("GetListOfPortMappings() returned %d (%s)\n", - r, strupnperror(r)); - } - r = UPNP_GetListOfPortMappings(urls->controlURL, - data->first.servicetype, - "0", - "65535", - "UDP", - "1000", - &pdata); - if(r == UPNPCOMMAND_SUCCESS) - { - for(pm = pdata.l_head; pm != NULL; pm = pm->l_next) - { - printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", - i, pm->protocol, pm->externalPort, pm->internalClient, - pm->internalPort, - pm->description, pm->remoteHost, - (unsigned)pm->leaseTime); - i++; - } - FreePortListing(&pdata); - } - else - { - printf("GetListOfPortMappings() returned %d (%s)\n", - r, strupnperror(r)); - } -} - -/* Test function - * 1 - get connection type - * 2 - get extenal ip address - * 3 - Add port mapping - * 4 - get this port mapping from the IGD */ -static int SetRedirectAndTest(struct UPNPUrls * urls, - struct IGDdatas * data, - const char * iaddr, - const char * iport, - const char * eport, - const char * proto, - const char * leaseDuration, - const char * description, - int addAny) -{ - char externalIPAddress[40]; - char intClient[40]; - char intPort[6]; - char reservedPort[6]; - char duration[16]; - int r; - - if(!iaddr || !iport || !eport || !proto) - { - fprintf(stderr, "Wrong arguments\n"); - return -1; - } - proto = protofix(proto); - if(!proto) - { - fprintf(stderr, "invalid protocol\n"); - return -1; - } - - r = UPNP_GetExternalIPAddress(urls->controlURL, - data->first.servicetype, - externalIPAddress); - if(r!=UPNPCOMMAND_SUCCESS) - printf("GetExternalIPAddress failed.\n"); - else - printf("ExternalIPAddress = %s\n", externalIPAddress); - - if (addAny) { - r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype, - eport, iport, iaddr, description, - proto, 0, leaseDuration, reservedPort); - if(r==UPNPCOMMAND_SUCCESS) - eport = reservedPort; - else - printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n", - eport, iport, iaddr, r, strupnperror(r)); - } else { - r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, - eport, iport, iaddr, description, - proto, 0, leaseDuration); - if(r!=UPNPCOMMAND_SUCCESS) - printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", - eport, iport, iaddr, r, strupnperror(r)); - } - - r = UPNP_GetSpecificPortMappingEntry(urls->controlURL, - data->first.servicetype, - eport, proto, NULL/*remoteHost*/, - intClient, intPort, NULL/*desc*/, - NULL/*enabled*/, duration); - if(r!=UPNPCOMMAND_SUCCESS) { - printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n", - r, strupnperror(r)); - return -2; - } else { - printf("InternalIP:Port = %s:%s\n", intClient, intPort); - printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n", - externalIPAddress, eport, proto, intClient, intPort, duration); - } - return 0; -} - -static int -RemoveRedirect(struct UPNPUrls * urls, - struct IGDdatas * data, - const char * eport, - const char * proto, - const char * remoteHost) -{ - int r; - if(!proto || !eport) - { - fprintf(stderr, "invalid arguments\n"); - return -1; - } - proto = protofix(proto); - if(!proto) - { - fprintf(stderr, "protocol invalid\n"); - return -1; - } - r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost); - if(r!=UPNPCOMMAND_SUCCESS) { - printf("UPNP_DeletePortMapping() failed with code : %d\n", r); - return -2; - }else { - printf("UPNP_DeletePortMapping() returned : %d\n", r); - } - return 0; -} - -static int -RemoveRedirectRange(struct UPNPUrls * urls, - struct IGDdatas * data, - const char * ePortStart, char const * ePortEnd, - const char * proto, const char * manage) -{ - int r; - - if (!manage) - manage = "0"; - - if(!proto || !ePortStart || !ePortEnd) - { - fprintf(stderr, "invalid arguments\n"); - return -1; - } - proto = protofix(proto); - if(!proto) - { - fprintf(stderr, "protocol invalid\n"); - return -1; - } - r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage); - if(r!=UPNPCOMMAND_SUCCESS) { - printf("UPNP_DeletePortMappingRange() failed with code : %d\n", r); - return -2; - }else { - printf("UPNP_DeletePortMappingRange() returned : %d\n", r); - } - return 0; -} - -/* IGD:2, functions for service WANIPv6FirewallControl:1 */ -static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data) -{ - unsigned int bytessent, bytesreceived, packetsreceived, packetssent; - int firewallEnabled = 0, inboundPinholeAllowed = 0; - - UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed); - printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed); - printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No"); - - bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); - bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); - packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); - packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); - printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); - printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); -} - -/* Test function - * 1 - Add pinhole - * 2 - Check if pinhole is working from the IGD side */ -static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data, - const char * remoteaddr, const char * eport, - const char * intaddr, const char * iport, - const char * proto, const char * lease_time) -{ - char uniqueID[8]; - /*int isWorking = 0;*/ - int r; - char proto_tmp[8]; - - if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time) - { - fprintf(stderr, "Wrong arguments\n"); - return; - } - if(atoi(proto) == 0) - { - const char * protocol; - protocol = protofix(proto); - if(protocol && (strcmp("TCP", protocol) == 0)) - { - snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP); - proto = proto_tmp; - } - else if(protocol && (strcmp("UDP", protocol) == 0)) - { - snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP); - proto = proto_tmp; - } - else - { - fprintf(stderr, "invalid protocol\n"); - return; - } - } - r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID); - if(r!=UPNPCOMMAND_SUCCESS) - printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", - remoteaddr, eport, intaddr, iport, r, strupnperror(r)); - else - { - printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n", - remoteaddr, eport, intaddr, iport, uniqueID); - /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking); - if(r!=UPNPCOMMAND_SUCCESS) - printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); - printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/ - } -} - -/* Test function - * 1 - Check if pinhole is working from the IGD side - * 2 - Update pinhole */ -static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data, - const char * uniqueID, const char * lease_time) -{ - int isWorking = 0; - int r; - - if(!uniqueID || !lease_time) - { - fprintf(stderr, "Wrong arguments\n"); - return; - } - r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); - printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); - if(r!=UPNPCOMMAND_SUCCESS) - printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); - if(isWorking || r==709) - { - r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time); - printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time); - if(r!=UPNPCOMMAND_SUCCESS) - printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r)); - } -} - -/* Test function - * Get pinhole timeout - */ -static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data, - const char * remoteaddr, const char * eport, - const char * intaddr, const char * iport, - const char * proto) -{ - int timeout = 0; - int r; - - if(!intaddr || !remoteaddr || !iport || !eport || !proto) - { - fprintf(stderr, "Wrong arguments\n"); - return; - } - - r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout); - if(r!=UPNPCOMMAND_SUCCESS) - printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", - intaddr, iport, remoteaddr, eport, r, strupnperror(r)); - else - printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout); -} - -static void -GetPinholePackets(struct UPNPUrls * urls, - struct IGDdatas * data, const char * uniqueID) -{ - int r, pinholePackets = 0; - if(!uniqueID) - { - fprintf(stderr, "invalid arguments\n"); - return; - } - r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets); - if(r!=UPNPCOMMAND_SUCCESS) - printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r)); - else - printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets); -} - -static void -CheckPinhole(struct UPNPUrls * urls, - struct IGDdatas * data, const char * uniqueID) -{ - int r, isWorking = 0; - if(!uniqueID) - { - fprintf(stderr, "invalid arguments\n"); - return; - } - r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); - if(r!=UPNPCOMMAND_SUCCESS) - printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); - else - printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); -} - -static void -RemovePinhole(struct UPNPUrls * urls, - struct IGDdatas * data, const char * uniqueID) -{ - int r; - if(!uniqueID) - { - fprintf(stderr, "invalid arguments\n"); - return; - } - r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID); - printf("UPNP_DeletePinhole() returned : %d\n", r); -} - - -/* sample upnp client program */ -int main(int argc, char ** argv) -{ - char command = 0; - char ** commandargv = 0; - int commandargc = 0; - struct UPNPDev * devlist = 0; - char lanaddr[64] = "unset"; /* my ip address on the LAN */ - int i; - const char * rootdescurl = 0; - const char * multicastif = 0; - const char * minissdpdpath = 0; - int localport = UPNP_LOCAL_PORT_ANY; - int retcode = 0; - int error = 0; - int ipv6 = 0; - unsigned char ttl = 2; /* defaulting to 2 */ - const char * description = 0; - -#ifdef _WIN32 - WSADATA wsaData; - int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); - if(nResult != NO_ERROR) - { - fprintf(stderr, "WSAStartup() failed.\n"); - return -1; - } -#endif - printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING); - printf(" (c) 2005-2016 Thomas Bernard.\n"); - printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" - "for more information.\n"); - /* command line processing */ - for(i=1; i65535 || - (localport >1 && localport < 1024)) - { - fprintf(stderr, "Invalid localport '%s'\n", argv[i]); - localport = UPNP_LOCAL_PORT_ANY; - break; - } - } - else if(argv[i][1] == 'p') - minissdpdpath = argv[++i]; - else if(argv[i][1] == '6') - ipv6 = 1; - else if(argv[i][1] == 'e') - description = argv[++i]; - else if(argv[i][1] == 't') - ttl = (unsigned char)atoi(argv[++i]); - else - { - command = argv[i][1]; - i++; - commandargv = argv + i; - commandargc = argc - i; - break; - } - } - else - { - fprintf(stderr, "option '%s' invalid\n", argv[i]); - } - } - - if(!command - || (command == 'a' && commandargc<4) - || (command == 'd' && argc<2) - || (command == 'r' && argc<2) - || (command == 'A' && commandargc<6) - || (command == 'U' && commandargc<2) - || (command == 'D' && commandargc<1)) - { - fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration]\n\t\tAdd port redirection\n", argv[0]); - fprintf(stderr, " \t%s [options] -d external_port protocol \n\t\tDelete port redirection\n", argv[0]); - fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]); - fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]); - fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]); - fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]); - fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]); - fprintf(stderr, " \t%s [options] -r port1 [external_port1] protocol1 [port2 [external_port2] protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]); - fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]); - fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]); - fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]); - fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]); - fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]); - fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]); - fprintf(stderr, " \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]); - fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]); - fprintf(stderr, "\nprotocol is UDP or TCP\n"); - fprintf(stderr, "Options:\n"); - fprintf(stderr, " -e description : set description for port mapping.\n"); - fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n"); - fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n"); - fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n"); - fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n"); - fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n"); - fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n"); - return 1; - } - - if( rootdescurl - || (devlist = upnpDiscover(2000, multicastif, minissdpdpath, - localport, ipv6, ttl, &error))) - { - struct UPNPDev * device; - struct UPNPUrls urls; - struct IGDdatas data; - if(devlist) - { - printf("List of UPNP devices found on the network :\n"); - for(device = devlist; device; device = device->pNext) - { - printf(" desc: %s\n st: %s\n\n", - device->descURL, device->st); - } - } - else if(!rootdescurl) - { - printf("upnpDiscover() error code=%d\n", error); - } - i = 1; - if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr))) - || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))) - { - switch(i) { - case 1: - printf("Found valid IGD : %s\n", urls.controlURL); - break; - case 2: - printf("Found a (not connected?) IGD : %s\n", urls.controlURL); - printf("Trying to continue anyway\n"); - break; - case 3: - printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL); - printf("Trying to continue anyway\n"); - break; - default: - printf("Found device (igd ?) : %s\n", urls.controlURL); - printf("Trying to continue anyway\n"); - } - printf("Local LAN ip address : %s\n", lanaddr); - #if 0 - printf("getting \"%s\"\n", urls.ipcondescURL); - descXML = miniwget(urls.ipcondescURL, &descXMLsize); - if(descXML) - { - /*fwrite(descXML, 1, descXMLsize, stdout);*/ - free(descXML); descXML = NULL; - } - #endif - - switch(command) - { - case 'l': - DisplayInfos(&urls, &data); - ListRedirections(&urls, &data); - break; - case 'L': - NewListRedirections(&urls, &data); - break; - case 'a': - if (SetRedirectAndTest(&urls, &data, - commandargv[0], commandargv[1], - commandargv[2], commandargv[3], - (commandargc > 4)?commandargv[4]:"0", - description, 0) < 0) - retcode = 2; - break; - case 'd': - if (RemoveRedirect(&urls, &data, commandargv[0], commandargv[1], - commandargc > 2 ? commandargv[2] : NULL) < 0) - retcode = 2; - break; - case 'n': /* aNy */ - if (SetRedirectAndTest(&urls, &data, - commandargv[0], commandargv[1], - commandargv[2], commandargv[3], - (commandargc > 4)?commandargv[4]:"0", - description, 1) < 0) - retcode = 2; - break; - case 'N': - if (commandargc < 3) - fprintf(stderr, "too few arguments\n"); - - if (RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2], - commandargc > 3 ? commandargv[3] : NULL) < 0) - retcode = 2; - break; - case 's': - GetConnectionStatus(&urls, &data); - break; - case 'r': - i = 0; - while(i */ - if (SetRedirectAndTest(&urls, &data, - lanaddr, commandargv[i], - commandargv[i+1], commandargv[i+2], "0", - description, 0) < 0) - retcode = 2; - i+=3; /* 3 parameters parsed */ - } else { - /* 2nd parameter not an integer : */ - if (SetRedirectAndTest(&urls, &data, - lanaddr, commandargv[i], - commandargv[i], commandargv[i+1], "0", - description, 0) < 0) - retcode = 2; - i+=2; /* 2 parameters parsed */ - } - } - break; - case 'A': - SetPinholeAndTest(&urls, &data, - commandargv[0], commandargv[1], - commandargv[2], commandargv[3], - commandargv[4], commandargv[5]); - break; - case 'U': - GetPinholeAndUpdate(&urls, &data, - commandargv[0], commandargv[1]); - break; - case 'C': - for(i=0; i -#include -#include -#include "upnpcommands.h" -#include "miniupnpc.h" -#include "portlistingparse.h" - -static UNSIGNED_INTEGER -my_atoui(const char * s) -{ - return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0; -} - -/* - * */ -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesSent(const char * controlURL, - const char * servicetype) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - unsigned int r = 0; - char * p; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetTotalBytesSent", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent"); - r = my_atoui(p); - ClearNameValueList(&pdata); - return r; -} - -/* - * */ -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesReceived(const char * controlURL, - const char * servicetype) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - unsigned int r = 0; - char * p; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetTotalBytesReceived", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived"); - r = my_atoui(p); - ClearNameValueList(&pdata); - return r; -} - -/* - * */ -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsSent(const char * controlURL, - const char * servicetype) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - unsigned int r = 0; - char * p; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetTotalPacketsSent", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent"); - r = my_atoui(p); - ClearNameValueList(&pdata); - return r; -} - -/* - * */ -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsReceived(const char * controlURL, - const char * servicetype) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - unsigned int r = 0; - char * p; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetTotalPacketsReceived", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived"); - r = my_atoui(p); - ClearNameValueList(&pdata); - return r; -} - -/* UPNP_GetStatusInfo() call the corresponding UPNP method - * returns the current status and uptime */ -MINIUPNP_LIBSPEC int -UPNP_GetStatusInfo(const char * controlURL, - const char * servicetype, - char * status, - unsigned int * uptime, - char * lastconnerror) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - char * p; - char * up; - char * err; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!status && !uptime) - return UPNPCOMMAND_INVALID_ARGS; - - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetStatusInfo", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; - up = GetValueFromNameValueList(&pdata, "NewUptime"); - p = GetValueFromNameValueList(&pdata, "NewConnectionStatus"); - err = GetValueFromNameValueList(&pdata, "NewLastConnectionError"); - if(p && up) - ret = UPNPCOMMAND_SUCCESS; - - if(status) { - if(p){ - strncpy(status, p, 64 ); - status[63] = '\0'; - }else - status[0]= '\0'; - } - - if(uptime) { - if(up) - sscanf(up,"%u",uptime); - else - *uptime = 0; - } - - if(lastconnerror) { - if(err) { - strncpy(lastconnerror, err, 64 ); - lastconnerror[63] = '\0'; - } else - lastconnerror[0] = '\0'; - } - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - ClearNameValueList(&pdata); - return ret; -} - -/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method - * returns the connection type */ -MINIUPNP_LIBSPEC int -UPNP_GetConnectionTypeInfo(const char * controlURL, - const char * servicetype, - char * connectionType) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - char * p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!connectionType) - return UPNPCOMMAND_INVALID_ARGS; - - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetConnectionTypeInfo", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "NewConnectionType"); - /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/ - /* PossibleConnectionTypes will have several values.... */ - if(p) { - strncpy(connectionType, p, 64 ); - connectionType[63] = '\0'; - ret = UPNPCOMMAND_SUCCESS; - } else - connectionType[0] = '\0'; - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - ClearNameValueList(&pdata); - return ret; -} - -/* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method. - * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth. - * One of the values can be null - * Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only - * We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */ -MINIUPNP_LIBSPEC int -UPNP_GetLinkLayerMaxBitRates(const char * controlURL, - const char * servicetype, - unsigned int * bitrateDown, - unsigned int * bitrateUp) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - char * down; - char * up; - char * p; - - if(!bitrateDown && !bitrateUp) - return UPNPCOMMAND_INVALID_ARGS; - - /* shouldn't we use GetCommonLinkProperties ? */ - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetCommonLinkProperties", 0, &bufsize))) { - /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/ - return UPNPCOMMAND_HTTP_ERROR; - } - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/ - /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/ - down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate"); - up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate"); - /*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/ - /*GetValueFromNameValueList(&pdata, "NewPhysicalLinkStatus");*/ - if(down && up) - ret = UPNPCOMMAND_SUCCESS; - - if(bitrateDown) { - if(down) - sscanf(down,"%u",bitrateDown); - else - *bitrateDown = 0; - } - - if(bitrateUp) { - if(up) - sscanf(up,"%u",bitrateUp); - else - *bitrateUp = 0; - } - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - ClearNameValueList(&pdata); - return ret; -} - - -/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. - * if the third arg is not null the value is copied to it. - * at least 16 bytes must be available - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR Either an UPnP error code or an unknown error. - * - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - */ -MINIUPNP_LIBSPEC int -UPNP_GetExternalIPAddress(const char * controlURL, - const char * servicetype, - char * extIpAdd) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - char * p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!extIpAdd || !controlURL || !servicetype) - return UPNPCOMMAND_INVALID_ARGS; - - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetExternalIPAddress", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/ - p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress"); - if(p) { - strncpy(extIpAdd, p, 16 ); - extIpAdd[15] = '\0'; - ret = UPNPCOMMAND_SUCCESS; - } else - extIpAdd[0] = '\0'; - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - - ClearNameValueList(&pdata); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_AddPortMapping(const char * controlURL, const char * servicetype, - const char * extPort, - const char * inPort, - const char * inClient, - const char * desc, - const char * proto, - const char * remoteHost, - const char * leaseDuration) -{ - struct UPNParg * AddPortMappingArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - int ret; - - if(!inPort || !inClient || !proto || !extPort) - return UPNPCOMMAND_INVALID_ARGS; - - AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); - if(AddPortMappingArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - AddPortMappingArgs[0].elt = "NewRemoteHost"; - AddPortMappingArgs[0].val = remoteHost; - AddPortMappingArgs[1].elt = "NewExternalPort"; - AddPortMappingArgs[1].val = extPort; - AddPortMappingArgs[2].elt = "NewProtocol"; - AddPortMappingArgs[2].val = proto; - AddPortMappingArgs[3].elt = "NewInternalPort"; - AddPortMappingArgs[3].val = inPort; - AddPortMappingArgs[4].elt = "NewInternalClient"; - AddPortMappingArgs[4].val = inClient; - AddPortMappingArgs[5].elt = "NewEnabled"; - AddPortMappingArgs[5].val = "1"; - AddPortMappingArgs[6].elt = "NewPortMappingDescription"; - AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; - AddPortMappingArgs[7].elt = "NewLeaseDuration"; - AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "AddPortMapping", AddPortMappingArgs, - &bufsize))) { - free(AddPortMappingArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - /*DisplayNameValueList(buffer, bufsize);*/ - /*buffer[bufsize] = '\0';*/ - /*puts(buffer);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) { - /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } else { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(AddPortMappingArgs); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, - const char * extPort, - const char * inPort, - const char * inClient, - const char * desc, - const char * proto, - const char * remoteHost, - const char * leaseDuration, - char * reservedPort) -{ - struct UPNParg * AddPortMappingArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - int ret; - - if(!inPort || !inClient || !proto || !extPort) - return UPNPCOMMAND_INVALID_ARGS; - - AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); - if(AddPortMappingArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - AddPortMappingArgs[0].elt = "NewRemoteHost"; - AddPortMappingArgs[0].val = remoteHost; - AddPortMappingArgs[1].elt = "NewExternalPort"; - AddPortMappingArgs[1].val = extPort; - AddPortMappingArgs[2].elt = "NewProtocol"; - AddPortMappingArgs[2].val = proto; - AddPortMappingArgs[3].elt = "NewInternalPort"; - AddPortMappingArgs[3].val = inPort; - AddPortMappingArgs[4].elt = "NewInternalClient"; - AddPortMappingArgs[4].val = inClient; - AddPortMappingArgs[5].elt = "NewEnabled"; - AddPortMappingArgs[5].val = "1"; - AddPortMappingArgs[6].elt = "NewPortMappingDescription"; - AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; - AddPortMappingArgs[7].elt = "NewLeaseDuration"; - AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "AddAnyPortMapping", AddPortMappingArgs, - &bufsize))) { - free(AddPortMappingArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } else { - char *p; - - p = GetValueFromNameValueList(&pdata, "NewReservedPort"); - if(p) { - strncpy(reservedPort, p, 6); - reservedPort[5] = '\0'; - ret = UPNPCOMMAND_SUCCESS; - } else { - ret = UPNPCOMMAND_INVALID_RESPONSE; - } - } - ClearNameValueList(&pdata); - free(AddPortMappingArgs); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, - const char * extPort, const char * proto, - const char * remoteHost) -{ - /*struct NameValueParserData pdata;*/ - struct UPNParg * DeletePortMappingArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - int ret; - - if(!extPort || !proto) - return UPNPCOMMAND_INVALID_ARGS; - - DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg)); - if(DeletePortMappingArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - DeletePortMappingArgs[0].elt = "NewRemoteHost"; - DeletePortMappingArgs[0].val = remoteHost; - DeletePortMappingArgs[1].elt = "NewExternalPort"; - DeletePortMappingArgs[1].val = extPort; - DeletePortMappingArgs[2].elt = "NewProtocol"; - DeletePortMappingArgs[2].val = proto; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "DeletePortMapping", - DeletePortMappingArgs, &bufsize))) { - free(DeletePortMappingArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } else { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(DeletePortMappingArgs); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, - const char * extPortStart, const char * extPortEnd, - const char * proto, - const char * manage) -{ - struct UPNParg * DeletePortMappingArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - int ret; - - if(!extPortStart || !extPortEnd || !proto || !manage) - return UPNPCOMMAND_INVALID_ARGS; - - DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg)); - if(DeletePortMappingArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - DeletePortMappingArgs[0].elt = "NewStartPort"; - DeletePortMappingArgs[0].val = extPortStart; - DeletePortMappingArgs[1].elt = "NewEndPort"; - DeletePortMappingArgs[1].val = extPortEnd; - DeletePortMappingArgs[2].elt = "NewProtocol"; - DeletePortMappingArgs[2].val = proto; - DeletePortMappingArgs[3].elt = "NewManage"; - DeletePortMappingArgs[3].val = manage; - - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "DeletePortMappingRange", - DeletePortMappingArgs, &bufsize))) { - free(DeletePortMappingArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } else { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(DeletePortMappingArgs); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_GetGenericPortMappingEntry(const char * controlURL, - const char * servicetype, - const char * index, - char * extPort, - char * intClient, - char * intPort, - char * protocol, - char * desc, - char * enabled, - char * rHost, - char * duration) -{ - struct NameValueParserData pdata; - struct UPNParg * GetPortMappingArgs; - char * buffer; - int bufsize; - char * p; - int r = UPNPCOMMAND_UNKNOWN_ERROR; - if(!index) - return UPNPCOMMAND_INVALID_ARGS; - intClient[0] = '\0'; - intPort[0] = '\0'; - GetPortMappingArgs = calloc(2, sizeof(struct UPNParg)); - if(GetPortMappingArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - GetPortMappingArgs[0].elt = "NewPortMappingIndex"; - GetPortMappingArgs[0].val = index; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetGenericPortMappingEntry", - GetPortMappingArgs, &bufsize))) { - free(GetPortMappingArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - p = GetValueFromNameValueList(&pdata, "NewRemoteHost"); - if(p && rHost) - { - strncpy(rHost, p, 64); - rHost[63] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "NewExternalPort"); - if(p && extPort) - { - strncpy(extPort, p, 6); - extPort[5] = '\0'; - r = UPNPCOMMAND_SUCCESS; - } - p = GetValueFromNameValueList(&pdata, "NewProtocol"); - if(p && protocol) - { - strncpy(protocol, p, 4); - protocol[3] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "NewInternalClient"); - if(p) - { - strncpy(intClient, p, 16); - intClient[15] = '\0'; - r = 0; - } - p = GetValueFromNameValueList(&pdata, "NewInternalPort"); - if(p) - { - strncpy(intPort, p, 6); - intPort[5] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "NewEnabled"); - if(p && enabled) - { - strncpy(enabled, p, 4); - enabled[3] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); - if(p && desc) - { - strncpy(desc, p, 80); - desc[79] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); - if(p && duration) - { - strncpy(duration, p, 16); - duration[15] = '\0'; - } - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - r = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &r); - } - ClearNameValueList(&pdata); - free(GetPortMappingArgs); - return r; -} - -MINIUPNP_LIBSPEC int -UPNP_GetPortMappingNumberOfEntries(const char * controlURL, - const char * servicetype, - unsigned int * numEntries) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - char* p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetPortMappingNumberOfEntries", 0, - &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; - } -#ifdef DEBUG - DisplayNameValueList(buffer, bufsize); -#endif - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); - if(numEntries && p) { - *numEntries = 0; - sscanf(p, "%u", numEntries); - ret = UPNPCOMMAND_SUCCESS; - } - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - - ClearNameValueList(&pdata); - return ret; -} - -/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping - * the result is returned in the intClient and intPort strings - * please provide 16 and 6 bytes of data */ -MINIUPNP_LIBSPEC int -UPNP_GetSpecificPortMappingEntry(const char * controlURL, - const char * servicetype, - const char * extPort, - const char * proto, - const char * remoteHost, - char * intClient, - char * intPort, - char * desc, - char * enabled, - char * leaseDuration) -{ - struct NameValueParserData pdata; - struct UPNParg * GetPortMappingArgs; - char * buffer; - int bufsize; - char * p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!intPort || !intClient || !extPort || !proto) - return UPNPCOMMAND_INVALID_ARGS; - - GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); - if(GetPortMappingArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - GetPortMappingArgs[0].elt = "NewRemoteHost"; - GetPortMappingArgs[0].val = remoteHost; - GetPortMappingArgs[1].elt = "NewExternalPort"; - GetPortMappingArgs[1].val = extPort; - GetPortMappingArgs[2].elt = "NewProtocol"; - GetPortMappingArgs[2].val = proto; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetSpecificPortMappingEntry", - GetPortMappingArgs, &bufsize))) { - free(GetPortMappingArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - p = GetValueFromNameValueList(&pdata, "NewInternalClient"); - if(p) { - strncpy(intClient, p, 16); - intClient[15] = '\0'; - ret = UPNPCOMMAND_SUCCESS; - } else - intClient[0] = '\0'; - - p = GetValueFromNameValueList(&pdata, "NewInternalPort"); - if(p) { - strncpy(intPort, p, 6); - intPort[5] = '\0'; - } else - intPort[0] = '\0'; - - p = GetValueFromNameValueList(&pdata, "NewEnabled"); - if(p && enabled) { - strncpy(enabled, p, 4); - enabled[3] = '\0'; - } - - p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); - if(p && desc) { - strncpy(desc, p, 80); - desc[79] = '\0'; - } - - p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); - if(p && leaseDuration) - { - strncpy(leaseDuration, p, 16); - leaseDuration[15] = '\0'; - } - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - - ClearNameValueList(&pdata); - free(GetPortMappingArgs); - return ret; -} - -/* UPNP_GetListOfPortMappings() - * - * Possible UPNP Error codes : - * 606 Action not Authorized - * 730 PortMappingNotFound - no port mapping is found in the specified range. - * 733 InconsistantParameters - NewStartPort and NewEndPort values are not - * consistent. - */ -MINIUPNP_LIBSPEC int -UPNP_GetListOfPortMappings(const char * controlURL, - const char * servicetype, - const char * startPort, - const char * endPort, - const char * protocol, - const char * numberOfPorts, - struct PortMappingParserData * data) -{ - struct NameValueParserData pdata; - struct UPNParg * GetListOfPortMappingsArgs; - const char * p; - char * buffer; - int bufsize; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!startPort || !endPort || !protocol) - return UPNPCOMMAND_INVALID_ARGS; - - GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg)); - if(GetListOfPortMappingsArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - GetListOfPortMappingsArgs[0].elt = "NewStartPort"; - GetListOfPortMappingsArgs[0].val = startPort; - GetListOfPortMappingsArgs[1].elt = "NewEndPort"; - GetListOfPortMappingsArgs[1].val = endPort; - GetListOfPortMappingsArgs[2].elt = "NewProtocol"; - GetListOfPortMappingsArgs[2].val = protocol; - GetListOfPortMappingsArgs[3].elt = "NewManage"; - GetListOfPortMappingsArgs[3].val = "1"; - GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts"; - GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000"; - - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetListOfPortMappings", - GetListOfPortMappingsArgs, &bufsize))) { - free(GetListOfPortMappingsArgs); - return UPNPCOMMAND_HTTP_ERROR; - } - free(GetListOfPortMappingsArgs); - - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - /*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/ - /*if(p) { - printf("NewPortListing : %s\n", p); - }*/ - /*printf("NewPortListing(%d chars) : %s\n", - pdata.portListingLength, pdata.portListing);*/ - if(pdata.portListing) - { - /*struct PortMapping * pm; - int i = 0;*/ - ParsePortListing(pdata.portListing, pdata.portListingLength, - data); - ret = UPNPCOMMAND_SUCCESS; - /* - for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next) - { - printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n", - i, pm->protocol, pm->externalPort, pm->internalClient, - pm->internalPort, - pm->description, pm->remoteHost); - i++; - } - */ - /*FreePortListing(&data);*/ - } - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - ClearNameValueList(&pdata); - - /*printf("%.*s", bufsize, buffer);*/ - - return ret; -} - -/* IGD:2, functions for service WANIPv6FirewallControl:1 */ -MINIUPNP_LIBSPEC int -UPNP_GetFirewallStatus(const char * controlURL, - const char * servicetype, - int * firewallEnabled, - int * inboundPinholeAllowed) -{ - struct NameValueParserData pdata; - char * buffer; - int bufsize; - char * fe, *ipa, *p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!firewallEnabled || !inboundPinholeAllowed) - return UPNPCOMMAND_INVALID_ARGS; - - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetFirewallStatus", 0, &bufsize); - if(!buffer) { - return UPNPCOMMAND_HTTP_ERROR; - } - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - fe = GetValueFromNameValueList(&pdata, "FirewallEnabled"); - ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed"); - if(ipa && fe) - ret = UPNPCOMMAND_SUCCESS; - if(fe) - *firewallEnabled = my_atoui(fe); - /*else - *firewallEnabled = 0;*/ - if(ipa) - *inboundPinholeAllowed = my_atoui(ipa); - /*else - *inboundPinholeAllowed = 0;*/ - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) - { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - ClearNameValueList(&pdata); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, - const char * remoteHost, - const char * remotePort, - const char * intClient, - const char * intPort, - const char * proto, - int * opTimeout) -{ - struct UPNParg * GetOutboundPinholeTimeoutArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - char * p; - int ret; - - if(!intPort || !intClient || !proto || !remotePort || !remoteHost) - return UPNPCOMMAND_INVALID_ARGS; - - GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg)); - if(GetOutboundPinholeTimeoutArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost"; - GetOutboundPinholeTimeoutArgs[0].val = remoteHost; - GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort"; - GetOutboundPinholeTimeoutArgs[1].val = remotePort; - GetOutboundPinholeTimeoutArgs[2].elt = "Protocol"; - GetOutboundPinholeTimeoutArgs[2].val = proto; - GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort"; - GetOutboundPinholeTimeoutArgs[3].val = intPort; - GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient"; - GetOutboundPinholeTimeoutArgs[4].val = intClient; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) - { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } - else - { - ret = UPNPCOMMAND_SUCCESS; - p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); - if(p) - *opTimeout = my_atoui(p); - } - ClearNameValueList(&pdata); - free(GetOutboundPinholeTimeoutArgs); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_AddPinhole(const char * controlURL, const char * servicetype, - const char * remoteHost, - const char * remotePort, - const char * intClient, - const char * intPort, - const char * proto, - const char * leaseTime, - char * uniqueID) -{ - struct UPNParg * AddPinholeArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - char * p; - int ret; - - if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime) - return UPNPCOMMAND_INVALID_ARGS; - - AddPinholeArgs = calloc(7, sizeof(struct UPNParg)); - if(AddPinholeArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - /* RemoteHost can be wilcarded */ - if(strncmp(remoteHost, "empty", 5)==0) - { - AddPinholeArgs[0].elt = "RemoteHost"; - AddPinholeArgs[0].val = ""; - } - else - { - AddPinholeArgs[0].elt = "RemoteHost"; - AddPinholeArgs[0].val = remoteHost; - } - AddPinholeArgs[1].elt = "RemotePort"; - AddPinholeArgs[1].val = remotePort; - AddPinholeArgs[2].elt = "Protocol"; - AddPinholeArgs[2].val = proto; - AddPinholeArgs[3].elt = "InternalPort"; - AddPinholeArgs[3].val = intPort; - if(strncmp(intClient, "empty", 5)==0) - { - AddPinholeArgs[4].elt = "InternalClient"; - AddPinholeArgs[4].val = ""; - } - else - { - AddPinholeArgs[4].elt = "InternalClient"; - AddPinholeArgs[4].val = intClient; - } - AddPinholeArgs[5].elt = "LeaseTime"; - AddPinholeArgs[5].val = leaseTime; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "AddPinhole", AddPinholeArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - p = GetValueFromNameValueList(&pdata, "UniqueID"); - if(p) - { - strncpy(uniqueID, p, 8); - uniqueID[7] = '\0'; - } - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) - { - /*printf("AddPortMapping errorCode = '%s'\n", resVal);*/ - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } - else - { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(AddPinholeArgs); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, - const char * uniqueID, - const char * leaseTime) -{ - struct UPNParg * UpdatePinholeArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - int ret; - - if(!uniqueID || !leaseTime) - return UPNPCOMMAND_INVALID_ARGS; - - UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg)); - if(UpdatePinholeArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - UpdatePinholeArgs[0].elt = "UniqueID"; - UpdatePinholeArgs[0].val = uniqueID; - UpdatePinholeArgs[1].elt = "NewLeaseTime"; - UpdatePinholeArgs[1].val = leaseTime; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "UpdatePinhole", UpdatePinholeArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) - { - /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } - else - { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(UpdatePinholeArgs); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID) -{ - /*struct NameValueParserData pdata;*/ - struct UPNParg * DeletePinholeArgs; - char * buffer; - int bufsize; - struct NameValueParserData pdata; - const char * resVal; - int ret; - - if(!uniqueID) - return UPNPCOMMAND_INVALID_ARGS; - - DeletePinholeArgs = calloc(2, sizeof(struct UPNParg)); - if(DeletePinholeArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - DeletePinholeArgs[0].elt = "UniqueID"; - DeletePinholeArgs[0].val = uniqueID; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "DeletePinhole", DeletePinholeArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - /*DisplayNameValueList(buffer, bufsize);*/ - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - resVal = GetValueFromNameValueList(&pdata, "errorCode"); - if(resVal) - { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(resVal, "%d", &ret); - } - else - { - ret = UPNPCOMMAND_SUCCESS; - } - ClearNameValueList(&pdata); - free(DeletePinholeArgs); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, - const char * uniqueID, int * isWorking) -{ - struct NameValueParserData pdata; - struct UPNParg * CheckPinholeWorkingArgs; - char * buffer; - int bufsize; - char * p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!uniqueID) - return UPNPCOMMAND_INVALID_ARGS; - - CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg)); - if(CheckPinholeWorkingArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - CheckPinholeWorkingArgs[0].elt = "UniqueID"; - CheckPinholeWorkingArgs[0].val = uniqueID; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - p = GetValueFromNameValueList(&pdata, "IsWorking"); - if(p) - { - *isWorking=my_atoui(p); - ret = UPNPCOMMAND_SUCCESS; - } - else - *isWorking = 0; - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) - { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - - ClearNameValueList(&pdata); - free(CheckPinholeWorkingArgs); - return ret; -} - -MINIUPNP_LIBSPEC int -UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, - const char * uniqueID, int * packets) -{ - struct NameValueParserData pdata; - struct UPNParg * GetPinholePacketsArgs; - char * buffer; - int bufsize; - char * p; - int ret = UPNPCOMMAND_UNKNOWN_ERROR; - - if(!uniqueID) - return UPNPCOMMAND_INVALID_ARGS; - - GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg)); - if(GetPinholePacketsArgs == NULL) - return UPNPCOMMAND_MEM_ALLOC_ERROR; - GetPinholePacketsArgs[0].elt = "UniqueID"; - GetPinholePacketsArgs[0].val = uniqueID; - buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetPinholePackets", GetPinholePacketsArgs, &bufsize); - if(!buffer) - return UPNPCOMMAND_HTTP_ERROR; - ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; - - p = GetValueFromNameValueList(&pdata, "PinholePackets"); - if(p) - { - *packets=my_atoui(p); - ret = UPNPCOMMAND_SUCCESS; - } - - p = GetValueFromNameValueList(&pdata, "errorCode"); - if(p) - { - ret = UPNPCOMMAND_UNKNOWN_ERROR; - sscanf(p, "%d", &ret); - } - - ClearNameValueList(&pdata); - free(GetPinholePacketsArgs); - return ret; -} - - diff --git a/zto/ext/miniupnpc/upnpcommands.h b/zto/ext/miniupnpc/upnpcommands.h deleted file mode 100644 index 22eda5e..0000000 --- a/zto/ext/miniupnpc/upnpcommands.h +++ /dev/null @@ -1,348 +0,0 @@ -/* $Id: upnpcommands.h,v 1.31 2015/07/21 13:16:55 nanard Exp $ */ -/* Miniupnp project : http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005-2015 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided within this distribution */ -#ifndef UPNPCOMMANDS_H_INCLUDED -#define UPNPCOMMANDS_H_INCLUDED - -#include "upnpreplyparse.h" -#include "portlistingparse.h" -#include "miniupnpc_declspec.h" -#include "miniupnpctypes.h" - -/* MiniUPnPc return codes : */ -#define UPNPCOMMAND_SUCCESS (0) -#define UPNPCOMMAND_UNKNOWN_ERROR (-1) -#define UPNPCOMMAND_INVALID_ARGS (-2) -#define UPNPCOMMAND_HTTP_ERROR (-3) -#define UPNPCOMMAND_INVALID_RESPONSE (-4) -#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5) - -#ifdef __cplusplus -extern "C" { -#endif - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesSent(const char * controlURL, - const char * servicetype); - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesReceived(const char * controlURL, - const char * servicetype); - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsSent(const char * controlURL, - const char * servicetype); - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsReceived(const char * controlURL, - const char * servicetype); - -/* UPNP_GetStatusInfo() - * status and lastconnerror are 64 byte buffers - * Return values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error code */ -MINIUPNP_LIBSPEC int -UPNP_GetStatusInfo(const char * controlURL, - const char * servicetype, - char * status, - unsigned int * uptime, - char * lastconnerror); - -/* UPNP_GetConnectionTypeInfo() - * argument connectionType is a 64 character buffer - * Return Values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error code */ -MINIUPNP_LIBSPEC int -UPNP_GetConnectionTypeInfo(const char * controlURL, - const char * servicetype, - char * connectionType); - -/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. - * if the third arg is not null the value is copied to it. - * at least 16 bytes must be available - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR Either an UPnP error code or an unknown error. - * - * possible UPnP Errors : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. */ -MINIUPNP_LIBSPEC int -UPNP_GetExternalIPAddress(const char * controlURL, - const char * servicetype, - char * extIpAdd); - -/* UPNP_GetLinkLayerMaxBitRates() - * call WANCommonInterfaceConfig:1#GetCommonLinkProperties - * - * return values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. */ -MINIUPNP_LIBSPEC int -UPNP_GetLinkLayerMaxBitRates(const char* controlURL, - const char* servicetype, - unsigned int * bitrateDown, - unsigned int * bitrateUp); - -/* UPNP_AddPortMapping() - * if desc is NULL, it will be defaulted to "libminiupnpc" - * remoteHost is usually NULL because IGD don't support it. - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR. Either an UPnP error code or an unknown error. - * - * List of possible UPnP errors for AddPortMapping : - * errorCode errorDescription (short) - Description (long) - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization and - * the sender was not authorized. - * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be - * wild-carded - * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded - * 718 ConflictInMappingEntry - The port mapping entry specified conflicts - * with a mapping assigned previously to another client - * 724 SamePortValuesRequired - Internal and External port values - * must be the same - * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports - * permanent lease times on port mappings - * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard - * and cannot be a specific IP address or DNS name - * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and - * cannot be a specific port value - * 728 NoPortMapsAvailable - There are not enough free ports available to - * complete port mapping. - * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed - * due to conflict with other mechanisms. - * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded - */ -MINIUPNP_LIBSPEC int -UPNP_AddPortMapping(const char * controlURL, const char * servicetype, - const char * extPort, - const char * inPort, - const char * inClient, - const char * desc, - const char * proto, - const char * remoteHost, - const char * leaseDuration); - -/* UPNP_AddAnyPortMapping() - * if desc is NULL, it will be defaulted to "libminiupnpc" - * remoteHost is usually NULL because IGD don't support it. - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR. Either an UPnP error code or an unknown error. - * - * List of possible UPnP errors for AddPortMapping : - * errorCode errorDescription (short) - Description (long) - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization and - * the sender was not authorized. - * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be - * wild-carded - * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded - * 728 NoPortMapsAvailable - There are not enough free ports available to - * complete port mapping. - * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed - * due to conflict with other mechanisms. - * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded - */ -MINIUPNP_LIBSPEC int -UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, - const char * extPort, - const char * inPort, - const char * inClient, - const char * desc, - const char * proto, - const char * remoteHost, - const char * leaseDuration, - char * reservedPort); - -/* UPNP_DeletePortMapping() - * Use same argument values as what was used for AddPortMapping(). - * remoteHost is usually NULL because IGD don't support it. - * Return Values : - * 0 : SUCCESS - * NON ZERO : error. Either an UPnP error code or an undefined error. - * - * List of possible UPnP errors for DeletePortMapping : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 714 NoSuchEntryInArray - The specified value does not exist in the array */ -MINIUPNP_LIBSPEC int -UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, - const char * extPort, const char * proto, - const char * remoteHost); - -/* UPNP_DeletePortRangeMapping() - * Use same argument values as what was used for AddPortMapping(). - * remoteHost is usually NULL because IGD don't support it. - * Return Values : - * 0 : SUCCESS - * NON ZERO : error. Either an UPnP error code or an undefined error. - * - * List of possible UPnP errors for DeletePortMapping : - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 730 PortMappingNotFound - This error message is returned if no port - * mapping is found in the specified range. - * 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */ -MINIUPNP_LIBSPEC int -UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, - const char * extPortStart, const char * extPortEnd, - const char * proto, - const char * manage); - -/* UPNP_GetPortMappingNumberOfEntries() - * not supported by all routers */ -MINIUPNP_LIBSPEC int -UPNP_GetPortMappingNumberOfEntries(const char* controlURL, - const char* servicetype, - unsigned int * num); - -/* UPNP_GetSpecificPortMappingEntry() - * retrieves an existing port mapping - * params : - * in extPort - * in proto - * in remoteHost - * out intClient (16 bytes) - * out intPort (6 bytes) - * out desc (80 bytes) - * out enabled (4 bytes) - * out leaseDuration (16 bytes) - * - * return value : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. - * - * List of possible UPnP errors for _GetSpecificPortMappingEntry : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 714 NoSuchEntryInArray - The specified value does not exist in the array. - */ -MINIUPNP_LIBSPEC int -UPNP_GetSpecificPortMappingEntry(const char * controlURL, - const char * servicetype, - const char * extPort, - const char * proto, - const char * remoteHost, - char * intClient, - char * intPort, - char * desc, - char * enabled, - char * leaseDuration); - -/* UPNP_GetGenericPortMappingEntry() - * params : - * in index - * out extPort (6 bytes) - * out intClient (16 bytes) - * out intPort (6 bytes) - * out protocol (4 bytes) - * out desc (80 bytes) - * out enabled (4 bytes) - * out rHost (64 bytes) - * out duration (16 bytes) - * - * return value : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. - * - * Possible UPNP Error codes : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds - */ -MINIUPNP_LIBSPEC int -UPNP_GetGenericPortMappingEntry(const char * controlURL, - const char * servicetype, - const char * index, - char * extPort, - char * intClient, - char * intPort, - char * protocol, - char * desc, - char * enabled, - char * rHost, - char * duration); - -/* UPNP_GetListOfPortMappings() Available in IGD v2 - * - * - * Possible UPNP Error codes : - * 606 Action not Authorized - * 730 PortMappingNotFound - no port mapping is found in the specified range. - * 733 InconsistantParameters - NewStartPort and NewEndPort values are not - * consistent. - */ -MINIUPNP_LIBSPEC int -UPNP_GetListOfPortMappings(const char * controlURL, - const char * servicetype, - const char * startPort, - const char * endPort, - const char * protocol, - const char * numberOfPorts, - struct PortMappingParserData * data); - -/* IGD:2, functions for service WANIPv6FirewallControl:1 */ -MINIUPNP_LIBSPEC int -UPNP_GetFirewallStatus(const char * controlURL, - const char * servicetype, - int * firewallEnabled, - int * inboundPinholeAllowed); - -MINIUPNP_LIBSPEC int -UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, - const char * remoteHost, - const char * remotePort, - const char * intClient, - const char * intPort, - const char * proto, - int * opTimeout); - -MINIUPNP_LIBSPEC int -UPNP_AddPinhole(const char * controlURL, const char * servicetype, - const char * remoteHost, - const char * remotePort, - const char * intClient, - const char * intPort, - const char * proto, - const char * leaseTime, - char * uniqueID); - -MINIUPNP_LIBSPEC int -UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, - const char * uniqueID, - const char * leaseTime); - -MINIUPNP_LIBSPEC int -UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); - -MINIUPNP_LIBSPEC int -UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, - const char * uniqueID, int * isWorking); - -MINIUPNP_LIBSPEC int -UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, - const char * uniqueID, int * packets); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/zto/ext/miniupnpc/upnpdev.c b/zto/ext/miniupnpc/upnpdev.c deleted file mode 100644 index d89a993..0000000 --- a/zto/ext/miniupnpc/upnpdev.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */ -/* Project : miniupnp - * Web : http://miniupnp.free.fr/ - * Author : Thomas BERNARD - * copyright (c) 2005-2015 Thomas Bernard - * This software is subjet to the conditions detailed in the - * provided LICENSE file. */ -#include -#include "upnpdev.h" - -/* freeUPNPDevlist() should be used to - * free the chained list returned by upnpDiscover() */ -void freeUPNPDevlist(struct UPNPDev * devlist) -{ - struct UPNPDev * next; - while(devlist) - { - next = devlist->pNext; - free(devlist); - devlist = next; - } -} - diff --git a/zto/ext/miniupnpc/upnpdev.h b/zto/ext/miniupnpc/upnpdev.h deleted file mode 100644 index f49fbe1..0000000 --- a/zto/ext/miniupnpc/upnpdev.h +++ /dev/null @@ -1,36 +0,0 @@ -/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */ -/* Project : miniupnp - * Web : http://miniupnp.free.fr/ - * Author : Thomas BERNARD - * copyright (c) 2005-2015 Thomas Bernard - * This software is subjet to the conditions detailed in the - * provided LICENSE file. */ -#ifndef UPNPDEV_H_INCLUDED -#define UPNPDEV_H_INCLUDED - -#include "miniupnpc_declspec.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct UPNPDev { - struct UPNPDev * pNext; - char * descURL; - char * st; - unsigned int scope_id; - char * usn; - char buffer[3]; -}; - -/* freeUPNPDevlist() - * free list returned by upnpDiscover() */ -MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); - - -#ifdef __cplusplus -} -#endif - - -#endif /* UPNPDEV_H_INCLUDED */ diff --git a/zto/ext/miniupnpc/upnperrors.c b/zto/ext/miniupnpc/upnperrors.c deleted file mode 100644 index 7ab8ee9..0000000 --- a/zto/ext/miniupnpc/upnperrors.c +++ /dev/null @@ -1,107 +0,0 @@ -/* $Id: upnperrors.c,v 1.8 2014/06/10 09:41:48 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas BERNARD - * copyright (c) 2007 Thomas Bernard - * All Right reserved. - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * This software is subjet to the conditions detailed in the - * provided LICENCE file. */ -#include -#include "upnperrors.h" -#include "upnpcommands.h" -#include "miniupnpc.h" - -const char * strupnperror(int err) -{ - const char * s = NULL; - switch(err) { - case UPNPCOMMAND_SUCCESS: - s = "Success"; - break; - case UPNPCOMMAND_UNKNOWN_ERROR: - s = "Miniupnpc Unknown Error"; - break; - case UPNPCOMMAND_INVALID_ARGS: - s = "Miniupnpc Invalid Arguments"; - break; - case UPNPCOMMAND_INVALID_RESPONSE: - s = "Miniupnpc Invalid response"; - break; - case UPNPDISCOVER_SOCKET_ERROR: - s = "Miniupnpc Socket error"; - break; - case UPNPDISCOVER_MEMORY_ERROR: - s = "Miniupnpc Memory allocation error"; - break; - case 401: - s = "Invalid Action"; - break; - case 402: - s = "Invalid Args"; - break; - case 501: - s = "Action Failed"; - break; - case 606: - s = "Action not authorized"; - break; - case 701: - s = "PinholeSpaceExhausted"; - break; - case 702: - s = "FirewallDisabled"; - break; - case 703: - s = "InboundPinholeNotAllowed"; - break; - case 704: - s = "NoSuchEntry"; - break; - case 705: - s = "ProtocolNotSupported"; - break; - case 706: - s = "InternalPortWildcardingNotAllowed"; - break; - case 707: - s = "ProtocolWildcardingNotAllowed"; - break; - case 708: - s = "WildcardNotPermittedInSrcIP"; - break; - case 709: - s = "NoPacketSent"; - break; - case 713: - s = "SpecifiedArrayIndexInvalid"; - break; - case 714: - s = "NoSuchEntryInArray"; - break; - case 715: - s = "WildCardNotPermittedInSrcIP"; - break; - case 716: - s = "WildCardNotPermittedInExtPort"; - break; - case 718: - s = "ConflictInMappingEntry"; - break; - case 724: - s = "SamePortValuesRequired"; - break; - case 725: - s = "OnlyPermanentLeasesSupported"; - break; - case 726: - s = "RemoteHostOnlySupportsWildcard"; - break; - case 727: - s = "ExternalPortOnlySupportsWildcard"; - break; - default: - s = "UnknownError"; - break; - } - return s; -} diff --git a/zto/ext/miniupnpc/upnperrors.h b/zto/ext/miniupnpc/upnperrors.h deleted file mode 100644 index 3115aee..0000000 --- a/zto/ext/miniupnpc/upnperrors.h +++ /dev/null @@ -1,26 +0,0 @@ -/* $Id: upnperrors.h,v 1.6 2015/07/21 13:16:55 nanard Exp $ */ -/* (c) 2007-2015 Thomas Bernard - * All rights reserved. - * MiniUPnP Project. - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * This software is subjet to the conditions detailed in the - * provided LICENCE file. */ -#ifndef UPNPERRORS_H_INCLUDED -#define UPNPERRORS_H_INCLUDED - -#include "miniupnpc_declspec.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* strupnperror() - * Return a string description of the UPnP error code - * or NULL for undefinded errors */ -MINIUPNP_LIBSPEC const char * strupnperror(int err); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/zto/ext/miniupnpc/upnpreplyparse.c b/zto/ext/miniupnpc/upnpreplyparse.c deleted file mode 100644 index 5de5796..0000000 --- a/zto/ext/miniupnpc/upnpreplyparse.c +++ /dev/null @@ -1,197 +0,0 @@ -/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2015 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ - -#include -#include -#include - -#include "upnpreplyparse.h" -#include "minixml.h" - -static void -NameValueParserStartElt(void * d, const char * name, int l) -{ - struct NameValueParserData * data = (struct NameValueParserData *)d; - data->topelt = 1; - if(l>63) - l = 63; - memcpy(data->curelt, name, l); - data->curelt[l] = '\0'; - data->cdata = NULL; - data->cdatalen = 0; -} - -static void -NameValueParserEndElt(void * d, const char * name, int l) -{ - struct NameValueParserData * data = (struct NameValueParserData *)d; - struct NameValue * nv; - (void)name; - (void)l; - if(!data->topelt) - return; - if(strcmp(data->curelt, "NewPortListing") != 0) - { - int l; - /* standard case. Limited to n chars strings */ - l = data->cdatalen; - nv = malloc(sizeof(struct NameValue)); - if(nv == NULL) - { - /* malloc error */ -#ifdef DEBUG - fprintf(stderr, "%s: error allocating memory", - "NameValueParserEndElt"); -#endif /* DEBUG */ - return; - } - if(l>=(int)sizeof(nv->value)) - l = sizeof(nv->value) - 1; - strncpy(nv->name, data->curelt, 64); - nv->name[63] = '\0'; - if(data->cdata != NULL) - { - memcpy(nv->value, data->cdata, l); - nv->value[l] = '\0'; - } - else - { - nv->value[0] = '\0'; - } - nv->l_next = data->l_head; /* insert in list */ - data->l_head = nv; - } - data->cdata = NULL; - data->cdatalen = 0; - data->topelt = 0; -} - -static void -NameValueParserGetData(void * d, const char * datas, int l) -{ - struct NameValueParserData * data = (struct NameValueParserData *)d; - if(strcmp(data->curelt, "NewPortListing") == 0) - { - /* specific case for NewPortListing which is a XML Document */ - data->portListing = malloc(l + 1); - if(!data->portListing) - { - /* malloc error */ -#ifdef DEBUG - fprintf(stderr, "%s: error allocating memory", - "NameValueParserGetData"); -#endif /* DEBUG */ - return; - } - memcpy(data->portListing, datas, l); - data->portListing[l] = '\0'; - data->portListingLength = l; - } - else - { - /* standard case. */ - data->cdata = datas; - data->cdatalen = l; - } -} - -void -ParseNameValue(const char * buffer, int bufsize, - struct NameValueParserData * data) -{ - struct xmlparser parser; - data->l_head = NULL; - data->portListing = NULL; - data->portListingLength = 0; - /* init xmlparser object */ - parser.xmlstart = buffer; - parser.xmlsize = bufsize; - parser.data = data; - parser.starteltfunc = NameValueParserStartElt; - parser.endeltfunc = NameValueParserEndElt; - parser.datafunc = NameValueParserGetData; - parser.attfunc = 0; - parsexml(&parser); -} - -void -ClearNameValueList(struct NameValueParserData * pdata) -{ - struct NameValue * nv; - if(pdata->portListing) - { - free(pdata->portListing); - pdata->portListing = NULL; - pdata->portListingLength = 0; - } - while((nv = pdata->l_head) != NULL) - { - pdata->l_head = nv->l_next; - free(nv); - } -} - -char * -GetValueFromNameValueList(struct NameValueParserData * pdata, - const char * Name) -{ - struct NameValue * nv; - char * p = NULL; - for(nv = pdata->l_head; - (nv != NULL) && (p == NULL); - nv = nv->l_next) - { - if(strcmp(nv->name, Name) == 0) - p = nv->value; - } - return p; -} - -#if 0 -/* useless now that minixml ignores namespaces by itself */ -char * -GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, - const char * Name) -{ - struct NameValue * nv; - char * p = NULL; - char * pname; - for(nv = pdata->head.lh_first; - (nv != NULL) && (p == NULL); - nv = nv->entries.le_next) - { - pname = strrchr(nv->name, ':'); - if(pname) - pname++; - else - pname = nv->name; - if(strcmp(pname, Name)==0) - p = nv->value; - } - return p; -} -#endif - -/* debug all-in-one function - * do parsing then display to stdout */ -#ifdef DEBUG -void -DisplayNameValueList(char * buffer, int bufsize) -{ - struct NameValueParserData pdata; - struct NameValue * nv; - ParseNameValue(buffer, bufsize, &pdata); - for(nv = pdata.l_head; - nv != NULL; - nv = nv->l_next) - { - printf("%s = %s\n", nv->name, nv->value); - } - ClearNameValueList(&pdata); -} -#endif /* DEBUG */ - diff --git a/zto/ext/miniupnpc/upnpreplyparse.h b/zto/ext/miniupnpc/upnpreplyparse.h deleted file mode 100644 index 6badd15..0000000 --- a/zto/ext/miniupnpc/upnpreplyparse.h +++ /dev/null @@ -1,63 +0,0 @@ -/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ - -#ifndef UPNPREPLYPARSE_H_INCLUDED -#define UPNPREPLYPARSE_H_INCLUDED - -#ifdef __cplusplus -extern "C" { -#endif - -struct NameValue { - struct NameValue * l_next; - char name[64]; - char value[128]; -}; - -struct NameValueParserData { - struct NameValue * l_head; - char curelt[64]; - char * portListing; - int portListingLength; - int topelt; - const char * cdata; - int cdatalen; -}; - -/* ParseNameValue() */ -void -ParseNameValue(const char * buffer, int bufsize, - struct NameValueParserData * data); - -/* ClearNameValueList() */ -void -ClearNameValueList(struct NameValueParserData * pdata); - -/* GetValueFromNameValueList() */ -char * -GetValueFromNameValueList(struct NameValueParserData * pdata, - const char * Name); - -#if 0 -/* GetValueFromNameValueListIgnoreNS() */ -char * -GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, - const char * Name); -#endif - -/* DisplayNameValueList() */ -#ifdef DEBUG -void -DisplayNameValueList(char * buffer, int bufsize); -#endif - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/zto/ext/miniupnpc/wingenminiupnpcstrings.c b/zto/ext/miniupnpc/wingenminiupnpcstrings.c deleted file mode 100644 index 50df06a..0000000 --- a/zto/ext/miniupnpc/wingenminiupnpcstrings.c +++ /dev/null @@ -1,83 +0,0 @@ -/* $Id: wingenminiupnpcstrings.c,v 1.4 2015/02/08 08:46:06 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author: Thomas Bernard - * Copyright (c) 2005-2015 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENSE file provided within this distribution */ -#include -#include - -/* This program display the Windows version and is used to - * generate the miniupnpcstrings.h - * wingenminiupnpcstrings miniupnpcstrings.h.in miniupnpcstrings.h - */ -int main(int argc, char * * argv) { - char buffer[256]; - OSVERSIONINFO osvi; - FILE * fin; - FILE * fout; - int n; - char miniupnpcVersion[32]; - /* dwMajorVersion : - The major version number of the operating system. For more information, see Remarks. - dwMinorVersion : - The minor version number of the operating system. For more information, see Remarks. - dwBuildNumber : - The build number of the operating system. - dwPlatformId - The operating system platform. This member can be the following value. - szCSDVersion - A null-terminated string, such as "Service Pack 3", that indicates the - latest Service Pack installed on the system. If no Service Pack has - been installed, the string is empty. - */ - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - - GetVersionEx(&osvi); - - printf("Windows %lu.%lu Build %lu %s\n", - osvi.dwMajorVersion, osvi.dwMinorVersion, - osvi.dwBuildNumber, (const char *)&(osvi.szCSDVersion)); - - fin = fopen("VERSION", "r"); - fgets(miniupnpcVersion, sizeof(miniupnpcVersion), fin); - fclose(fin); - for(n = 0; n < sizeof(miniupnpcVersion); n++) { - if(miniupnpcVersion[n] < ' ') - miniupnpcVersion[n] = '\0'; - } - printf("MiniUPnPc version %s\n", miniupnpcVersion); - - if(argc >= 3) { - fin = fopen(argv[1], "r"); - if(!fin) { - fprintf(stderr, "Cannot open %s for reading.\n", argv[1]); - return 1; - } - fout = fopen(argv[2], "w"); - if(!fout) { - fprintf(stderr, "Cannot open %s for writing.\n", argv[2]); - fclose(fin); - return 1; - } - n = 0; - while(fgets(buffer, sizeof(buffer), fin)) { - if(0 == memcmp(buffer, "#define OS_STRING \"OS/version\"", 30)) { - sprintf(buffer, "#define OS_STRING \"MSWindows/%ld.%ld.%ld\"\n", - osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); - } else if(0 == memcmp(buffer, "#define MINIUPNPC_VERSION_STRING \"version\"", 42)) { - sprintf(buffer, "#define MINIUPNPC_VERSION_STRING \"%s\"\n", - miniupnpcVersion); - } - /*fputs(buffer, stdout);*/ - fputs(buffer, fout); - n++; - } - fclose(fin); - fclose(fout); - printf("%d lines written to %s.\n", n, argv[2]); - } - return 0; -} diff --git a/zto/ext/tap-mac/README.txt b/zto/ext/tap-mac/README.txt deleted file mode 100644 index 177b936..0000000 --- a/zto/ext/tap-mac/README.txt +++ /dev/null @@ -1,19 +0,0 @@ -This is a hack of tuntaposx. It's here for two reasons: - -1) There seem to be issues with large MTUs in the original tuntap code, - so we set up our zt0 tap with the correct ZeroTier MTU as the default. - -2) Lots of other mac products (VPNs, etc.) ship their own tap device - drivers that like to conflict with one another. This gives us no - choice but to play along. But we call our tap device zt0, which means - it won't conflict with everyone else's tap0. - -3) It's nice to call the device zt0, same as Linux, for consistency across - *nix platforms. Mac does not seem to support interface renaming. - -This will be placed in the ZeroTier home as a kext and is auto-loaded by the -ZeroTier One binary if /dev/zt0 is not found. It can also be auto-updated. - -See this page for the original: - -http://tuntaposx.sourceforge.net diff --git a/zto/ext/tap-mac/tuntap/Makefile b/zto/ext/tap-mac/tuntap/Makefile deleted file mode 100644 index 53ab1a9..0000000 --- a/zto/ext/tap-mac/tuntap/Makefile +++ /dev/null @@ -1,95 +0,0 @@ -# Lets have a version, at last! -TUNTAP_VERSION = 20150118 - -# BASE install directory -BASE= - -all: tap.kext - -keysetup: - -security delete-keychain net.sf.tuntaposx.tmp - security create-keychain -p $$(head -c 32 /dev/urandom | hexdump -e '"%02x"') \ - net.sf.tuntaposx.tmp - security set-keychain-settings -lut 60 net.sf.tuntaposx.tmp - security import identity.p12 -k net.sf.tuntaposx.tmp -f pkcs12 \ - -P $$(read -sp 'identity passphrase: ' pw && echo "$$pw") -A - security find-identity -v net.sf.tuntaposx.tmp | \ - awk -F \" '$$2 ~ /^Developer ID Application:/ { print $$2 }' > .signing_identity - security find-identity -v net.sf.tuntaposx.tmp | \ - awk -F \" '$$2 ~ /^Developer ID Installer:/ { print $$2 }' > .installer_identity - -pkgbuild/%.pkg: %.kext - mkdir -p pkgbuild/$*_root/Library/Extensions - cp -pR $*.kext pkgbuild/$*_root/Library/Extensions - mkdir -p pkgbuild/$*_root/Library/LaunchDaemons - cp pkg/launchd/net.sf.tuntaposx.$*.plist pkgbuild/$*_root/Library/LaunchDaemons - pkgbuild --root pkgbuild/$*_root \ - --component-plist pkg/components/$*.plist \ - --scripts pkg/scripts/$* pkgbuild/$*.pkg - -tuntap_$(TUNTAP_VERSION).pkg: pkgbuild/tap.pkg pkgbuild/tun.pkg - productbuild --distribution pkg/distribution.xml --package-path pkgbuild \ - --resources pkg/res.dummy \ - tuntap_$(TUNTAP_VERSION).pkg ; \ - pkgutil --expand tuntap_$(TUNTAP_VERSION).pkg pkgbuild/tuntap_pkg.d - cp -pR pkg/res/ pkgbuild/tuntap_pkg.d/Resources - pkgutil --flatten pkgbuild/tuntap_pkg.d tuntap_$(TUNTAP_VERSION).pkg - if test -s ".installer_identity"; then \ - productsign --sign "$$(cat .installer_identity)" --keychain net.sf.tuntaposx.tmp \ - tuntap_$(TUNTAP_VERSION).pkg tuntap_$(TUNTAP_VERSION).pkg.signed ; \ - mv tuntap_$(TUNTAP_VERSION).pkg.signed tuntap_$(TUNTAP_VERSION).pkg ; \ - fi - -pkg: tuntap_$(TUNTAP_VERSION).pkg - tar czf tuntap_$(TUNTAP_VERSION).tar.gz \ - README.installer README tuntap_$(TUNTAP_VERSION).pkg - -# Install targets -# They are provided for the gentoo ebuild, but should work just fine for other people as well. -install_%_kext: %.kext - mkdir -p $(BASE)/Library/Extensions - cp -pR $*.kext $(BASE)/Library/Extensions/ - chown -R root:wheel $(BASE)/Library/Extensions/$*.kext - mkdir -p $(BASE)/Library/LaunchDaemons - cp pkg/launchd/net.sf.tuntaposx.$*.plist $(BASE)/Library/LaunchDaemons - chown -R root:wheel $(BASE)/Library/LaunchDaemons/net.sf.tuntaposx.$*.plist - -install: install_tap_kext install_tun_kext - -tarball: clean - touch tuntap_$(TUNTAP_VERSION)_src.tar.gz - tar czf tuntap_$(TUNTAP_VERSION)_src.tar.gz \ - -C .. \ - --exclude "tuntap/identity.p12" \ - --exclude "tuntap/tuntap_$(TUNTAP_VERSION)_src.tar.gz" \ - --exclude "tuntap/tuntap_$(TUNTAP_VERSION).tar.gz" \ - --exclude "tuntap/tuntap_$(TUNTAP_VERSION).pkg" \ - --exclude "*/.*" \ - tuntap - -clean: - cd src/tap && make -f Makefile clean - cd src/tun && make -f Makefile clean - -rm -rf pkgbuild - -rm -rf tuntap_$(TUNTAP_VERSION).pkg - -rm -f tuntap_$(TUNTAP_VERSION).tar.gz - -rm -f tuntap_$(TUNTAP_VERSION)_src.tar.gz - -%.kext: - cd src/$* && make TUNTAP_VERSION=$(TUNTAP_VERSION) -f Makefile all - if test -s ".signing_identity"; then \ - codesign -fv --keychain net.sf.tuntaposx.tmp -s "$$(cat .signing_identity)" \ - $*.kext ; \ - fi - -test: - # configd messes with interface flags, issuing SIOCSIFFLAGS ioctls upon receiving kernel - # events indicating protocols have been attached and detached. Unfortunately, configd does - # this asynchronously, making the SIOCSIFFLAGS changes totally unpredictable when we bring - # our interfaces up and down in rapid succession during our tests. I haven't found a good - # way to suppress or handle this mess other than disabling configd temporarily. - killall -STOP configd - -PYTHONPATH=test python test/tuntap/tuntap_tests.py --tests='$(TESTS)' - killall -CONT configd - -.PHONY: test diff --git a/zto/ext/tap-mac/tuntap/src/lock.cc b/zto/ext/tap-mac/tuntap/src/lock.cc deleted file mode 100644 index 9c78783..0000000 --- a/zto/ext/tap-mac/tuntap/src/lock.cc +++ /dev/null @@ -1,206 +0,0 @@ -/* - * ip tunnel/ethertap device for MacOSX. - * - * Locking implementation. - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 "lock.h" - -extern "C" { - -#include - -#include -#include - -} - -#if 0 -#define dprintf(...) log(LOG_INFO, __VA_ARGS__) -#else -#define dprintf(...) -#endif - -/* class tt_lock */ -lck_grp_t *tt_lock::tt_lck_grp = NULL; - -bool -tt_lock::initialize() -{ - /* init if necessary */ - if (tt_lck_grp == NULL) { - dprintf("initing lock group\n"); - tt_lck_grp = lck_grp_alloc_init("tuntap locks", LCK_GRP_ATTR_NULL); - - if (tt_lck_grp == NULL) { - /* if something fails, the lock won't work */ - log(LOG_ERR, "tuntap: could not allocate locking group\n"); - return false; - } - } - - return true; -} - -void -tt_lock::shutdown() -{ - /* free the locking group */ - if (tt_lck_grp != NULL) { - dprintf("freeing lock group\n"); - lck_grp_free(tt_lck_grp); - tt_lck_grp = NULL; - } -} - -/* tt_mutex */ -tt_mutex::tt_mutex() -{ - /* fail if locking group not initialized */ - if (tt_lck_grp == NULL) - return; - - /* allocate the lock */ - lck = lck_rw_alloc_init(tt_lck_grp, NULL); - - if (lck == NULL) - log(LOG_ERR, "tuntap: could not allocate mutex\n"); -} - -tt_mutex::~tt_mutex() -{ - /* if the lock doesn't exist, this will be a no-op */ - if (lck == NULL) - return; - - /* free the lock */ - lck_rw_free(lck, tt_lck_grp); -} - -void -tt_mutex::lock() -{ - if (lck != NULL) - lck_rw_lock_exclusive(lck); -} - -void -tt_mutex::unlock() -{ - if (lck != NULL) - lck_rw_unlock_exclusive(lck); -} - -void -tt_mutex::sleep(void *cond) -{ - if (lck != NULL) - lck_rw_sleep(lck, LCK_SLEEP_DEFAULT, cond, THREAD_INTERRUPTIBLE); -} - -void -tt_mutex::sleep(void *cond, uint64_t nanoseconds) -{ - if (lck != NULL) { - uint64_t abstime; - nanoseconds_to_absolutetime(nanoseconds, &abstime); - lck_rw_sleep_deadline(lck, LCK_SLEEP_DEFAULT, cond, THREAD_INTERRUPTIBLE, abstime); - } -} - -void -tt_mutex::wakeup(void *cond) -{ - if (lck != NULL) - ::wakeup(cond); -} - -/* tt_gate */ -tt_gate::tt_gate() - : ticket_number(0), - population(0) -{ -} - -void -tt_gate::enter() -{ - /* just try to grab the lock, increase the ticket number and the population */ - auto_lock l(&slock); - ticket_number++; - population++; -} - -void -tt_gate::exit() -{ - auto_lock l(&slock); - ticket_number--; - population--; -} - -bool -tt_gate::is_anyone_in() -{ - return population != 0; -} - -unsigned int -tt_gate::get_ticket_number() -{ - return ticket_number; -} - -void -tt_gate::lock() -{ - slock.lock(); -} - -void -tt_gate::unlock() -{ - slock.unlock(); -} - -void -tt_gate::sleep(void* cond) -{ - slock.sleep(cond); -} - -void -tt_gate::sleep(void* cond, uint64_t nanoseconds) -{ - slock.sleep(cond, nanoseconds); -} - -void -tt_gate::wakeup(void* cond) -{ - slock.wakeup(cond); -} - diff --git a/zto/ext/tap-mac/tuntap/src/lock.h b/zto/ext/tap-mac/tuntap/src/lock.h deleted file mode 100644 index 51d3299..0000000 --- a/zto/ext/tap-mac/tuntap/src/lock.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * ip tunnel/ethertap device for MacOSX. - * - * Locking is not as straightforward for Tiger. So declare our own locking class. - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 __LOCK_H__ -#define __LOCK_H__ - -extern "C" { - -#include -#include - -} - -/* our own locking class. declares the common interface of the locking primitives. */ -class tt_lock { - - protected: - /* locking group */ - static lck_grp_t *tt_lck_grp; - - public: - /* be virtual */ - virtual ~tt_lock() { }; - - /* static intialization (inits the locking group) */ - static bool initialize(); - static void shutdown(); - - /* locking */ - virtual void lock() = 0; - virtual void unlock() = 0; - - /* monitor primitives */ - virtual void sleep(void* cond) = 0; - virtual void sleep(void* cond, uint64_t) = 0; - virtual void wakeup(void* cond) = 0; -}; - -/* simple mutex */ -class tt_mutex : public tt_lock { - - private: - /* underlying darwin lock */ - lck_rw_t *lck; - - public: - tt_mutex(); - virtual ~tt_mutex(); - - void lock(); - void unlock(); - - /* monitor primitives */ - void sleep(void* cond); - void sleep(void* cond, uint64_t); - void wakeup(void* cond); -}; - -/* A very special locking class that we use to track threads that enter and leave the character - * device service functions. They call enter() before entering the actual service routinge and - * exit() when done. enter() only permits them to pass when the gate isn't locked. Furthermore, the - * gate assigns ticket numbers to everyone that passes the gate, so you can check whether more - * threads came through. See tuntap_mgr::shutdown() for how we use that stuff. - */ -class tt_gate : public tt_lock { - - private: - /* synchronization lock */ - tt_mutex slock; - /* ticket number */ - unsigned int ticket_number; - /* count of threads that are in */ - unsigned int population; - - public: - /* construct a new gate */ - tt_gate(); - - /* enter - pass the gate */ - void enter(); - /* exit - pass the gate */ - void exit(); - - /* check whether anyone is in */ - bool is_anyone_in(); - /* gets the next ticket number */ - unsigned int get_ticket_number(); - - /* lock the gate */ - void lock(); - /* unlock the gate */ - void unlock(); - - /* monitor primitives */ - void sleep(void* cond); - void sleep(void* cond, uint64_t); - void wakeup(void* cond); -}; - -/* auto_lock and auto_rwlock serve as automatic lock managers: Create an object, passing the - * tt_[rw]lock you want to lock to have it grab the lock. When the object goes out of scope, the - * destructor of the class will release the lock. - */ -class auto_lock { - - protected: - /* the lock we hold */ - tt_lock *l; - - public: - auto_lock(tt_lock *m) - : l(m) - { - lock(); - } - - ~auto_lock() - { - unlock(); - } - - void lock() - { - l->lock(); - } - - void unlock() - { - l->unlock(); - } -}; - -#endif /* __LOCK_H__ */ - diff --git a/zto/ext/tap-mac/tuntap/src/mem.cc b/zto/ext/tap-mac/tuntap/src/mem.cc deleted file mode 100644 index cd3264f..0000000 --- a/zto/ext/tap-mac/tuntap/src/mem.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* - * ip tunnel/ethertap device for MacOSX. Common functionality of tap_interface and tun_interface. - * - * Memory management implementation. - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 "mem.h" - -extern "C" { - -#include - -} - -#if 0 -#define dprintf(...) log(LOG_INFO, __VA_ARGS__) -#else -#define dprintf(...) -#endif - -static int inited = 0; -static OSMallocTag tag; - -void -mem_initialize(const char* name) { - - if (!inited) { - tag = OSMalloc_Tagalloc(name, OSMT_DEFAULT); - inited = 1; - } -} - -void -mem_shutdown() { - - if (inited) { - OSMalloc_Tagfree(tag); - inited = 0; - } -} - -void * -mem_alloc(uint32_t size) { - - return OSMalloc(size, tag); -} - -void -mem_free(void *addr, uint32_t size) { - - OSFree(addr, size, tag); -} - diff --git a/zto/ext/tap-mac/tuntap/src/mem.h b/zto/ext/tap-mac/tuntap/src/mem.h deleted file mode 100644 index 4d06fd8..0000000 --- a/zto/ext/tap-mac/tuntap/src/mem.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * ip tunnel/ethertap device for MacOSX. Common functionality of tap_interface and tun_interface. - * - * Memory management. - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 __MEM_H__ -#define __MEM_H__ - -extern "C" { - -#include - -} - -/* Memory manager initalization and shutdown */ -void mem_initialize(const char *name); -void mem_shutdown(); - -/* Memory allocation functions */ -void *mem_alloc(uint32_t size); -void mem_free(void *addr, uint32_t size); - -#endif /* __MEM_H__ */ - diff --git a/zto/ext/tap-mac/tuntap/src/tap/Info.plist b/zto/ext/tap-mac/tuntap/src/tap/Info.plist deleted file mode 100644 index bb9b03f..0000000 --- a/zto/ext/tap-mac/tuntap/src/tap/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - @@CFBUNDLEDEVELOPMENTREGION@@ - CFBundleExecutable - @@CFBUNDLEEXECUTABLE@@ - CFBundleIdentifier - @@CFBUNDLEIDENTIFIER@@ - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - @@CFBUNDLEEXECUTABLE@@ - CFBundlePackageType - @@CFBUNDLEPACKAGETYPE@@ - CFBundleShortVersionString - @@CFBUNDLEVERSION@@ - CFBundleSignature - @@CFBUNDLESIGNATURE@@ - CFBundleVersion - 1.0 - OSBundleLibraries - - com.apple.kpi.mach - 8.0 - com.apple.kpi.bsd - 8.0 - com.apple.kpi.libkern - 8.0 - com.apple.kpi.unsupported - 8.0 - - - - diff --git a/zto/ext/tap-mac/tuntap/src/tap/Makefile b/zto/ext/tap-mac/tuntap/src/tap/Makefile deleted file mode 100644 index 306a86d..0000000 --- a/zto/ext/tap-mac/tuntap/src/tap/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# -# ethertap driver for MacOSX -# -# Makefile -# -# (c) 2004, 2005, 2006, 2007, 2008 Mattias Nissler -# - -OBJS = ../tuntap.o ../tuntap_mgr.o ../lock.o ../mem.o kmod.o tap.o -KMOD_BIN = tap -BUNDLE_DIR = ../.. -BUNDLE_NAME = tap.kext - -TAP_KEXT_VERSION = $(TUNTAP_VERSION) - -BUNDLE_REGION = English -BUNDLE_IDENTIFIER = com.zerotier.tap -BUNDLE_SIGNATURE = ???? -BUNDLE_PACKAGETYPE = KEXT -BUNDLE_VERSION = $(TAP_KEXT_VERSION) - -INCLUDE = -I.. -I/System/Library/Frameworks/Kernel.framework/Headers -CFLAGS = -Wall -Werror -mkernel -force_cpusubtype_ALL \ - -nostdinc -fno-builtin -fno-stack-protector -msoft-float -fno-common \ - -arch x86_64 \ - -DKERNEL -DAPPLE -DKERNEL_PRIVATE -DTUNTAP_VERSION=\"$(TUNTAP_VERSION)\" \ - -DTAP_KEXT_VERSION=\"$(TAP_KEXT_VERSION)\" -CCFLAGS = $(CFLAGS) -LDFLAGS = -Wall -Werror -arch x86_64 -Xlinker -kext -nostdlib -lkmodc++ -lkmod -lcc_kext - -CCP = clang -x c++ -CC = clang -x c -LD = clang - -all: $(KMOD_BIN) bundle - -.c.o: - $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ -.cc.o: - $(CCP) $(CCFLAGS) $(INCLUDE) -c $< -o $@ - -$(KMOD_BIN): $(OBJS) - $(LD) $(LDFLAGS) -o $(KMOD_BIN) $(OBJS) - -bundle: $(KMOD_BIN) - rm -rf $(BUNDLE_DIR)/$(BUNDLE_NAME) - mkdir -p $(BUNDLE_DIR)/$(BUNDLE_NAME)/Contents/MacOS - cp $(KMOD_BIN) $(BUNDLE_DIR)/$(BUNDLE_NAME)/Contents/MacOS - sed -e "s/@@CFBUNDLEEXECUTABLE@@/$(KMOD_BIN)/" \ - -e "s/@@CFBUNDLEDEVELOPMENTREGION@@/$(BUNDLE_REGION)/" \ - -e "s/@@CFBUNDLEIDENTIFIER@@/$(BUNDLE_IDENTIFIER)/" \ - -e "s/@@CFBUNDLESIGNATURE@@/$(BUNDLE_SIGNATURE)/" \ - -e "s/@@CFBUNDLEPACKAGETYPE@@/$(BUNDLE_PACKAGETYPE)/" \ - -e "s/@@CFBUNDLEVERSION@@/$(BUNDLE_VERSION)/" \ - Info.plist > $(BUNDLE_DIR)/$(BUNDLE_NAME)/Contents/Info.plist - -clean: - -rm -f $(OBJS) $(KMOD_BIN) - -rm -rf $(BUNDLE_DIR)/$(BUNDLE_NAME) - diff --git a/zto/ext/tap-mac/tuntap/src/tap/kmod.cc b/zto/ext/tap-mac/tuntap/src/tap/kmod.cc deleted file mode 100644 index f9c4a40..0000000 --- a/zto/ext/tap-mac/tuntap/src/tap/kmod.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* - * ethertap device for MacOSX. - * - * Kext definition (it is a mach kmod really...) - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 "tap.h" -#include "mem.h" - -extern "C" { - -#include - -#include - -static tap_manager *mgr; - -/* - * start function. called when the kext gets loaded. - */ -static kern_return_t tap_module_start(struct kmod_info *ki, void *data) -{ - mem_initialize(TAP_FAMILY_NAME); - - /* initialize locking */ - if (!tt_lock::initialize()) - return KMOD_RETURN_FAILURE; - - /* create a tap manager that will handle the rest */ - mgr = new tap_manager(); - - if (mgr != NULL) { - if (mgr->initialize(TAP_IF_COUNT, (char *) TAP_FAMILY_NAME)) - return KMOD_RETURN_SUCCESS; - - delete mgr; - mgr = NULL; - /* clean up locking */ - tt_lock::shutdown(); - } - - return KMOD_RETURN_FAILURE; -} - -/* - * stop function. called when the kext should be unloaded. unloading can be prevented by - * returning failure - */ -static kern_return_t tap_module_stop(struct kmod_info *ki, void *data) -{ - if (mgr != NULL) { - if (!mgr->shutdown()) - return KMOD_RETURN_FAILURE; - - delete mgr; - mgr = NULL; - } - - /* clean up locking */ - tt_lock::shutdown(); - - mem_shutdown(); - - return KMOD_RETURN_SUCCESS; -} - -KMOD_DECL(tap, TAP_KEXT_VERSION) - -} - diff --git a/zto/ext/tap-mac/tuntap/src/tap/tap.cc b/zto/ext/tap-mac/tuntap/src/tap/tap.cc deleted file mode 100644 index b348a85..0000000 --- a/zto/ext/tap-mac/tuntap/src/tap/tap.cc +++ /dev/null @@ -1,533 +0,0 @@ -/* - * ethertap device for macosx. - * - * tap_interface class definition - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 "tap.h" - -extern "C" { - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -} - -#if 0 -#define dprintf(...) log(LOG_INFO, __VA_ARGS__) -#else -#define dprintf(...) -#endif - -// These declarations are missing in the Kernel.framework headers, put present in userspace :-/ -#pragma pack(4) -struct ifmediareq { - char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - int ifm_current; /* current media options */ - int ifm_mask; /* don't care mask */ - int ifm_status; /* media status */ - int ifm_active; /* active options */ - int ifm_count; /* # entries in ifm_ulist array */ - int *ifm_ulist; /* media words */ -}; - -struct ifmediareq64 { - char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - int ifm_current; /* current media options */ - int ifm_mask; /* don't care mask */ - int ifm_status; /* media status */ - int ifm_active; /* active options */ - int ifm_count; /* # entries in ifm_ulist array */ - user64_addr_t ifmu_ulist __attribute__((aligned(8))); -}; - -struct ifmediareq32 { - char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - int ifm_current; /* current media options */ - int ifm_mask; /* don't care mask */ - int ifm_status; /* media status */ - int ifm_active; /* active options */ - int ifm_count; /* # entries in ifm_ulist array */ - user32_addr_t ifmu_ulist; /* 32-bit pointer */ -}; -#pragma pack() - -#define SIOCGIFMEDIA32 _IOWR('i', 56, struct ifmediareq32) /* get net media */ -#define SIOCGIFMEDIA64 _IOWR('i', 56, struct ifmediareq64) /* get net media (64-bit) */ - -/* thread_policy_set is exported in Mach.kext, but commented in mach/thread_policy.h in the - * Kernel.Framework headers (why?). Add a local declaration to work around that. - */ -extern "C" { -kern_return_t thread_policy_set( - thread_t thread, - thread_policy_flavor_t flavor, - thread_policy_t policy_info, - mach_msg_type_number_t count); -} - -static unsigned char ETHER_BROADCAST_ADDR[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - -/* members */ -tap_interface::tap_interface() { - bzero(attached_protos, sizeof(attached_protos)); - input_thread = THREAD_NULL; -} - -bool -tap_interface::initialize(unsigned short major, unsigned short unit) -{ - this->unit = unit; - this->family_name = TAP_FAMILY_NAME; - this->family = IFNET_FAMILY_ETHERNET; - this->type = IFT_ETHER; - bzero(unique_id, UIDLEN); - snprintf(unique_id, UIDLEN, "%s%d", family_name, unit); - - dprintf("tap: starting interface %s%d\n", TAP_FAMILY_NAME, unit); - - /* register character device */ - if (!tuntap_interface::register_chardev(major)) - return false; - - return true; -} - -void -tap_interface::shutdown() -{ - dprintf("tap: shutting down tap interface %s%d\n", TAP_FAMILY_NAME, unit); - - unregister_chardev(); -} - -int -tap_interface::initialize_interface() -{ - struct sockaddr_dl lladdr; - lladdr.sdl_len = sizeof(lladdr); - lladdr.sdl_family = AF_LINK; - lladdr.sdl_alen = ETHER_ADDR_LEN; - lladdr.sdl_nlen = lladdr.sdl_slen = 0; - - /* generate a random MAC address */ - read_random(LLADDR(&lladdr), ETHER_ADDR_LEN); - - /* clear multicast bit and set local assignment bit (see IEEE 802) */ - (LLADDR(&lladdr))[0] &= 0xfe; - (LLADDR(&lladdr))[0] |= 0x02; - - dprintf("tap: random tap address: %02x:%02x:%02x:%02x:%02x:%02x\n", - (LLADDR(&lladdr))[0] & 0xff, - (LLADDR(&lladdr))[1] & 0xff, - (LLADDR(&lladdr))[2] & 0xff, - (LLADDR(&lladdr))[3] & 0xff, - (LLADDR(&lladdr))[4] & 0xff, - (LLADDR(&lladdr))[5] & 0xff); - - /* register interface */ - if (!tuntap_interface::register_interface(&lladdr, ETHER_BROADCAST_ADDR, ETHER_ADDR_LEN)) - return EIO; - - /* Set link level address. Yes, we need to do that again. Darwin sucks. */ - errno_t err = ifnet_set_lladdr(ifp, LLADDR(&lladdr), ETHER_ADDR_LEN); - if (err) - dprintf("tap: failed to set lladdr on %s%d: %d\n", family_name, unit, err); - - /* set mtu */ - ifnet_set_mtu(ifp, TAP_MTU); - /* set header length */ - ifnet_set_hdrlen(ifp, sizeof(struct ether_header)); - /* add the broadcast flag */ - ifnet_set_flags(ifp, IFF_BROADCAST, IFF_BROADCAST); - - /* we must call bpfattach(). Otherwise we deadlock BPF while unloading. Seems to be a bug in - * the kernel, see bpfdetach() in net/bpf.c, it will return without releasing the lock if - * the interface wasn't attached. I wonder what they were smoking while writing it ;-) - */ - bpfattach(ifp, DLT_EN10MB, ifnet_hdrlen(ifp)); - - /* Inject an empty packet to trigger the input thread calling demux(), which will unblock - * thread_sync_lock. This is part of a hack to avoid a kernel crash on re-attaching - * interfaces, see comment in shutdown_interface for more information. - */ - mbuf_t empty_mbuf; - mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &empty_mbuf); - if (empty_mbuf != NULL) { - mbuf_pkthdr_setrcvif(empty_mbuf, ifp); - mbuf_pkthdr_setlen(empty_mbuf, 0); - mbuf_pkthdr_setheader(empty_mbuf, mbuf_data(empty_mbuf)); - mbuf_set_csum_performed(empty_mbuf, 0, 0); - if (ifnet_input(ifp, empty_mbuf, NULL) == 0) { - auto_lock l(&thread_sync_lock); - for (int i = 0; i < 100 && input_thread == THREAD_NULL; ++i) { - dprintf("input thread not found, waiting...\n"); - thread_sync_lock.sleep(&input_thread, 10000000); - } - } else { - mbuf_freem(empty_mbuf); - } - } - if (input_thread == THREAD_NULL) - dprintf("Failed to determine input thread!\n"); - - return 0; -} - -void -tap_interface::shutdown_interface() -{ - dprintf("tap: shutting down network interface of device %s%d\n", TAP_FAMILY_NAME, unit); - - /* detach all protocols */ - for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) { - if (attached_protos[i].used) { - errno_t err = ifnet_detach_protocol(ifp, attached_protos[i].proto); - if (err) - log(LOG_WARNING, "tap: could not detach protocol %d from %s%d\n", - attached_protos[i].proto, TAP_FAMILY_NAME, unit); - } - } - - cleanup_interface(); - unregister_interface(); - - /* There's a race condition in the kernel that may cause crashes when quickly re-attaching - * interfaces. The crash happens when the interface gets re-attached before the input thread - * for the interface managed to terminate, in which case an assert on the input_waiting flag - * to be clear triggers in ifnet_attach. The bug is really that there's no synchronization - * for terminating the input thread. To work around this, the following code does add the - * missing synchronization to wait for the input thread to terminate. Of course, threading - * primitives available to kexts are few, and I'm not aware of a way to wait for a thread to - * terminate. Hence, the code calls thread_policy_set (passing bogus parameters) in a loop, - * until it returns KERN_TERMINATED. Since this is all rather fragile, there's an upper - * limit on the loop iteratations we're willing to make, so this terminates eventually even - * if things change on the kernel side eventually. - */ - if (input_thread != THREAD_NULL) { - dprintf("Waiting for input thread...\n"); - kern_return_t result = 0; - for (int i = 0; i < 100; ++i) { - result = thread_policy_set(input_thread, -1, NULL, 0); - dprintf("thread_policy_set result: %d\n", result); - if (result == KERN_TERMINATED) { - dprintf("Input thread terminated.\n"); - thread_deallocate(input_thread); - input_thread = THREAD_NULL; - break; - } - - auto_lock l(&thread_sync_lock); - thread_sync_lock.sleep(&input_thread, 10000000); - } - } -} - -errno_t -tap_interface::if_ioctl(u_int32_t cmd, void *arg) -{ - dprintf("tap: if_ioctl cmd: %d (%x)\n", cmd & 0xff, cmd); - - switch (cmd) { - case SIOCSIFLLADDR: - { - /* set ethernet address */ - struct sockaddr *ea = &(((struct ifreq *) arg)->ifr_addr); - - dprintf("tap: SIOCSIFLLADDR family %d len %d\n", - ea->sa_family, ea->sa_len); - - /* check if it is really an ethernet address */ - if (ea->sa_family != AF_LINK || ea->sa_len != ETHER_ADDR_LEN) - return EINVAL; - - /* ok, copy */ - errno_t err = ifnet_set_lladdr(ifp, ea->sa_data, ETHER_ADDR_LEN); - if (err) { - dprintf("tap: failed to set lladdr on %s%d: %d\n", - family_name, unit, err); - return err; - } - - /* Generate a LINK_ON event. This necessary for configd to re-read - * the interface data and refresh the MAC address. Not doing so - * would result in the DHCP client using a stale MAC address... - */ - generate_link_event(KEV_DL_LINK_ON); - - return 0; - } - - case SIOCGIFMEDIA32: - case SIOCGIFMEDIA64: - { - struct ifmediareq *ifmr = (struct ifmediareq*) arg; - user_addr_t list = USER_ADDR_NULL; - - ifmr->ifm_current = IFM_ETHER; - ifmr->ifm_mask = 0; - ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; - ifmr->ifm_active = IFM_ETHER; - ifmr->ifm_count = 1; - - if (cmd == SIOCGIFMEDIA64) - list = ((struct ifmediareq64*) ifmr)->ifmu_ulist; - else - list = CAST_USER_ADDR_T( - ((struct ifmediareq32*) ifmr)->ifmu_ulist); - - if (list != USER_ADDR_NULL) - return copyout(&ifmr->ifm_current, list, sizeof(int)); - - return 0; - } - - default: - /* let our superclass handle it */ - return tuntap_interface::if_ioctl(cmd, arg); - } - - return EOPNOTSUPP; -} - -errno_t -tap_interface::if_demux(mbuf_t m, char *header, protocol_family_t *proto) -{ - struct ether_header *eh = (struct ether_header *) header; - unsigned char lladdr[ETHER_ADDR_LEN]; - - dprintf("tap: if_demux\n"); - - /* Make note of what input thread this interface is running on. This is part of a hack to - * avoid a crash on re-attaching interfaces, see comment in shutdown_interface for details. - */ - if (input_thread == THREAD_NULL) { - auto_lock l(&thread_sync_lock); - input_thread = current_thread(); - thread_reference(input_thread); - thread_sync_lock.wakeup(&input_thread); - } - - /* size check */ - if (mbuf_len(m) < sizeof(struct ether_header)) - return ENOENT; - - /* catch broadcast and multicast (stolen from bsd/net/ether_if_module.c) */ - if (eh->ether_dhost[0] & 1) { - if (memcmp(ETHER_BROADCAST_ADDR, eh->ether_dhost, ETHER_ADDR_LEN) == 0) { - /* broadcast */ - dprintf("tap: broadcast packet.\n"); - mbuf_setflags_mask(m, MBUF_BCAST, MBUF_BCAST); - } else { - /* multicast */ - dprintf("tap: multicast packet.\n"); - mbuf_setflags_mask(m, MBUF_MCAST, MBUF_MCAST); - } - } else { - /* check wether the packet has our address */ - ifnet_lladdr_copy_bytes(ifp, lladdr, ETHER_ADDR_LEN); - if (memcmp(lladdr, eh->ether_dhost, ETHER_ADDR_LEN) != 0) - mbuf_setflags_mask(m, MBUF_PROMISC, MBUF_PROMISC); - } - - /* find the protocol */ - for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) { - if (attached_protos[i].used && attached_protos[i].type == eh->ether_type) { - *proto = attached_protos[i].proto; - return 0; - } - } - - dprintf("tap: if_demux() failed to find proto.\n"); - - /* no matching proto found */ - return ENOENT; -} - -errno_t -tap_interface::if_framer(mbuf_t *m, const struct sockaddr *dest, const char *dest_linkaddr, - const char *frame_type) -{ - struct ether_header *eh; - mbuf_t nm = *m; - errno_t err; - - dprintf("tap: if_framer\n"); - - /* prepend the ethernet header */ - err = mbuf_prepend(&nm, sizeof (struct ether_header), MBUF_WAITOK); - if (err) { - dprintf("tap: could not prepend data to mbuf: %d\n", err); - return err; - } - *m = nm; - - /* fill the header */ - eh = (struct ether_header *) mbuf_data(*m); - memcpy(eh->ether_dhost, dest_linkaddr, ETHER_ADDR_LEN); - ifnet_lladdr_copy_bytes(ifp, eh->ether_shost, ETHER_ADDR_LEN); - eh->ether_type = *((u_int16_t *) frame_type); - - return 0; -} - -errno_t -tap_interface::if_add_proto(protocol_family_t proto, const struct ifnet_demux_desc *desc, - u_int32_t ndesc) -{ - errno_t err; - - dprintf("tap: if_add_proto proto %d\n", proto); - - for (unsigned int i = 0; i < ndesc; i++) { - /* try to add the protocol */ - err = add_one_proto(proto, desc[i]); - if (err != 0) { - /* if that fails, remove everything stored so far */ - if_del_proto(proto); - return err; - } - } - - return 0; -} - -errno_t -tap_interface::if_del_proto(protocol_family_t proto) -{ - dprintf("tap: if_del_proto proto %d\n", proto); - - /* delete all matching entries in attached_protos */ - for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) { - if (attached_protos[i].proto == proto) - attached_protos[i].used = false; - } - - return 0; -} - -errno_t -tap_interface::if_check_multi(const struct sockaddr *maddr) -{ - dprintf("tap: if_check_multi family %d\n", maddr->sa_family); - - /* see whether it is a ethernet address with the multicast bit set */ - if (maddr->sa_family == AF_LINK) { - struct sockaddr_dl *dlmaddr = (struct sockaddr_dl *) maddr; - if (LLADDR(dlmaddr)[0] & 0x01) - return 0; - else - return EADDRNOTAVAIL; - } - - return EOPNOTSUPP; -} - -errno_t -tap_interface::add_one_proto(protocol_family_t proto, const struct ifnet_demux_desc &dd) -{ - int free = -1; - u_int16_t dt; - - /* we only support DLIL_DESC_ETYPE2 */ - if (dd.type != DLIL_DESC_ETYPE2 || dd.datalen != 2) { - log(LOG_WARNING, "tap: tap only supports DLIL_DESC_ETYPE2 protocols.\n"); - return EINVAL; - } - - dt = *((u_int16_t *) (dd.data)); - - /* see if the protocol is already registered */ - for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) { - if (attached_protos[i].used) { - if (dt == attached_protos[i].type) { - /* already registered */ - if (attached_protos[i].proto == proto) { - /* matches the old entry */ - return 0; - } else - return EEXIST; - } - } else if (free == -1) - free = i; - } - - /* did we find a free entry? */ - if (free == -1) - /* is ENOBUFS correct? */ - return ENOBUFS; - - /* ok, save information */ - attached_protos[free].used = true; - attached_protos[free].type = dt; - attached_protos[free].proto = proto; - - return 0; -} - -/* This code is shamelessly stolen from if_bond.c */ -void -tap_interface::generate_link_event(u_int32_t code) -{ - struct { - struct kern_event_msg header; - u_int32_t unit; - char if_name[IFNAMSIZ]; - } event; - - bzero(&event, sizeof(event)); - event.header.total_size = sizeof(event); - event.header.vendor_code = KEV_VENDOR_APPLE; - event.header.kev_class = KEV_NETWORK_CLASS; - event.header.kev_subclass = KEV_DL_SUBCLASS; - event.header.event_code = code; - event.header.event_data[0] = family; - event.unit = (u_int32_t) unit; - strncpy(event.if_name, ifnet_name(ifp), IFNAMSIZ); - - ifnet_event(ifp, &event.header); -} - -/* tap_manager members */ -tuntap_interface * -tap_manager::create_interface() -{ - return new tap_interface(); -} - diff --git a/zto/ext/tap-mac/tuntap/src/tap/tap.h b/zto/ext/tap-mac/tuntap/src/tap/tap.h deleted file mode 100644 index a5164d4..0000000 --- a/zto/ext/tap-mac/tuntap/src/tap/tap.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * ethertap device for MacOSX. - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 __TAP_H__ -#define __TAP_H__ - -#include "tuntap.h" - -extern "C" { - -#include - -} - -#define TAP_FAMILY_NAME ((char *) "zt") -#define TAP_IF_COUNT 32 /* max number of tap interfaces */ -#define TAP_MTU 2800 -#define TAP_LLADDR tap_lladdr - -/* the mac address of our interfaces. note that the last byte will be replaced by the unit number */ -extern u_char tap_lladdr[]; - -/* tap manager */ -class tap_manager : public tuntap_manager { - - protected: - /* just define the interface creation method */ - virtual tuntap_interface *create_interface(); - -}; - -/* the tap network interface */ -class tap_interface : public tuntap_interface { - public: - tap_interface(); - - protected: - /* maximum number of protocols that can be attached */ - static const unsigned int MAX_ATTACHED_PROTOS = 8; - - /* information about attached protocols for demuxing is stored here */ - struct { - /* whether this entry is used */ - bool used; - /* type in the ethernet header */ - u_int16_t type; - /* protocol passed to add_proto */ - protocol_family_t proto; - } attached_protos[MAX_ATTACHED_PROTOS]; - - /* The input thread for the network interface. */ - thread_t input_thread; - - /* initializes the interface */ - virtual bool initialize(unsigned short major, unsigned short unit); - - /* shuts the interface down */ - virtual void shutdown(); - - /* called when the character device is opened in order to intialize the network - * interface. - */ - virtual int initialize_interface(); - /* called when the character device is closed to shutdown the network interface */ - virtual void shutdown_interface(); - - /* override interface routines */ - virtual errno_t if_ioctl(u_int32_t cmd, void *arg); - virtual errno_t if_demux(mbuf_t m, char *header, protocol_family_t *proto); - virtual errno_t if_framer(mbuf_t *m, const struct sockaddr *dest, - const char *dest_linkaddr, const char *frame_type); - virtual errno_t if_add_proto(protocol_family_t proto, - const struct ifnet_demux_desc *ddesc, u_int32_t ndesc); - virtual errno_t if_del_proto(protocol_family_t proto); - virtual errno_t if_check_multi(const struct sockaddr *maddr); - - /* if_add_proto helper */ - errno_t add_one_proto(protocol_family_t proto, const struct ifnet_demux_desc &dd); - - /* generates a kernel event */ - void generate_link_event(u_int32_t code); - - friend class tap_manager; -}; - -#endif /* __TAP_H__ */ - diff --git a/zto/ext/tap-mac/tuntap/src/tuntap.cc b/zto/ext/tap-mac/tuntap/src/tuntap.cc deleted file mode 100644 index d0f8901..0000000 --- a/zto/ext/tap-mac/tuntap/src/tuntap.cc +++ /dev/null @@ -1,963 +0,0 @@ -/* - * ip tunnel/ethertap device for MacOSX. Common functionality of tap_interface and tun_interface. - * - * tuntap_interface class definition - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 "tuntap.h" - -#if 0 -#define dprintf(...) log(LOG_INFO, __VA_ARGS__) -#else -#define dprintf(...) -#endif - -extern "C" { - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include - -} - -extern "C" { - -/* interface service functions that delegate to the appropriate tuntap_interface instance */ -errno_t -tuntap_if_output(ifnet_t ifp, mbuf_t m) -{ - if (ifp != NULL) { - tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); - if (ttif != NULL) - return ttif->if_output(m); - } - - if (m != NULL) - mbuf_freem_list(m); - - return ENODEV; -} - -errno_t -tuntap_if_ioctl(ifnet_t ifp, long unsigned int cmd, void *arg) -{ - if (ifp != NULL) { - tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); - if (ttif != NULL) - return ttif->if_ioctl(cmd, arg); - } - - return ENODEV; -} - -errno_t -tuntap_if_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t)) -{ - if (ifp != NULL) { - tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); - if (ttif != NULL) - return ttif->if_set_bpf_tap(mode, cb); - } - - return ENODEV; -} - -errno_t -tuntap_if_demux(ifnet_t ifp, mbuf_t m, char *header, protocol_family_t *proto) -{ - if (ifp != NULL) { - tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); - if (ttif != NULL) - return ttif->if_demux(m, header, proto); - } - - return ENODEV; -} - -errno_t -tuntap_if_framer(ifnet_t ifp, mbuf_t *m, const struct sockaddr *dest, const char *dest_linkaddr, - const char *frame_type) -{ - if (ifp != NULL) { - tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); - if (ttif != NULL) - return ttif->if_framer(m, dest, dest_linkaddr, frame_type); - } - - return ENODEV; -} - -errno_t -tuntap_if_add_proto(ifnet_t ifp, protocol_family_t proto, const struct ifnet_demux_desc *ddesc, - u_int32_t ndesc) -{ - if (ifp != NULL) { - tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); - if (ttif != NULL) - return ttif->if_add_proto(proto, ddesc, ndesc); - } - - return ENODEV; -} - -errno_t -tuntap_if_del_proto(ifnet_t ifp, protocol_family_t proto) -{ - if (ifp != NULL) { - tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); - if (ttif != NULL) - return ttif->if_del_proto(proto); - } - - return ENODEV; -} - -errno_t -tuntap_if_check_multi(ifnet_t ifp, const struct sockaddr* maddr) -{ - if (ifp != NULL) - { - tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); - if (ttif != NULL) - return ttif->if_check_multi(maddr); - } - - return ENODEV; -} - -void -tuntap_if_detached(ifnet_t ifp) -{ - if (ifp != NULL) { - tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); - if (ttif != NULL) - ttif->if_detached(); - } -} - -errno_t -tuntap_if_noop_output(ifnet_t, mbuf_t) -{ - return ENODEV; -} - -errno_t -tuntap_if_noop_demux(ifnet_t, mbuf_t, char*, protocol_family_t*) -{ - return ENODEV; -} - -errno_t -tuntap_if_noop_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc*, u_int32_t) -{ - return ENODEV; -} - -errno_t -tuntap_if_noop_del_proto(ifnet_t, protocol_family_t) -{ - return ENODEV; -} - -} /* extern "C" */ - -/* tuntap_mbuf_queue */ -tuntap_mbuf_queue::tuntap_mbuf_queue() -{ - head = tail = NULL; - size = 0; -} - -tuntap_mbuf_queue::~tuntap_mbuf_queue() -{ - clear(); -} - -bool -tuntap_mbuf_queue::enqueue(mbuf_t mb) -{ - if (size == QUEUE_SIZE) - return false; - - mbuf_setnextpkt(mb, NULL); - - if (head == NULL) - head = tail = mb; - else { - mbuf_setnextpkt(tail, mb); - tail = mb; - } - size++; - - return true; -} - -mbuf_t -tuntap_mbuf_queue::dequeue() -{ - mbuf_t ret; - - /* check wether there is a packet in the queue */ - if (head == NULL) - return NULL; - - /* fetch it */ - ret = head; - head = mbuf_nextpkt(head); - mbuf_setnextpkt(ret, NULL); - size--; - - return ret; -} - -void -tuntap_mbuf_queue::clear() -{ - /* free mbufs that are in the queue */ - if (head != NULL) - mbuf_freem_list(head); - - head = NULL; - tail = NULL; - size = 0; -} - -/* tuntap_interface members */ -tuntap_interface::tuntap_interface() -{ - /* initialize the members */ - ifp = NULL; - open = false; - block_io = true; - dev_handle = NULL; - pid = 0; - selthreadclear(&rsel); - bpf_mode = BPF_MODE_DISABLED; - bpf_callback = NULL; - bzero(unique_id, UIDLEN); - in_ioctl = false; -} - -tuntap_interface::~tuntap_interface() -{ -} - -bool -tuntap_interface::register_chardev(unsigned short major) -{ - /* register character device */ - dev_handle = devfs_make_node(makedev(major, unit), DEVFS_CHAR, 0, 0, 0660, "%s%d", - family_name, (int) unit); - - if (dev_handle == NULL) { - log(LOG_ERR, "tuntap: could not make /dev/%s%d\n", family_name, (int) unit); - return false; - } - - return true; -} - -void -tuntap_interface::unregister_chardev() -{ - dprintf("unregistering character device\n"); - - /* unregister character device */ - if (dev_handle != NULL) - devfs_remove(dev_handle); - dev_handle = NULL; -} - -bool -tuntap_interface::register_interface(const struct sockaddr_dl* lladdr, void *bcaddr, - u_int32_t bcaddrlen) -{ - struct ifnet_init_params ip; - errno_t err; - - dprintf("register_interface\n"); - - /* initialize an initialization info struct */ - ip.uniqueid_len = UIDLEN; - ip.uniqueid = unique_id; - ip.name = family_name; - ip.unit = unit; - ip.family = family; - ip.type = type; - ip.output = tuntap_if_output; - ip.demux = tuntap_if_demux; - ip.add_proto = tuntap_if_add_proto; - ip.del_proto = tuntap_if_del_proto; - ip.check_multi = tuntap_if_check_multi; - ip.framer = tuntap_if_framer; - ip.softc = this; - ip.ioctl = tuntap_if_ioctl; - ip.set_bpf_tap = tuntap_if_set_bpf_tap; - ip.detach = tuntap_if_detached; - ip.event = NULL; - ip.broadcast_addr = bcaddr; - ip.broadcast_len = bcaddrlen; - - dprintf("tuntap: tuntap_if_check_multi is at 0x%08x\n", (void*) tuntap_if_check_multi); - - /* allocate the interface */ - err = ifnet_allocate(&ip, &ifp); - if (err) { - log(LOG_ERR, "tuntap: could not allocate interface for %s%d: %d\n", family_name, - (int) unit, err); - ifp = NULL; - return false; - } - - /* activate the interface */ - err = ifnet_attach(ifp, lladdr); - if (err) { - log(LOG_ERR, "tuntap: could not attach interface %s%d: %d\n", family_name, - (int) unit, err); - ifnet_release(ifp); - ifp = NULL; - return false; - } - - dprintf("setting interface flags\n"); - - /* set interface flags */ - ifnet_set_flags(ifp, IFF_RUNNING | IFF_MULTICAST | IFF_SIMPLEX, (u_int16_t) ~0UL); - - dprintf("flags: %x\n", ifnet_flags(ifp)); - - return true; -} - -void -tuntap_interface::unregister_interface() -{ - errno_t err; - - dprintf("unregistering network interface\n"); - - if (ifp != NULL) { - interface_detached = false; - - /* detach interface */ - err = ifnet_detach(ifp); - if (err) - log(LOG_ERR, "tuntap: error detaching interface %s%d: %d\n", - family_name, unit, err); - - dprintf("interface detaching\n"); - - /* Wait until the interface has completely been detached. */ - thread_sync_lock.lock(); - while (!interface_detached) - thread_sync_lock.sleep(&interface_detached); - thread_sync_lock.unlock(); - - dprintf("interface detached\n"); - - /* release the interface */ - ifnet_release(ifp); - - ifp = NULL; - } - - dprintf("network interface unregistered\n"); -} - -void -tuntap_interface::cleanup_interface() -{ - errno_t err; - ifaddr_t *addrs; - ifaddr_t *a; - struct ifreq ifr; - - /* mark the interface down */ - ifnet_set_flags(ifp, 0, IFF_UP | IFF_RUNNING); - - /* Unregister all interface addresses. This works around a deficiency in the Darwin kernel. - * If we don't remove all IP addresses that are attached to the interface it can happen that - * the IP code fails to clean them up itself. When the interface is recycled, the IP code - * might then think some addresses are still attached to the interface... - */ - - err = ifnet_get_address_list(ifp, &addrs); - if (!err) { - - /* Execute a SIOCDIFADDR ioctl for each address. For technical reasons, we can only - * do that with a socket of the appropriate family. So try to create a dummy socket. - * I know this is a little expensive, but better than crashing... - * - * This really sucks. - */ - for (a = addrs; *a != NULL; a++) { - /* initialize the request parameters */ - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", - ifnet_name(ifp), ifnet_unit(ifp)); - ifaddr_address(*a, &(ifr.ifr_addr), sizeof(ifr.ifr_addr)); - if (ifr.ifr_addr.sa_family != AF_INET) - continue; - - dprintf("trying to delete address of family %d\n", ifr.ifr_addr.sa_family); - - do_sock_ioctl(ifr.ifr_addr.sa_family, SIOCDIFADDR, &ifr); - } - - /* release the address list */ - ifnet_free_address_list(addrs); - } -} - -bool -tuntap_interface::idle() -{ - return !(open); -} - -void -tuntap_interface::notify_bpf(mbuf_t mb, bool out) -{ - auto_lock l(&bpf_lock); - - if ((out && bpf_mode == BPF_MODE_OUTPUT) - || (!out && bpf_mode == BPF_MODE_INPUT) - || (bpf_mode == BPF_MODE_INPUT_OUTPUT)) - (*bpf_callback)(ifp, mb); -} - -void -tuntap_interface::do_sock_ioctl(sa_family_t af, unsigned long cmd, void* arg) { - if (in_ioctl) { - log(LOG_ERR, "tuntap: ioctl recursion detected, aborting.\n"); - return; - } - - socket_t sock; - errno_t err = sock_socket(af, SOCK_RAW, 0, NULL, NULL, &sock); - if (err) { - log(LOG_ERR, "tuntap: failed to create socket: %d\n", err); - return; - } - - in_ioctl = true; - - /* issue the ioctl */ - err = sock_ioctl(sock, cmd, arg); - if (err) - log(LOG_ERR, "tuntap: socket ioctl %d failed: %d\n", cmd, err); - - in_ioctl = false; - - /* get rid of the socket */ - sock_close(sock); -} - -/* character device service methods */ -int -tuntap_interface::cdev_open(int flags, int devtype, proc_t p) -{ - dprintf("tuntap: cdev_open()\n"); - - /* grab the lock so that there can only be one thread inside */ - auto_lock l(&lock); - - /* check wether it is already open */ - if (open) - return EBUSY; - - /* bring the network interface up */ - int error = initialize_interface(); - if (error) - return error; - - open = true; - pid = proc_pid(p); - - return 0; -} - -int -tuntap_interface::cdev_close(int flags, int devtype, proc_t p) -{ - dprintf("tuntap: cdev_close()\n"); - - auto_lock l(&lock); - - if (open) { - open = false; - - /* shut down the network interface */ - shutdown_interface(); - - /* clear the queue */ - send_queue.clear(); - - /* wakeup the cdev thread and notify selects */ - wakeup(this); - selwakeup(&rsel); - - return 0; - } - - return EBADF; -} - -int -tuntap_interface::cdev_read(uio_t uio, int ioflag) -{ - auto_lock l(&lock); - - unsigned int nb = 0; - int error; - - dprintf("tuntap: cdev read\n"); - - if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP)) - return EIO; - - /* fetch a new mbuf from the queue if necessary */ - mbuf_t cur_mbuf = NULL; - while (cur_mbuf == NULL) { - dprintf("tuntap: fetching new mbuf\n"); - - cur_mbuf = send_queue.dequeue(); - if (cur_mbuf == NULL) { - /* nothing in queue, block or return */ - if (!block_io) { - dprintf("tuntap: aborting (nbio)\n"); - return EWOULDBLOCK; - } else { - /* block */ - dprintf("tuntap: waiting\n"); - /* release the lock while waiting */ - l.unlock(); - error = msleep(this, NULL, PZERO | PCATCH, "tuntap", NULL); - - l.lock(); - - if (error) - return error; - - /* see whether the device was closed in the meantime */ - if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP)) - return EIO; - - } - } - } - - /* notify bpf */ - notify_bpf(cur_mbuf, true); - - /* output what we have */ - do { - dprintf("tuntap: got new mbuf: %p uio_resid: %d\n", cur_mbuf, uio_resid(uio)); - - /* now we have an mbuf */ - int chunk_len = min(mbuf_len(cur_mbuf), uio_resid(uio)); - error = uiomove((char *) mbuf_data(cur_mbuf), chunk_len, uio); - if (error) { - mbuf_freem(cur_mbuf); - return error; - } - nb += chunk_len; - - dprintf("tuntap: moved %d bytes to userspace uio_resid: %d\n", chunk_len, - uio_resid(uio)); - - /* update cur_mbuf */ - cur_mbuf = mbuf_free(cur_mbuf); - - } while (uio_resid(uio) > 0 && cur_mbuf != NULL); - - /* update statistics */ - ifnet_stat_increment_out(ifp, 1, nb, 0); - - /* still data left? forget about that ;-) */ - if (cur_mbuf != NULL) - mbuf_freem(cur_mbuf); - - dprintf("tuntap: read done\n"); - - return 0; -} - -int -tuntap_interface::cdev_write(uio_t uio, int ioflag) -{ - auto_lock l(&lock); - - if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP)) - return EIO; - - dprintf("tuntap: cdev write. uio_resid: %d\n", uio_resid(uio)); - - /* pack the data into an mbuf chain */ - mbuf_t first, mb; - - /* first we need an mbuf having a header */ - mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &first); - if (first == NULL) { - log(LOG_ERR, "tuntap: could not get mbuf.\n"); - return ENOMEM; - } - mbuf_setlen(first, 0); - - unsigned int mlen = mbuf_maxlen(first); - unsigned int chunk_len; - unsigned int copied = 0; - unsigned int max_data_len = ifnet_mtu(ifp) + ifnet_hdrlen(ifp); - int error; - - /* stuff the data into the mbuf(s) */ - mb = first; - while (uio_resid(uio) > 0) { - /* copy a chunk. enforce mtu (don't know if this is correct behaviour) */ - chunk_len = min(max_data_len - copied, min(uio_resid(uio), mlen)); - error = uiomove((caddr_t) mbuf_data(mb), chunk_len, uio); - if (error) { - log(LOG_ERR, "tuntap: could not copy data from userspace: %d\n", error); - mbuf_freem(first); - return error; - } - - dprintf("tuntap: copied %d bytes, uio_resid %d\n", chunk_len, - uio_resid(uio)); - - mlen -= chunk_len; - mbuf_setlen(mb, mbuf_len(mb) + chunk_len); - copied += chunk_len; - - /* if done, break the loop */ - if (uio_resid(uio) <= 0 || copied >= max_data_len) - break; - - /* allocate a new mbuf if the current is filled */ - if (mlen == 0) { - mbuf_t next; - mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &next); - if (next == NULL) { - log(LOG_ERR, "tuntap: could not get mbuf.\n"); - mbuf_freem(first); - return ENOMEM; - } - mbuf_setnext(mb, next); - mb = next; - mbuf_setlen(mb, 0); - mlen = mbuf_maxlen(mb); - } - } - - /* fill in header info */ - mbuf_pkthdr_setrcvif(first, ifp); - mbuf_pkthdr_setlen(first, copied); - mbuf_pkthdr_setheader(first, mbuf_data(first)); - mbuf_set_csum_performed(first, 0, 0); - - /* update statistics */ - ifnet_stat_increment_in(ifp, 1, copied, 0); - - dprintf("tuntap: mbuf chain constructed. first: %p mb: %p len: %d data: %p\n", - first, mb, mbuf_len(first), mbuf_data(first)); - - /* notify bpf */ - notify_bpf(first, false); - - /* need to adjust the data pointer to point directly behind the linklevel header. The header - * itself is later accessed via m_pkthdr.header. Well, if something is ugly, here is it. - */ - mbuf_adj(first, ifnet_hdrlen(ifp)); - - /* pass the packet over to the network stack */ - error = ifnet_input(ifp, first, NULL); - - if (error) { - log(LOG_ERR, "tuntap: could not input packet into network stack.\n"); - mbuf_freem(first); - return error; - } - - return 0; -} - -int -tuntap_interface::cdev_ioctl(u_long cmd, caddr_t data, int fflag, proc_t p) -{ - auto_lock l(&lock); - - dprintf("tuntap: cdev ioctl: %d\n", (int) (cmd & 0xff)); - - switch (cmd) { - case FIONBIO: - /* set i/o mode */ - block_io = *((int *) data) ? false : true; - return 0; - case FIOASYNC: - /* don't allow switching it on */ - if (*((int *) data)) - return ENOTTY; - return 0; - } - - return ENOTTY; -} - -int -tuntap_interface::cdev_select(int which, void *wql, proc_t p) -{ - auto_lock l(&lock); - - int ret = 0; - - dprintf("tuntap: select. which: %d\n", which); - - switch (which) { - case FREAD: - /* check wether data is available */ - { - if (!send_queue.empty()) - ret = 1; - else { - dprintf("tuntap: select: waiting\n"); - selrecord(p, &rsel, wql); - } - } - break; - case FWRITE: - /* we are always writeable */ - ret = 1; - } - - return ret; -} - -/* interface service methods */ -errno_t -tuntap_interface::if_output(mbuf_t m) -{ - mbuf_t pkt; - - dprintf("tuntap: if output\n"); - - /* just to be sure */ - if (m == NULL) - return 0; - - if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP)) { - mbuf_freem_list(m); - return EHOSTDOWN; - } - - /* check whether packet has a header */ - if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) { - log(LOG_ERR, "tuntap: packet to be output has no mbuf header.\n"); - mbuf_freem_list(m); - return EINVAL; - } - - /* put the packet(s) into the output queue */ - while (m != NULL) { - /* keep pointer, iterate */ - pkt = m; - m = mbuf_nextpkt(m); - mbuf_setnextpkt(pkt, NULL); - - auto_lock l(&lock); - - if (!send_queue.enqueue(pkt)) { - mbuf_freem(pkt); - mbuf_freem_list(m); - return ENOBUFS; - } - } - - /* protect the wakeup calls with the lock, not sure they are safe. */ - { - auto_lock l(&lock); - - /* wakeup the cdev thread and notify selects */ - wakeup(this); - selwakeup(&rsel); - } - - return 0; -} - -errno_t -tuntap_interface::if_ioctl(u_int32_t cmd, void *arg) -{ - dprintf("tuntap: if ioctl: %d\n", (int) (cmd & 0xff)); - - switch (cmd) { - case SIOCSIFADDR: - { - dprintf("tuntap: if_ioctl: SIOCSIFADDR\n"); - - /* Unfortunately, ifconfig sets the address family field of an INET - * netmask to zero, which makes early mDNSresponder versions ignore - * the interface. Fix that here. This one is of the category "ugly - * workaround". Dumb Darwin... - * - * Meanwhile, Apple has fixed mDNSResponder, and recent versions of - * Leopard don't need this hack anymore. However, Tiger still has a - * broken version so we leave the hack in for now. - * - * TODO: Revisit when dropping Tiger support. - * - * Btw. If you configure other network interfaces using ifconfig, - * you run into the same problem. I still don't know how to make the - * tap devices show up in the network configuration panel... - */ - ifaddr_t ifa = (ifaddr_t) arg; - if (ifa == NULL) - return 0; - - sa_family_t af = ifaddr_address_family(ifa); - if (af != AF_INET) - return 0; - - struct ifaliasreq ifra; - int sa_size = sizeof(struct sockaddr); - if (ifaddr_address(ifa, &ifra.ifra_addr, sa_size) - || ifaddr_dstaddress(ifa, &ifra.ifra_broadaddr, sa_size) - || ifaddr_netmask(ifa, &ifra.ifra_mask, sa_size)) { - log(LOG_WARNING, - "tuntap: failed to parse interface address.\n"); - return 0; - } - - // Check that the address family fields match. If not, issue another - // SIOCAIFADDR to fix the entry. - if (ifra.ifra_addr.sa_family != af - || ifra.ifra_broadaddr.sa_family != af - || ifra.ifra_mask.sa_family != af) { - log(LOG_INFO, "tuntap: Fixing address family for %s%d\n", - family_name, unit); - - snprintf(ifra.ifra_name, sizeof(ifra.ifra_name), "%s%d", - family_name, unit); - ifra.ifra_addr.sa_family = af; - ifra.ifra_broadaddr.sa_family = af; - ifra.ifra_mask.sa_family = af; - - do_sock_ioctl(af, SIOCAIFADDR, &ifra); - } - - return 0; - } - - case SIOCSIFFLAGS: - return 0; - - case SIOCGIFSTATUS: - { - struct ifstat *stat = (struct ifstat *) arg; - int len; - char *p; - - if (stat == NULL) - return EINVAL; - - /* print status */ - len = strlen(stat->ascii); - p = stat->ascii + len; - if (open) { - snprintf(p, IFSTATMAX - len, "\topen (pid %u)\n", pid); - } else { - snprintf(p, IFSTATMAX - len, "\tclosed\n"); - } - - return 0; - } - - case SIOCSIFMTU: - { - struct ifreq *ifr = (struct ifreq *) arg; - - if (ifr == NULL) - return EINVAL; - - ifnet_set_mtu(ifp, ifr->ifr_mtu); - - return 0; - } - - case SIOCDIFADDR: - return 0; - - } - - return EOPNOTSUPP; -} - -errno_t -tuntap_interface::if_set_bpf_tap(bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t)) -{ - dprintf("tuntap: mode %d\n", mode); - - auto_lock l(&bpf_lock); - - bpf_callback = cb; - bpf_mode = mode; - - return 0; -} - -errno_t -tuntap_interface::if_check_multi(const struct sockaddr *maddr) -{ - dprintf("tuntap: if_check_multi\n"); - - return EOPNOTSUPP; -} - -void -tuntap_interface::if_detached() -{ - dprintf("tuntap: if_detached\n"); - - /* wake unregister_interface() */ - thread_sync_lock.lock(); - interface_detached = true; - thread_sync_lock.wakeup(&interface_detached); - thread_sync_lock.unlock(); - - dprintf("if_detached done\n"); -} - diff --git a/zto/ext/tap-mac/tuntap/src/tuntap.h b/zto/ext/tap-mac/tuntap/src/tuntap.h deleted file mode 100644 index d5f398d..0000000 --- a/zto/ext/tap-mac/tuntap/src/tuntap.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * ip tunnel/ethertap device for MacOSX. - * - * The class tuntaptap_interface contains the common functionality of tuntap_interface and - * tap_interface. - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 __TUNTAP_H__ -#define __TUNTAP_H__ - -#include "util.h" -#include "lock.h" - -extern "C" { - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -} - -extern "C" { - -errno_t tuntap_if_output(ifnet_t ifp, mbuf_t m); -errno_t tuntap_if_ioctl(ifnet_t ifp, long unsigned int cmd, void *arg); -errno_t tuntap_if_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t)); -errno_t tuntap_if_demux(ifnet_t ifp, mbuf_t m, char *header, protocol_family_t *proto); -errno_t tuntap_if_framer(ifnet_t ifp, mbuf_t *m, const struct sockaddr *dest, - const char *dest_linkaddr, const char *frame_type); -errno_t tuntap_if_add_proto(ifnet_t ifp, protocol_family_t proto, - const struct ifnet_demux_desc *ddesc, u_int32_t ndesc); -errno_t tuntap_if_del_proto(ifnet_t ifp, protocol_family_t proto); -errno_t tuntap_if_check_multi(ifnet_t ifp, const struct sockaddr *maddr); -void tuntap_if_detached(ifnet_t ifp); - -} - -/* forward declaration */ -class tuntap_interface; - -/* both interface families have their manager object that will create, initialize, shutdown and - * delete interfaces. This is (mostly) generic so it can be used both for tun and tap. The only - * exception is the interface creation, therefore this class is abstract. tun and tap have their own - * versions that simply fill in create_interface(). - */ -class tuntap_manager { - - protected: - /* manager cdev gate */ - tt_gate cdev_gate; - /* interface count */ - unsigned int count; - /* an array holding all the interface instances */ - tuntap_interface **tuntaps; - /* the major device number */ - int dev_major; - /* family name */ - char *family; - - /* wether static members are initialized */ - static bool statics_initialized; - - /* major-to-manager-map */ - static const int MAX_CDEV = 256; - static tuntap_manager *mgr_map[MAX_CDEV]; - - /* initializes static members */ - void initialize_statics(); - - public: - /* sets major device number, allocates the interface table. */ - bool initialize(unsigned int count, char *family); - - /* tries to shutdown the family. returns true if successful. the manager object may - * not be deleted if this wasn't called successfully. - */ - bool shutdown(); - - /* the destructor deletes allocated memory and unregisters the character device - * switch */ - virtual ~tuntap_manager(); - - /* here are the cdev routines for the class. They will figure out the manager object - * and call the service methods declared below. - */ - static int cdev_open(dev_t dev, int flags, int devtype, proc_t p); - static int cdev_close(dev_t dev, int flags, int devtype, proc_t p); - static int cdev_read(dev_t dev, uio_t uio, int ioflag); - static int cdev_write(dev_t dev, uio_t uio, int ioflag); - static int cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, - proc_t p); - static int cdev_select(dev_t dev, int which, void *wql, proc_t p); - - protected: - /* Here are the actual service routines that will do the required things (creating - * interfaces and such) and forward to the interface's implementation. - */ - int do_cdev_open(dev_t dev, int flags, int devtype, proc_t p); - int do_cdev_close(dev_t dev, int flags, int devtype, proc_t p); - int do_cdev_read(dev_t dev, uio_t uio, int ioflag); - int do_cdev_write(dev_t dev, uio_t uio, int ioflag); - int do_cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, proc_t p); - int do_cdev_select(dev_t dev, int which, void *wql, proc_t p); - - /* abstract method that will create an interface. Implemented by tun and tap */ - virtual tuntap_interface *create_interface() = 0; - - /* makes sure there is one idle interface available (if nothing fails */ - void ensure_idle_device(); - -}; - -/* a class implementing a mbuf packet queue. On Darwin 7 we had struct ifqueue, but that is now - * internal to the kernel for Darwin 8. So lets have our own. - */ -class tuntap_mbuf_queue { - - private: - /* output end of the queue. dequeueing takes mbufs from here */ - mbuf_t head; - /* input end. new mbufs are appended here. */ - mbuf_t tail; - - /* size */ - unsigned int size; - - /* maximum queue size */ - static const unsigned int QUEUE_SIZE = 128; - - public: - /* initialize new empty queue */ - tuntap_mbuf_queue(); - ~tuntap_mbuf_queue(); - - /* is the queue full? */ - bool full() { return size == QUEUE_SIZE; } - /* is it emtpy? */ - bool empty() { return size == 0; } - - /* enqueue an mbuf. returns true if there was space left, so the mbuf could be - * queued, false otherwise */ - bool enqueue(mbuf_t mb); - - /* tries to dequeue the next mbuf. If the queue is empty, NULL is returned */ - mbuf_t dequeue(); - - /* makes the queue empty, discarding any queue packets */ - void clear(); -}; - -class tuntap_interface { - - protected: - /* interface number */ - unsigned int unit; - /* family name */ - char *family_name; - /* family identifier */ - ifnet_family_t family; - /* interface type */ - u_int32_t type; - /* id string */ - static const unsigned int UIDLEN = 20; - char unique_id[UIDLEN]; - - /* synchronization */ - tt_mutex lock; - tt_mutex bpf_lock; - tt_mutex thread_sync_lock; - - /* the interface structure registered */ - ifnet_t ifp; - /* whether the device has been opened */ - bool open; - /* whether we are doing blocking i/o */ - bool block_io; - /* whether the interface has properly been detached */ - bool interface_detached; - /* handle to the devfs node for the character device */ - void *dev_handle; - /* the pid of the process that opened the cdev, if any */ - pid_t pid; - /* read select info */ - struct selinfo rsel; - /* bpf mode, wether filtering is on or off */ - bpf_tap_mode bpf_mode; - /* bpf callback. called when packet arrives/leaves */ - int (*bpf_callback)(ifnet_t, mbuf_t); - /* pending packets queue (for output), must be accessed with the lock held */ - tuntap_mbuf_queue send_queue; - /* whether an ioctl that we issued is currently being processed */ - bool in_ioctl; - - /* protected constructor. initializes most of the members */ - tuntap_interface(); - virtual ~tuntap_interface(); - - /* initialize the device */ - virtual bool initialize(unsigned short major, unsigned short unit) = 0; - - /* character device management */ - virtual bool register_chardev(unsigned short major); - virtual void unregister_chardev(); - - /* network interface management */ - virtual bool register_interface(const struct sockaddr_dl *lladdr, - void *bcaddr, u_int32_t bcaddrlen); - virtual void unregister_interface(); - virtual void cleanup_interface(); - - /* called when the character device is opened in order to intialize the network - * interface. - */ - virtual int initialize_interface() = 0; - /* called when the character device is closed to shutdown the network interface */ - virtual void shutdown_interface() = 0; - - /* check wether the interface is idle (so it can be brought down) */ - virtual bool idle(); - - /* shut it down */ - virtual void shutdown() = 0; - - /* notifies BPF of a packet coming through */ - virtual void notify_bpf(mbuf_t mb, bool out); - - /* executes a socket ioctl through a temporary socket */ - virtual void do_sock_ioctl(sa_family_t af, unsigned long cmd, void* arg); - - /* character device service methods. Called by the manager */ - virtual int cdev_open(int flags, int devtype, proc_t p); - virtual int cdev_close(int flags, int devtype, proc_t p); - virtual int cdev_read(uio_t uio, int ioflag); - virtual int cdev_write(uio_t uio, int ioflag); - virtual int cdev_ioctl(u_long cmd, caddr_t data, int fflag, proc_t p); - virtual int cdev_select(int which, void *wql, proc_t p); - - /* interface functions. friends and implementation methods */ - friend errno_t tuntap_if_output(ifnet_t ifp, mbuf_t m); - friend errno_t tuntap_if_ioctl(ifnet_t ifp, long unsigned int cmd, void *arg); - friend errno_t tuntap_if_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, - int (*cb)(ifnet_t, mbuf_t)); - friend errno_t tuntap_if_demux(ifnet_t ifp, mbuf_t m, char *header, - protocol_family_t *proto); - friend errno_t tuntap_if_framer(ifnet_t ifp, mbuf_t *m, const struct sockaddr *dest, - const char *dest_linkaddr, const char *frame_type); - friend errno_t tuntap_if_add_proto(ifnet_t ifp, protocol_family_t proto, - const struct ifnet_demux_desc *ddesc, u_int32_t ndesc); - friend errno_t tuntap_if_del_proto(ifnet_t ifp, protocol_family_t proto); - friend errno_t tuntap_if_check_multi(ifnet_t ifp, const struct sockaddr *maddr); - friend void tuntap_if_detached(ifnet_t ifp); - - virtual errno_t if_output(mbuf_t m); - virtual errno_t if_ioctl(u_int32_t cmd, void *arg); - virtual errno_t if_set_bpf_tap(bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t)); - virtual errno_t if_demux(mbuf_t m, char *header, protocol_family_t *proto) = 0; - virtual errno_t if_framer(mbuf_t *m, const struct sockaddr *dest, - const char *dest_linkaddr, const char *frame_type) = 0; - virtual errno_t if_add_proto(protocol_family_t proto, - const struct ifnet_demux_desc *ddesc, u_int32_t ndesc) = 0; - virtual errno_t if_del_proto(protocol_family_t proto) = 0; - virtual errno_t if_check_multi(const struct sockaddr *maddr); - virtual void if_detached(); - - /* tuntap_manager feeds us with cdev input, so it is our friend */ - friend class tuntap_manager; -}; - -#endif /* __TUNTAP_H__ */ - diff --git a/zto/ext/tap-mac/tuntap/src/tuntap_mgr.cc b/zto/ext/tap-mac/tuntap/src/tuntap_mgr.cc deleted file mode 100644 index f41394e..0000000 --- a/zto/ext/tap-mac/tuntap/src/tuntap_mgr.cc +++ /dev/null @@ -1,372 +0,0 @@ -/* - * ip tunnel/ethertap device for MacOSX. - * - * tuntap_manager definition. - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 "tuntap.h" -#include "mem.h" - -extern "C" { - -#include -#include -#include -#include - -#include - -#include - -} - -#if 0 -#define dprintf(...) log(LOG_INFO, __VA_ARGS__) -#else -#define dprintf(...) -#endif - -/* cdevsw for tuntap_manager */ -static struct cdevsw mgr_cdevsw = -{ - tuntap_manager::cdev_open, - tuntap_manager::cdev_close, - tuntap_manager::cdev_read, - tuntap_manager::cdev_write, - tuntap_manager::cdev_ioctl, - eno_stop, - eno_reset, - NULL, - tuntap_manager::cdev_select, - eno_mmap, - eno_strat, - eno_getc, - eno_putc, - 0 -}; - -/* tuntap_manager members */ -tuntap_manager *tuntap_manager::mgr_map[MAX_CDEV]; - -bool tuntap_manager::statics_initialized = false; - -/* static initializer */ -void -tuntap_manager::initialize_statics() -{ - dprintf("initializing mgr_map\n"); - - /* initialize the major-to-manager map */ - for (int i = 0; i < MAX_CDEV; i++) - mgr_map[i] = NULL; - - statics_initialized = true; -} - -bool -tuntap_manager::initialize(unsigned int count, char *family) -{ - this->count = count; - this->family = family; - this->tuntaps = NULL; - - if (!statics_initialized) - initialize_statics(); - - /* make sure noone can access the character devices until we are done */ - auto_lock l(&cdev_gate); - - /* register the switch for the tap character devices */ - dev_major = cdevsw_add(-1, &mgr_cdevsw); - if (dev_major == -1) { - log(LOG_ERR, "%s: could not register character device switch.\n", family); - return false; - } - - /* allocate memory for the interface instance table */ - tuntaps = (tuntap_interface **) mem_alloc(count * sizeof(tuntap_interface *)); - if (tuntaps == NULL) - { - log(LOG_ERR, "%s: no memory!\n", family); - return false; - } - - bzero(tuntaps, count * sizeof(tuntap_interface *)); - - /* Create the interfaces. This will only add the character devices. The network devices will - * be created upon open()ing the corresponding character devices. - */ - for (int i = 0; i < (int) count; i++) - { - tuntaps[i] = create_interface(); - - if (tuntaps[i] != NULL) - { - if (tuntaps[i]->initialize(dev_major, i)) - { - continue; - } - - /* error here. current interface needs to be shut down */ - i++; - } - - /* something went wrong. clean up. */ - while (--i >= 0) - { - tuntaps[i]->shutdown(); - delete tuntaps[i]; - } - - return false; - } - - /* register the new family in the mgr switch */ - mgr_map[dev_major] = this; - - log(LOG_INFO, "%s kernel extension version %s \n", - family, TUNTAP_VERSION); - - return true; -} - -bool -tuntap_manager::shutdown() -{ - bool ok = true; - - /* we halt the whole thing while we check whether we can shutdown */ - auto_lock l(&cdev_gate); - - /* anyone in? */ - if (cdev_gate.is_anyone_in()) { - dprintf("tuntap_mgr: won't shutdown, threads still behind the gate."); - ok = false; - } else { - /* query the interfaces to see if shutting down is ok */ - if (tuntaps != NULL) { - for (unsigned int i = 0; i < count; i++) { - if (tuntaps[i] != NULL) - ok &= tuntaps[i]->idle(); - } - - /* if yes, do it now */ - if (ok) { - for (unsigned int i = 0; i < count; i++) { - if (tuntaps[i] != NULL) { - tuntaps[i]->shutdown(); - delete tuntaps[i]; - tuntaps[i] = NULL; - } - } - } - } - } - - /* unregister the character device switch */ - if (ok) { - if (dev_major != -1 && cdevsw_remove(dev_major, &mgr_cdevsw) == -1) { - log(LOG_WARNING, - "%s: character device switch got lost. strange.\n", family); - } - mgr_map[dev_major] = NULL; - dev_major = -1; - - /* at this point there is still a chance that some thread hangs at the cdev_gate in - * one of the cdev service functions. I can't imagine any way that would aviod this. - * So lets unblock the gate such that they fail. - */ - unsigned int old_number; - do { - old_number = cdev_gate.get_ticket_number(); - - dprintf("tuntap_manager: waiting for other threads to give up.\n"); - - /* wait one second */ - cdev_gate.sleep(&cdev_gate, 1000000); - - } while (cdev_gate.get_ticket_number() != old_number); - - /* I hope it is safe to unload now. */ - - } else { - log(LOG_WARNING, "%s: won't unload, at least one interface is busy.\n", family); - } - - dprintf("tuntap manager: shutdown %s\n", ok ? "ok" : "failed"); - - return ok; -} - -tuntap_manager::~tuntap_manager() -{ - dprintf("freeing interface table\n"); - - /* free memory */ - if (tuntaps != NULL) - mem_free(tuntaps, count * sizeof(tuntap_interface *)); -} - -/* service method dispatchers */ -int -tuntap_manager::cdev_open(dev_t dev, int flags, int devtype, proc_t p) -{ - return (mgr_map[major(dev)] == NULL ? ENOENT - : mgr_map[major(dev)]->do_cdev_open(dev, flags, devtype, p)); -} - -int -tuntap_manager::cdev_close(dev_t dev, int flags, int devtype, proc_t p) -{ - return (mgr_map[major(dev)] == NULL ? EBADF - : mgr_map[major(dev)]->do_cdev_close(dev, flags, devtype, p)); -} - -int -tuntap_manager::cdev_read(dev_t dev, uio_t uio, int ioflag) -{ - return (mgr_map[major(dev)] == NULL ? EBADF - : mgr_map[major(dev)]->do_cdev_read(dev, uio, ioflag)); -} - -int -tuntap_manager::cdev_write(dev_t dev, uio_t uio, int ioflag) -{ - return (mgr_map[major(dev)] == NULL ? EBADF - : mgr_map[major(dev)]->do_cdev_write(dev, uio, ioflag)); -} - -int -tuntap_manager::cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, proc_t p) -{ - return (mgr_map[major(dev)] == NULL ? EBADF - : mgr_map[major(dev)]->do_cdev_ioctl(dev, cmd, data, fflag, p)); -} - -int -tuntap_manager::cdev_select(dev_t dev, int which, void *wql, proc_t p) -{ - return (mgr_map[major(dev)] == NULL ? EBADF - : mgr_map[major(dev)]->do_cdev_select(dev, which, wql, p)); -} - -/* character device service methods */ -int -tuntap_manager::do_cdev_open(dev_t dev, int flags, int devtype, proc_t p) -{ - int dmin = minor(dev); - int error = ENOENT; - - cdev_gate.enter(); - - if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL) - error = tuntaps[dmin]->cdev_open(flags, devtype, p); - - cdev_gate.exit(); - - return error; -} - -int -tuntap_manager::do_cdev_close(dev_t dev, int flags, int devtype, proc_t p) -{ - int dmin = minor(dev); - int error = EBADF; - - cdev_gate.enter(); - - if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL) - error = tuntaps[dmin]->cdev_close(flags, devtype, p); - - cdev_gate.exit(); - - return error; -} - -int -tuntap_manager::do_cdev_read(dev_t dev, uio_t uio, int ioflag) -{ - int dmin = minor(dev); - int error = EBADF; - - cdev_gate.enter(); - - if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL) - error = tuntaps[dmin]->cdev_read(uio, ioflag); - - cdev_gate.exit(); - - return error; -} - -int -tuntap_manager::do_cdev_write(dev_t dev, uio_t uio, int ioflag) -{ - int dmin = minor(dev); - int error = EBADF; - - cdev_gate.enter(); - - if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL) - error = tuntaps[dmin]->cdev_write(uio, ioflag); - - cdev_gate.exit(); - - return error; -} - -int -tuntap_manager::do_cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, proc_t p) -{ - int dmin = minor(dev); - int error = EBADF; - - cdev_gate.enter(); - - if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL) - error = tuntaps[dmin]->cdev_ioctl(cmd, data, fflag, p); - - cdev_gate.exit(); - - return error; -} - -int -tuntap_manager::do_cdev_select(dev_t dev, int which, void *wql, proc_t p) -{ - int dmin = minor(dev); - int error = EBADF; - - cdev_gate.enter(); - - if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL) - error = tuntaps[dmin]->cdev_select(which, wql, p); - - cdev_gate.exit(); - - return error; -} - diff --git a/zto/ext/tap-mac/tuntap/src/util.h b/zto/ext/tap-mac/tuntap/src/util.h deleted file mode 100644 index 0f6955e..0000000 --- a/zto/ext/tap-mac/tuntap/src/util.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ip tunnel/ethertap device for MacOSX. - * - * Some utilities and misc stuff. - */ -/* - * Copyright (c) 2011 Mattias Nissler - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 __UTIL_H__ -#define __UTIL_H__ - -extern "C" { - -/* In Darwin 8 (OS X Tiger) there is a problem with struct selinfo. It was made `private' to the - * kernel, so its definition is not available from the headers in Kernel.framework. However, we need - * to declare something :-( - */ -struct selinfo { - char data[128]; /* should be enough... */ -}; - -} /* extern "C" */ - -#endif /* __UTIL_H__ */ - diff --git a/zto/include/README.md b/zto/include/README.md deleted file mode 100644 index a3254ba..0000000 --- a/zto/include/README.md +++ /dev/null @@ -1,4 +0,0 @@ -ZeroTier Node API -====== - -This is the externally facing plain C API, which wraps the Node class in the node/ folder. It provides a platform-agnostic interface to the core ZeroTier network virtualization engine. diff --git a/zto/include/ZeroTierOne.h b/zto/include/ZeroTierOne.h deleted file mode 100644 index 747e185..0000000 --- a/zto/include/ZeroTierOne.h +++ /dev/null @@ -1,2147 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* - * This defines the external C API for ZeroTier's core network virtualization - * engine. - */ - -#ifndef ZT_ZEROTIERONE_H -#define ZT_ZEROTIERONE_H - -#include - -// For the struct sockaddr_storage structure -#if defined(_WIN32) || defined(_WIN64) -#include -#include -#include -#else /* not Windows */ -#include -#include -#include -#include -#endif /* Windows or not */ - -#ifdef __cplusplus -extern "C" { -#endif - -/****************************************************************************/ -/* Core constants */ -/****************************************************************************/ - -/** - * Default UDP port for devices running a ZeroTier endpoint - */ -#define ZT_DEFAULT_PORT 9993 - -/** - * Maximum MTU for ZeroTier virtual networks - * - * This is pretty much an unchangeable global constant. To make it change - * across nodes would require logic to send ICMP packet too big messages, - * which would complicate things. 1500 has been good enough on most LANs - * for ages, so a larger MTU should be fine for the forseeable future. This - * typically results in two UDP packets per single large frame. Experimental - * results seem to show that this is good. Larger MTUs resulting in more - * fragments seemed too brittle on slow/crummy links for no benefit. - * - * If this does change, also change it in tap.h in the tuntaposx code under - * mac-tap. - * - * Overhead for a normal frame split into two packets: - * - * 1414 = 1444 (typical UDP MTU) - 28 (packet header) - 2 (ethertype) - * 1428 = 1444 (typical UDP MTU) - 16 (fragment header) - * SUM: 2842 - * - * We use 2800, which leaves some room for other payload in other types of - * messages such as multicast propagation or future support for bridging. - */ -#define ZT_MAX_MTU 2800 - -/** - * Maximum length of network short name - */ -#define ZT_MAX_NETWORK_SHORT_NAME_LENGTH 127 - -/** - * Maximum number of pushed routes on a network - */ -#define ZT_MAX_NETWORK_ROUTES 32 - -/** - * Maximum number of statically assigned IP addresses per network endpoint using ZT address management (not DHCP) - */ -#define ZT_MAX_ZT_ASSIGNED_ADDRESSES 16 - -/** - * Maximum number of "specialists" on a network -- bridges, relays, etc. - */ -#define ZT_MAX_NETWORK_SPECIALISTS 256 - -/** - * Maximum number of multicast group subscriptions per network - */ -#define ZT_MAX_NETWORK_MULTICAST_SUBSCRIPTIONS 4096 - -/** - * Rules engine revision ID, which specifies rules engine capabilities - */ -#define ZT_RULES_ENGINE_REVISION 1 - -/** - * Maximum number of base (non-capability) network rules - */ -#define ZT_MAX_NETWORK_RULES 1024 - -/** - * Maximum number of per-member capabilities per network - */ -#define ZT_MAX_NETWORK_CAPABILITIES 128 - -/** - * Maximum number of per-member tags per network - */ -#define ZT_MAX_NETWORK_TAGS 128 - -/** - * Maximum number of direct network paths to a given peer - */ -#define ZT_MAX_PEER_NETWORK_PATHS 4 - -/** - * Maximum number of trusted physical network paths - */ -#define ZT_MAX_TRUSTED_PATHS 16 - -/** - * Maximum number of rules per capability - */ -#define ZT_MAX_CAPABILITY_RULES 64 - -/** - * Maximum number of certificates of ownership to assign to a single network member - */ -#define ZT_MAX_CERTIFICATES_OF_OWNERSHIP 4 - -/** - * Global maximum length for capability chain of custody (including initial issue) - */ -#define ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH 7 - -/** - * Maximum number of hops in a ZeroTier circuit test - * - * This is more or less the max that can be fit in a given packet (with - * fragmentation) and only one address per hop. - */ -#define ZT_CIRCUIT_TEST_MAX_HOPS 256 - -/** - * Maximum number of addresses per hop in a circuit test - */ -#define ZT_CIRCUIT_TEST_MAX_HOP_BREADTH 8 - -/** - * Circuit test report flag: upstream peer authorized in path (e.g. by network COM) - */ -#define ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH 0x0000000000000001ULL - -/** - * Maximum number of cluster members (and max member ID plus one) - */ -#define ZT_CLUSTER_MAX_MEMBERS 128 - -/** - * Maximum number of physical ZeroTier addresses a cluster member can report - */ -#define ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES 16 - -/** - * Maximum allowed cluster message length in bytes - */ -#define ZT_CLUSTER_MAX_MESSAGE_LENGTH (1500 - 48) - -/** - * Maximum value for link quality (min is 0) - */ -#define ZT_PATH_LINK_QUALITY_MAX 0xff - -/** - * Packet characteristics flag: packet direction, 1 if inbound 0 if outbound - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_INBOUND 0x8000000000000000ULL - -/** - * Packet characteristics flag: multicast or broadcast destination MAC - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST 0x4000000000000000ULL - -/** - * Packet characteristics flag: broadcast destination MAC - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST 0x2000000000000000ULL - -/** - * Packet characteristics flag: sending IP address has a certificate of ownership - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED 0x1000000000000000ULL - -/** - * Packet characteristics flag: sending MAC address has a certificate of ownership - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED 0x0800000000000000ULL - -/** - * Packet characteristics flag: TCP left-most reserved bit - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_0 0x0000000000000800ULL - -/** - * Packet characteristics flag: TCP middle reserved bit - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_1 0x0000000000000400ULL - -/** - * Packet characteristics flag: TCP right-most reserved bit - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_2 0x0000000000000200ULL - -/** - * Packet characteristics flag: TCP NS flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_NS 0x0000000000000100ULL - -/** - * Packet characteristics flag: TCP CWR flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_CWR 0x0000000000000080ULL - -/** - * Packet characteristics flag: TCP ECE flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_ECE 0x0000000000000040ULL - -/** - * Packet characteristics flag: TCP URG flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_URG 0x0000000000000020ULL - -/** - * Packet characteristics flag: TCP ACK flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK 0x0000000000000010ULL - -/** - * Packet characteristics flag: TCP PSH flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_PSH 0x0000000000000008ULL - -/** - * Packet characteristics flag: TCP RST flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RST 0x0000000000000004ULL - -/** - * Packet characteristics flag: TCP SYN flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN 0x0000000000000002ULL - -/** - * Packet characteristics flag: TCP FIN flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL - -/** - * A null/empty sockaddr (all zero) to signify an unspecified socket address - */ -extern const struct sockaddr_storage ZT_SOCKADDR_NULL; - -/****************************************************************************/ -/* Structures and other types */ -/****************************************************************************/ - -/** - * Function return code: OK (0) or error results - * - * Use ZT_ResultCode_isFatal() to check for a fatal error. If a fatal error - * occurs, the node should be considered to not be working correctly. These - * indicate serious problems like an inaccessible data store or a compile - * problem. - */ -enum ZT_ResultCode -{ - /** - * Operation completed normally - */ - ZT_RESULT_OK = 0, - - // Fatal errors (>0, <1000) - - /** - * Ran out of memory - */ - ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY = 1, - - /** - * Data store is not writable or has failed - */ - ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED = 2, - - /** - * Internal error (e.g. unexpected exception indicating bug or build problem) - */ - ZT_RESULT_FATAL_ERROR_INTERNAL = 3, - - // Non-fatal errors (>1000) - - /** - * Network ID not valid - */ - ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000, - - /** - * The requested operation is not supported on this version or build - */ - ZT_RESULT_ERROR_UNSUPPORTED_OPERATION = 1001, - - /** - * The requestion operation was given a bad parameter or was called in an invalid state - */ - ZT_RESULT_ERROR_BAD_PARAMETER = 1002 -}; - -/** - * @param x Result code - * @return True if result code indicates a fatal error - */ -#define ZT_ResultCode_isFatal(x) ((((int)(x)) > 0)&&(((int)(x)) < 1000)) - -/** - * Status codes sent to status update callback when things happen - */ -enum ZT_Event -{ - /** - * Node has been initialized - * - * This is the first event generated, and is always sent. It may occur - * before Node's constructor returns. - * - * Meta-data: none - */ - ZT_EVENT_UP = 0, - - /** - * Node is offline -- network does not seem to be reachable by any available strategy - * - * Meta-data: none - */ - ZT_EVENT_OFFLINE = 1, - - /** - * Node is online -- at least one upstream node appears reachable - * - * Meta-data: none - */ - ZT_EVENT_ONLINE = 2, - - /** - * Node is shutting down - * - * This is generated within Node's destructor when it is being shut down. - * It's done for convenience, since cleaning up other state in the event - * handler may appear more idiomatic. - * - * Meta-data: none - */ - ZT_EVENT_DOWN = 3, - - /** - * Your identity has collided with another node's ZeroTier address - * - * This happens if two different public keys both hash (via the algorithm - * in Identity::generate()) to the same 40-bit ZeroTier address. - * - * This is something you should "never" see, where "never" is defined as - * once per 2^39 new node initializations / identity creations. If you do - * see it, you're going to see it very soon after a node is first - * initialized. - * - * This is reported as an event rather than a return code since it's - * detected asynchronously via error messages from authoritative nodes. - * - * If this occurs, you must shut down and delete the node, delete the - * identity.secret record/file from the data store, and restart to generate - * a new identity. If you don't do this, you will not be able to communicate - * with other nodes. - * - * We'd automate this process, but we don't think silently deleting - * private keys or changing our address without telling the calling code - * is good form. It violates the principle of least surprise. - * - * You can technically get away with not handling this, but we recommend - * doing so in a mature reliable application. Besides, handling this - * condition is a good way to make sure it never arises. It's like how - * umbrellas prevent rain and smoke detectors prevent fires. They do, right? - * - * Meta-data: none - */ - ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION = 4, - - /** - * Trace (debugging) message - * - * These events are only generated if this is a TRACE-enabled build. - * - * Meta-data: C string, TRACE message - */ - ZT_EVENT_TRACE = 5, - - /** - * VERB_USER_MESSAGE received - * - * These are generated when a VERB_USER_MESSAGE packet is received via - * ZeroTier VL1. - * - * Meta-data: ZT_UserMessage structure - */ - ZT_EVENT_USER_MESSAGE = 6 -}; - -/** - * User message used with ZT_EVENT_USER_MESSAGE - */ -typedef struct -{ - /** - * ZeroTier address of sender (least significant 40 bits) - */ - uint64_t origin; - - /** - * User message type ID - */ - uint64_t typeId; - - /** - * User message data (not including type ID) - */ - const void *data; - - /** - * Length of data in bytes - */ - unsigned int length; -} ZT_UserMessage; - -/** - * Current node status - */ -typedef struct -{ - /** - * 40-bit ZeroTier address of this node - */ - uint64_t address; - - /** - * Public identity in string-serialized form (safe to send to others) - * - * This pointer will remain valid as long as the node exists. - */ - const char *publicIdentity; - - /** - * Full identity including secret key in string-serialized form - * - * This pointer will remain valid as long as the node exists. - */ - const char *secretIdentity; - - /** - * True if some kind of connectivity appears available - */ - int online; -} ZT_NodeStatus; - -/** - * Virtual network status codes - */ -enum ZT_VirtualNetworkStatus -{ - /** - * Waiting for network configuration (also means revision == 0) - */ - ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION = 0, - - /** - * Configuration received and we are authorized - */ - ZT_NETWORK_STATUS_OK = 1, - - /** - * Netconf master told us 'nope' - */ - ZT_NETWORK_STATUS_ACCESS_DENIED = 2, - - /** - * Netconf master exists, but this virtual network does not - */ - ZT_NETWORK_STATUS_NOT_FOUND = 3, - - /** - * Initialization of network failed or other internal error - */ - ZT_NETWORK_STATUS_PORT_ERROR = 4, - - /** - * ZeroTier core version too old - */ - ZT_NETWORK_STATUS_CLIENT_TOO_OLD = 5 -}; - -/** - * Virtual network type codes - */ -enum ZT_VirtualNetworkType -{ - /** - * Private networks are authorized via certificates of membership - */ - ZT_NETWORK_TYPE_PRIVATE = 0, - - /** - * Public networks have no access control -- they'll always be AUTHORIZED - */ - ZT_NETWORK_TYPE_PUBLIC = 1 -}; - -/** - * The type of a virtual network rules table entry - * - * These must be from 0 to 63 since the most significant two bits of each - * rule type are NOT (MSB) and AND/OR. - * - * Each rule is composed of zero or more MATCHes followed by an ACTION. - * An ACTION with no MATCHes is always taken. - */ -enum ZT_VirtualNetworkRuleType -{ - // 0 to 15 reserved for actions - - /** - * Drop frame - */ - ZT_NETWORK_RULE_ACTION_DROP = 0, - - /** - * Accept and pass frame - */ - ZT_NETWORK_RULE_ACTION_ACCEPT = 1, - - /** - * Forward a copy of this frame to an observer (by ZT address) - */ - ZT_NETWORK_RULE_ACTION_TEE = 2, - - /** - * Exactly like TEE but mandates ACKs from observer - */ - ZT_NETWORK_RULE_ACTION_WATCH = 3, - - /** - * Drop and redirect this frame to another node (by ZT address) - */ - ZT_NETWORK_RULE_ACTION_REDIRECT = 4, - - /** - * Stop evaluating rule set (drops unless there are capabilities, etc.) - */ - ZT_NETWORK_RULE_ACTION_BREAK = 5, - - /** - * Maximum ID for an ACTION, anything higher is a MATCH - */ - ZT_NETWORK_RULE_ACTION__MAX_ID = 15, - - // 16 to 63 reserved for match criteria - - ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS = 24, - ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS = 25, - ZT_NETWORK_RULE_MATCH_VLAN_ID = 26, - ZT_NETWORK_RULE_MATCH_VLAN_PCP = 27, - ZT_NETWORK_RULE_MATCH_VLAN_DEI = 28, - ZT_NETWORK_RULE_MATCH_MAC_SOURCE = 29, - ZT_NETWORK_RULE_MATCH_MAC_DEST = 30, - ZT_NETWORK_RULE_MATCH_IPV4_SOURCE = 31, - ZT_NETWORK_RULE_MATCH_IPV4_DEST = 32, - ZT_NETWORK_RULE_MATCH_IPV6_SOURCE = 33, - ZT_NETWORK_RULE_MATCH_IPV6_DEST = 34, - ZT_NETWORK_RULE_MATCH_IP_TOS = 35, - ZT_NETWORK_RULE_MATCH_IP_PROTOCOL = 36, - ZT_NETWORK_RULE_MATCH_ETHERTYPE = 37, - ZT_NETWORK_RULE_MATCH_ICMP = 38, - ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE = 39, - ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE = 40, - ZT_NETWORK_RULE_MATCH_CHARACTERISTICS = 41, - ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 42, - ZT_NETWORK_RULE_MATCH_RANDOM = 43, - ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE = 44, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 45, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 46, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 47, - ZT_NETWORK_RULE_MATCH_TAGS_EQUAL = 48, - ZT_NETWORK_RULE_MATCH_TAG_SENDER = 49, - ZT_NETWORK_RULE_MATCH_TAG_RECEIVER = 50, - - /** - * Maximum ID allowed for a MATCH entry in the rules table - */ - ZT_NETWORK_RULE_MATCH__MAX_ID = 63 -}; - -/** - * Network flow rule - * - * Rules are stored in a table in which one or more match entries is followed - * by an action. If more than one match precedes an action, the rule is - * the AND of all matches. An action with no match is always taken since it - * matches anything. If nothing matches, the default action is DROP. - * - * This is designed to be a more memory-efficient way of storing rules than - * a wide table, yet still fast and simple to access in code. - */ -typedef struct -{ - /** - * Type and flags - * - * Bits are: NOTTTTTT - * - * N - If true, sense of match is inverted (no effect on actions) - * O - If true, result is ORed with previous instead of ANDed (no effect on actions) - * T - Rule or action type - * - * AND with 0x3f to get type, 0x80 to get NOT bit, and 0x40 to get OR bit. - */ - uint8_t t; - - /** - * Union containing the value of this rule -- which field is used depends on 't' - */ - union { - /** - * IPv6 address in big-endian / network byte order and netmask bits - */ - struct { - uint8_t ip[16]; - uint8_t mask; - } ipv6; - - /** - * IPv4 address in big-endian / network byte order - */ - struct { - uint32_t ip; - uint8_t mask; - } ipv4; - - /** - * Packet characteristic flags being matched - */ - uint64_t characteristics; - - /** - * IP port range -- start-end inclusive -- host byte order - */ - uint16_t port[2]; - - /** - * 40-bit ZeroTier address (in least significant bits, host byte order) - */ - uint64_t zt; - - /** - * 0 = never, UINT32_MAX = always - */ - uint32_t randomProbability; - - /** - * 48-bit Ethernet MAC address in big-endian order - */ - uint8_t mac[6]; - - /** - * VLAN ID in host byte order - */ - uint16_t vlanId; - - /** - * VLAN PCP (least significant 3 bits) - */ - uint8_t vlanPcp; - - /** - * VLAN DEI (single bit / boolean) - */ - uint8_t vlanDei; - - /** - * Ethernet type in host byte order - */ - uint16_t etherType; - - /** - * IP protocol - */ - uint8_t ipProtocol; - - /** - * IP type of service a.k.a. DSCP field - */ - struct { - uint8_t mask; - uint8_t value[2]; - } ipTos; - - /** - * Ethernet packet size in host byte order (start-end, inclusive) - */ - uint16_t frameSize[2]; - - /** - * ICMP type and code - */ - struct { - uint8_t type; // ICMP type, always matched - uint8_t code; // ICMP code if matched - uint8_t flags; // flag 0x01 means also match code, otherwise only match type - } icmp; - - /** - * For tag-related rules - */ - struct { - uint32_t id; - uint32_t value; - } tag; - - /** - * Destinations for TEE and REDIRECT - */ - struct { - uint64_t address; - uint32_t flags; - uint16_t length; - } fwd; - } v; -} ZT_VirtualNetworkRule; - -typedef struct -{ - /** - * 128-bit ID (GUID) of this capability - */ - uint64_t id[2]; - - /** - * Expiration time (measured vs. network config timestamp issued by controller) - */ - uint64_t expiration; - - - struct { - uint64_t from; - uint64_t to; - } custody[ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH]; -} ZT_VirtualNetworkCapability; - -/** - * A route to be pushed on a virtual network - */ -typedef struct -{ - /** - * Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default - */ - struct sockaddr_storage target; - - /** - * Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway) - */ - struct sockaddr_storage via; - - /** - * Route flags - */ - uint16_t flags; - - /** - * Route metric (not currently used) - */ - uint16_t metric; -} ZT_VirtualNetworkRoute; - -/** - * An Ethernet multicast group - */ -typedef struct -{ - /** - * MAC address (least significant 48 bits) - */ - uint64_t mac; - - /** - * Additional distinguishing information (usually zero) - */ - unsigned long adi; -} ZT_MulticastGroup; - -/** - * Virtual network configuration update type - */ -enum ZT_VirtualNetworkConfigOperation -{ - /** - * Network is coming up (either for the first time or after service restart) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP = 1, - - /** - * Network configuration has been updated - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE = 2, - - /** - * Network is going down (not permanently) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN = 3, - - /** - * Network is going down permanently (leave/delete) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 -}; - -/** - * What trust hierarchy role does this peer have? - */ -enum ZT_PeerRole -{ - ZT_PEER_ROLE_LEAF = 0, // ordinary node - ZT_PEER_ROLE_MOON = 1, // moon root - ZT_PEER_ROLE_PLANET = 2 // planetary root -}; - -/** - * Vendor ID - */ -enum ZT_Vendor -{ - ZT_VENDOR_UNSPECIFIED = 0, - ZT_VENDOR_ZEROTIER = 1 -}; - -/** - * Platform type - */ -enum ZT_Platform -{ - ZT_PLATFORM_UNSPECIFIED = 0, - ZT_PLATFORM_LINUX = 1, - ZT_PLATFORM_WINDOWS = 2, - ZT_PLATFORM_MACOS = 3, - ZT_PLATFORM_ANDROID = 4, - ZT_PLATFORM_IOS = 5, - ZT_PLATFORM_SOLARIS_SMARTOS = 6, - ZT_PLATFORM_FREEBSD = 7, - ZT_PLATFORM_NETBSD = 8, - ZT_PLATFORM_OPENBSD = 9, - ZT_PLATFORM_RISCOS = 10, - ZT_PLATFORM_VXWORKS = 11, - ZT_PLATFORM_FREERTOS = 12, - ZT_PLATFORM_SYSBIOS = 13, - ZT_PLATFORM_HURD = 14, - ZT_PLATFORM_WEB = 15 -}; - -/** - * Architecture type - */ -enum ZT_Architecture -{ - ZT_ARCHITECTURE_UNSPECIFIED = 0, - ZT_ARCHITECTURE_X86 = 1, - ZT_ARCHITECTURE_X64 = 2, - ZT_ARCHITECTURE_ARM32 = 3, - ZT_ARCHITECTURE_ARM64 = 4, - ZT_ARCHITECTURE_MIPS32 = 5, - ZT_ARCHITECTURE_MIPS64 = 6, - ZT_ARCHITECTURE_POWER32 = 7, - ZT_ARCHITECTURE_POWER64 = 8, - ZT_ARCHITECTURE_OPENRISC32 = 9, - ZT_ARCHITECTURE_OPENRISC64 = 10, - ZT_ARCHITECTURE_SPARC32 = 11, - ZT_ARCHITECTURE_SPARC64 = 12, - ZT_ARCHITECTURE_DOTNET_CLR = 13, - ZT_ARCHITECTURE_JAVA_JVM = 14, - ZT_ARCHITECTURE_WEB = 15 -}; - -/** - * Virtual network configuration - */ -typedef struct -{ - /** - * 64-bit ZeroTier network ID - */ - uint64_t nwid; - - /** - * Ethernet MAC (48 bits) that should be assigned to port - */ - uint64_t mac; - - /** - * Network name (from network configuration master) - */ - char name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; - - /** - * Network configuration request status - */ - enum ZT_VirtualNetworkStatus status; - - /** - * Network type - */ - enum ZT_VirtualNetworkType type; - - /** - * Maximum interface MTU - */ - unsigned int mtu; - - /** - * Recommended MTU to avoid fragmentation at the physical layer (hint) - */ - unsigned int physicalMtu; - - /** - * If nonzero, the network this port belongs to indicates DHCP availability - * - * This is a suggestion. The underlying implementation is free to ignore it - * for security or other reasons. This is simply a netconf parameter that - * means 'DHCP is available on this network.' - */ - int dhcp; - - /** - * If nonzero, this port is allowed to bridge to other networks - * - * This is informational. If this is false (0), bridged packets will simply - * be dropped and bridging won't work. - */ - int bridge; - - /** - * If nonzero, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic - */ - int broadcastEnabled; - - /** - * If the network is in PORT_ERROR state, this is the (negative) error code most recently reported - */ - int portError; - - /** - * Revision number as reported by controller or 0 if still waiting for config - */ - unsigned long netconfRevision; - - /** - * Number of assigned addresses - */ - unsigned int assignedAddressCount; - - /** - * ZeroTier-assigned addresses (in sockaddr_storage structures) - * - * For IP, the port number of the sockaddr_XX structure contains the number - * of bits in the address netmask. Only the IP address and port are used. - * Other fields like interface number can be ignored. - * - * This is only used for ZeroTier-managed address assignments sent by the - * virtual network's configuration master. - */ - struct sockaddr_storage assignedAddresses[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; - - /** - * Number of ZT-pushed routes - */ - unsigned int routeCount; - - /** - * Routes (excluding those implied by assigned addresses and their masks) - */ - ZT_VirtualNetworkRoute routes[ZT_MAX_NETWORK_ROUTES]; -} ZT_VirtualNetworkConfig; - -/** - * A list of networks - */ -typedef struct -{ - ZT_VirtualNetworkConfig *networks; - unsigned long networkCount; -} ZT_VirtualNetworkList; - -/** - * Physical network path to a peer - */ -typedef struct -{ - /** - * Address of endpoint - */ - struct sockaddr_storage address; - - /** - * Time of last send in milliseconds or 0 for never - */ - uint64_t lastSend; - - /** - * Time of last receive in milliseconds or 0 for never - */ - uint64_t lastReceive; - - /** - * Is this a trusted path? If so this will be its nonzero ID. - */ - uint64_t trustedPathId; - - /** - * Path link quality from 0 to 255 (always 255 if peer does not support) - */ - int linkQuality; - - /** - * Is path expired? - */ - int expired; - - /** - * Is path preferred? - */ - int preferred; -} ZT_PeerPhysicalPath; - -/** - * Peer status result buffer - */ -typedef struct -{ - /** - * ZeroTier address (40 bits) - */ - uint64_t address; - - /** - * Remote major version or -1 if not known - */ - int versionMajor; - - /** - * Remote minor version or -1 if not known - */ - int versionMinor; - - /** - * Remote revision or -1 if not known - */ - int versionRev; - - /** - * Last measured latency in milliseconds or zero if unknown - */ - unsigned int latency; - - /** - * What trust hierarchy role does this device have? - */ - enum ZT_PeerRole role; - - /** - * Number of paths (size of paths[]) - */ - unsigned int pathCount; - - /** - * Known network paths to peer - */ - ZT_PeerPhysicalPath paths[ZT_MAX_PEER_NETWORK_PATHS]; -} ZT_Peer; - -/** - * List of peers - */ -typedef struct -{ - ZT_Peer *peers; - unsigned long peerCount; -} ZT_PeerList; - -/** - * ZeroTier circuit test configuration and path - */ -typedef struct { - /** - * Test ID -- an arbitrary 64-bit identifier - */ - uint64_t testId; - - /** - * Timestamp -- sent with test and echoed back by each reporter - */ - uint64_t timestamp; - - /** - * Originator credential: network ID - * - * If this is nonzero, a network ID will be set for this test and - * the originator must be its primary network controller. This is - * currently the only authorization method available, so it must - * be set to run a test. - */ - uint64_t credentialNetworkId; - - /** - * Hops in circuit test (a.k.a. FIFO for graph traversal) - */ - struct { - /** - * Hop flags (currently unused, must be zero) - */ - unsigned int flags; - - /** - * Number of addresses in this hop (max: ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) - */ - unsigned int breadth; - - /** - * 40-bit ZeroTier addresses (most significant 24 bits ignored) - */ - uint64_t addresses[ZT_CIRCUIT_TEST_MAX_HOP_BREADTH]; - } hops[ZT_CIRCUIT_TEST_MAX_HOPS]; - - /** - * Number of hops (max: ZT_CIRCUIT_TEST_MAX_HOPS) - */ - unsigned int hopCount; - - /** - * If non-zero, circuit test will report back at every hop - */ - int reportAtEveryHop; - - /** - * An arbitrary user-settable pointer - */ - void *ptr; - - /** - * Pointer for internal use -- initialize to zero and do not modify - */ - void *_internalPtr; -} ZT_CircuitTest; - -/** - * Circuit test result report - */ -typedef struct { - /** - * Sender of report (current hop) - */ - uint64_t current; - - /** - * Previous hop - */ - uint64_t upstream; - - /** - * 64-bit test ID - */ - uint64_t testId; - - /** - * Timestamp from original test (echoed back at each hop) - */ - uint64_t timestamp; - - /** - * 64-bit packet ID of packet received by the reporting device - */ - uint64_t sourcePacketId; - - /** - * Flags - */ - uint64_t flags; - - /** - * ZeroTier protocol-level hop count of packet received by reporting device (>0 indicates relayed) - */ - unsigned int sourcePacketHopCount; - - /** - * Error code (currently unused, will be zero) - */ - unsigned int errorCode; - - /** - * Remote device vendor ID - */ - enum ZT_Vendor vendor; - - /** - * Remote device protocol compliance version - */ - unsigned int protocolVersion; - - /** - * Software major version - */ - unsigned int majorVersion; - - /** - * Software minor version - */ - unsigned int minorVersion; - - /** - * Software revision - */ - unsigned int revision; - - /** - * Platform / OS - */ - enum ZT_Platform platform; - - /** - * System architecture - */ - enum ZT_Architecture architecture; - - /** - * Local device address on which packet was received by reporting device - * - * This may have ss_family equal to zero (null address) if unspecified. - */ - struct sockaddr_storage receivedOnLocalAddress; - - /** - * Remote address from which reporter received the test packet - * - * This may have ss_family set to zero (null address) if unspecified. - */ - struct sockaddr_storage receivedFromRemoteAddress; - - /** - * Path link quality of physical path over which test was received - */ - int receivedFromLinkQuality; - - /** - * Next hops to which packets are being or will be sent by the reporter - * - * In addition to reporting back, the reporter may send the test on if - * there are more recipients in the FIFO. If it does this, it can report - * back the address(es) that make up the next hop and the physical address - * for each if it has one. The physical address being null/unspecified - * typically indicates that no direct path exists and the next packet - * will be relayed. - */ - struct { - /** - * 40-bit ZeroTier address - */ - uint64_t address; - - /** - * Physical address or null address (ss_family == 0) if unspecified or unknown - */ - struct sockaddr_storage physicalAddress; - } nextHops[ZT_CIRCUIT_TEST_MAX_HOP_BREADTH]; - - /** - * Number of next hops reported in nextHops[] - */ - unsigned int nextHopCount; -} ZT_CircuitTestReport; - -/** - * A cluster member's status - */ -typedef struct { - /** - * This cluster member's ID (from 0 to 1-ZT_CLUSTER_MAX_MEMBERS) - */ - unsigned int id; - - /** - * Number of milliseconds since last 'alive' heartbeat message received via cluster backplane address - */ - unsigned int msSinceLastHeartbeat; - - /** - * Non-zero if cluster member is alive - */ - int alive; - - /** - * X, Y, and Z coordinates of this member (if specified, otherwise zero) - * - * What these mean depends on the location scheme being used for - * location-aware clustering. At present this is GeoIP and these - * will be the X, Y, and Z coordinates of the location on a spherical - * approximation of Earth where Earth's core is the origin (in km). - * They don't have to be perfect and need only be comparable with others - * to find shortest path via the standard vector distance formula. - */ - int x,y,z; - - /** - * Cluster member's last reported load - */ - uint64_t load; - - /** - * Number of peers - */ - uint64_t peers; - - /** - * Physical ZeroTier endpoints for this member (where peers are sent when directed here) - */ - struct sockaddr_storage zeroTierPhysicalEndpoints[ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES]; - - /** - * Number of physical ZeroTier endpoints this member is announcing - */ - unsigned int numZeroTierPhysicalEndpoints; -} ZT_ClusterMemberStatus; - -/** - * ZeroTier cluster status - */ -typedef struct { - /** - * My cluster member ID (a record for 'self' is included in member[]) - */ - unsigned int myId; - - /** - * Number of cluster members - */ - unsigned int clusterSize; - - /** - * Cluster member statuses - */ - ZT_ClusterMemberStatus members[ZT_CLUSTER_MAX_MEMBERS]; -} ZT_ClusterStatus; - -/** - * An instance of a ZeroTier One node (opaque) - */ -typedef void ZT_Node; - -/****************************************************************************/ -/* Callbacks used by Node API */ -/****************************************************************************/ - -/** - * Callback called to update virtual network port configuration - * - * This can be called at any time to update the configuration of a virtual - * network port. The parameter after the network ID specifies whether this - * port is being brought up, updated, brought down, or permanently deleted. - * - * This in turn should be used by the underlying implementation to create - * and configure tap devices at the OS (or virtual network stack) layer. - * - * The supplied config pointer is not guaranteed to remain valid, so make - * a copy if you want one. - * - * This should not call multicastSubscribe() or other network-modifying - * methods, as this could cause a deadlock in multithreaded or interrupt - * driven environments. - * - * This must return 0 on success. It can return any OS-dependent error code - * on failure, and this results in the network being placed into the - * PORT_ERROR state. - */ -typedef int (*ZT_VirtualNetworkConfigFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* Network ID */ - void **, /* Modifiable network user PTR */ - enum ZT_VirtualNetworkConfigOperation, /* Config operation */ - const ZT_VirtualNetworkConfig *); /* Network configuration */ - -/** - * Function to send a frame out to a virtual network port - * - * Parameters: (1) node, (2) user ptr, (3) network ID, (4) source MAC, - * (5) destination MAC, (6) ethertype, (7) VLAN ID, (8) frame data, - * (9) frame length. - */ -typedef void (*ZT_VirtualNetworkFrameFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* Network ID */ - void **, /* Modifiable network user PTR */ - uint64_t, /* Source MAC */ - uint64_t, /* Destination MAC */ - unsigned int, /* Ethernet type */ - unsigned int, /* VLAN ID (0 for none) */ - const void *, /* Frame data */ - unsigned int); /* Frame length */ - -/** - * Callback for events - * - * Events are generated when the node's status changes in a significant way - * and on certain non-fatal errors and events of interest. The final void - * parameter points to event meta-data. The type of event meta-data (and - * whether it is present at all) is event type dependent. See the comments - * in the definition of ZT_Event. - */ -typedef void (*ZT_EventCallback)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_Event, /* Event type */ - const void *); /* Event payload (if applicable) */ - -/** - * Function to get an object from the data store - * - * Parameters: (1) object name, (2) buffer to fill, (3) size of buffer, (4) - * index in object to start reading, (5) result parameter that must be set - * to the actual size of the object if it exists. - * - * Object names can contain forward slash (/) path separators. They will - * never contain .. or backslash (\), so this is safe to map as a Unix-style - * path if the underlying storage permits. For security reasons we recommend - * returning errors if .. or \ are used. - * - * The function must return the actual number of bytes read. If the object - * doesn't exist, it should return -1. -2 should be returned on other errors - * such as errors accessing underlying storage. - * - * If the read doesn't fit in the buffer, the max number of bytes should be - * read. The caller may call the function multiple times to read the whole - * object. - */ -typedef long (*ZT_DataStoreGetFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - const char *, - void *, - unsigned long, - unsigned long, - unsigned long *); - -/** - * Function to store an object in the data store - * - * Parameters: (1) node, (2) user ptr, (3) object name, (4) object data, - * (5) object size, (6) secure? (bool). - * - * If secure is true, the file should be set readable and writable only - * to the user running ZeroTier One. What this means is platform-specific. - * - * Name semantics are the same as the get function. This must return zero on - * success. You can return any OS-specific error code on failure, as these - * may be visible in logs or error messages and might aid in debugging. - * - * If the data pointer is null, this must be interpreted as a delete - * operation. - */ -typedef int (*ZT_DataStorePutFunction)( - ZT_Node *, - void *, - void *, /* Thread ptr */ - const char *, - const void *, - unsigned long, - int); - -/** - * Function to send a ZeroTier packet out over the wire - * - * Parameters: - * (1) Node - * (2) User pointer - * (3) Local interface address - * (4) Remote address - * (5) Packet data - * (6) Packet length - * (7) Desired IP TTL or 0 to use default - * - * If there is only one local interface it is safe to ignore the local - * interface address. Otherwise if running with multiple interfaces, the - * correct local interface should be chosen by address unless NULL. If - * the ss_family field is zero (NULL address), a random or preferred - * default interface should be used. - * - * If TTL is nonzero, packets should have their IP TTL value set to this - * value if possible. If this is not possible it is acceptable to ignore - * this value and send anyway with normal or default TTL. - * - * The function must return zero on success and may return any error code - * on failure. Note that success does not (of course) guarantee packet - * delivery. It only means that the packet appears to have been sent. - */ -typedef int (*ZT_WirePacketSendFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - const struct sockaddr_storage *, /* Local address */ - const struct sockaddr_storage *, /* Remote address */ - const void *, /* Packet data */ - unsigned int, /* Packet length */ - unsigned int); /* TTL or 0 to use default */ - -/** - * Function to check whether a path should be used for ZeroTier traffic - * - * Paramters: - * (1) Node - * (2) User pointer - * (3) ZeroTier address or 0 for none/any - * (4) Local interface address - * (5) Remote address - * - * This function must return nonzero (true) if the path should be used. - * - * If no path check function is specified, ZeroTier will still exclude paths - * that overlap with ZeroTier-assigned and managed IP address blocks. But the - * use of a path check function is recommended to ensure that recursion does - * not occur in cases where addresses are assigned by the OS or managed by - * an out of band mechanism like DHCP. The path check function should examine - * all configured ZeroTier interfaces and check to ensure that the supplied - * addresses will not result in ZeroTier traffic being sent over a ZeroTier - * interface (recursion). - * - * Obviously this is not required in configurations where this can't happen, - * such as network containers or embedded. - */ -typedef int (*ZT_PathCheckFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* ZeroTier address */ - const struct sockaddr_storage *, /* Local address */ - const struct sockaddr_storage *); /* Remote address */ - -/** - * Function to get physical addresses for ZeroTier peers - * - * Parameters: - * (1) Node - * (2) User pointer - * (3) ZeroTier address (least significant 40 bits) - * (4) Desried address family or -1 for any - * (5) Buffer to fill with result - * - * If provided this function will be occasionally called to get physical - * addresses that might be tried to reach a ZeroTier address. It must - * return a nonzero (true) value if the result buffer has been filled - * with an address. - */ -typedef int (*ZT_PathLookupFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* ZeroTier address (40 bits) */ - int, /* Desired ss_family or -1 for any */ - struct sockaddr_storage *); /* Result buffer */ - -/****************************************************************************/ -/* C Node API */ -/****************************************************************************/ - -/** - * Structure for configuring ZeroTier core callback functions - */ -struct ZT_Node_Callbacks -{ - /** - * Struct version -- must currently be 0 - */ - long version; - - /** - * REQUIRED: Function to get objects from persistent storage - */ - ZT_DataStoreGetFunction dataStoreGetFunction; - - /** - * REQUIRED: Function to store objects in persistent storage - */ - ZT_DataStorePutFunction dataStorePutFunction; - - /** - * REQUIRED: Function to send packets over the physical wire - */ - ZT_WirePacketSendFunction wirePacketSendFunction; - - /** - * REQUIRED: Function to inject frames into a virtual network's TAP - */ - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction; - - /** - * REQUIRED: Function to be called when virtual networks are configured or changed - */ - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction; - - /** - * REQUIRED: Function to be called to notify external code of important events - */ - ZT_EventCallback eventCallback; - - /** - * OPTIONAL: Function to check whether a given physical path should be used - */ - ZT_PathCheckFunction pathCheckFunction; - - /** - * OPTIONAL: Function to get hints to physical paths to ZeroTier addresses - */ - ZT_PathLookupFunction pathLookupFunction; -}; - -/** - * Create a new ZeroTier One node - * - * Note that this can take a few seconds the first time it's called, as it - * will generate an identity. - * - * TODO: should consolidate function pointers into versioned structure for - * better API stability. - * - * @param node Result: pointer is set to new node instance on success - * @param uptr User pointer to pass to functions/callbacks - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param callbacks Callback function configuration - * @param now Current clock in milliseconds - * @return OK (0) or error code if a fatal error condition has occurred - */ -enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); - -/** - * Delete a node and free all resources it consumes - * - * If you are using multiple threads, all other threads must be shut down - * first. This can crash if processXXX() methods are in progress. - * - * @param node Node to delete - */ -void ZT_Node_delete(ZT_Node *node); - -/** - * Process a packet received from the physical wire - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param now Current clock in milliseconds - * @param localAddress Local address, or point to ZT_SOCKADDR_NULL if unspecified - * @param remoteAddress Origin of packet - * @param packetData Packet data - * @param packetLength Packet length - * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() - * @return OK (0) or error code if a fatal error condition has occurred - */ -enum ZT_ResultCode ZT_Node_processWirePacket( - ZT_Node *node, - void *tptr, - uint64_t now, - const struct sockaddr_storage *localAddress, - const struct sockaddr_storage *remoteAddress, - const void *packetData, - unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline); - -/** - * Process a frame from a virtual network port (tap) - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param now Current clock in milliseconds - * @param nwid ZeroTier 64-bit virtual network ID - * @param sourceMac Source MAC address (least significant 48 bits) - * @param destMac Destination MAC address (least significant 48 bits) - * @param etherType 16-bit Ethernet frame type - * @param vlanId 10-bit VLAN ID or 0 if none - * @param frameData Frame payload data - * @param frameLength Frame payload length - * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() - * @return OK (0) or error code if a fatal error condition has occurred - */ -enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( - ZT_Node *node, - void *tptr, - uint64_t now, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline); - -/** - * Perform periodic background operations - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param now Current clock in milliseconds - * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() - * @return OK (0) or error code if a fatal error condition has occurred - */ -enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); - -/** - * Join a network - * - * This may generate calls to the port config callback before it returns, - * or these may be deffered if a netconf is not available yet. - * - * If we are already a member of the network, nothing is done and OK is - * returned. - * - * @param node Node instance - * @param nwid 64-bit ZeroTier network ID - * @param uptr An arbitrary pointer to associate with this network (default: NULL) - * @return OK (0) or error code if a fatal error condition has occurred - */ -enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr); - -/** - * Leave a network - * - * If a port has been configured for this network this will generate a call - * to the port config callback with a NULL second parameter to indicate that - * the port is now deleted. - * - * The uptr parameter is optional and is NULL by default. If it is not NULL, - * the pointer it points to is set to this network's uptr on success. - * - * @param node Node instance - * @param nwid 64-bit network ID - * @param uptr Target pointer is set to uptr (if not NULL) - * @return OK (0) or error code if a fatal error condition has occurred - */ -enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr); - -/** - * Subscribe to an Ethernet multicast group - * - * ADI stands for additional distinguishing information. This defaults to zero - * and is rarely used. Right now its only use is to enable IPv4 ARP to scale, - * and this must be done. - * - * For IPv4 ARP, the implementation must subscribe to 0xffffffffffff (the - * broadcast address) but with an ADI equal to each IPv4 address in host - * byte order. This converts ARP from a non-scalable broadcast protocol to - * a scalable multicast protocol with perfect address specificity. - * - * If this is not done, ARP will not work reliably. - * - * Multiple calls to subscribe to the same multicast address will have no - * effect. It is perfectly safe to do this. - * - * This does not generate an update call to networkConfigCallback(). - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param nwid 64-bit network ID - * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) - * @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed) - * @return OK (0) or error code if a fatal error condition has occurred - */ -enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); - -/** - * Unsubscribe from an Ethernet multicast group (or all groups) - * - * If multicastGroup is zero (0), this will unsubscribe from all groups. If - * you are not subscribed to a group this has no effect. - * - * This does not generate an update call to networkConfigCallback(). - * - * @param node Node instance - * @param nwid 64-bit network ID - * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) - * @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed) - * @return OK (0) or error code if a fatal error condition has occurred - */ -enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); - -/** - * Add or update a moon - * - * Moons are persisted in the data store in moons.d/, so this can persist - * across invocations if the contents of moon.d are scanned and orbit is - * called for each on startup. - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param moonWorldId Moon's world ID - * @param moonSeed If non-zero, the ZeroTier address of any member of the moon to query for moon definition - * @param len Length of moonWorld in bytes - * @return Error if moon was invalid or failed to be added - */ -enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed); - -/** - * Remove a moon (does nothing if not present) - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param moonWorldId World ID of moon to remove - * @return Error if anything bad happened - */ -enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId); - -/** - * Get this node's 40-bit ZeroTier address - * - * @param node Node instance - * @return ZeroTier address (least significant 40 bits of 64-bit int) - */ -uint64_t ZT_Node_address(ZT_Node *node); - -/** - * Get the status of this node - * - * @param node Node instance - * @param status Buffer to fill with current node status - */ -void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status); - -/** - * Get a list of known peer nodes - * - * The pointer returned here must be freed with freeQueryResult() - * when you are done with it. - * - * @param node Node instance - * @return List of known peers or NULL on failure - */ -ZT_PeerList *ZT_Node_peers(ZT_Node *node); - -/** - * Get the status of a virtual network - * - * The pointer returned here must be freed with freeQueryResult() - * when you are done with it. - * - * @param node Node instance - * @param nwid 64-bit network ID - * @return Network configuration or NULL if we are not a member of this network - */ -ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t nwid); - -/** - * Enumerate and get status of all networks - * - * @param node Node instance - * @return List of networks or NULL on failure - */ -ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node); - -/** - * Free a query result buffer - * - * Use this to free the return values of listNetworks(), listPeers(), etc. - * - * @param node Node instance - * @param qr Query result buffer - */ -void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); - -/** - * Add a local interface address - * - * This is used to make ZeroTier aware of those local interface addresses - * that you wish to use for ZeroTier communication. This is optional, and if - * it is not used ZeroTier will rely upon upstream peers (and roots) to - * perform empirical address discovery and NAT traversal. But the use of this - * method is recommended as it improves peer discovery when both peers are - * on the same LAN. - * - * It is the responsibility of the caller to take care that these are never - * ZeroTier interface addresses, whether these are assigned by ZeroTier or - * are otherwise assigned to an interface managed by this ZeroTier instance. - * This can cause recursion or other undesirable behavior. - * - * This returns a boolean indicating whether or not the address was - * accepted. ZeroTier will only communicate over certain address types - * and (for IP) address classes. - * - * @param addr Local interface address - * @return Boolean: non-zero if address was accepted and added - */ -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr); - -/** - * Clear local interface addresses - */ -void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); - -/** - * Send a VERB_USER_MESSAGE to another ZeroTier node - * - * There is no delivery guarantee here. Failure can occur if the message is - * too large or if dest is not a valid ZeroTier address. - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param dest Destination ZeroTier address - * @param typeId VERB_USER_MESSAGE type ID - * @param data Payload data to attach to user message - * @param len Length of data in bytes - * @return Boolean: non-zero on success, zero on failure - */ -int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); - -/** - * Set a network configuration master instance for this node - * - * Normal nodes should not need to use this. This is for nodes with - * special compiled-in support for acting as network configuration - * masters / controllers. - * - * The supplied instance must be a C++ object that inherits from the - * NetworkConfigMaster base class in node/. No type checking is performed, - * so a pointer to anything else will result in a crash. - * - * @param node ZertTier One node - * @param networkConfigMasterInstance Instance of NetworkConfigMaster C++ class or NULL to disable - * @return OK (0) or error code if a fatal error condition has occurred - */ -void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); - -/** - * Initiate a VL1 circuit test - * - * This sends an initial VERB_CIRCUIT_TEST and reports results back to the - * supplied callback until circuitTestEnd() is called. The supplied - * ZT_CircuitTest structure should be initially zeroed and then filled - * in with settings and hops. - * - * It is the caller's responsibility to call circuitTestEnd() and then - * to dispose of the test structure. Otherwise this node will listen - * for results forever. - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param test Test configuration - * @param reportCallback Function to call each time a report is received - * @return OK or error if, for example, test is too big for a packet or support isn't compiled in - */ -enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *, ZT_CircuitTest *,const ZT_CircuitTestReport *)); - -/** - * Stop listening for results to a given circuit test - * - * This does not free the 'test' structure. The caller may do that - * after calling this method to unregister it. - * - * Any reports that are received for a given test ID after it is - * terminated are ignored. - * - * @param node Node instance - * @param test Test configuration to unregister - */ -void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test); - -/** - * Initialize cluster operation - * - * This initializes the internal structures and state for cluster operation. - * It takes two function pointers. The first is to a function that can be - * used to send data to cluster peers (mechanism is not defined by Node), - * and the second is to a function that can be used to get the location of - * a physical address in X,Y,Z coordinate space (e.g. as cartesian coordinates - * projected from the center of the Earth). - * - * Send function takes an arbitrary pointer followed by the cluster member ID - * to send data to, a pointer to the data, and the length of the data. The - * maximum message length is ZT_CLUSTER_MAX_MESSAGE_LENGTH (65535). Messages - * must be delivered whole and may be dropped or transposed, though high - * failure rates are undesirable and can cause problems. Validity checking or - * CRC is also not required since the Node validates the authenticity of - * cluster messages using cryptogrphic methods and will silently drop invalid - * messages. - * - * Address to location function is optional and if NULL geo-handoff is not - * enabled (in this case x, y, and z in clusterInit are also unused). It - * takes an arbitrary pointer followed by a physical address and three result - * parameters for x, y, and z. It returns zero on failure or nonzero if these - * three coordinates have been set. Coordinate space is arbitrary and can be - * e.g. coordinates on Earth relative to Earth's center. These can be obtained - * from latitutde and longitude with versions of the Haversine formula. - * - * See: http://stackoverflow.com/questions/1185408/converting-from-longitude-latitude-to-cartesian-coordinates - * - * Neither the send nor the address to location function should block. If the - * address to location function does not have a location for an address, it - * should return zero and then look up the address for future use since it - * will be called again in (typically) 1-3 minutes. - * - * Note that both functions can be called from any thread from which the - * various Node functions are called, and so must be thread safe if multiple - * threads are being used. - * - * @param node Node instance - * @param myId My cluster member ID (less than or equal to ZT_CLUSTER_MAX_MEMBERS) - * @param zeroTierPhysicalEndpoints Preferred physical address(es) for ZeroTier clients to contact this cluster member (for peer redirect) - * @param numZeroTierPhysicalEndpoints Number of physical endpoints in zeroTierPhysicalEndpoints[] (max allowed: 255) - * @param x My cluster member's X location - * @param y My cluster member's Y location - * @param z My cluster member's Z location - * @param sendFunction Function to be called to send data to other cluster members - * @param sendFunctionArg First argument to sendFunction() - * @param addressToLocationFunction Function to be called to get the location of a physical address or NULL to disable geo-handoff - * @param addressToLocationFunctionArg First argument to addressToLocationFunction() - * @return OK or UNSUPPORTED_OPERATION if this Node was not built with cluster support - */ -enum ZT_ResultCode ZT_Node_clusterInit( - ZT_Node *node, - unsigned int myId, - const struct sockaddr_storage *zeroTierPhysicalEndpoints, - unsigned int numZeroTierPhysicalEndpoints, - int x, - int y, - int z, - void (*sendFunction)(void *,unsigned int,const void *,unsigned int), - void *sendFunctionArg, - int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), - void *addressToLocationFunctionArg); - -/** - * Add a member to this cluster - * - * Calling this without having called clusterInit() will do nothing. - * - * @param node Node instance - * @param memberId Member ID (must be less than or equal to ZT_CLUSTER_MAX_MEMBERS) - * @return OK or error if clustering is disabled, ID invalid, etc. - */ -enum ZT_ResultCode ZT_Node_clusterAddMember(ZT_Node *node,unsigned int memberId); - -/** - * Remove a member from this cluster - * - * Calling this without having called clusterInit() will do nothing. - * - * @param node Node instance - * @param memberId Member ID to remove (nothing happens if not present) - */ -void ZT_Node_clusterRemoveMember(ZT_Node *node,unsigned int memberId); - -/** - * Handle an incoming cluster state message - * - * The message itself contains cluster member IDs, and invalid or badly - * addressed messages will be silently discarded. - * - * Calling this without having called clusterInit() will do nothing. - * - * @param node Node instance - * @param msg Cluster message - * @param len Length of cluster message - */ -void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned int len); - -/** - * Get the current status of the cluster from this node's point of view - * - * Calling this without clusterInit() or without cluster support will just - * zero out the structure and show a cluster size of zero. - * - * @param node Node instance - * @param cs Cluster status structure to fill with data - */ -void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs); - -/** - * Set trusted paths - * - * A trusted path is a physical network (network/bits) over which both - * encryption and authentication can be skipped to improve performance. - * Each trusted path must have a non-zero unique ID that is the same across - * all participating nodes. - * - * We don't recommend using trusted paths at all unless you really *need* - * near-bare-metal performance. Even on a LAN authentication and encryption - * are never a bad thing, and anything that introduces an "escape hatch" - * for encryption should be treated with the utmost care. - * - * Calling with NULL pointers for networks and ids and a count of zero clears - * all trusted paths. - * - * @param node Node instance - * @param networks Array of [count] networks - * @param ids Array of [count] corresponding non-zero path IDs (zero path IDs are ignored) - * @param count Number of trusted paths-- values greater than ZT_MAX_TRUSTED_PATHS are clipped - */ -void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); - -/** - * Get ZeroTier One version - * - * @param major Result: major version - * @param minor Result: minor version - * @param revision Result: revision - */ -void ZT_version(int *major,int *minor,int *revision); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/zto/make-bsd.mk b/zto/make-bsd.mk deleted file mode 100644 index b038d13..0000000 --- a/zto/make-bsd.mk +++ /dev/null @@ -1,84 +0,0 @@ -INCLUDES= -DEFS= -LIBS= - -include objects.mk -OBJS+=osdep/BSDEthernetTap.o ext/http-parser/http_parser.o - -# Build with ZT_ENABLE_CLUSTER=1 to build with cluster support -ifeq ($(ZT_ENABLE_CLUSTER),1) - DEFS+=-DZT_ENABLE_CLUSTER -endif - -# "make debug" is a shortcut for this -ifeq ($(ZT_DEBUG),1) - DEFS+=-DZT_TRACE - CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS) - LDFLAGS+= - STRIP=echo - # The following line enables optimization for the crypto code, since - # C25519 in particular is almost UNUSABLE in heavy testing without it. -node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS) -else - CFLAGS?=-O3 -fstack-protector - CFLAGS+=-Wall -fPIE -fvisibility=hidden -fstack-protector -pthread $(INCLUDES) -DNDEBUG $(DEFS) - LDFLAGS+=-pie -Wl,-z,relro,-z,now - STRIP=strip --strip-all -endif - -# Determine system build architecture from compiler target -CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1) -ZT_ARCHITECTURE=0 -ifeq ($(CC_MACH),x86_64) - ZT_ARCHITECTURE=2 -endif -ifeq ($(CC_MACH),amd64) - ZT_ARCHITECTURE=2 -endif -ifeq ($(CC_MACH),i386) - ZT_ARCHITECTURE=1 -endif -ifeq ($(CC_MACH),i686) - ZT_ARCHITECTURE=1 -endif -ifeq ($(CC_MACH),arm) - ZT_ARCHITECTURE=3 -endif -ifeq ($(CC_MACH),arm64) - ZT_ARCHITECTURE=4 -endif -ifeq ($(CC_MACH),aarch64) - ZT_ARCHITECTURE=4 -endif -DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" - -CXXFLAGS+=$(CFLAGS) -fno-rtti -std=c++11 -D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1 - -all: one - -one: $(OBJS) service/OneService.o one.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o $(LIBS) - $(STRIP) zerotier-one - ln -sf zerotier-one zerotier-idtool - ln -sf zerotier-one zerotier-cli - -selftest: $(OBJS) selftest.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS) - $(STRIP) zerotier-selftest - -clean: - rm -rf *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o build-* zerotier-one zerotier-idtool zerotier-selftest zerotier-cli ZeroTierOneInstaller-* - -debug: FORCE - make -j 4 ZT_DEBUG=1 - -install: one - rm -f /usr/local/sbin/zerotier-one - cp zerotier-one /usr/local/sbin - ln -sf /usr/local/sbin/zerotier-one /usr/local/sbin/zerotier-cli - ln -sf /usr/local/sbin/zerotier-one /usr/local/bin/zerotier-idtool - -uninstall: FORCE - rm -rf /usr/local/sbin/zerotier-one /usr/local/sbin/zerotier-cli /usr/local/bin/zerotier-idtool /var/db/zerotier-one/zerotier-one.port /var/db/zerotier-one/zerotier-one.pid /var/db/zerotier-one/iddb.d - -FORCE: diff --git a/zto/make-linux.mk b/zto/make-linux.mk deleted file mode 100644 index a606d58..0000000 --- a/zto/make-linux.mk +++ /dev/null @@ -1,213 +0,0 @@ -# Automagically pick clang or gcc, with preference for clang -# This is only done if we have not overridden these with an environment or CLI variable -ifeq ($(origin CC),default) - CC=$(shell if [ -e /usr/bin/clang ]; then echo clang; else echo gcc; fi) -endif -ifeq ($(origin CXX),default) - CXX=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) -endif - -INCLUDES?= -DEFS?=-D_FORTIFY_SOURCE=2 -LDLIBS?= -DESTDIR?= - -include objects.mk - -# Use bundled http-parser since distribution versions are NOT API-stable or compatible! -# Trying to use dynamically linked libhttp-parser causes tons of compatibility problems. -OBJS+=ext/http-parser/http_parser.o - -# Auto-detect miniupnpc and nat-pmp as well and use system libs if present, -# otherwise build into binary as done on Mac and Windows. -OBJS+=osdep/PortMapper.o -DEFS+=-DZT_USE_MINIUPNPC -MINIUPNPC_IS_NEW_ENOUGH=$(shell grep -sqr '.*define.*MINIUPNPC_VERSION.*"2.."' /usr/include/miniupnpc/miniupnpc.h && echo 1) -ifeq ($(MINIUPNPC_IS_NEW_ENOUGH),1) - DEFS+=-DZT_USE_SYSTEM_MINIUPNPC - LDLIBS+=-lminiupnpc -else - DEFS+=-DMINIUPNP_STATICLIB -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DOS_STRING=\"Linux\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR - OBJS+=ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o -endif -ifeq ($(wildcard /usr/include/natpmp.h),) - OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o -else - LDLIBS+=-lnatpmp - DEFS+=-DZT_USE_SYSTEM_NATPMP -endif - -ifeq ($(ZT_ENABLE_CLUSTER),1) - DEFS+=-DZT_ENABLE_CLUSTER -endif - -ifeq ($(ZT_SYNOLOGY), 1) - DEFS+=-D__SYNOLOGY__ -endif - -ifeq ($(ZT_TRACE),1) - DEFS+=-DZT_TRACE -endif - -ifeq ($(ZT_RULES_ENGINE_DEBUGGING),1) - DEFS+=-DZT_RULES_ENGINE_DEBUGGING -endif - -ifeq ($(ZT_DEBUG),1) - DEFS+=-DZT_TRACE - override CFLAGS+=-Wall -g -O -pthread $(INCLUDES) $(DEFS) - override CXXFLAGS+=-Wall -g -O -std=c++11 -pthread $(INCLUDES) $(DEFS) - override LDFLAGS+= - STRIP?=echo - # The following line enables optimization for the crypto code, since - # C25519 in particular is almost UNUSABLE in -O0 even on a 3ghz box! -node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS) -else - CFLAGS?=-O3 -fstack-protector - override CFLAGS+=-Wall -fPIE -pthread $(INCLUDES) -DNDEBUG $(DEFS) - CXXFLAGS?=-O3 -fstack-protector - override CXXFLAGS+=-Wall -Wno-unused-result -Wreorder -fPIE -std=c++11 -pthread $(INCLUDES) -DNDEBUG $(DEFS) - override LDFLAGS+=-pie -Wl,-z,relro,-z,now - STRIP?=strip - STRIP+=--strip-all -endif - -# Uncomment for gprof profile build -#CFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS) -#CXXFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS) -#LDFLAGS= -#STRIP=echo - -# Determine system build architecture from compiler target -CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1) -ZT_ARCHITECTURE=0 -ifeq ($(CC_MACH),x86_64) - ZT_ARCHITECTURE=2 -endif -ifeq ($(CC_MACH),amd64) - ZT_ARCHITECTURE=2 -endif -ifeq ($(CC_MACH),i386) - ZT_ARCHITECTURE=1 -endif -ifeq ($(CC_MACH),i686) - ZT_ARCHITECTURE=1 -endif -ifeq ($(CC_MACH),arm) - ZT_ARCHITECTURE=3 -endif -ifeq ($(CC_MACH),armel) - ZT_ARCHITECTURE=3 -endif -ifeq ($(CC_MACH),armhf) - ZT_ARCHITECTURE=3 -endif -ifeq ($(CC_MACH),armv6) - ZT_ARCHITECTURE=3 -endif -ifeq ($(CC_MACH),armv7) - ZT_ARCHITECTURE=3 -endif -ifeq ($(CC_MACH),arm64) - ZT_ARCHITECTURE=4 -endif -ifeq ($(CC_MACH),aarch64) - ZT_ARCHITECTURE=4 -endif -DEFS+=-DZT_BUILD_PLATFORM=1 -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" - -# Define some conservative CPU instruction set flags for arm32 since there's a ton of variation out there -ifeq ($(ZT_ARCHITECTURE),3) - override CFLAGS+=-march=armv6zk -mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp - override CXXFLAGS+=-march=armv6zk -mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp - override DEFS+=-DZT_NO_TYPE_PUNNING -endif - -# Define this to build a static binary, which is needed to make this runnable on a few ancient Linux distros -ifeq ($(ZT_STATIC),1) - override LDFLAGS+=-static -endif - -all: one - -one: $(OBJS) service/OneService.o one.o osdep/LinuxEthernetTap.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o osdep/LinuxEthernetTap.o $(LDLIBS) - $(STRIP) zerotier-one - ln -sf zerotier-one zerotier-idtool - ln -sf zerotier-one zerotier-cli - -selftest: $(OBJS) selftest.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LDLIBS) - $(STRIP) zerotier-selftest - -manpages: FORCE - cd doc ; ./build.sh - -doc: manpages - -clean: FORCE - rm -rf *.so *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/miniupnpc/*.o ext/libnatpmp/*.o $(OBJS) zerotier-one zerotier-idtool zerotier-cli zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm .depend debian/files debian/zerotier-one*.debhelper debian/zerotier-one.substvars debian/*.log debian/zerotier-one doc/node_modules - -distclean: clean - -realclean: distclean - -debug: FORCE - make ZT_DEBUG=1 one - make ZT_DEBUG=1 selftest - -# Note: keep the symlinks in /var/lib/zerotier-one to the binaries since these -# provide backward compatibility with old releases where the binaries actually -# lived here. Folks got scripts. - -install: FORCE - mkdir -p $(DESTDIR)/usr/sbin - rm -f $(DESTDIR)/usr/sbin/zerotier-one - cp -f zerotier-one $(DESTDIR)/usr/sbin/zerotier-one - rm -f $(DESTDIR)/usr/sbin/zerotier-cli - rm -f $(DESTDIR)/usr/sbin/zerotier-idtool - ln -s zerotier-one $(DESTDIR)/usr/sbin/zerotier-cli - ln -s zerotier-one $(DESTDIR)/usr/sbin/zerotier-idtool - mkdir -p $(DESTDIR)/var/lib/zerotier-one - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-one - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-cli - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-idtool - ln -s ../../../usr/sbin/zerotier-one $(DESTDIR)/var/lib/zerotier-one/zerotier-one - ln -s ../../../usr/sbin/zerotier-one $(DESTDIR)/var/lib/zerotier-one/zerotier-cli - ln -s ../../../usr/sbin/zerotier-one $(DESTDIR)/var/lib/zerotier-one/zerotier-idtool - mkdir -p $(DESTDIR)/usr/share/man/man8 - rm -f $(DESTDIR)/usr/share/man/man8/zerotier-one.8.gz - cat doc/zerotier-one.8 | gzip -9 >$(DESTDIR)/usr/share/man/man8/zerotier-one.8.gz - mkdir -p $(DESTDIR)/usr/share/man/man1 - rm -f $(DESTDIR)/usr/share/man/man1/zerotier-idtool.1.gz - rm -f $(DESTDIR)/usr/share/man/man1/zerotier-cli.1.gz - cat doc/zerotier-cli.1 | gzip -9 >$(DESTDIR)/usr/share/man/man1/zerotier-cli.1.gz - cat doc/zerotier-idtool.1 | gzip -9 >$(DESTDIR)/usr/share/man/man1/zerotier-idtool.1.gz - -# Uninstall preserves identity.public and identity.secret since the user might -# want to save these. These are your ZeroTier address. - -uninstall: FORCE - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-one - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-cli - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-idtool - rm -f $(DESTDIR)/usr/sbin/zerotier-cli - rm -f $(DESTDIR)/usr/sbin/zerotier-idtool - rm -f $(DESTDIR)/usr/sbin/zerotier-one - rm -rf $(DESTDIR)/var/lib/zerotier-one/iddb.d - rm -rf $(DESTDIR)/var/lib/zerotier-one/updates.d - rm -rf $(DESTDIR)/var/lib/zerotier-one/networks.d - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-one.port - rm -f $(DESTDIR)/usr/share/man/man8/zerotier-one.8.gz - rm -f $(DESTDIR)/usr/share/man/man1/zerotier-idtool.1.gz - rm -f $(DESTDIR)/usr/share/man/man1/zerotier-cli.1.gz - -# These are just for convenience for building Linux packages - -debian: FORCE - debuild -I -i -us -uc -nc -b - -redhat: FORCE - rpmbuild -ba zerotier-one.spec - -FORCE: diff --git a/zto/make-mac.mk b/zto/make-mac.mk deleted file mode 100644 index 8ff1b77..0000000 --- a/zto/make-mac.mk +++ /dev/null @@ -1,111 +0,0 @@ -CC=clang -CXX=clang++ -INCLUDES= -DEFS= -LIBS= -ARCH_FLAGS= -CODESIGN=echo -PRODUCTSIGN=echo -CODESIGN_APP_CERT= -CODESIGN_INSTALLER_CERT= - -ZT_BUILD_PLATFORM=3 -ZT_BUILD_ARCHITECTURE=2 -ZT_VERSION_MAJOR=$(shell cat version.h | grep -F VERSION_MAJOR | cut -d ' ' -f 3) -ZT_VERSION_MINOR=$(shell cat version.h | grep -F VERSION_MINOR | cut -d ' ' -f 3) -ZT_VERSION_REV=$(shell cat version.h | grep -F VERSION_REVISION | cut -d ' ' -f 3) -ZT_VERSION_BUILD=$(shell cat version.h | grep -F VERSION_BUILD | cut -d ' ' -f 3) - -DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_BUILD_ARCHITECTURE) - -include objects.mk -OBJS+=osdep/OSXEthernetTap.o ext/http-parser/http_parser.o - -# Official releases are signed with our Apple cert and apply software updates by default -ifeq ($(ZT_OFFICIAL_RELEASE),1) - DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"apply\"" - ZT_USE_MINIUPNPC=1 - CODESIGN=codesign - PRODUCTSIGN=productsign - CODESIGN_APP_CERT="Developer ID Application: ZeroTier, Inc (8ZD9JUCZ4V)" - CODESIGN_INSTALLER_CERT="Developer ID Installer: ZeroTier, Inc (8ZD9JUCZ4V)" -else - DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"download\"" -endif - -ifeq ($(ZT_ENABLE_CLUSTER),1) - DEFS+=-DZT_ENABLE_CLUSTER -endif - -# Build miniupnpc and nat-pmp as included libraries -- extra defs are required for these sources -DEFS+=-DMACOSX -DZT_USE_MINIUPNPC -DMINIUPNP_STATICLIB -D_DARWIN_C_SOURCE -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -DOS_STRING=\"Darwin/15.0.0\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR -OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o osdep/PortMapper.o - -# Debug mode -- dump trace output, build binary with -g -ifeq ($(ZT_DEBUG),1) - DEFS+=-DZT_TRACE - CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS) - STRIP=echo - # The following line enables optimization for the crypto code, since - # C25519 in particular is almost UNUSABLE in heavy testing without it. -node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS) -else - CFLAGS?=-Ofast -fstack-protector-strong - CFLAGS+=$(ARCH_FLAGS) -Wall -flto -fPIE -pthread -mmacosx-version-min=10.7 -DNDEBUG -Wno-unused-private-field $(INCLUDES) $(DEFS) - STRIP=strip -endif - -CXXFLAGS=$(CFLAGS) -std=c++11 -stdlib=libc++ - -all: one macui - -one: $(OBJS) service/OneService.o one.o - $(CXX) $(CXXFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o $(LIBS) - $(STRIP) zerotier-one - ln -sf zerotier-one zerotier-idtool - ln -sf zerotier-one zerotier-cli - $(CODESIGN) -f -s $(CODESIGN_APP_CERT) zerotier-one - -macui: FORCE - cd macui && xcodebuild -target "ZeroTier One" -configuration Release - $(CODESIGN) -f -s $(CODESIGN_APP_CERT) "macui/build/Release/ZeroTier One.app" - -#cli: FORCE -# $(CXX) $(CXXFLAGS) -o zerotier cli/zerotier.cpp osdep/OSUtils.cpp node/InetAddress.cpp node/Utils.cpp node/Salsa20.cpp node/Identity.cpp node/SHA512.cpp node/C25519.cpp -lcurl -# $(STRIP) zerotier - -selftest: $(OBJS) selftest.o - $(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS) - $(STRIP) zerotier-selftest - -# Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html -mac-dist-pkg: FORCE - packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj" - rm -f "ZeroTier One Signed.pkg" - $(PRODUCTSIGN) --sign $(CODESIGN_INSTALLER_CERT) "ZeroTier One.pkg" "ZeroTier One Signed.pkg" - if [ -f "ZeroTier One Signed.pkg" ]; then mv -f "ZeroTier One Signed.pkg" "ZeroTier One.pkg"; fi - rm -f zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_* - cat ext/installfiles/mac-update/updater.tmpl.sh "ZeroTier One.pkg" >zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_$(ZT_VERSION_MAJOR).$(ZT_VERSION_MINOR).$(ZT_VERSION_REV)_$(ZT_VERSION_BUILD).exe - -# For ZeroTier, Inc. to build official signed packages -official: FORCE - make clean - make ZT_OFFICIAL_RELEASE=1 -j 4 one - make ZT_OFFICIAL_RELEASE=1 macui - make ZT_OFFICIAL_RELEASE=1 mac-dist-pkg - -clean: - rm -rf *.dSYM build-* *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o $(OBJS) zerotier-one zerotier-idtool zerotier-selftest zerotier-cli zerotier mkworld doc/node_modules macui/build zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_* - -distclean: clean - -realclean: clean - -# For those building from source -- installs signed binary tap driver in system ZT home -install-mac-tap: FORCE - mkdir -p /Library/Application\ Support/ZeroTier/One - rm -rf /Library/Application\ Support/ZeroTier/One/tap.kext - cp -R ext/bin/tap-mac/tap.kext /Library/Application\ Support/ZeroTier/One - chown -R root:wheel /Library/Application\ Support/ZeroTier/One/tap.kext - -FORCE: diff --git a/zto/node/Address.hpp b/zto/node/Address.hpp deleted file mode 100644 index 4a5883b..0000000 --- a/zto/node/Address.hpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_ADDRESS_HPP -#define ZT_ADDRESS_HPP - -#include -#include -#include -#include - -#include - -#include "Constants.hpp" -#include "Utils.hpp" -#include "Buffer.hpp" - -namespace ZeroTier { - -/** - * A ZeroTier address - */ -class Address -{ -public: - Address() : _a(0) {} - Address(const Address &a) : _a(a._a) {} - Address(uint64_t a) : _a(a & 0xffffffffffULL) {} - - /** - * @param bits Raw address -- 5 bytes, big-endian byte order - * @param len Length of array - */ - Address(const void *bits,unsigned int len) - { - setTo(bits,len); - } - - inline Address &operator=(const Address &a) - { - _a = a._a; - return *this; - } - - inline Address &operator=(const uint64_t a) - { - _a = (a & 0xffffffffffULL); - return *this; - } - - /** - * @param bits Raw address -- 5 bytes, big-endian byte order - * @param len Length of array - */ - inline void setTo(const void *bits,unsigned int len) - { - if (len < ZT_ADDRESS_LENGTH) { - _a = 0; - return; - } - const unsigned char *b = (const unsigned char *)bits; - uint64_t a = ((uint64_t)*b++) << 32; - a |= ((uint64_t)*b++) << 24; - a |= ((uint64_t)*b++) << 16; - a |= ((uint64_t)*b++) << 8; - a |= ((uint64_t)*b); - _a = a; - } - - /** - * @param bits Buffer to hold 5-byte address in big-endian byte order - * @param len Length of array - */ - inline void copyTo(void *bits,unsigned int len) const - { - if (len < ZT_ADDRESS_LENGTH) - return; - unsigned char *b = (unsigned char *)bits; - *(b++) = (unsigned char)((_a >> 32) & 0xff); - *(b++) = (unsigned char)((_a >> 24) & 0xff); - *(b++) = (unsigned char)((_a >> 16) & 0xff); - *(b++) = (unsigned char)((_a >> 8) & 0xff); - *b = (unsigned char)(_a & 0xff); - } - - /** - * Append to a buffer in big-endian byte order - * - * @param b Buffer to append to - */ - template - inline void appendTo(Buffer &b) const - { - unsigned char *p = (unsigned char *)b.appendField(ZT_ADDRESS_LENGTH); - *(p++) = (unsigned char)((_a >> 32) & 0xff); - *(p++) = (unsigned char)((_a >> 24) & 0xff); - *(p++) = (unsigned char)((_a >> 16) & 0xff); - *(p++) = (unsigned char)((_a >> 8) & 0xff); - *p = (unsigned char)(_a & 0xff); - } - - /** - * @return Integer containing address (0 to 2^40) - */ - inline uint64_t toInt() const - { - return _a; - } - - /** - * @return Hash code for use with Hashtable - */ - inline unsigned long hashCode() const - { - return (unsigned long)_a; - } - - /** - * @return Hexadecimal string - */ - inline std::string toString() const - { - char buf[16]; - Utils::snprintf(buf,sizeof(buf),"%.10llx",(unsigned long long)_a); - return std::string(buf); - }; - - /** - * @param buf Buffer to fill - * @param len Length of buffer - */ - inline void toString(char *buf,unsigned int len) const - { - Utils::snprintf(buf,len,"%.10llx",(unsigned long long)_a); - } - - /** - * @return True if this address is not zero - */ - inline operator bool() const { return (_a != 0); } - - /** - * Set to null/zero - */ - inline void zero() { _a = 0; } - - /** - * Check if this address is reserved - * - * The all-zero null address and any address beginning with 0xff are - * reserved. (0xff is reserved for future use to designate possibly - * longer addresses, addresses based on IPv6 innards, etc.) - * - * @return True if address is reserved and may not be used - */ - inline bool isReserved() const - { - return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX)); - } - - /** - * @param i Value from 0 to 4 (inclusive) - * @return Byte at said position (address interpreted in big-endian order) - */ - inline unsigned char operator[](unsigned int i) const { return (unsigned char)((_a >> (32 - (i * 8))) & 0xff); } - - inline bool operator==(const uint64_t &a) const { return (_a == (a & 0xffffffffffULL)); } - inline bool operator!=(const uint64_t &a) const { return (_a != (a & 0xffffffffffULL)); } - inline bool operator>(const uint64_t &a) const { return (_a > (a & 0xffffffffffULL)); } - inline bool operator<(const uint64_t &a) const { return (_a < (a & 0xffffffffffULL)); } - inline bool operator>=(const uint64_t &a) const { return (_a >= (a & 0xffffffffffULL)); } - inline bool operator<=(const uint64_t &a) const { return (_a <= (a & 0xffffffffffULL)); } - - inline bool operator==(const Address &a) const { return (_a == a._a); } - inline bool operator!=(const Address &a) const { return (_a != a._a); } - inline bool operator>(const Address &a) const { return (_a > a._a); } - inline bool operator<(const Address &a) const { return (_a < a._a); } - inline bool operator>=(const Address &a) const { return (_a >= a._a); } - inline bool operator<=(const Address &a) const { return (_a <= a._a); } - -private: - uint64_t _a; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Array.hpp b/zto/node/Array.hpp deleted file mode 100644 index 19b29eb..0000000 --- a/zto/node/Array.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_ARRAY_HPP -#define ZT_ARRAY_HPP - -#include -#include - -namespace ZeroTier { - -/** - * Static array -- a simple thing that's belonged in STL since the time of the dinosaurs - */ -template -class Array -{ -public: - Array() throw() {} - - Array(const Array &a) - { - for(std::size_t i=0;i reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - inline iterator begin() throw() { return data; } - inline iterator end() throw() { return &(data[S]); } - inline const_iterator begin() const throw() { return data; } - inline const_iterator end() const throw() { return &(data[S]); } - - inline reverse_iterator rbegin() throw() { return reverse_iterator(begin()); } - inline reverse_iterator rend() throw() { return reverse_iterator(end()); } - inline const_reverse_iterator rbegin() const throw() { return const_reverse_iterator(begin()); } - inline const_reverse_iterator rend() const throw() { return const_reverse_iterator(end()); } - - inline std::size_t size() const throw() { return S; } - inline std::size_t max_size() const throw() { return S; } - - inline reference operator[](const std::size_t n) throw() { return data[n]; } - inline const_reference operator[](const std::size_t n) const throw() { return data[n]; } - - inline reference front() throw() { return data[0]; } - inline const_reference front() const throw() { return data[0]; } - inline reference back() throw() { return data[S-1]; } - inline const_reference back() const throw() { return data[S-1]; } - - inline bool operator==(const Array &k) const throw() - { - for(unsigned long i=0;i(const Array &k) const throw() { return (k < *this); } - inline bool operator<=(const Array &k) const throw() { return !(k < *this); } - inline bool operator>=(const Array &k) const throw() { return !(*this < k); } - - T data[S]; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/AtomicCounter.hpp b/zto/node/AtomicCounter.hpp deleted file mode 100644 index a0f29ba..0000000 --- a/zto/node/AtomicCounter.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_ATOMICCOUNTER_HPP -#define ZT_ATOMICCOUNTER_HPP - -#include "Constants.hpp" -#include "NonCopyable.hpp" - -#ifndef __GNUC__ -#include -#endif - -namespace ZeroTier { - -/** - * Simple atomic counter supporting increment and decrement - */ -class AtomicCounter : NonCopyable -{ -public: - AtomicCounter() - { - _v = 0; - } - - inline int operator++() - { -#ifdef __GNUC__ - return __sync_add_and_fetch(&_v,1); -#else - return ++_v; -#endif - } - - inline int operator--() - { -#ifdef __GNUC__ - return __sync_sub_and_fetch(&_v,1); -#else - return --_v; -#endif - } - -private: -#ifdef __GNUC__ - int _v; -#else - std::atomic_int _v; -#endif -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Buffer.hpp b/zto/node/Buffer.hpp deleted file mode 100644 index 37f39e7..0000000 --- a/zto/node/Buffer.hpp +++ /dev/null @@ -1,496 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_BUFFER_HPP -#define ZT_BUFFER_HPP - -#include -#include - -#include -#include -#include -#include - -#include "Constants.hpp" -#include "Utils.hpp" - -#if defined(__GNUC__) && (!defined(ZT_NO_TYPE_PUNNING)) -#define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__)) -#else -#define ZT_VAR_MAY_ALIAS -#endif - -namespace ZeroTier { - -/** - * A variable length but statically allocated buffer - * - * Bounds-checking is done everywhere, since this is used in security - * critical code. This supports construction and assignment from buffers - * of differing capacities, provided the data actually in them fits. - * It throws std::out_of_range on any boundary violation. - * - * The at(), append(), etc. methods encode integers larger than 8-bit in - * big-endian (network) byte order. - * - * @tparam C Total capacity - */ -template -class Buffer -{ - // I love me! - template friend class Buffer; - -public: - // STL container idioms - typedef unsigned char value_type; - typedef unsigned char * pointer; - typedef const char * const_pointer; - typedef char & reference; - typedef const char & const_reference; - typedef char * iterator; - typedef const char * const_iterator; - typedef unsigned int size_type; - typedef int difference_type; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - inline iterator begin() { return _b; } - inline iterator end() { return (_b + _l); } - inline const_iterator begin() const { return _b; } - inline const_iterator end() const { return (_b + _l); } - inline reverse_iterator rbegin() { return reverse_iterator(begin()); } - inline reverse_iterator rend() { return reverse_iterator(end()); } - inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); } - inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); } - - Buffer() : - _l(0) - { - } - - Buffer(unsigned int l) - throw(std::out_of_range) - { - if (l > C) - throw std::out_of_range("Buffer: construct with size larger than capacity"); - _l = l; - } - - template - Buffer(const Buffer &b) - throw(std::out_of_range) - { - *this = b; - } - - Buffer(const void *b,unsigned int l) - throw(std::out_of_range) - { - copyFrom(b,l); - } - - Buffer(const std::string &s) - throw(std::out_of_range) - { - copyFrom(s.data(),s.length()); - } - - template - inline Buffer &operator=(const Buffer &b) - throw(std::out_of_range) - { - if (b._l > C) - throw std::out_of_range("Buffer: assignment from buffer larger than capacity"); - memcpy(_b,b._b,_l = b._l); - return *this; - } - - inline Buffer &operator=(const std::string &s) - throw(std::out_of_range) - { - copyFrom(s.data(),s.length()); - return *this; - } - - inline void copyFrom(const void *b,unsigned int l) - throw(std::out_of_range) - { - if (l > C) - throw std::out_of_range("Buffer: set from C array larger than capacity"); - _l = l; - memcpy(_b,b,l); - } - - unsigned char operator[](const unsigned int i) const - throw(std::out_of_range) - { - if (i >= _l) - throw std::out_of_range("Buffer: [] beyond end of data"); - return (unsigned char)_b[i]; - } - - unsigned char &operator[](const unsigned int i) - throw(std::out_of_range) - { - if (i >= _l) - throw std::out_of_range("Buffer: [] beyond end of data"); - return ((unsigned char *)_b)[i]; - } - - /** - * Get a raw pointer to a field with bounds checking - * - * This isn't perfectly safe in that the caller could still overflow - * the pointer, but its use provides both a sanity check and - * documentation / reminder to the calling code to treat the returned - * pointer as being of size [l]. - * - * @param i Index of field in buffer - * @param l Length of field in bytes - * @return Pointer to field data - * @throws std::out_of_range Field extends beyond data size - */ - unsigned char *field(unsigned int i,unsigned int l) - throw(std::out_of_range) - { - if ((i + l) > _l) - throw std::out_of_range("Buffer: field() beyond end of data"); - return (unsigned char *)(_b + i); - } - const unsigned char *field(unsigned int i,unsigned int l) const - throw(std::out_of_range) - { - if ((i + l) > _l) - throw std::out_of_range("Buffer: field() beyond end of data"); - return (const unsigned char *)(_b + i); - } - - /** - * Place a primitive integer value at a given position - * - * @param i Index to place value - * @param v Value - * @tparam T Integer type (e.g. uint16_t, int64_t) - */ - template - inline void setAt(unsigned int i,const T v) - throw(std::out_of_range) - { - if ((i + sizeof(T)) > _l) - throw std::out_of_range("Buffer: setAt() beyond end of data"); -#ifdef ZT_NO_TYPE_PUNNING - uint8_t *p = reinterpret_cast(_b + i); - for(unsigned int x=1;x<=sizeof(T);++x) - *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); -#else - T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast(_b + i); - *p = Utils::hton(v); -#endif - } - - /** - * Get a primitive integer value at a given position - * - * @param i Index to get integer - * @tparam T Integer type (e.g. uint16_t, int64_t) - * @return Integer value - */ - template - inline T at(unsigned int i) const - throw(std::out_of_range) - { - if ((i + sizeof(T)) > _l) - throw std::out_of_range("Buffer: at() beyond end of data"); -#ifdef ZT_NO_TYPE_PUNNING - T v = 0; - const uint8_t *p = reinterpret_cast(_b + i); - for(unsigned int x=0;x(_b + i); - return Utils::ntoh(*p); -#endif - } - - /** - * Append an integer type to this buffer - * - * @param v Value to append - * @tparam T Integer type (e.g. uint16_t, int64_t) - * @throws std::out_of_range Attempt to append beyond capacity - */ - template - inline void append(const T v) - throw(std::out_of_range) - { - if ((_l + sizeof(T)) > C) - throw std::out_of_range("Buffer: append beyond capacity"); -#ifdef ZT_NO_TYPE_PUNNING - uint8_t *p = reinterpret_cast(_b + _l); - for(unsigned int x=1;x<=sizeof(T);++x) - *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); -#else - T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast(_b + _l); - *p = Utils::hton(v); -#endif - _l += sizeof(T); - } - - /** - * Append a run of bytes - * - * @param c Character value to append - * @param n Number of times to append - * @throws std::out_of_range Attempt to append beyond capacity - */ - inline void append(unsigned char c,unsigned int n) - throw(std::out_of_range) - { - if ((_l + n) > C) - throw std::out_of_range("Buffer: append beyond capacity"); - for(unsigned int i=0;i C) - throw std::out_of_range("Buffer: append beyond capacity"); - memcpy(_b + _l,b,l); - _l += l; - } - - /** - * Append a string - * - * @param s String to append - * @throws std::out_of_range Attempt to append beyond capacity - */ - inline void append(const std::string &s) - throw(std::out_of_range) - { - append(s.data(),(unsigned int)s.length()); - } - - /** - * Append a C string including null termination byte - * - * @param s C string - * @throws std::out_of_range Attempt to append beyond capacity - */ - inline void appendCString(const char *s) - throw(std::out_of_range) - { - for(;;) { - if (_l >= C) - throw std::out_of_range("Buffer: append beyond capacity"); - if (!(_b[_l++] = *(s++))) - break; - } - } - - /** - * Append a buffer - * - * @param b Buffer to append - * @tparam C2 Capacity of second buffer (typically inferred) - * @throws std::out_of_range Attempt to append beyond capacity - */ - template - inline void append(const Buffer &b) - throw(std::out_of_range) - { - append(b._b,b._l); - } - - /** - * Increment size and return pointer to field of specified size - * - * Nothing is actually written to the memory. This is a shortcut - * for addSize() followed by field() to reference the previous - * position and the new size. - * - * @param l Length of field to append - * @return Pointer to beginning of appended field of length 'l' - */ - inline char *appendField(unsigned int l) - throw(std::out_of_range) - { - if ((_l + l) > C) - throw std::out_of_range("Buffer: append beyond capacity"); - char *r = _b + _l; - _l += l; - return r; - } - - /** - * Increment size by a given number of bytes - * - * The contents of new space are undefined. - * - * @param i Bytes to increment - * @throws std::out_of_range Capacity exceeded - */ - inline void addSize(unsigned int i) - throw(std::out_of_range) - { - if ((i + _l) > C) - throw std::out_of_range("Buffer: setSize to larger than capacity"); - _l += i; - } - - /** - * Set size of data in buffer - * - * The contents of new space are undefined. - * - * @param i New size - * @throws std::out_of_range Size larger than capacity - */ - inline void setSize(const unsigned int i) - throw(std::out_of_range) - { - if (i > C) - throw std::out_of_range("Buffer: setSize to larger than capacity"); - _l = i; - } - - /** - * Move everything after 'at' to the buffer's front and truncate - * - * @param at Truncate before this position - * @throw std::out_of_range Position is beyond size of buffer - */ - inline void behead(const unsigned int at) - throw(std::out_of_range) - { - if (!at) - return; - if (at > _l) - throw std::out_of_range("Buffer: behead() beyond capacity"); - ::memmove(_b,_b + at,_l -= at); - } - - /** - * Erase something from the middle of the buffer - * - * @param start Starting position - * @param length Length of block to erase - * @throw std::out_of_range Position plus length is beyond size of buffer - */ - inline void erase(const unsigned int at,const unsigned int length) - throw(std::out_of_range) - { - const unsigned int endr = at + length; - if (endr > _l) - throw std::out_of_range("Buffer: erase() range beyond end of buffer"); - ::memmove(_b + at,_b + endr,_l - endr); - _l -= length; - } - - /** - * Set buffer data length to zero - */ - inline void clear() { _l = 0; } - - /** - * Zero buffer up to size() - */ - inline void zero() { memset(_b,0,_l); } - - /** - * Zero unused capacity area - */ - inline void zeroUnused() { memset(_b + _l,0,C - _l); } - - /** - * Unconditionally and securely zero buffer's underlying memory - */ - inline void burn() { Utils::burn(_b,sizeof(_b)); } - - /** - * @return Constant pointer to data in buffer - */ - inline const void *data() const { return _b; } - - /** - * @return Non-constant pointer to data in buffer - */ - inline void *unsafeData() { return _b; } - - /** - * @return Size of data in buffer - */ - inline unsigned int size() const { return _l; } - - /** - * @return Capacity of buffer - */ - inline unsigned int capacity() const { return C; } - - template - inline bool operator==(const Buffer &b) const - { - return ((_l == b._l)&&(!memcmp(_b,b._b,_l))); - } - template - inline bool operator!=(const Buffer &b) const - { - return ((_l != b._l)||(memcmp(_b,b._b,_l))); - } - template - inline bool operator<(const Buffer &b) const - { - return (memcmp(_b,b._b,std::min(_l,b._l)) < 0); - } - template - inline bool operator>(const Buffer &b) const - { - return (b < *this); - } - template - inline bool operator<=(const Buffer &b) const - { - return !(b < *this); - } - template - inline bool operator>=(const Buffer &b) const - { - return !(*this < b); - } - -private: - unsigned int _l; - char ZT_VAR_MAY_ALIAS _b[C]; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/C25519.cpp b/zto/node/C25519.cpp deleted file mode 100644 index e9ffecc..0000000 --- a/zto/node/C25519.cpp +++ /dev/null @@ -1,2398 +0,0 @@ -// Code taken from NaCl by D. J. Bernstein and others - -/* -Matthew Dempsky -Public domain. -Derived from public domain code by D. J. Bernstein. -*/ - -// Modified very slightly for ZeroTier One by Adam Ierymenko -// (no functional changes) - -#include -#include -#include - -#include "Constants.hpp" -#include "C25519.hpp" -#include "SHA512.hpp" -#include "Buffer.hpp" - -#ifdef __WINDOWS__ -#pragma warning(disable: 4146) -#endif - -namespace ZeroTier { - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -#define crypto_int32 int32_t -#define crypto_uint32 uint32_t -#define crypto_int64 int64_t -#define crypto_uint64 uint64_t -#define crypto_hash_sha512_BYTES 64 - -static inline void add(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) -{ - unsigned int j; - unsigned int u; - u = 0; - for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; } - u += a[31] + b[31]; out[31] = u; -} - -static inline void sub(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) -{ - unsigned int j; - unsigned int u; - u = 218; - for (j = 0;j < 31;++j) { - u += a[j] + 65280 - b[j]; - out[j] = u & 255; - u >>= 8; - } - u += a[31] - b[31]; - out[31] = u; -} - -static inline void squeeze(unsigned int a[32]) -{ - unsigned int j; - unsigned int u; - u = 0; - for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; } - u += a[31]; a[31] = u & 127; - u = 19 * (u >> 7); - for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; } - u += a[31]; a[31] = u; -} - -static const unsigned int minusp[32] = { - 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128 -} ; - -static inline void freeze(unsigned int a[32]) -{ - unsigned int aorig[32]; - unsigned int j; - unsigned int negative; - - for (j = 0;j < 32;++j) aorig[j] = a[j]; - add(a,a,minusp); - negative = -((a[31] >> 7) & 1); - for (j = 0;j < 32;++j) a[j] ^= negative & (aorig[j] ^ a[j]); -} - -static inline void mult(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) -{ - unsigned int i; - unsigned int j; - unsigned int u; - - for (i = 0;i < 32;++i) { - u = 0; - for (j = 0;j <= i;++j) u += a[j] * b[i - j]; - for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j]; - out[i] = u; - } - squeeze(out); -} - -static inline void mult121665(unsigned int out[32],const unsigned int a[32]) -{ - unsigned int j; - unsigned int u; - - u = 0; - for (j = 0;j < 31;++j) { u += 121665 * a[j]; out[j] = u & 255; u >>= 8; } - u += 121665 * a[31]; out[31] = u & 127; - u = 19 * (u >> 7); - for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; } - u += out[j]; out[j] = u; -} - -static inline void square(unsigned int out[32],const unsigned int a[32]) -{ - unsigned int i; - unsigned int j; - unsigned int u; - - for (i = 0;i < 32;++i) { - u = 0; - for (j = 0;j < i - j;++j) u += a[j] * a[i - j]; - for (j = i + 1;j < i + 32 - j;++j) u += 38 * a[j] * a[i + 32 - j]; - u *= 2; - if ((i & 1) == 0) { - u += a[i / 2] * a[i / 2]; - u += 38 * a[i / 2 + 16] * a[i / 2 + 16]; - } - out[i] = u; - } - squeeze(out); -} - -static inline void select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b) -{ - unsigned int j; - unsigned int t; - unsigned int bminus1; - - bminus1 = b - 1; - for (j = 0;j < 64;++j) { - t = bminus1 & (r[j] ^ s[j]); - p[j] = s[j] ^ t; - q[j] = r[j] ^ t; - } -} - -static void mainloop(unsigned int work[64],const unsigned char e[32]) -{ - unsigned int xzm1[64]; - unsigned int xzm[64]; - unsigned int xzmb[64]; - unsigned int xzm1b[64]; - unsigned int xznb[64]; - unsigned int xzn1b[64]; - unsigned int a0[64]; - unsigned int a1[64]; - unsigned int b0[64]; - unsigned int b1[64]; - unsigned int c1[64]; - unsigned int r[32]; - unsigned int s[32]; - unsigned int t[32]; - unsigned int u[32]; - //unsigned int i; - unsigned int j; - unsigned int b; - int pos; - - for (j = 0;j < 32;++j) xzm1[j] = work[j]; - xzm1[32] = 1; - for (j = 33;j < 64;++j) xzm1[j] = 0; - - xzm[0] = 1; - for (j = 1;j < 64;++j) xzm[j] = 0; - - for (pos = 254;pos >= 0;--pos) { - b = e[pos / 8] >> (pos & 7); - b &= 1; - select(xzmb,xzm1b,xzm,xzm1,b); - add(a0,xzmb,xzmb + 32); - sub(a0 + 32,xzmb,xzmb + 32); - add(a1,xzm1b,xzm1b + 32); - sub(a1 + 32,xzm1b,xzm1b + 32); - square(b0,a0); - square(b0 + 32,a0 + 32); - mult(b1,a1,a0 + 32); - mult(b1 + 32,a1 + 32,a0); - add(c1,b1,b1 + 32); - sub(c1 + 32,b1,b1 + 32); - square(r,c1 + 32); - sub(s,b0,b0 + 32); - mult121665(t,s); - add(u,t,b0); - mult(xznb,b0,b0 + 32); - mult(xznb + 32,s,u); - square(xzn1b,c1); - mult(xzn1b + 32,r,work); - select(xzm,xzm1,xznb,xzn1b,b); - } - - for (j = 0;j < 64;++j) work[j] = xzm[j]; -} - -static void recip(unsigned int out[32],const unsigned int z[32]) -{ - unsigned int z2[32]; - unsigned int z9[32]; - unsigned int z11[32]; - unsigned int z2_5_0[32]; - unsigned int z2_10_0[32]; - unsigned int z2_20_0[32]; - unsigned int z2_50_0[32]; - unsigned int z2_100_0[32]; - unsigned int t0[32]; - unsigned int t1[32]; - int i; - - /* 2 */ square(z2,z); - /* 4 */ square(t1,z2); - /* 8 */ square(t0,t1); - /* 9 */ mult(z9,t0,z); - /* 11 */ mult(z11,z9,z2); - /* 22 */ square(t0,z11); - /* 2^5 - 2^0 = 31 */ mult(z2_5_0,t0,z9); - - /* 2^6 - 2^1 */ square(t0,z2_5_0); - /* 2^7 - 2^2 */ square(t1,t0); - /* 2^8 - 2^3 */ square(t0,t1); - /* 2^9 - 2^4 */ square(t1,t0); - /* 2^10 - 2^5 */ square(t0,t1); - /* 2^10 - 2^0 */ mult(z2_10_0,t0,z2_5_0); - - /* 2^11 - 2^1 */ square(t0,z2_10_0); - /* 2^12 - 2^2 */ square(t1,t0); - /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t0,t1); square(t1,t0); } - /* 2^20 - 2^0 */ mult(z2_20_0,t1,z2_10_0); - - /* 2^21 - 2^1 */ square(t0,z2_20_0); - /* 2^22 - 2^2 */ square(t1,t0); - /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { square(t0,t1); square(t1,t0); } - /* 2^40 - 2^0 */ mult(t0,t1,z2_20_0); - - /* 2^41 - 2^1 */ square(t1,t0); - /* 2^42 - 2^2 */ square(t0,t1); - /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t1,t0); square(t0,t1); } - /* 2^50 - 2^0 */ mult(z2_50_0,t0,z2_10_0); - - /* 2^51 - 2^1 */ square(t0,z2_50_0); - /* 2^52 - 2^2 */ square(t1,t0); - /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); } - /* 2^100 - 2^0 */ mult(z2_100_0,t1,z2_50_0); - - /* 2^101 - 2^1 */ square(t1,z2_100_0); - /* 2^102 - 2^2 */ square(t0,t1); - /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { square(t1,t0); square(t0,t1); } - /* 2^200 - 2^0 */ mult(t1,t0,z2_100_0); - - /* 2^201 - 2^1 */ square(t0,t1); - /* 2^202 - 2^2 */ square(t1,t0); - /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); } - /* 2^250 - 2^0 */ mult(t0,t1,z2_50_0); - - /* 2^251 - 2^1 */ square(t1,t0); - /* 2^252 - 2^2 */ square(t0,t1); - /* 2^253 - 2^3 */ square(t1,t0); - /* 2^254 - 2^4 */ square(t0,t1); - /* 2^255 - 2^5 */ square(t1,t0); - /* 2^255 - 21 */ mult(out,t1,z11); -} - -static inline int crypto_scalarmult(unsigned char *q, - const unsigned char *n, - const unsigned char *p) -{ - unsigned int work[96]; - unsigned char e[32]; - unsigned int i; - for (i = 0;i < 32;++i) e[i] = n[i]; - e[0] &= 248; - e[31] &= 127; - e[31] |= 64; - for (i = 0;i < 32;++i) work[i] = p[i]; - mainloop(work,e); - recip(work + 32,work + 32); - mult(work + 64,work,work + 32); - freeze(work + 64); - for (i = 0;i < 32;++i) q[i] = work[64 + i]; - return 0; -} - -static const unsigned char base[32] = {9}; - -static inline int crypto_scalarmult_base(unsigned char *q, - const unsigned char *n) -{ - return crypto_scalarmult(q,n,base); -} - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -// This is the Ed25519 stuff from SUPERCOP: -// http://bench.cr.yp.to/supercop.html - -// Also public domain, newer version than the Ed25519 found in NaCl - -typedef struct -{ - crypto_uint32 v[32]; -} -fe25519; - -static void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y); - -static inline crypto_uint32 equal(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */ -{ - crypto_uint32 x = a ^ b; /* 0: yes; 1..65535: no */ - x -= 1; /* 4294967295: yes; 0..65534: no */ - x >>= 31; /* 1: yes; 0: no */ - return x; -} - -static inline crypto_uint32 ge(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */ -{ - unsigned int x = a; - x -= (unsigned int) b; /* 0..65535: yes; 4294901761..4294967295: no */ - x >>= 31; /* 0: yes; 1: no */ - x ^= 1; /* 1: yes; 0: no */ - return x; -} - -static inline crypto_uint32 times19(crypto_uint32 a) -{ - return (a << 4) + (a << 1) + a; -} - -static inline crypto_uint32 times38(crypto_uint32 a) -{ - return (a << 5) + (a << 2) + (a << 1); -} - -static inline void reduce_add_sub(fe25519 *r) -{ - crypto_uint32 t; - int i,rep; - - for(rep=0;rep<4;rep++) - { - t = r->v[31] >> 7; - r->v[31] &= 127; - t = times19(t); - r->v[0] += t; - for(i=0;i<31;i++) - { - t = r->v[i] >> 8; - r->v[i+1] += t; - r->v[i] &= 255; - } - } -} - -static inline void reduce_mul(fe25519 *r) -{ - crypto_uint32 t; - int i,rep; - - for(rep=0;rep<2;rep++) - { - t = r->v[31] >> 7; - r->v[31] &= 127; - t = times19(t); - r->v[0] += t; - for(i=0;i<31;i++) - { - t = r->v[i] >> 8; - r->v[i+1] += t; - r->v[i] &= 255; - } - } -} - -/* reduction modulo 2^255-19 */ -static inline void fe25519_freeze(fe25519 *r) -{ - int i; - crypto_uint32 m = equal(r->v[31],127); - for(i=30;i>0;i--) - m &= equal(r->v[i],255); - m &= ge(r->v[0],237); - - m = -m; - - r->v[31] -= m&127; - for(i=30;i>0;i--) - r->v[i] -= m&255; - r->v[0] -= m&237; -} - -static inline void fe25519_unpack(fe25519 *r, const unsigned char x[32]) -{ - int i; - for(i=0;i<32;i++) r->v[i] = x[i]; - r->v[31] &= 127; -} - -/* Assumes input x being reduced below 2^255 */ -static inline void fe25519_pack(unsigned char r[32], const fe25519 *x) -{ - int i; - fe25519 y = *x; - fe25519_freeze(&y); - for(i=0;i<32;i++) - r[i] = y.v[i]; -} - -#if 0 -static int fe25519_iszero(const fe25519 *x) -{ - int i; - int r; - fe25519 t = *x; - fe25519_freeze(&t); - r = equal(t.v[0],0); - for(i=1;i<32;i++) - r &= equal(t.v[i],0); - return r; -} -#endif - -static inline int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y) -{ - int i; - fe25519 t1 = *x; - fe25519 t2 = *y; - fe25519_freeze(&t1); - fe25519_freeze(&t2); - for(i=0;i<32;i++) - if(t1.v[i] != t2.v[i]) return 0; - return 1; -} - -static inline void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b) -{ - int i; - crypto_uint32 mask = b; - mask = -mask; - for(i=0;i<32;i++) r->v[i] ^= mask & (x->v[i] ^ r->v[i]); -} - -static inline unsigned char fe25519_getparity(const fe25519 *x) -{ - fe25519 t = *x; - fe25519_freeze(&t); - return t.v[0] & 1; -} - -static inline void fe25519_setone(fe25519 *r) -{ - int i; - r->v[0] = 1; - for(i=1;i<32;i++) r->v[i]=0; -} - -static inline void fe25519_setzero(fe25519 *r) -{ - int i; - for(i=0;i<32;i++) r->v[i]=0; -} - -static inline void fe25519_neg(fe25519 *r, const fe25519 *x) -{ - fe25519 t; - int i; - for(i=0;i<32;i++) t.v[i]=x->v[i]; - fe25519_setzero(r); - fe25519_sub(r, r, &t); -} - -static inline void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y) -{ - int i; - for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i]; - reduce_add_sub(r); -} - -static inline void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y) -{ - int i; - crypto_uint32 t[32]; - t[0] = x->v[0] + 0x1da; - t[31] = x->v[31] + 0xfe; - for(i=1;i<31;i++) t[i] = x->v[i] + 0x1fe; - for(i=0;i<32;i++) r->v[i] = t[i] - y->v[i]; - reduce_add_sub(r); -} - -static inline void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y) -{ - int i,j; - crypto_uint32 t[63]; - for(i=0;i<63;i++)t[i] = 0; - - for(i=0;i<32;i++) - for(j=0;j<32;j++) - t[i+j] += x->v[i] * y->v[j]; - - for(i=32;i<63;i++) - r->v[i-32] = t[i-32] + times38(t[i]); - r->v[31] = t[31]; /* result now in r[0]...r[31] */ - - reduce_mul(r); -} - -static inline void fe25519_square(fe25519 *r, const fe25519 *x) -{ - fe25519_mul(r, x, x); -} - -static void fe25519_invert(fe25519 *r, const fe25519 *x) -{ - fe25519 z2; - fe25519 z9; - fe25519 z11; - fe25519 z2_5_0; - fe25519 z2_10_0; - fe25519 z2_20_0; - fe25519 z2_50_0; - fe25519 z2_100_0; - fe25519 t0; - fe25519 t1; - int i; - - /* 2 */ fe25519_square(&z2,x); - /* 4 */ fe25519_square(&t1,&z2); - /* 8 */ fe25519_square(&t0,&t1); - /* 9 */ fe25519_mul(&z9,&t0,x); - /* 11 */ fe25519_mul(&z11,&z9,&z2); - /* 22 */ fe25519_square(&t0,&z11); - /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t0,&z9); - - /* 2^6 - 2^1 */ fe25519_square(&t0,&z2_5_0); - /* 2^7 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^8 - 2^3 */ fe25519_square(&t0,&t1); - /* 2^9 - 2^4 */ fe25519_square(&t1,&t0); - /* 2^10 - 2^5 */ fe25519_square(&t0,&t1); - /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t0,&z2_5_0); - - /* 2^11 - 2^1 */ fe25519_square(&t0,&z2_10_0); - /* 2^12 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t1,&z2_10_0); - - /* 2^21 - 2^1 */ fe25519_square(&t0,&z2_20_0); - /* 2^22 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^40 - 2^0 */ fe25519_mul(&t0,&t1,&z2_20_0); - - /* 2^41 - 2^1 */ fe25519_square(&t1,&t0); - /* 2^42 - 2^2 */ fe25519_square(&t0,&t1); - /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fe25519_square(&t1,&t0); fe25519_square(&t0,&t1); } - /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t0,&z2_10_0); - - /* 2^51 - 2^1 */ fe25519_square(&t0,&z2_50_0); - /* 2^52 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t1,&z2_50_0); - - /* 2^101 - 2^1 */ fe25519_square(&t1,&z2_100_0); - /* 2^102 - 2^2 */ fe25519_square(&t0,&t1); - /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fe25519_square(&t1,&t0); fe25519_square(&t0,&t1); } - /* 2^200 - 2^0 */ fe25519_mul(&t1,&t0,&z2_100_0); - - /* 2^201 - 2^1 */ fe25519_square(&t0,&t1); - /* 2^202 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^250 - 2^0 */ fe25519_mul(&t0,&t1,&z2_50_0); - - /* 2^251 - 2^1 */ fe25519_square(&t1,&t0); - /* 2^252 - 2^2 */ fe25519_square(&t0,&t1); - /* 2^253 - 2^3 */ fe25519_square(&t1,&t0); - /* 2^254 - 2^4 */ fe25519_square(&t0,&t1); - /* 2^255 - 2^5 */ fe25519_square(&t1,&t0); - /* 2^255 - 21 */ fe25519_mul(r,&t1,&z11); -} - -static void fe25519_pow2523(fe25519 *r, const fe25519 *x) -{ - fe25519 z2; - fe25519 z9; - fe25519 z11; - fe25519 z2_5_0; - fe25519 z2_10_0; - fe25519 z2_20_0; - fe25519 z2_50_0; - fe25519 z2_100_0; - fe25519 t; - int i; - - /* 2 */ fe25519_square(&z2,x); - /* 4 */ fe25519_square(&t,&z2); - /* 8 */ fe25519_square(&t,&t); - /* 9 */ fe25519_mul(&z9,&t,x); - /* 11 */ fe25519_mul(&z11,&z9,&z2); - /* 22 */ fe25519_square(&t,&z11); - /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t,&z9); - - /* 2^6 - 2^1 */ fe25519_square(&t,&z2_5_0); - /* 2^10 - 2^5 */ for (i = 1;i < 5;i++) { fe25519_square(&t,&t); } - /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t,&z2_5_0); - - /* 2^11 - 2^1 */ fe25519_square(&t,&z2_10_0); - /* 2^20 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } - /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t,&z2_10_0); - - /* 2^21 - 2^1 */ fe25519_square(&t,&z2_20_0); - /* 2^40 - 2^20 */ for (i = 1;i < 20;i++) { fe25519_square(&t,&t); } - /* 2^40 - 2^0 */ fe25519_mul(&t,&t,&z2_20_0); - - /* 2^41 - 2^1 */ fe25519_square(&t,&t); - /* 2^50 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } - /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t,&z2_10_0); - - /* 2^51 - 2^1 */ fe25519_square(&t,&z2_50_0); - /* 2^100 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } - /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t,&z2_50_0); - - /* 2^101 - 2^1 */ fe25519_square(&t,&z2_100_0); - /* 2^200 - 2^100 */ for (i = 1;i < 100;i++) { fe25519_square(&t,&t); } - /* 2^200 - 2^0 */ fe25519_mul(&t,&t,&z2_100_0); - - /* 2^201 - 2^1 */ fe25519_square(&t,&t); - /* 2^250 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } - /* 2^250 - 2^0 */ fe25519_mul(&t,&t,&z2_50_0); - - /* 2^251 - 2^1 */ fe25519_square(&t,&t); - /* 2^252 - 2^2 */ fe25519_square(&t,&t); - /* 2^252 - 3 */ fe25519_mul(r,&t,x); -} - -typedef struct -{ - crypto_uint32 v[32]; -} -sc25519; - -typedef struct -{ - crypto_uint32 v[16]; -} -shortsc25519; - -static const crypto_uint32 m[32] = {0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, 0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; - -static const crypto_uint32 mu[33] = {0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21, - 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F}; - -static inline crypto_uint32 lt(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */ -{ - unsigned int x = a; - x -= (unsigned int) b; /* 0..65535: no; 4294901761..4294967295: yes */ - x >>= 31; /* 0: no; 1: yes */ - return x; -} - -/* Reduce coefficients of r before calling reduce_add_sub */ -static inline void reduce_add_sub(sc25519 *r) -{ - crypto_uint32 pb = 0; - crypto_uint32 b; - crypto_uint32 mask; - int i; - unsigned char t[32]; - - for(i=0;i<32;i++) - { - pb += m[i]; - b = lt(r->v[i],pb); - t[i] = r->v[i]-pb+(b<<8); - pb = b; - } - mask = b - 1; - for(i=0;i<32;i++) - r->v[i] ^= mask & (r->v[i] ^ t[i]); -} - -/* Reduce coefficients of x before calling barrett_reduce */ -static inline void barrett_reduce(sc25519 *r, const crypto_uint32 x[64]) -{ - /* See HAC, Alg. 14.42 */ - int i,j; - crypto_uint32 q2[66]; - crypto_uint32 *q3 = q2 + 33; - crypto_uint32 r1[33]; - crypto_uint32 r2[33]; - crypto_uint32 carry; - crypto_uint32 pb = 0; - crypto_uint32 b; - - for (i = 0;i < 66;++i) q2[i] = 0; - for (i = 0;i < 33;++i) r2[i] = 0; - - for(i=0;i<33;i++) - for(j=0;j<33;j++) - if(i+j >= 31) q2[i+j] += mu[i]*x[j+31]; - carry = q2[31] >> 8; - q2[32] += carry; - carry = q2[32] >> 8; - q2[33] += carry; - - for(i=0;i<33;i++)r1[i] = x[i]; - for(i=0;i<32;i++) - for(j=0;j<33;j++) - if(i+j < 33) r2[i+j] += m[i]*q3[j]; - - for(i=0;i<32;i++) - { - carry = r2[i] >> 8; - r2[i+1] += carry; - r2[i] &= 0xff; - } - - for(i=0;i<32;i++) - { - pb += r2[i]; - b = lt(r1[i],pb); - r->v[i] = r1[i]-pb+(b<<8); - pb = b; - } - - /* XXX: Can it really happen that r<0?, See HAC, Alg 14.42, Step 3 - * If so: Handle it here! - */ - - reduce_add_sub(r); - reduce_add_sub(r); -} - -static inline void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]) -{ - int i; - crypto_uint32 t[64]; - for(i=0;i<32;i++) t[i] = x[i]; - for(i=32;i<64;++i) t[i] = 0; - barrett_reduce(r, t); -} - -#if 0 -static void shortsc25519_from16bytes(shortsc25519 *r, const unsigned char x[16]) -{ - int i; - for(i=0;i<16;i++) r->v[i] = x[i]; -} -#endif - -static inline void sc25519_from64bytes(sc25519 *r, const unsigned char x[64]) -{ - int i; - crypto_uint32 t[64]; - for(i=0;i<64;i++) t[i] = x[i]; - barrett_reduce(r, t); -} - -#if 0 -static void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x) -{ - int i; - for(i=0;i<16;i++) - r->v[i] = x->v[i]; - for(i=0;i<16;i++) - r->v[16+i] = 0; -} -#endif - -static inline void sc25519_to32bytes(unsigned char r[32], const sc25519 *x) -{ - int i; - for(i=0;i<32;i++) r[i] = x->v[i]; -} - -#if 0 -static int sc25519_iszero_vartime(const sc25519 *x) -{ - int i; - for(i=0;i<32;i++) - if(x->v[i] != 0) return 0; - return 1; -} -#endif - -#if 0 -static int sc25519_isshort_vartime(const sc25519 *x) -{ - int i; - for(i=31;i>15;i--) - if(x->v[i] != 0) return 0; - return 1; -} -#endif - -#if 0 -static int sc25519_lt_vartime(const sc25519 *x, const sc25519 *y) -{ - int i; - for(i=31;i>=0;i--) - { - if(x->v[i] < y->v[i]) return 1; - if(x->v[i] > y->v[i]) return 0; - } - return 0; -} -#endif - -static inline void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y) -{ - int i, carry; - for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i]; - for(i=0;i<31;i++) - { - carry = r->v[i] >> 8; - r->v[i+1] += carry; - r->v[i] &= 0xff; - } - reduce_add_sub(r); -} - -#if 0 -static void sc25519_sub_nored(sc25519 *r, const sc25519 *x, const sc25519 *y) -{ - crypto_uint32 b = 0; - crypto_uint32 t; - int i; - for(i=0;i<32;i++) - { - t = x->v[i] - y->v[i] - b; - r->v[i] = t & 255; - b = (t >> 8) & 1; - } -} -#endif - -static inline void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y) -{ - int i,j,carry; - crypto_uint32 t[64]; - for(i=0;i<64;i++)t[i] = 0; - - for(i=0;i<32;i++) - for(j=0;j<32;j++) - t[i+j] += x->v[i] * y->v[j]; - - /* Reduce coefficients */ - for(i=0;i<63;i++) - { - carry = t[i] >> 8; - t[i+1] += carry; - t[i] &= 0xff; - } - - barrett_reduce(r, t); -} - -#if 0 -static void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y) -{ - sc25519 t; - sc25519_from_shortsc(&t, y); - sc25519_mul(r, x, &t); -} -#endif - -static inline void sc25519_window3(signed char r[85], const sc25519 *s) -{ - char carry; - int i; - for(i=0;i<10;i++) - { - r[8*i+0] = s->v[3*i+0] & 7; - r[8*i+1] = (s->v[3*i+0] >> 3) & 7; - r[8*i+2] = (s->v[3*i+0] >> 6) & 7; - r[8*i+2] ^= (s->v[3*i+1] << 2) & 7; - r[8*i+3] = (s->v[3*i+1] >> 1) & 7; - r[8*i+4] = (s->v[3*i+1] >> 4) & 7; - r[8*i+5] = (s->v[3*i+1] >> 7) & 7; - r[8*i+5] ^= (s->v[3*i+2] << 1) & 7; - r[8*i+6] = (s->v[3*i+2] >> 2) & 7; - r[8*i+7] = (s->v[3*i+2] >> 5) & 7; - } - r[8*i+0] = s->v[3*i+0] & 7; - r[8*i+1] = (s->v[3*i+0] >> 3) & 7; - r[8*i+2] = (s->v[3*i+0] >> 6) & 7; - r[8*i+2] ^= (s->v[3*i+1] << 2) & 7; - r[8*i+3] = (s->v[3*i+1] >> 1) & 7; - r[8*i+4] = (s->v[3*i+1] >> 4) & 7; - - /* Making it signed */ - carry = 0; - for(i=0;i<84;i++) - { - r[i] += carry; - r[i+1] += r[i] >> 3; - r[i] &= 7; - carry = r[i] >> 2; - r[i] -= carry<<3; - } - r[84] += carry; -} - -#if 0 -static void sc25519_window5(signed char r[51], const sc25519 *s) -{ - char carry; - int i; - for(i=0;i<6;i++) - { - r[8*i+0] = s->v[5*i+0] & 31; - r[8*i+1] = (s->v[5*i+0] >> 5) & 31; - r[8*i+1] ^= (s->v[5*i+1] << 3) & 31; - r[8*i+2] = (s->v[5*i+1] >> 2) & 31; - r[8*i+3] = (s->v[5*i+1] >> 7) & 31; - r[8*i+3] ^= (s->v[5*i+2] << 1) & 31; - r[8*i+4] = (s->v[5*i+2] >> 4) & 31; - r[8*i+4] ^= (s->v[5*i+3] << 4) & 31; - r[8*i+5] = (s->v[5*i+3] >> 1) & 31; - r[8*i+6] = (s->v[5*i+3] >> 6) & 31; - r[8*i+6] ^= (s->v[5*i+4] << 2) & 31; - r[8*i+7] = (s->v[5*i+4] >> 3) & 31; - } - r[8*i+0] = s->v[5*i+0] & 31; - r[8*i+1] = (s->v[5*i+0] >> 5) & 31; - r[8*i+1] ^= (s->v[5*i+1] << 3) & 31; - r[8*i+2] = (s->v[5*i+1] >> 2) & 31; - - /* Making it signed */ - carry = 0; - for(i=0;i<50;i++) - { - r[i] += carry; - r[i+1] += r[i] >> 5; - r[i] &= 31; - carry = r[i] >> 4; - r[i] -= carry<<5; - } - r[50] += carry; -} -#endif - -static inline void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2) -{ - int i; - for(i=0;i<31;i++) - { - r[4*i] = ( s1->v[i] & 3) ^ (( s2->v[i] & 3) << 2); - r[4*i+1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2); - r[4*i+2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2); - r[4*i+3] = ((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2); - } - r[124] = ( s1->v[31] & 3) ^ (( s2->v[31] & 3) << 2); - r[125] = ((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2); - r[126] = ((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2); -} - -typedef struct -{ - fe25519 x; - fe25519 y; - fe25519 z; - fe25519 t; -} ge25519; - -/* d */ -static const fe25519 ge25519_ecd = {{0xA3, 0x78, 0x59, 0x13, 0xCA, 0x4D, 0xEB, 0x75, 0xAB, 0xD8, 0x41, 0x41, 0x4D, 0x0A, 0x70, 0x00, - 0x98, 0xE8, 0x79, 0x77, 0x79, 0x40, 0xC7, 0x8C, 0x73, 0xFE, 0x6F, 0x2B, 0xEE, 0x6C, 0x03, 0x52}}; -/* 2*d */ -static const fe25519 ge25519_ec2d = {{0x59, 0xF1, 0xB2, 0x26, 0x94, 0x9B, 0xD6, 0xEB, 0x56, 0xB1, 0x83, 0x82, 0x9A, 0x14, 0xE0, 0x00, - 0x30, 0xD1, 0xF3, 0xEE, 0xF2, 0x80, 0x8E, 0x19, 0xE7, 0xFC, 0xDF, 0x56, 0xDC, 0xD9, 0x06, 0x24}}; -/* sqrt(-1) */ -static const fe25519 ge25519_sqrtm1 = {{0xB0, 0xA0, 0x0E, 0x4A, 0x27, 0x1B, 0xEE, 0xC4, 0x78, 0xE4, 0x2F, 0xAD, 0x06, 0x18, 0x43, 0x2F, - 0xA7, 0xD7, 0xFB, 0x3D, 0x99, 0x00, 0x4D, 0x2B, 0x0B, 0xDF, 0xC1, 0x4F, 0x80, 0x24, 0x83, 0x2B}}; - -#define ge25519_p3 ge25519 - -typedef struct -{ - fe25519 x; - fe25519 z; - fe25519 y; - fe25519 t; -} ge25519_p1p1; - -typedef struct -{ - fe25519 x; - fe25519 y; - fe25519 z; -} ge25519_p2; - -typedef struct -{ - fe25519 x; - fe25519 y; -} ge25519_aff; - - -/* Packed coordinates of the base point */ -static const ge25519 ge25519_base = {{{0x1A, 0xD5, 0x25, 0x8F, 0x60, 0x2D, 0x56, 0xC9, 0xB2, 0xA7, 0x25, 0x95, 0x60, 0xC7, 0x2C, 0x69, - 0x5C, 0xDC, 0xD6, 0xFD, 0x31, 0xE2, 0xA4, 0xC0, 0xFE, 0x53, 0x6E, 0xCD, 0xD3, 0x36, 0x69, 0x21}}, - {{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}}, - {{0x01, 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}}, - {{0xA3, 0xDD, 0xB7, 0xA5, 0xB3, 0x8A, 0xDE, 0x6D, 0xF5, 0x52, 0x51, 0x77, 0x80, 0x9F, 0xF0, 0x20, - 0x7D, 0xE3, 0xAB, 0x64, 0x8E, 0x4E, 0xEA, 0x66, 0x65, 0x76, 0x8B, 0xD7, 0x0F, 0x5F, 0x87, 0x67}}}; - -/* Multiples of the base point in affine representation */ -static const ge25519_aff ge25519_base_multiples_affine[425] = { -{{{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}}, - {{0x01, 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}}}, -{{{0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21}} , - {{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}}}, -{{{0x0e, 0xce, 0x43, 0x28, 0x4e, 0xa1, 0xc5, 0x83, 0x5f, 0xa4, 0xd7, 0x15, 0x45, 0x8e, 0x0d, 0x08, 0xac, 0xe7, 0x33, 0x18, 0x7d, 0x3b, 0x04, 0x3d, 0x6c, 0x04, 0x5a, 0x9f, 0x4c, 0x38, 0xab, 0x36}} , - {{0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0x0e, 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22}}}, -{{{0x5c, 0xe2, 0xf8, 0xd3, 0x5f, 0x48, 0x62, 0xac, 0x86, 0x48, 0x62, 0x81, 0x19, 0x98, 0x43, 0x63, 0x3a, 0xc8, 0xda, 0x3e, 0x74, 0xae, 0xf4, 0x1f, 0x49, 0x8f, 0x92, 0x22, 0x4a, 0x9c, 0xae, 0x67}} , - {{0xd4, 0xb4, 0xf5, 0x78, 0x48, 0x68, 0xc3, 0x02, 0x04, 0x03, 0x24, 0x67, 0x17, 0xec, 0x16, 0x9f, 0xf7, 0x9e, 0x26, 0x60, 0x8e, 0xa1, 0x26, 0xa1, 0xab, 0x69, 0xee, 0x77, 0xd1, 0xb1, 0x67, 0x12}}}, -{{{0x70, 0xf8, 0xc9, 0xc4, 0x57, 0xa6, 0x3a, 0x49, 0x47, 0x15, 0xce, 0x93, 0xc1, 0x9e, 0x73, 0x1a, 0xf9, 0x20, 0x35, 0x7a, 0xb8, 0xd4, 0x25, 0x83, 0x46, 0xf1, 0xcf, 0x56, 0xdb, 0xa8, 0x3d, 0x20}} , - {{0x2f, 0x11, 0x32, 0xca, 0x61, 0xab, 0x38, 0xdf, 0xf0, 0x0f, 0x2f, 0xea, 0x32, 0x28, 0xf2, 0x4c, 0x6c, 0x71, 0xd5, 0x80, 0x85, 0xb8, 0x0e, 0x47, 0xe1, 0x95, 0x15, 0xcb, 0x27, 0xe8, 0xd0, 0x47}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xc8, 0x84, 0xa5, 0x08, 0xbc, 0xfd, 0x87, 0x3b, 0x99, 0x8b, 0x69, 0x80, 0x7b, 0xc6, 0x3a, 0xeb, 0x93, 0xcf, 0x4e, 0xf8, 0x5c, 0x2d, 0x86, 0x42, 0xb6, 0x71, 0xd7, 0x97, 0x5f, 0xe1, 0x42, 0x67}} , - {{0xb4, 0xb9, 0x37, 0xfc, 0xa9, 0x5b, 0x2f, 0x1e, 0x93, 0xe4, 0x1e, 0x62, 0xfc, 0x3c, 0x78, 0x81, 0x8f, 0xf3, 0x8a, 0x66, 0x09, 0x6f, 0xad, 0x6e, 0x79, 0x73, 0xe5, 0xc9, 0x00, 0x06, 0xd3, 0x21}}}, -{{{0xf8, 0xf9, 0x28, 0x6c, 0x6d, 0x59, 0xb2, 0x59, 0x74, 0x23, 0xbf, 0xe7, 0x33, 0x8d, 0x57, 0x09, 0x91, 0x9c, 0x24, 0x08, 0x15, 0x2b, 0xe2, 0xb8, 0xee, 0x3a, 0xe5, 0x27, 0x06, 0x86, 0xa4, 0x23}} , - {{0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70}}}, -{{{0x81, 0x6b, 0x88, 0xe8, 0x1e, 0xc7, 0x77, 0x96, 0x0e, 0xa1, 0xa9, 0x52, 0xe0, 0xd8, 0x0e, 0x61, 0x9e, 0x79, 0x2d, 0x95, 0x9c, 0x8d, 0x96, 0xe0, 0x06, 0x40, 0x5d, 0x87, 0x28, 0x5f, 0x98, 0x70}} , - {{0xf1, 0x79, 0x7b, 0xed, 0x4f, 0x44, 0xb2, 0xe7, 0x08, 0x0d, 0xc2, 0x08, 0x12, 0xd2, 0x9f, 0xdf, 0xcd, 0x93, 0x20, 0x8a, 0xcf, 0x33, 0xca, 0x6d, 0x89, 0xb9, 0x77, 0xc8, 0x93, 0x1b, 0x4e, 0x60}}}, -{{{0x26, 0x4f, 0x7e, 0x97, 0xf6, 0x40, 0xdd, 0x4f, 0xfc, 0x52, 0x78, 0xf9, 0x90, 0x31, 0x03, 0xe6, 0x7d, 0x56, 0x39, 0x0b, 0x1d, 0x56, 0x82, 0x85, 0xf9, 0x1a, 0x42, 0x17, 0x69, 0x6c, 0xcf, 0x39}} , - {{0x69, 0xd2, 0x06, 0x3a, 0x4f, 0x39, 0x2d, 0xf9, 0x38, 0x40, 0x8c, 0x4c, 0xe7, 0x05, 0x12, 0xb4, 0x78, 0x8b, 0xf8, 0xc0, 0xec, 0x93, 0xde, 0x7a, 0x6b, 0xce, 0x2c, 0xe1, 0x0e, 0xa9, 0x34, 0x44}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x0b, 0xa4, 0x3c, 0xb0, 0x0f, 0x7a, 0x51, 0xf1, 0x78, 0xd6, 0xd9, 0x6a, 0xfd, 0x46, 0xe8, 0xb8, 0xa8, 0x79, 0x1d, 0x87, 0xf9, 0x90, 0xf2, 0x9c, 0x13, 0x29, 0xf8, 0x0b, 0x20, 0x64, 0xfa, 0x05}} , - {{0x26, 0x09, 0xda, 0x17, 0xaf, 0x95, 0xd6, 0xfb, 0x6a, 0x19, 0x0d, 0x6e, 0x5e, 0x12, 0xf1, 0x99, 0x4c, 0xaa, 0xa8, 0x6f, 0x79, 0x86, 0xf4, 0x72, 0x28, 0x00, 0x26, 0xf9, 0xea, 0x9e, 0x19, 0x3d}}}, -{{{0x87, 0xdd, 0xcf, 0xf0, 0x5b, 0x49, 0xa2, 0x5d, 0x40, 0x7a, 0x23, 0x26, 0xa4, 0x7a, 0x83, 0x8a, 0xb7, 0x8b, 0xd2, 0x1a, 0xbf, 0xea, 0x02, 0x24, 0x08, 0x5f, 0x7b, 0xa9, 0xb1, 0xbe, 0x9d, 0x37}} , - {{0xfc, 0x86, 0x4b, 0x08, 0xee, 0xe7, 0xa0, 0xfd, 0x21, 0x45, 0x09, 0x34, 0xc1, 0x61, 0x32, 0x23, 0xfc, 0x9b, 0x55, 0x48, 0x53, 0x99, 0xf7, 0x63, 0xd0, 0x99, 0xce, 0x01, 0xe0, 0x9f, 0xeb, 0x28}}}, -{{{0x47, 0xfc, 0xab, 0x5a, 0x17, 0xf0, 0x85, 0x56, 0x3a, 0x30, 0x86, 0x20, 0x28, 0x4b, 0x8e, 0x44, 0x74, 0x3a, 0x6e, 0x02, 0xf1, 0x32, 0x8f, 0x9f, 0x3f, 0x08, 0x35, 0xe9, 0xca, 0x16, 0x5f, 0x6e}} , - {{0x1c, 0x59, 0x1c, 0x65, 0x5d, 0x34, 0xa4, 0x09, 0xcd, 0x13, 0x9c, 0x70, 0x7d, 0xb1, 0x2a, 0xc5, 0x88, 0xaf, 0x0b, 0x60, 0xc7, 0x9f, 0x34, 0x8d, 0xd6, 0xb7, 0x7f, 0xea, 0x78, 0x65, 0x8d, 0x77}}}, -{{{0x56, 0xa5, 0xc2, 0x0c, 0xdd, 0xbc, 0xb8, 0x20, 0x6d, 0x57, 0x61, 0xb5, 0xfb, 0x78, 0xb5, 0xd4, 0x49, 0x54, 0x90, 0x26, 0xc1, 0xcb, 0xe9, 0xe6, 0xbf, 0xec, 0x1d, 0x4e, 0xed, 0x07, 0x7e, 0x5e}} , - {{0xc7, 0xf6, 0x6c, 0x56, 0x31, 0x20, 0x14, 0x0e, 0xa8, 0xd9, 0x27, 0xc1, 0x9a, 0x3d, 0x1b, 0x7d, 0x0e, 0x26, 0xd3, 0x81, 0xaa, 0xeb, 0xf5, 0x6b, 0x79, 0x02, 0xf1, 0x51, 0x5c, 0x75, 0x55, 0x0f}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x0a, 0x34, 0xcd, 0x82, 0x3c, 0x33, 0x09, 0x54, 0xd2, 0x61, 0x39, 0x30, 0x9b, 0xfd, 0xef, 0x21, 0x26, 0xd4, 0x70, 0xfa, 0xee, 0xf9, 0x31, 0x33, 0x73, 0x84, 0xd0, 0xb3, 0x81, 0xbf, 0xec, 0x2e}} , - {{0xe8, 0x93, 0x8b, 0x00, 0x64, 0xf7, 0x9c, 0xb8, 0x74, 0xe0, 0xe6, 0x49, 0x48, 0x4d, 0x4d, 0x48, 0xb6, 0x19, 0xa1, 0x40, 0xb7, 0xd9, 0x32, 0x41, 0x7c, 0x82, 0x37, 0xa1, 0x2d, 0xdc, 0xd2, 0x54}}}, -{{{0x68, 0x2b, 0x4a, 0x5b, 0xd5, 0xc7, 0x51, 0x91, 0x1d, 0xe1, 0x2a, 0x4b, 0xc4, 0x47, 0xf1, 0xbc, 0x7a, 0xb3, 0xcb, 0xc8, 0xb6, 0x7c, 0xac, 0x90, 0x05, 0xfd, 0xf3, 0xf9, 0x52, 0x3a, 0x11, 0x6b}} , - {{0x3d, 0xc1, 0x27, 0xf3, 0x59, 0x43, 0x95, 0x90, 0xc5, 0x96, 0x79, 0xf5, 0xf4, 0x95, 0x65, 0x29, 0x06, 0x9c, 0x51, 0x05, 0x18, 0xda, 0xb8, 0x2e, 0x79, 0x7e, 0x69, 0x59, 0x71, 0x01, 0xeb, 0x1a}}}, -{{{0x15, 0x06, 0x49, 0xb6, 0x8a, 0x3c, 0xea, 0x2f, 0x34, 0x20, 0x14, 0xc3, 0xaa, 0xd6, 0xaf, 0x2c, 0x3e, 0xbd, 0x65, 0x20, 0xe2, 0x4d, 0x4b, 0x3b, 0xeb, 0x9f, 0x4a, 0xc3, 0xad, 0xa4, 0x3b, 0x60}} , - {{0xbc, 0x58, 0xe6, 0xc0, 0x95, 0x2a, 0x2a, 0x81, 0x9a, 0x7a, 0xf3, 0xd2, 0x06, 0xbe, 0x48, 0xbc, 0x0c, 0xc5, 0x46, 0xe0, 0x6a, 0xd4, 0xac, 0x0f, 0xd9, 0xcc, 0x82, 0x34, 0x2c, 0xaf, 0xdb, 0x1f}}}, -{{{0xf7, 0x17, 0x13, 0xbd, 0xfb, 0xbc, 0xd2, 0xec, 0x45, 0xb3, 0x15, 0x31, 0xe9, 0xaf, 0x82, 0x84, 0x3d, 0x28, 0xc6, 0xfc, 0x11, 0xf5, 0x41, 0xb5, 0x8b, 0xd3, 0x12, 0x76, 0x52, 0xe7, 0x1a, 0x3c}} , - {{0x4e, 0x36, 0x11, 0x07, 0xa2, 0x15, 0x20, 0x51, 0xc4, 0x2a, 0xc3, 0x62, 0x8b, 0x5e, 0x7f, 0xa6, 0x0f, 0xf9, 0x45, 0x85, 0x6c, 0x11, 0x86, 0xb7, 0x7e, 0xe5, 0xd7, 0xf9, 0xc3, 0x91, 0x1c, 0x05}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xea, 0xd6, 0xde, 0x29, 0x3a, 0x00, 0xb9, 0x02, 0x59, 0xcb, 0x26, 0xc4, 0xba, 0x99, 0xb1, 0x97, 0x2f, 0x8e, 0x00, 0x92, 0x26, 0x4f, 0x52, 0xeb, 0x47, 0x1b, 0x89, 0x8b, 0x24, 0xc0, 0x13, 0x7d}} , - {{0xd5, 0x20, 0x5b, 0x80, 0xa6, 0x80, 0x20, 0x95, 0xc3, 0xe9, 0x9f, 0x8e, 0x87, 0x9e, 0x1e, 0x9e, 0x7a, 0xc7, 0xcc, 0x75, 0x6c, 0xa5, 0xf1, 0x91, 0x1a, 0xa8, 0x01, 0x2c, 0xab, 0x76, 0xa9, 0x59}}}, -{{{0xde, 0xc9, 0xb1, 0x31, 0x10, 0x16, 0xaa, 0x35, 0x14, 0x6a, 0xd4, 0xb5, 0x34, 0x82, 0x71, 0xd2, 0x4a, 0x5d, 0x9a, 0x1f, 0x53, 0x26, 0x3c, 0xe5, 0x8e, 0x8d, 0x33, 0x7f, 0xff, 0xa9, 0xd5, 0x17}} , - {{0x89, 0xaf, 0xf6, 0xa4, 0x64, 0xd5, 0x10, 0xe0, 0x1d, 0xad, 0xef, 0x44, 0xbd, 0xda, 0x83, 0xac, 0x7a, 0xa8, 0xf0, 0x1c, 0x07, 0xf9, 0xc3, 0x43, 0x6c, 0x3f, 0xb7, 0xd3, 0x87, 0x22, 0x02, 0x73}}}, -{{{0x64, 0x1d, 0x49, 0x13, 0x2f, 0x71, 0xec, 0x69, 0x87, 0xd0, 0x42, 0xee, 0x13, 0xec, 0xe3, 0xed, 0x56, 0x7b, 0xbf, 0xbd, 0x8c, 0x2f, 0x7d, 0x7b, 0x9d, 0x28, 0xec, 0x8e, 0x76, 0x2f, 0x6f, 0x08}} , - {{0x22, 0xf5, 0x5f, 0x4d, 0x15, 0xef, 0xfc, 0x4e, 0x57, 0x03, 0x36, 0x89, 0xf0, 0xeb, 0x5b, 0x91, 0xd6, 0xe2, 0xca, 0x01, 0xa5, 0xee, 0x52, 0xec, 0xa0, 0x3c, 0x8f, 0x33, 0x90, 0x5a, 0x94, 0x72}}}, -{{{0x8a, 0x4b, 0xe7, 0x38, 0xbc, 0xda, 0xc2, 0xb0, 0x85, 0xe1, 0x4a, 0xfe, 0x2d, 0x44, 0x84, 0xcb, 0x20, 0x6b, 0x2d, 0xbf, 0x11, 0x9c, 0xd7, 0xbe, 0xd3, 0x3e, 0x5f, 0xbf, 0x68, 0xbc, 0xa8, 0x07}} , - {{0x01, 0x89, 0x28, 0x22, 0x6a, 0x78, 0xaa, 0x29, 0x03, 0xc8, 0x74, 0x95, 0x03, 0x3e, 0xdc, 0xbd, 0x07, 0x13, 0xa8, 0xa2, 0x20, 0x2d, 0xb3, 0x18, 0x70, 0x42, 0xfd, 0x7a, 0xc4, 0xd7, 0x49, 0x72}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x02, 0xff, 0x32, 0x2b, 0x5c, 0x93, 0x54, 0x32, 0xe8, 0x57, 0x54, 0x1a, 0x8b, 0x33, 0x60, 0x65, 0xd3, 0x67, 0xa4, 0xc1, 0x26, 0xc4, 0xa4, 0x34, 0x1f, 0x9b, 0xa7, 0xa9, 0xf4, 0xd9, 0x4f, 0x5b}} , - {{0x46, 0x8d, 0xb0, 0x33, 0x54, 0x26, 0x5b, 0x68, 0xdf, 0xbb, 0xc5, 0xec, 0xc2, 0xf9, 0x3c, 0x5a, 0x37, 0xc1, 0x8e, 0x27, 0x47, 0xaa, 0x49, 0x5a, 0xf8, 0xfb, 0x68, 0x04, 0x23, 0xd1, 0xeb, 0x40}}}, -{{{0x65, 0xa5, 0x11, 0x84, 0x8a, 0x67, 0x9d, 0x9e, 0xd1, 0x44, 0x68, 0x7a, 0x34, 0xe1, 0x9f, 0xa3, 0x54, 0xcd, 0x07, 0xca, 0x79, 0x1f, 0x54, 0x2f, 0x13, 0x70, 0x4e, 0xee, 0xa2, 0xfa, 0xe7, 0x5d}} , - {{0x36, 0xec, 0x54, 0xf8, 0xce, 0xe4, 0x85, 0xdf, 0xf6, 0x6f, 0x1d, 0x90, 0x08, 0xbc, 0xe8, 0xc0, 0x92, 0x2d, 0x43, 0x6b, 0x92, 0xa9, 0x8e, 0xab, 0x0a, 0x2e, 0x1c, 0x1e, 0x64, 0x23, 0x9f, 0x2c}}}, -{{{0xa7, 0xd6, 0x2e, 0xd5, 0xcc, 0xd4, 0xcb, 0x5a, 0x3b, 0xa7, 0xf9, 0x46, 0x03, 0x1d, 0xad, 0x2b, 0x34, 0x31, 0x90, 0x00, 0x46, 0x08, 0x82, 0x14, 0xc4, 0xe0, 0x9c, 0xf0, 0xe3, 0x55, 0x43, 0x31}} , - {{0x60, 0xd6, 0xdd, 0x78, 0xe6, 0xd4, 0x22, 0x42, 0x1f, 0x00, 0xf9, 0xb1, 0x6a, 0x63, 0xe2, 0x92, 0x59, 0xd1, 0x1a, 0xb7, 0x00, 0x54, 0x29, 0xc9, 0xc1, 0xf6, 0x6f, 0x7a, 0xc5, 0x3c, 0x5f, 0x65}}}, -{{{0x27, 0x4f, 0xd0, 0x72, 0xb1, 0x11, 0x14, 0x27, 0x15, 0x94, 0x48, 0x81, 0x7e, 0x74, 0xd8, 0x32, 0xd5, 0xd1, 0x11, 0x28, 0x60, 0x63, 0x36, 0x32, 0x37, 0xb5, 0x13, 0x1c, 0xa0, 0x37, 0xe3, 0x74}} , - {{0xf1, 0x25, 0x4e, 0x11, 0x96, 0x67, 0xe6, 0x1c, 0xc2, 0xb2, 0x53, 0xe2, 0xda, 0x85, 0xee, 0xb2, 0x9f, 0x59, 0xf3, 0xba, 0xbd, 0xfa, 0xcf, 0x6e, 0xf9, 0xda, 0xa4, 0xb3, 0x02, 0x8f, 0x64, 0x08}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x34, 0x94, 0xf2, 0x64, 0x54, 0x47, 0x37, 0x07, 0x40, 0x8a, 0x20, 0xba, 0x4a, 0x55, 0xd7, 0x3f, 0x47, 0xba, 0x25, 0x23, 0x14, 0xb0, 0x2c, 0xe8, 0x55, 0xa8, 0xa6, 0xef, 0x51, 0xbd, 0x6f, 0x6a}} , - {{0x71, 0xd6, 0x16, 0x76, 0xb2, 0x06, 0xea, 0x79, 0xf5, 0xc4, 0xc3, 0x52, 0x7e, 0x61, 0xd1, 0xe1, 0xad, 0x70, 0x78, 0x1d, 0x16, 0x11, 0xf8, 0x7c, 0x2b, 0xfc, 0x55, 0x9f, 0x52, 0xf8, 0xf5, 0x16}}}, -{{{0x34, 0x96, 0x9a, 0xf6, 0xc5, 0xe0, 0x14, 0x03, 0x24, 0x0e, 0x4c, 0xad, 0x9e, 0x9a, 0x70, 0x23, 0x96, 0xb2, 0xf1, 0x2e, 0x9d, 0xc3, 0x32, 0x9b, 0x54, 0xa5, 0x73, 0xde, 0x88, 0xb1, 0x3e, 0x24}} , - {{0xf6, 0xe2, 0x4c, 0x1f, 0x5b, 0xb2, 0xaf, 0x82, 0xa5, 0xcf, 0x81, 0x10, 0x04, 0xef, 0xdb, 0xa2, 0xcc, 0x24, 0xb2, 0x7e, 0x0b, 0x7a, 0xeb, 0x01, 0xd8, 0x52, 0xf4, 0x51, 0x89, 0x29, 0x79, 0x37}}}, -{{{0x74, 0xde, 0x12, 0xf3, 0x68, 0xb7, 0x66, 0xc3, 0xee, 0x68, 0xdc, 0x81, 0xb5, 0x55, 0x99, 0xab, 0xd9, 0x28, 0x63, 0x6d, 0x8b, 0x40, 0x69, 0x75, 0x6c, 0xcd, 0x5c, 0x2a, 0x7e, 0x32, 0x7b, 0x29}} , - {{0x02, 0xcc, 0x22, 0x74, 0x4d, 0x19, 0x07, 0xc0, 0xda, 0xb5, 0x76, 0x51, 0x2a, 0xaa, 0xa6, 0x0a, 0x5f, 0x26, 0xd4, 0xbc, 0xaf, 0x48, 0x88, 0x7f, 0x02, 0xbc, 0xf2, 0xe1, 0xcf, 0xe9, 0xdd, 0x15}}}, -{{{0xed, 0xb5, 0x9a, 0x8c, 0x9a, 0xdd, 0x27, 0xf4, 0x7f, 0x47, 0xd9, 0x52, 0xa7, 0xcd, 0x65, 0xa5, 0x31, 0x22, 0xed, 0xa6, 0x63, 0x5b, 0x80, 0x4a, 0xad, 0x4d, 0xed, 0xbf, 0xee, 0x49, 0xb3, 0x06}} , - {{0xf8, 0x64, 0x8b, 0x60, 0x90, 0xe9, 0xde, 0x44, 0x77, 0xb9, 0x07, 0x36, 0x32, 0xc2, 0x50, 0xf5, 0x65, 0xdf, 0x48, 0x4c, 0x37, 0xaa, 0x68, 0xab, 0x9a, 0x1f, 0x3e, 0xff, 0x89, 0x92, 0xa0, 0x07}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x7d, 0x4f, 0x9c, 0x19, 0xc0, 0x4a, 0x31, 0xec, 0xf9, 0xaa, 0xeb, 0xb2, 0x16, 0x9c, 0xa3, 0x66, 0x5f, 0xd1, 0xd4, 0xed, 0xb8, 0x92, 0x1c, 0xab, 0xda, 0xea, 0xd9, 0x57, 0xdf, 0x4c, 0x2a, 0x48}} , - {{0x4b, 0xb0, 0x4e, 0x6e, 0x11, 0x3b, 0x51, 0xbd, 0x6a, 0xfd, 0xe4, 0x25, 0xa5, 0x5f, 0x11, 0x3f, 0x98, 0x92, 0x51, 0x14, 0xc6, 0x5f, 0x3c, 0x0b, 0xa8, 0xf7, 0xc2, 0x81, 0x43, 0xde, 0x91, 0x73}}}, -{{{0x3c, 0x8f, 0x9f, 0x33, 0x2a, 0x1f, 0x43, 0x33, 0x8f, 0x68, 0xff, 0x1f, 0x3d, 0x73, 0x6b, 0xbf, 0x68, 0xcc, 0x7d, 0x13, 0x6c, 0x24, 0x4b, 0xcc, 0x4d, 0x24, 0x0d, 0xfe, 0xde, 0x86, 0xad, 0x3b}} , - {{0x79, 0x51, 0x81, 0x01, 0xdc, 0x73, 0x53, 0xe0, 0x6e, 0x9b, 0xea, 0x68, 0x3f, 0x5c, 0x14, 0x84, 0x53, 0x8d, 0x4b, 0xc0, 0x9f, 0x9f, 0x89, 0x2b, 0x8c, 0xba, 0x86, 0xfa, 0xf2, 0xcd, 0xe3, 0x2d}}}, -{{{0x06, 0xf9, 0x29, 0x5a, 0xdb, 0x3d, 0x84, 0x52, 0xab, 0xcc, 0x6b, 0x60, 0x9d, 0xb7, 0x4a, 0x0e, 0x36, 0x63, 0x91, 0xad, 0xa0, 0x95, 0xb0, 0x97, 0x89, 0x4e, 0xcf, 0x7d, 0x3c, 0xe5, 0x7c, 0x28}} , - {{0x2e, 0x69, 0x98, 0xfd, 0xc6, 0xbd, 0xcc, 0xca, 0xdf, 0x9a, 0x44, 0x7e, 0x9d, 0xca, 0x89, 0x6d, 0xbf, 0x27, 0xc2, 0xf8, 0xcd, 0x46, 0x00, 0x2b, 0xb5, 0x58, 0x4e, 0xb7, 0x89, 0x09, 0xe9, 0x2d}}}, -{{{0x54, 0xbe, 0x75, 0xcb, 0x05, 0xb0, 0x54, 0xb7, 0xe7, 0x26, 0x86, 0x4a, 0xfc, 0x19, 0xcf, 0x27, 0x46, 0xd4, 0x22, 0x96, 0x5a, 0x11, 0xe8, 0xd5, 0x1b, 0xed, 0x71, 0xc5, 0x5d, 0xc8, 0xaf, 0x45}} , - {{0x40, 0x7b, 0x77, 0x57, 0x49, 0x9e, 0x80, 0x39, 0x23, 0xee, 0x81, 0x0b, 0x22, 0xcf, 0xdb, 0x7a, 0x2f, 0x14, 0xb8, 0x57, 0x8f, 0xa1, 0x39, 0x1e, 0x77, 0xfc, 0x0b, 0xa6, 0xbf, 0x8a, 0x0c, 0x6c}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x77, 0x3a, 0xd4, 0xd8, 0x27, 0xcf, 0xe8, 0xa1, 0x72, 0x9d, 0xca, 0xdd, 0x0d, 0x96, 0xda, 0x79, 0xed, 0x56, 0x42, 0x15, 0x60, 0xc7, 0x1c, 0x6b, 0x26, 0x30, 0xf6, 0x6a, 0x95, 0x67, 0xf3, 0x0a}} , - {{0xc5, 0x08, 0xa4, 0x2b, 0x2f, 0xbd, 0x31, 0x81, 0x2a, 0xa6, 0xb6, 0xe4, 0x00, 0x91, 0xda, 0x3d, 0xb2, 0xb0, 0x96, 0xce, 0x8a, 0xd2, 0x8d, 0x70, 0xb3, 0xd3, 0x34, 0x01, 0x90, 0x8d, 0x10, 0x21}}}, -{{{0x33, 0x0d, 0xe7, 0xba, 0x4f, 0x07, 0xdf, 0x8d, 0xea, 0x7d, 0xa0, 0xc5, 0xd6, 0xb1, 0xb0, 0xe5, 0x57, 0x1b, 0x5b, 0xf5, 0x45, 0x13, 0x14, 0x64, 0x5a, 0xeb, 0x5c, 0xfc, 0x54, 0x01, 0x76, 0x2b}} , - {{0x02, 0x0c, 0xc2, 0xaf, 0x96, 0x36, 0xfe, 0x4a, 0xe2, 0x54, 0x20, 0x6a, 0xeb, 0xb2, 0x9f, 0x62, 0xd7, 0xce, 0xa2, 0x3f, 0x20, 0x11, 0x34, 0x37, 0xe0, 0x42, 0xed, 0x6f, 0xf9, 0x1a, 0xc8, 0x7d}}}, -{{{0xd8, 0xb9, 0x11, 0xe8, 0x36, 0x3f, 0x42, 0xc1, 0xca, 0xdc, 0xd3, 0xf1, 0xc8, 0x23, 0x3d, 0x4f, 0x51, 0x7b, 0x9d, 0x8d, 0xd8, 0xe4, 0xa0, 0xaa, 0xf3, 0x04, 0xd6, 0x11, 0x93, 0xc8, 0x35, 0x45}} , - {{0x61, 0x36, 0xd6, 0x08, 0x90, 0xbf, 0xa7, 0x7a, 0x97, 0x6c, 0x0f, 0x84, 0xd5, 0x33, 0x2d, 0x37, 0xc9, 0x6a, 0x80, 0x90, 0x3d, 0x0a, 0xa2, 0xaa, 0xe1, 0xb8, 0x84, 0xba, 0x61, 0x36, 0xdd, 0x69}}}, -{{{0x6b, 0xdb, 0x5b, 0x9c, 0xc6, 0x92, 0xbc, 0x23, 0xaf, 0xc5, 0xb8, 0x75, 0xf8, 0x42, 0xfa, 0xd6, 0xb6, 0x84, 0x94, 0x63, 0x98, 0x93, 0x48, 0x78, 0x38, 0xcd, 0xbb, 0x18, 0x34, 0xc3, 0xdb, 0x67}} , - {{0x96, 0xf3, 0x3a, 0x09, 0x56, 0xb0, 0x6f, 0x7c, 0x51, 0x1e, 0x1b, 0x39, 0x48, 0xea, 0xc9, 0x0c, 0x25, 0xa2, 0x7a, 0xca, 0xe7, 0x92, 0xfc, 0x59, 0x30, 0xa3, 0x89, 0x85, 0xdf, 0x6f, 0x43, 0x38}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x79, 0x84, 0x44, 0x19, 0xbd, 0xe9, 0x54, 0xc4, 0xc0, 0x6e, 0x2a, 0xa8, 0xa8, 0x9b, 0x43, 0xd5, 0x71, 0x22, 0x5f, 0xdc, 0x01, 0xfa, 0xdf, 0xb3, 0xb8, 0x47, 0x4b, 0x0a, 0xa5, 0x44, 0xea, 0x29}} , - {{0x05, 0x90, 0x50, 0xaf, 0x63, 0x5f, 0x9d, 0x9e, 0xe1, 0x9d, 0x38, 0x97, 0x1f, 0x6c, 0xac, 0x30, 0x46, 0xb2, 0x6a, 0x19, 0xd1, 0x4b, 0xdb, 0xbb, 0x8c, 0xda, 0x2e, 0xab, 0xc8, 0x5a, 0x77, 0x6c}}}, -{{{0x2b, 0xbe, 0xaf, 0xa1, 0x6d, 0x2f, 0x0b, 0xb1, 0x8f, 0xe3, 0xe0, 0x38, 0xcd, 0x0b, 0x41, 0x1b, 0x4a, 0x15, 0x07, 0xf3, 0x6f, 0xdc, 0xb8, 0xe9, 0xde, 0xb2, 0xa3, 0x40, 0x01, 0xa6, 0x45, 0x1e}} , - {{0x76, 0x0a, 0xda, 0x8d, 0x2c, 0x07, 0x3f, 0x89, 0x7d, 0x04, 0xad, 0x43, 0x50, 0x6e, 0xd2, 0x47, 0xcb, 0x8a, 0xe6, 0x85, 0x1a, 0x24, 0xf3, 0xd2, 0x60, 0xfd, 0xdf, 0x73, 0xa4, 0x0d, 0x73, 0x0e}}}, -{{{0xfd, 0x67, 0x6b, 0x71, 0x9b, 0x81, 0x53, 0x39, 0x39, 0xf4, 0xb8, 0xd5, 0xc3, 0x30, 0x9b, 0x3b, 0x7c, 0xa3, 0xf0, 0xd0, 0x84, 0x21, 0xd6, 0xbf, 0xb7, 0x4c, 0x87, 0x13, 0x45, 0x2d, 0xa7, 0x55}} , - {{0x5d, 0x04, 0xb3, 0x40, 0x28, 0x95, 0x2d, 0x30, 0x83, 0xec, 0x5e, 0xe4, 0xff, 0x75, 0xfe, 0x79, 0x26, 0x9d, 0x1d, 0x36, 0xcd, 0x0a, 0x15, 0xd2, 0x24, 0x14, 0x77, 0x71, 0xd7, 0x8a, 0x1b, 0x04}}}, -{{{0x5d, 0x93, 0xc9, 0xbe, 0xaa, 0x90, 0xcd, 0x9b, 0xfb, 0x73, 0x7e, 0xb0, 0x64, 0x98, 0x57, 0x44, 0x42, 0x41, 0xb1, 0xaf, 0xea, 0xc1, 0xc3, 0x22, 0xff, 0x60, 0x46, 0xcb, 0x61, 0x81, 0x70, 0x61}} , - {{0x0d, 0x82, 0xb9, 0xfe, 0x21, 0xcd, 0xc4, 0xf5, 0x98, 0x0c, 0x4e, 0x72, 0xee, 0x87, 0x49, 0xf8, 0xa1, 0x95, 0xdf, 0x8f, 0x2d, 0xbd, 0x21, 0x06, 0x7c, 0x15, 0xe8, 0x12, 0x6d, 0x93, 0xd6, 0x38}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x91, 0xf7, 0x51, 0xd9, 0xef, 0x7d, 0x42, 0x01, 0x13, 0xe9, 0xb8, 0x7f, 0xa6, 0x49, 0x17, 0x64, 0x21, 0x80, 0x83, 0x2c, 0x63, 0x4c, 0x60, 0x09, 0x59, 0x91, 0x92, 0x77, 0x39, 0x51, 0xf4, 0x48}} , - {{0x60, 0xd5, 0x22, 0x83, 0x08, 0x2f, 0xff, 0x99, 0x3e, 0x69, 0x6d, 0x88, 0xda, 0xe7, 0x5b, 0x52, 0x26, 0x31, 0x2a, 0xe5, 0x89, 0xde, 0x68, 0x90, 0xb6, 0x22, 0x5a, 0xbd, 0xd3, 0x85, 0x53, 0x31}}}, -{{{0xd8, 0xce, 0xdc, 0xf9, 0x3c, 0x4b, 0xa2, 0x1d, 0x2c, 0x2f, 0x36, 0xbe, 0x7a, 0xfc, 0xcd, 0xbc, 0xdc, 0xf9, 0x30, 0xbd, 0xff, 0x05, 0xc7, 0xe4, 0x8e, 0x17, 0x62, 0xf8, 0x4d, 0xa0, 0x56, 0x79}} , - {{0x82, 0xe7, 0xf6, 0xba, 0x53, 0x84, 0x0a, 0xa3, 0x34, 0xff, 0x3c, 0xa3, 0x6a, 0xa1, 0x37, 0xea, 0xdd, 0xb6, 0x95, 0xb3, 0x78, 0x19, 0x76, 0x1e, 0x55, 0x2f, 0x77, 0x2e, 0x7f, 0xc1, 0xea, 0x5e}}}, -{{{0x83, 0xe1, 0x6e, 0xa9, 0x07, 0x33, 0x3e, 0x83, 0xff, 0xcb, 0x1c, 0x9f, 0xb1, 0xa3, 0xb4, 0xc9, 0xe1, 0x07, 0x97, 0xff, 0xf8, 0x23, 0x8f, 0xce, 0x40, 0xfd, 0x2e, 0x5e, 0xdb, 0x16, 0x43, 0x2d}} , - {{0xba, 0x38, 0x02, 0xf7, 0x81, 0x43, 0x83, 0xa3, 0x20, 0x4f, 0x01, 0x3b, 0x8a, 0x04, 0x38, 0x31, 0xc6, 0x0f, 0xc8, 0xdf, 0xd7, 0xfa, 0x2f, 0x88, 0x3f, 0xfc, 0x0c, 0x76, 0xc4, 0xa6, 0x45, 0x72}}}, -{{{0xbb, 0x0c, 0xbc, 0x6a, 0xa4, 0x97, 0x17, 0x93, 0x2d, 0x6f, 0xde, 0x72, 0x10, 0x1c, 0x08, 0x2c, 0x0f, 0x80, 0x32, 0x68, 0x27, 0xd4, 0xab, 0xdd, 0xc5, 0x58, 0x61, 0x13, 0x6d, 0x11, 0x1e, 0x4d}} , - {{0x1a, 0xb9, 0xc9, 0x10, 0xfb, 0x1e, 0x4e, 0xf4, 0x84, 0x4b, 0x8a, 0x5e, 0x7b, 0x4b, 0xe8, 0x43, 0x8c, 0x8f, 0x00, 0xb5, 0x54, 0x13, 0xc5, 0x5c, 0xb6, 0x35, 0x4e, 0x9d, 0xe4, 0x5b, 0x41, 0x6d}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x15, 0x7d, 0x12, 0x48, 0x82, 0x14, 0x42, 0xcd, 0x32, 0xd4, 0x4b, 0xc1, 0x72, 0x61, 0x2a, 0x8c, 0xec, 0xe2, 0xf8, 0x24, 0x45, 0x94, 0xe3, 0xbe, 0xdd, 0x67, 0xa8, 0x77, 0x5a, 0xae, 0x5b, 0x4b}} , - {{0xcb, 0x77, 0x9a, 0x20, 0xde, 0xb8, 0x23, 0xd9, 0xa0, 0x0f, 0x8c, 0x7b, 0xa5, 0xcb, 0xae, 0xb6, 0xec, 0x42, 0x67, 0x0e, 0x58, 0xa4, 0x75, 0x98, 0x21, 0x71, 0x84, 0xb3, 0xe0, 0x76, 0x94, 0x73}}}, -{{{0xdf, 0xfc, 0x69, 0x28, 0x23, 0x3f, 0x5b, 0xf8, 0x3b, 0x24, 0x37, 0xf3, 0x1d, 0xd5, 0x22, 0x6b, 0xd0, 0x98, 0xa8, 0x6c, 0xcf, 0xff, 0x06, 0xe1, 0x13, 0xdf, 0xb9, 0xc1, 0x0c, 0xa9, 0xbf, 0x33}} , - {{0xd9, 0x81, 0xda, 0xb2, 0x4f, 0x82, 0x9d, 0x43, 0x81, 0x09, 0xf1, 0xd2, 0x01, 0xef, 0xac, 0xf4, 0x2d, 0x7d, 0x01, 0x09, 0xf1, 0xff, 0xa5, 0x9f, 0xe5, 0xca, 0x27, 0x63, 0xdb, 0x20, 0xb1, 0x53}}}, -{{{0x67, 0x02, 0xe8, 0xad, 0xa9, 0x34, 0xd4, 0xf0, 0x15, 0x81, 0xaa, 0xc7, 0x4d, 0x87, 0x94, 0xea, 0x75, 0xe7, 0x4c, 0x94, 0x04, 0x0e, 0x69, 0x87, 0xe7, 0x51, 0x91, 0x10, 0x03, 0xc7, 0xbe, 0x56}} , - {{0x32, 0xfb, 0x86, 0xec, 0x33, 0x6b, 0x2e, 0x51, 0x2b, 0xc8, 0xfa, 0x6c, 0x70, 0x47, 0x7e, 0xce, 0x05, 0x0c, 0x71, 0xf3, 0xb4, 0x56, 0xa6, 0xdc, 0xcc, 0x78, 0x07, 0x75, 0xd0, 0xdd, 0xb2, 0x6a}}}, -{{{0xc6, 0xef, 0xb9, 0xc0, 0x2b, 0x22, 0x08, 0x1e, 0x71, 0x70, 0xb3, 0x35, 0x9c, 0x7a, 0x01, 0x92, 0x44, 0x9a, 0xf6, 0xb0, 0x58, 0x95, 0xc1, 0x9b, 0x02, 0xed, 0x2d, 0x7c, 0x34, 0x29, 0x49, 0x44}} , - {{0x45, 0x62, 0x1d, 0x2e, 0xff, 0x2a, 0x1c, 0x21, 0xa4, 0x25, 0x7b, 0x0d, 0x8c, 0x15, 0x39, 0xfc, 0x8f, 0x7c, 0xa5, 0x7d, 0x1e, 0x25, 0xa3, 0x45, 0xd6, 0xab, 0xbd, 0xcb, 0xc5, 0x5e, 0x78, 0x77}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xd0, 0xd3, 0x42, 0xed, 0x1d, 0x00, 0x3c, 0x15, 0x2c, 0x9c, 0x77, 0x81, 0xd2, 0x73, 0xd1, 0x06, 0xd5, 0xc4, 0x7f, 0x94, 0xbb, 0x92, 0x2d, 0x2c, 0x4b, 0x45, 0x4b, 0xe9, 0x2a, 0x89, 0x6b, 0x2b}} , - {{0xd2, 0x0c, 0x88, 0xc5, 0x48, 0x4d, 0xea, 0x0d, 0x4a, 0xc9, 0x52, 0x6a, 0x61, 0x79, 0xe9, 0x76, 0xf3, 0x85, 0x52, 0x5c, 0x1b, 0x2c, 0xe1, 0xd6, 0xc4, 0x0f, 0x18, 0x0e, 0x4e, 0xf6, 0x1c, 0x7f}}}, -{{{0xb4, 0x04, 0x2e, 0x42, 0xcb, 0x1f, 0x2b, 0x11, 0x51, 0x7b, 0x08, 0xac, 0xaa, 0x3e, 0x9e, 0x52, 0x60, 0xb7, 0xc2, 0x61, 0x57, 0x8c, 0x84, 0xd5, 0x18, 0xa6, 0x19, 0xfc, 0xb7, 0x75, 0x91, 0x1b}} , - {{0xe8, 0x68, 0xca, 0x44, 0xc8, 0x38, 0x38, 0xcc, 0x53, 0x0a, 0x32, 0x35, 0xcc, 0x52, 0xcb, 0x0e, 0xf7, 0xc5, 0xe7, 0xec, 0x3d, 0x85, 0xcc, 0x58, 0xe2, 0x17, 0x47, 0xff, 0x9f, 0xa5, 0x30, 0x17}}}, -{{{0xe3, 0xae, 0xc8, 0xc1, 0x71, 0x75, 0x31, 0x00, 0x37, 0x41, 0x5c, 0x0e, 0x39, 0xda, 0x73, 0xa0, 0xc7, 0x97, 0x36, 0x6c, 0x5b, 0xf2, 0xee, 0x64, 0x0a, 0x3d, 0x89, 0x1e, 0x1d, 0x49, 0x8c, 0x37}} , - {{0x4c, 0xe6, 0xb0, 0xc1, 0xa5, 0x2a, 0x82, 0x09, 0x08, 0xad, 0x79, 0x9c, 0x56, 0xf6, 0xf9, 0xc1, 0xd7, 0x7c, 0x39, 0x7f, 0x93, 0xca, 0x11, 0x55, 0xbf, 0x07, 0x1b, 0x82, 0x29, 0x69, 0x95, 0x5c}}}, -{{{0x87, 0xee, 0xa6, 0x56, 0x9e, 0xc2, 0x9a, 0x56, 0x24, 0x42, 0x85, 0x4d, 0x98, 0x31, 0x1e, 0x60, 0x4d, 0x87, 0x85, 0x04, 0xae, 0x46, 0x12, 0xf9, 0x8e, 0x7f, 0xe4, 0x7f, 0xf6, 0x1c, 0x37, 0x01}} , - {{0x73, 0x4c, 0xb6, 0xc5, 0xc4, 0xe9, 0x6c, 0x85, 0x48, 0x4a, 0x5a, 0xac, 0xd9, 0x1f, 0x43, 0xf8, 0x62, 0x5b, 0xee, 0x98, 0x2a, 0x33, 0x8e, 0x79, 0xce, 0x61, 0x06, 0x35, 0xd8, 0xd7, 0xca, 0x71}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x72, 0xd3, 0xae, 0xa6, 0xca, 0x8f, 0xcd, 0xcc, 0x78, 0x8e, 0x19, 0x4d, 0xa7, 0xd2, 0x27, 0xe9, 0xa4, 0x3c, 0x16, 0x5b, 0x84, 0x80, 0xf9, 0xd0, 0xcc, 0x6a, 0x1e, 0xca, 0x1e, 0x67, 0xbd, 0x63}} , - {{0x7b, 0x6e, 0x2a, 0xd2, 0x87, 0x48, 0xff, 0xa1, 0xca, 0xe9, 0x15, 0x85, 0xdc, 0xdb, 0x2c, 0x39, 0x12, 0x91, 0xa9, 0x20, 0xaa, 0x4f, 0x29, 0xf4, 0x15, 0x7a, 0xd2, 0xf5, 0x32, 0xcc, 0x60, 0x04}}}, -{{{0xe5, 0x10, 0x47, 0x3b, 0xfa, 0x90, 0xfc, 0x30, 0xb5, 0xea, 0x6f, 0x56, 0x8f, 0xfb, 0x0e, 0xa7, 0x3b, 0xc8, 0xb2, 0xff, 0x02, 0x7a, 0x33, 0x94, 0x93, 0x2a, 0x03, 0xe0, 0x96, 0x3a, 0x6c, 0x0f}} , - {{0x5a, 0x63, 0x67, 0xe1, 0x9b, 0x47, 0x78, 0x9f, 0x38, 0x79, 0xac, 0x97, 0x66, 0x1d, 0x5e, 0x51, 0xee, 0x24, 0x42, 0xe8, 0x58, 0x4b, 0x8a, 0x03, 0x75, 0x86, 0x37, 0x86, 0xe2, 0x97, 0x4e, 0x3d}}}, -{{{0x3f, 0x75, 0x8e, 0xb4, 0xff, 0xd8, 0xdd, 0xd6, 0x37, 0x57, 0x9d, 0x6d, 0x3b, 0xbd, 0xd5, 0x60, 0x88, 0x65, 0x9a, 0xb9, 0x4a, 0x68, 0x84, 0xa2, 0x67, 0xdd, 0x17, 0x25, 0x97, 0x04, 0x8b, 0x5e}} , - {{0xbb, 0x40, 0x5e, 0xbc, 0x16, 0x92, 0x05, 0xc4, 0xc0, 0x4e, 0x72, 0x90, 0x0e, 0xab, 0xcf, 0x8a, 0xed, 0xef, 0xb9, 0x2d, 0x3b, 0xf8, 0x43, 0x5b, 0xba, 0x2d, 0xeb, 0x2f, 0x52, 0xd2, 0xd1, 0x5a}}}, -{{{0x40, 0xb4, 0xab, 0xe6, 0xad, 0x9f, 0x46, 0x69, 0x4a, 0xb3, 0x8e, 0xaa, 0xea, 0x9c, 0x8a, 0x20, 0x16, 0x5d, 0x8c, 0x13, 0xbd, 0xf6, 0x1d, 0xc5, 0x24, 0xbd, 0x90, 0x2a, 0x1c, 0xc7, 0x13, 0x3b}} , - {{0x54, 0xdc, 0x16, 0x0d, 0x18, 0xbe, 0x35, 0x64, 0x61, 0x52, 0x02, 0x80, 0xaf, 0x05, 0xf7, 0xa6, 0x42, 0xd3, 0x8f, 0x2e, 0x79, 0x26, 0xa8, 0xbb, 0xb2, 0x17, 0x48, 0xb2, 0x7a, 0x0a, 0x89, 0x14}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x20, 0xa8, 0x88, 0xe3, 0x91, 0xc0, 0x6e, 0xbb, 0x8a, 0x27, 0x82, 0x51, 0x83, 0xb2, 0x28, 0xa9, 0x83, 0xeb, 0xa6, 0xa9, 0x4d, 0x17, 0x59, 0x22, 0x54, 0x00, 0x50, 0x45, 0xcb, 0x48, 0x4b, 0x18}} , - {{0x33, 0x7c, 0xe7, 0x26, 0xba, 0x4d, 0x32, 0xfe, 0x53, 0xf4, 0xfa, 0x83, 0xe3, 0xa5, 0x79, 0x66, 0x73, 0xef, 0x80, 0x23, 0x68, 0xc2, 0x60, 0xdd, 0xa9, 0x33, 0xdc, 0x03, 0x7a, 0xe0, 0xe0, 0x3e}}}, -{{{0x34, 0x5c, 0x13, 0xfb, 0xc0, 0xe3, 0x78, 0x2b, 0x54, 0x58, 0x22, 0x9b, 0x76, 0x81, 0x7f, 0x93, 0x9c, 0x25, 0x3c, 0xd2, 0xe9, 0x96, 0x21, 0x26, 0x08, 0xf5, 0xed, 0x95, 0x11, 0xae, 0x04, 0x5a}} , - {{0xb9, 0xe8, 0xc5, 0x12, 0x97, 0x1f, 0x83, 0xfe, 0x3e, 0x94, 0x99, 0xd4, 0x2d, 0xf9, 0x52, 0x59, 0x5c, 0x82, 0xa6, 0xf0, 0x75, 0x7e, 0xe8, 0xec, 0xcc, 0xac, 0x18, 0x21, 0x09, 0x67, 0x66, 0x67}}}, -{{{0xb3, 0x40, 0x29, 0xd1, 0xcb, 0x1b, 0x08, 0x9e, 0x9c, 0xb7, 0x53, 0xb9, 0x3b, 0x71, 0x08, 0x95, 0x12, 0x1a, 0x58, 0xaf, 0x7e, 0x82, 0x52, 0x43, 0x4f, 0x11, 0x39, 0xf4, 0x93, 0x1a, 0x26, 0x05}} , - {{0x6e, 0x44, 0xa3, 0xf9, 0x64, 0xaf, 0xe7, 0x6d, 0x7d, 0xdf, 0x1e, 0xac, 0x04, 0xea, 0x3b, 0x5f, 0x9b, 0xe8, 0x24, 0x9d, 0x0e, 0xe5, 0x2e, 0x3e, 0xdf, 0xa9, 0xf7, 0xd4, 0x50, 0x71, 0xf0, 0x78}}}, -{{{0x3e, 0xa8, 0x38, 0xc2, 0x57, 0x56, 0x42, 0x9a, 0xb1, 0xe2, 0xf8, 0x45, 0xaa, 0x11, 0x48, 0x5f, 0x17, 0xc4, 0x54, 0x27, 0xdc, 0x5d, 0xaa, 0xdd, 0x41, 0xbc, 0xdf, 0x81, 0xb9, 0x53, 0xee, 0x52}} , - {{0xc3, 0xf1, 0xa7, 0x6d, 0xb3, 0x5f, 0x92, 0x6f, 0xcc, 0x91, 0xb8, 0x95, 0x05, 0xdf, 0x3c, 0x64, 0x57, 0x39, 0x61, 0x51, 0xad, 0x8c, 0x38, 0x7b, 0xc8, 0xde, 0x00, 0x34, 0xbe, 0xa1, 0xb0, 0x7e}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x25, 0x24, 0x1d, 0x8a, 0x67, 0x20, 0xee, 0x42, 0xeb, 0x38, 0xed, 0x0b, 0x8b, 0xcd, 0x46, 0x9d, 0x5e, 0x6b, 0x1e, 0x24, 0x9d, 0x12, 0x05, 0x1a, 0xcc, 0x05, 0x4e, 0x92, 0x38, 0xe1, 0x1f, 0x50}} , - {{0x4e, 0xee, 0x1c, 0x91, 0xe6, 0x11, 0xbd, 0x8e, 0x55, 0x1a, 0x18, 0x75, 0x66, 0xaf, 0x4d, 0x7b, 0x0f, 0xae, 0x6d, 0x85, 0xca, 0x82, 0x58, 0x21, 0x9c, 0x18, 0xe0, 0xed, 0xec, 0x22, 0x80, 0x2f}}}, -{{{0x68, 0x3b, 0x0a, 0x39, 0x1d, 0x6a, 0x15, 0x57, 0xfc, 0xf0, 0x63, 0x54, 0xdb, 0x39, 0xdb, 0xe8, 0x5c, 0x64, 0xff, 0xa0, 0x09, 0x4f, 0x3b, 0xb7, 0x32, 0x60, 0x99, 0x94, 0xfd, 0x94, 0x82, 0x2d}} , - {{0x24, 0xf6, 0x5a, 0x44, 0xf1, 0x55, 0x2c, 0xdb, 0xea, 0x7c, 0x84, 0x7c, 0x01, 0xac, 0xe3, 0xfd, 0xc9, 0x27, 0xc1, 0x5a, 0xb9, 0xde, 0x4f, 0x5a, 0x90, 0xdd, 0xc6, 0x67, 0xaa, 0x6f, 0x8a, 0x3a}}}, -{{{0x78, 0x52, 0x87, 0xc9, 0x97, 0x63, 0xb1, 0xdd, 0x54, 0x5f, 0xc1, 0xf8, 0xf1, 0x06, 0xa6, 0xa8, 0xa3, 0x88, 0x82, 0xd4, 0xcb, 0xa6, 0x19, 0xdd, 0xd1, 0x11, 0x87, 0x08, 0x17, 0x4c, 0x37, 0x2a}} , - {{0xa1, 0x0c, 0xf3, 0x08, 0x43, 0xd9, 0x24, 0x1e, 0x83, 0xa7, 0xdf, 0x91, 0xca, 0xbd, 0x69, 0x47, 0x8d, 0x1b, 0xe2, 0xb9, 0x4e, 0xb5, 0xe1, 0x76, 0xb3, 0x1c, 0x93, 0x03, 0xce, 0x5f, 0xb3, 0x5a}}}, -{{{0x1d, 0xda, 0xe4, 0x61, 0x03, 0x50, 0xa9, 0x8b, 0x68, 0x18, 0xef, 0xb2, 0x1c, 0x84, 0x3b, 0xa2, 0x44, 0x95, 0xa3, 0x04, 0x3b, 0xd6, 0x99, 0x00, 0xaf, 0x76, 0x42, 0x67, 0x02, 0x7d, 0x85, 0x56}} , - {{0xce, 0x72, 0x0e, 0x29, 0x84, 0xb2, 0x7d, 0xd2, 0x45, 0xbe, 0x57, 0x06, 0xed, 0x7f, 0xcf, 0xed, 0xcd, 0xef, 0x19, 0xd6, 0xbc, 0x15, 0x79, 0x64, 0xd2, 0x18, 0xe3, 0x20, 0x67, 0x3a, 0x54, 0x0b}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x52, 0xfd, 0x04, 0xc5, 0xfb, 0x99, 0xe7, 0xe8, 0xfb, 0x8c, 0xe1, 0x42, 0x03, 0xef, 0x9d, 0xd9, 0x9e, 0x4d, 0xf7, 0x80, 0xcf, 0x2e, 0xcc, 0x9b, 0x45, 0xc9, 0x7b, 0x7a, 0xbc, 0x37, 0xa8, 0x52}} , - {{0x96, 0x11, 0x41, 0x8a, 0x47, 0x91, 0xfe, 0xb6, 0xda, 0x7a, 0x54, 0x63, 0xd1, 0x14, 0x35, 0x05, 0x86, 0x8c, 0xa9, 0x36, 0x3f, 0xf2, 0x85, 0x54, 0x4e, 0x92, 0xd8, 0x85, 0x01, 0x46, 0xd6, 0x50}}}, -{{{0x53, 0xcd, 0xf3, 0x86, 0x40, 0xe6, 0x39, 0x42, 0x95, 0xd6, 0xcb, 0x45, 0x1a, 0x20, 0xc8, 0x45, 0x4b, 0x32, 0x69, 0x04, 0xb1, 0xaf, 0x20, 0x46, 0xc7, 0x6b, 0x23, 0x5b, 0x69, 0xee, 0x30, 0x3f}} , - {{0x70, 0x83, 0x47, 0xc0, 0xdb, 0x55, 0x08, 0xa8, 0x7b, 0x18, 0x6d, 0xf5, 0x04, 0x5a, 0x20, 0x0c, 0x4a, 0x8c, 0x60, 0xae, 0xae, 0x0f, 0x64, 0x55, 0x55, 0x2e, 0xd5, 0x1d, 0x53, 0x31, 0x42, 0x41}}}, -{{{0xca, 0xfc, 0x88, 0x6b, 0x96, 0x78, 0x0a, 0x8b, 0x83, 0xdc, 0xbc, 0xaf, 0x40, 0xb6, 0x8d, 0x7f, 0xef, 0xb4, 0xd1, 0x3f, 0xcc, 0xa2, 0x74, 0xc9, 0xc2, 0x92, 0x55, 0x00, 0xab, 0xdb, 0xbf, 0x4f}} , - {{0x93, 0x1c, 0x06, 0x2d, 0x66, 0x65, 0x02, 0xa4, 0x97, 0x18, 0xfd, 0x00, 0xe7, 0xab, 0x03, 0xec, 0xce, 0xc1, 0xbf, 0x37, 0xf8, 0x13, 0x53, 0xa5, 0xe5, 0x0c, 0x3a, 0xa8, 0x55, 0xb9, 0xff, 0x68}}}, -{{{0xe4, 0xe6, 0x6d, 0x30, 0x7d, 0x30, 0x35, 0xc2, 0x78, 0x87, 0xf9, 0xfc, 0x6b, 0x5a, 0xc3, 0xb7, 0x65, 0xd8, 0x2e, 0xc7, 0xa5, 0x0c, 0xc6, 0xdc, 0x12, 0xaa, 0xd6, 0x4f, 0xc5, 0x38, 0xbc, 0x0e}} , - {{0xe2, 0x3c, 0x76, 0x86, 0x38, 0xf2, 0x7b, 0x2c, 0x16, 0x78, 0x8d, 0xf5, 0xa4, 0x15, 0xda, 0xdb, 0x26, 0x85, 0xa0, 0x56, 0xdd, 0x1d, 0xe3, 0xb3, 0xfd, 0x40, 0xef, 0xf2, 0xd9, 0xa1, 0xb3, 0x04}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xdb, 0x49, 0x0e, 0xe6, 0x58, 0x10, 0x7a, 0x52, 0xda, 0xb5, 0x7d, 0x37, 0x6a, 0x3e, 0xa1, 0x78, 0xce, 0xc7, 0x1c, 0x24, 0x23, 0xdb, 0x7d, 0xfb, 0x8c, 0x8d, 0xdc, 0x30, 0x67, 0x69, 0x75, 0x3b}} , - {{0xa9, 0xea, 0x6d, 0x16, 0x16, 0x60, 0xf4, 0x60, 0x87, 0x19, 0x44, 0x8c, 0x4a, 0x8b, 0x3e, 0xfb, 0x16, 0x00, 0x00, 0x54, 0xa6, 0x9e, 0x9f, 0xef, 0xcf, 0xd9, 0xd2, 0x4c, 0x74, 0x31, 0xd0, 0x34}}}, -{{{0xa4, 0xeb, 0x04, 0xa4, 0x8c, 0x8f, 0x71, 0x27, 0x95, 0x85, 0x5d, 0x55, 0x4b, 0xb1, 0x26, 0x26, 0xc8, 0xae, 0x6a, 0x7d, 0xa2, 0x21, 0xca, 0xce, 0x38, 0xab, 0x0f, 0xd0, 0xd5, 0x2b, 0x6b, 0x00}} , - {{0xe5, 0x67, 0x0c, 0xf1, 0x3a, 0x9a, 0xea, 0x09, 0x39, 0xef, 0xd1, 0x30, 0xbc, 0x33, 0xba, 0xb1, 0x6a, 0xc5, 0x27, 0x08, 0x7f, 0x54, 0x80, 0x3d, 0xab, 0xf6, 0x15, 0x7a, 0xc2, 0x40, 0x73, 0x72}}}, -{{{0x84, 0x56, 0x82, 0xb6, 0x12, 0x70, 0x7f, 0xf7, 0xf0, 0xbd, 0x5b, 0xa9, 0xd5, 0xc5, 0x5f, 0x59, 0xbf, 0x7f, 0xb3, 0x55, 0x22, 0x02, 0xc9, 0x44, 0x55, 0x87, 0x8f, 0x96, 0x98, 0x64, 0x6d, 0x15}} , - {{0xb0, 0x8b, 0xaa, 0x1e, 0xec, 0xc7, 0xa5, 0x8f, 0x1f, 0x92, 0x04, 0xc6, 0x05, 0xf6, 0xdf, 0xa1, 0xcc, 0x1f, 0x81, 0xf5, 0x0e, 0x9c, 0x57, 0xdc, 0xe3, 0xbb, 0x06, 0x87, 0x1e, 0xfe, 0x23, 0x6c}}}, -{{{0xd8, 0x2b, 0x5b, 0x16, 0xea, 0x20, 0xf1, 0xd3, 0x68, 0x8f, 0xae, 0x5b, 0xd0, 0xa9, 0x1a, 0x19, 0xa8, 0x36, 0xfb, 0x2b, 0x57, 0x88, 0x7d, 0x90, 0xd5, 0xa6, 0xf3, 0xdc, 0x38, 0x89, 0x4e, 0x1f}} , - {{0xcc, 0x19, 0xda, 0x9b, 0x3b, 0x43, 0x48, 0x21, 0x2e, 0x23, 0x4d, 0x3d, 0xae, 0xf8, 0x8c, 0xfc, 0xdd, 0xa6, 0x74, 0x37, 0x65, 0xca, 0xee, 0x1a, 0x19, 0x8e, 0x9f, 0x64, 0x6f, 0x0c, 0x8b, 0x5a}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x25, 0xb9, 0xc2, 0xf0, 0x72, 0xb8, 0x15, 0x16, 0xcc, 0x8d, 0x3c, 0x6f, 0x25, 0xed, 0xf4, 0x46, 0x2e, 0x0c, 0x60, 0x0f, 0xe2, 0x84, 0x34, 0x55, 0x89, 0x59, 0x34, 0x1b, 0xf5, 0x8d, 0xfe, 0x08}} , - {{0xf8, 0xab, 0x93, 0xbc, 0x44, 0xba, 0x1b, 0x75, 0x4b, 0x49, 0x6f, 0xd0, 0x54, 0x2e, 0x63, 0xba, 0xb5, 0xea, 0xed, 0x32, 0x14, 0xc9, 0x94, 0xd8, 0xc5, 0xce, 0xf4, 0x10, 0x68, 0xe0, 0x38, 0x27}}}, -{{{0x74, 0x1c, 0x14, 0x9b, 0xd4, 0x64, 0x61, 0x71, 0x5a, 0xb6, 0x21, 0x33, 0x4f, 0xf7, 0x8e, 0xba, 0xa5, 0x48, 0x9a, 0xc7, 0xfa, 0x9a, 0xf0, 0xb4, 0x62, 0xad, 0xf2, 0x5e, 0xcc, 0x03, 0x24, 0x1a}} , - {{0xf5, 0x76, 0xfd, 0xe4, 0xaf, 0xb9, 0x03, 0x59, 0xce, 0x63, 0xd2, 0x3b, 0x1f, 0xcd, 0x21, 0x0c, 0xad, 0x44, 0xa5, 0x97, 0xac, 0x80, 0x11, 0x02, 0x9b, 0x0c, 0xe5, 0x8b, 0xcd, 0xfb, 0x79, 0x77}}}, -{{{0x15, 0xbe, 0x9a, 0x0d, 0xba, 0x38, 0x72, 0x20, 0x8a, 0xf5, 0xbe, 0x59, 0x93, 0x79, 0xb7, 0xf6, 0x6a, 0x0c, 0x38, 0x27, 0x1a, 0x60, 0xf4, 0x86, 0x3b, 0xab, 0x5a, 0x00, 0xa0, 0xce, 0x21, 0x7d}} , - {{0x6c, 0xba, 0x14, 0xc5, 0xea, 0x12, 0x9e, 0x2e, 0x82, 0x63, 0xce, 0x9b, 0x4a, 0xe7, 0x1d, 0xec, 0xf1, 0x2e, 0x51, 0x1c, 0xf4, 0xd0, 0x69, 0x15, 0x42, 0x9d, 0xa3, 0x3f, 0x0e, 0xbf, 0xe9, 0x5c}}}, -{{{0xe4, 0x0d, 0xf4, 0xbd, 0xee, 0x31, 0x10, 0xed, 0xcb, 0x12, 0x86, 0xad, 0xd4, 0x2f, 0x90, 0x37, 0x32, 0xc3, 0x0b, 0x73, 0xec, 0x97, 0x85, 0xa4, 0x01, 0x1c, 0x76, 0x35, 0xfe, 0x75, 0xdd, 0x71}} , - {{0x11, 0xa4, 0x88, 0x9f, 0x3e, 0x53, 0x69, 0x3b, 0x1b, 0xe0, 0xf7, 0xba, 0x9b, 0xad, 0x4e, 0x81, 0x5f, 0xb5, 0x5c, 0xae, 0xbe, 0x67, 0x86, 0x37, 0x34, 0x8e, 0x07, 0x32, 0x45, 0x4a, 0x67, 0x39}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x90, 0x70, 0x58, 0x20, 0x03, 0x1e, 0x67, 0xb2, 0xc8, 0x9b, 0x58, 0xc5, 0xb1, 0xeb, 0x2d, 0x4a, 0xde, 0x82, 0x8c, 0xf2, 0xd2, 0x14, 0xb8, 0x70, 0x61, 0x4e, 0x73, 0xd6, 0x0b, 0x6b, 0x0d, 0x30}} , - {{0x81, 0xfc, 0x55, 0x5c, 0xbf, 0xa7, 0xc4, 0xbd, 0xe2, 0xf0, 0x4b, 0x8f, 0xe9, 0x7d, 0x99, 0xfa, 0xd3, 0xab, 0xbc, 0xc7, 0x83, 0x2b, 0x04, 0x7f, 0x0c, 0x19, 0x43, 0x03, 0x3d, 0x07, 0xca, 0x40}}}, -{{{0xf9, 0xc8, 0xbe, 0x8c, 0x16, 0x81, 0x39, 0x96, 0xf6, 0x17, 0x58, 0xc8, 0x30, 0x58, 0xfb, 0xc2, 0x03, 0x45, 0xd2, 0x52, 0x76, 0xe0, 0x6a, 0x26, 0x28, 0x5c, 0x88, 0x59, 0x6a, 0x5a, 0x54, 0x42}} , - {{0x07, 0xb5, 0x2e, 0x2c, 0x67, 0x15, 0x9b, 0xfb, 0x83, 0x69, 0x1e, 0x0f, 0xda, 0xd6, 0x29, 0xb1, 0x60, 0xe0, 0xb2, 0xba, 0x69, 0xa2, 0x9e, 0xbd, 0xbd, 0xe0, 0x1c, 0xbd, 0xcd, 0x06, 0x64, 0x70}}}, -{{{0x41, 0xfa, 0x8c, 0xe1, 0x89, 0x8f, 0x27, 0xc8, 0x25, 0x8f, 0x6f, 0x5f, 0x55, 0xf8, 0xde, 0x95, 0x6d, 0x2f, 0x75, 0x16, 0x2b, 0x4e, 0x44, 0xfd, 0x86, 0x6e, 0xe9, 0x70, 0x39, 0x76, 0x97, 0x7e}} , - {{0x17, 0x62, 0x6b, 0x14, 0xa1, 0x7c, 0xd0, 0x79, 0x6e, 0xd8, 0x8a, 0xa5, 0x6d, 0x8c, 0x93, 0xd2, 0x3f, 0xec, 0x44, 0x8d, 0x6e, 0x91, 0x01, 0x8c, 0x8f, 0xee, 0x01, 0x8f, 0xc0, 0xb4, 0x85, 0x0e}}}, -{{{0x02, 0x3a, 0x70, 0x41, 0xe4, 0x11, 0x57, 0x23, 0xac, 0xe6, 0xfc, 0x54, 0x7e, 0xcd, 0xd7, 0x22, 0xcb, 0x76, 0x9f, 0x20, 0xce, 0xa0, 0x73, 0x76, 0x51, 0x3b, 0xa4, 0xf8, 0xe3, 0x62, 0x12, 0x6c}} , - {{0x7f, 0x00, 0x9c, 0x26, 0x0d, 0x6f, 0x48, 0x7f, 0x3a, 0x01, 0xed, 0xc5, 0x96, 0xb0, 0x1f, 0x4f, 0xa8, 0x02, 0x62, 0x27, 0x8a, 0x50, 0x8d, 0x9a, 0x8b, 0x52, 0x0f, 0x1e, 0xcf, 0x41, 0x38, 0x19}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xf5, 0x6c, 0xd4, 0x2f, 0x0f, 0x69, 0x0f, 0x87, 0x3f, 0x61, 0x65, 0x1e, 0x35, 0x34, 0x85, 0xba, 0x02, 0x30, 0xac, 0x25, 0x3d, 0xe2, 0x62, 0xf1, 0xcc, 0xe9, 0x1b, 0xc2, 0xef, 0x6a, 0x42, 0x57}} , - {{0x34, 0x1f, 0x2e, 0xac, 0xd1, 0xc7, 0x04, 0x52, 0x32, 0x66, 0xb2, 0x33, 0x73, 0x21, 0x34, 0x54, 0xf7, 0x71, 0xed, 0x06, 0xb0, 0xff, 0xa6, 0x59, 0x6f, 0x8a, 0x4e, 0xfb, 0x02, 0xb0, 0x45, 0x6b}}}, -{{{0xf5, 0x48, 0x0b, 0x03, 0xc5, 0x22, 0x7d, 0x80, 0x08, 0x53, 0xfe, 0x32, 0xb1, 0xa1, 0x8a, 0x74, 0x6f, 0xbd, 0x3f, 0x85, 0xf4, 0xcf, 0xf5, 0x60, 0xaf, 0x41, 0x7e, 0x3e, 0x46, 0xa3, 0x5a, 0x20}} , - {{0xaa, 0x35, 0x87, 0x44, 0x63, 0x66, 0x97, 0xf8, 0x6e, 0x55, 0x0c, 0x04, 0x3e, 0x35, 0x50, 0xbf, 0x93, 0x69, 0xd2, 0x8b, 0x05, 0x55, 0x99, 0xbe, 0xe2, 0x53, 0x61, 0xec, 0xe8, 0x08, 0x0b, 0x32}}}, -{{{0xb3, 0x10, 0x45, 0x02, 0x69, 0x59, 0x2e, 0x97, 0xd9, 0x64, 0xf8, 0xdb, 0x25, 0x80, 0xdc, 0xc4, 0xd5, 0x62, 0x3c, 0xed, 0x65, 0x91, 0xad, 0xd1, 0x57, 0x81, 0x94, 0xaa, 0xa1, 0x29, 0xfc, 0x68}} , - {{0xdd, 0xb5, 0x7d, 0xab, 0x5a, 0x21, 0x41, 0x53, 0xbb, 0x17, 0x79, 0x0d, 0xd1, 0xa8, 0x0c, 0x0c, 0x20, 0x88, 0x09, 0xe9, 0x84, 0xe8, 0x25, 0x11, 0x67, 0x7a, 0x8b, 0x1a, 0xe4, 0x5d, 0xe1, 0x5d}}}, -{{{0x37, 0xea, 0xfe, 0x65, 0x3b, 0x25, 0xe8, 0xe1, 0xc2, 0xc5, 0x02, 0xa4, 0xbe, 0x98, 0x0a, 0x2b, 0x61, 0xc1, 0x9b, 0xe2, 0xd5, 0x92, 0xe6, 0x9e, 0x7d, 0x1f, 0xca, 0x43, 0x88, 0x8b, 0x2c, 0x59}} , - {{0xe0, 0xb5, 0x00, 0x1d, 0x2a, 0x6f, 0xaf, 0x79, 0x86, 0x2f, 0xa6, 0x5a, 0x93, 0xd1, 0xfe, 0xae, 0x3a, 0xee, 0xdb, 0x7c, 0x61, 0xbe, 0x7c, 0x01, 0xf9, 0xfe, 0x52, 0xdc, 0xd8, 0x52, 0xa3, 0x42}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x22, 0xaf, 0x13, 0x37, 0xbd, 0x37, 0x71, 0xac, 0x04, 0x46, 0x63, 0xac, 0xa4, 0x77, 0xed, 0x25, 0x38, 0xe0, 0x15, 0xa8, 0x64, 0x00, 0x0d, 0xce, 0x51, 0x01, 0xa9, 0xbc, 0x0f, 0x03, 0x1c, 0x04}} , - {{0x89, 0xf9, 0x80, 0x07, 0xcf, 0x3f, 0xb3, 0xe9, 0xe7, 0x45, 0x44, 0x3d, 0x2a, 0x7c, 0xe9, 0xe4, 0x16, 0x5c, 0x5e, 0x65, 0x1c, 0xc7, 0x7d, 0xc6, 0x7a, 0xfb, 0x43, 0xee, 0x25, 0x76, 0x46, 0x72}}}, -{{{0x02, 0xa2, 0xed, 0xf4, 0x8f, 0x6b, 0x0b, 0x3e, 0xeb, 0x35, 0x1a, 0xd5, 0x7e, 0xdb, 0x78, 0x00, 0x96, 0x8a, 0xa0, 0xb4, 0xcf, 0x60, 0x4b, 0xd4, 0xd5, 0xf9, 0x2d, 0xbf, 0x88, 0xbd, 0x22, 0x62}} , - {{0x13, 0x53, 0xe4, 0x82, 0x57, 0xfa, 0x1e, 0x8f, 0x06, 0x2b, 0x90, 0xba, 0x08, 0xb6, 0x10, 0x54, 0x4f, 0x7c, 0x1b, 0x26, 0xed, 0xda, 0x6b, 0xdd, 0x25, 0xd0, 0x4e, 0xea, 0x42, 0xbb, 0x25, 0x03}}}, -{{{0x51, 0x16, 0x50, 0x7c, 0xd5, 0x5d, 0xf6, 0x99, 0xe8, 0x77, 0x72, 0x4e, 0xfa, 0x62, 0xcb, 0x76, 0x75, 0x0c, 0xe2, 0x71, 0x98, 0x92, 0xd5, 0xfa, 0x45, 0xdf, 0x5c, 0x6f, 0x1e, 0x9e, 0x28, 0x69}} , - {{0x0d, 0xac, 0x66, 0x6d, 0xc3, 0x8b, 0xba, 0x16, 0xb5, 0xe2, 0xa0, 0x0d, 0x0c, 0xbd, 0xa4, 0x8e, 0x18, 0x6c, 0xf2, 0xdc, 0xf9, 0xdc, 0x4a, 0x86, 0x25, 0x95, 0x14, 0xcb, 0xd8, 0x1a, 0x04, 0x0f}}}, -{{{0x97, 0xa5, 0xdb, 0x8b, 0x2d, 0xaa, 0x42, 0x11, 0x09, 0xf2, 0x93, 0xbb, 0xd9, 0x06, 0x84, 0x4e, 0x11, 0xa8, 0xa0, 0x25, 0x2b, 0xa6, 0x5f, 0xae, 0xc4, 0xb4, 0x4c, 0xc8, 0xab, 0xc7, 0x3b, 0x02}} , - {{0xee, 0xc9, 0x29, 0x0f, 0xdf, 0x11, 0x85, 0xed, 0xce, 0x0d, 0x62, 0x2c, 0x8f, 0x4b, 0xf9, 0x04, 0xe9, 0x06, 0x72, 0x1d, 0x37, 0x20, 0x50, 0xc9, 0x14, 0xeb, 0xec, 0x39, 0xa7, 0x97, 0x2b, 0x4d}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x69, 0xd1, 0x39, 0xbd, 0xfb, 0x33, 0xbe, 0xc4, 0xf0, 0x5c, 0xef, 0xf0, 0x56, 0x68, 0xfc, 0x97, 0x47, 0xc8, 0x72, 0xb6, 0x53, 0xa4, 0x0a, 0x98, 0xa5, 0xb4, 0x37, 0x71, 0xcf, 0x66, 0x50, 0x6d}} , - {{0x17, 0xa4, 0x19, 0x52, 0x11, 0x47, 0xb3, 0x5c, 0x5b, 0xa9, 0x2e, 0x22, 0xb4, 0x00, 0x52, 0xf9, 0x57, 0x18, 0xb8, 0xbe, 0x5a, 0xe3, 0xab, 0x83, 0xc8, 0x87, 0x0a, 0x2a, 0xd8, 0x8c, 0xbb, 0x54}}}, -{{{0xa9, 0x62, 0x93, 0x85, 0xbe, 0xe8, 0x73, 0x4a, 0x0e, 0xb0, 0xb5, 0x2d, 0x94, 0x50, 0xaa, 0xd3, 0xb2, 0xea, 0x9d, 0x62, 0x76, 0x3b, 0x07, 0x34, 0x4e, 0x2d, 0x70, 0xc8, 0x9a, 0x15, 0x66, 0x6b}} , - {{0xc5, 0x96, 0xca, 0xc8, 0x22, 0x1a, 0xee, 0x5f, 0xe7, 0x31, 0x60, 0x22, 0x83, 0x08, 0x63, 0xce, 0xb9, 0x32, 0x44, 0x58, 0x5d, 0x3a, 0x9b, 0xe4, 0x04, 0xd5, 0xef, 0x38, 0xef, 0x4b, 0xdd, 0x19}}}, -{{{0x4d, 0xc2, 0x17, 0x75, 0xa1, 0x68, 0xcd, 0xc3, 0xc6, 0x03, 0x44, 0xe3, 0x78, 0x09, 0x91, 0x47, 0x3f, 0x0f, 0xe4, 0x92, 0x58, 0xfa, 0x7d, 0x1f, 0x20, 0x94, 0x58, 0x5e, 0xbc, 0x19, 0x02, 0x6f}} , - {{0x20, 0xd6, 0xd8, 0x91, 0x54, 0xa7, 0xf3, 0x20, 0x4b, 0x34, 0x06, 0xfa, 0x30, 0xc8, 0x6f, 0x14, 0x10, 0x65, 0x74, 0x13, 0x4e, 0xf0, 0x69, 0x26, 0xce, 0xcf, 0x90, 0xf4, 0xd0, 0xc5, 0xc8, 0x64}}}, -{{{0x26, 0xa2, 0x50, 0x02, 0x24, 0x72, 0xf1, 0xf0, 0x4e, 0x2d, 0x93, 0xd5, 0x08, 0xe7, 0xae, 0x38, 0xf7, 0x18, 0xa5, 0x32, 0x34, 0xc2, 0xf0, 0xa6, 0xec, 0xb9, 0x61, 0x7b, 0x64, 0x99, 0xac, 0x71}} , - {{0x25, 0xcf, 0x74, 0x55, 0x1b, 0xaa, 0xa9, 0x38, 0x41, 0x40, 0xd5, 0x95, 0x95, 0xab, 0x1c, 0x5e, 0xbc, 0x41, 0x7e, 0x14, 0x30, 0xbe, 0x13, 0x89, 0xf4, 0xe5, 0xeb, 0x28, 0xc0, 0xc2, 0x96, 0x3a}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x2b, 0x77, 0x45, 0xec, 0x67, 0x76, 0x32, 0x4c, 0xb9, 0xdf, 0x25, 0x32, 0x6b, 0xcb, 0xe7, 0x14, 0x61, 0x43, 0xee, 0xba, 0x9b, 0x71, 0xef, 0xd2, 0x48, 0x65, 0xbb, 0x1b, 0x8a, 0x13, 0x1b, 0x22}} , - {{0x84, 0xad, 0x0c, 0x18, 0x38, 0x5a, 0xba, 0xd0, 0x98, 0x59, 0xbf, 0x37, 0xb0, 0x4f, 0x97, 0x60, 0x20, 0xb3, 0x9b, 0x97, 0xf6, 0x08, 0x6c, 0xa4, 0xff, 0xfb, 0xb7, 0xfa, 0x95, 0xb2, 0x51, 0x79}}}, -{{{0x28, 0x5c, 0x3f, 0xdb, 0x6b, 0x18, 0x3b, 0x5c, 0xd1, 0x04, 0x28, 0xde, 0x85, 0x52, 0x31, 0xb5, 0xbb, 0xf6, 0xa9, 0xed, 0xbe, 0x28, 0x4f, 0xb3, 0x7e, 0x05, 0x6a, 0xdb, 0x95, 0x0d, 0x1b, 0x1c}} , - {{0xd5, 0xc5, 0xc3, 0x9a, 0x0a, 0xd0, 0x31, 0x3e, 0x07, 0x36, 0x8e, 0xc0, 0x8a, 0x62, 0xb1, 0xca, 0xd6, 0x0e, 0x1e, 0x9d, 0xef, 0xab, 0x98, 0x4d, 0xbb, 0x6c, 0x05, 0xe0, 0xe4, 0x5d, 0xbd, 0x57}}}, -{{{0xcc, 0x21, 0x27, 0xce, 0xfd, 0xa9, 0x94, 0x8e, 0xe1, 0xab, 0x49, 0xe0, 0x46, 0x26, 0xa1, 0xa8, 0x8c, 0xa1, 0x99, 0x1d, 0xb4, 0x27, 0x6d, 0x2d, 0xc8, 0x39, 0x30, 0x5e, 0x37, 0x52, 0xc4, 0x6e}} , - {{0xa9, 0x85, 0xf4, 0xe7, 0xb0, 0x15, 0x33, 0x84, 0x1b, 0x14, 0x1a, 0x02, 0xd9, 0x3b, 0xad, 0x0f, 0x43, 0x6c, 0xea, 0x3e, 0x0f, 0x7e, 0xda, 0xdd, 0x6b, 0x4c, 0x7f, 0x6e, 0xd4, 0x6b, 0xbf, 0x0f}}}, -{{{0x47, 0x9f, 0x7c, 0x56, 0x7c, 0x43, 0x91, 0x1c, 0xbb, 0x4e, 0x72, 0x3e, 0x64, 0xab, 0xa0, 0xa0, 0xdf, 0xb4, 0xd8, 0x87, 0x3a, 0xbd, 0xa8, 0x48, 0xc9, 0xb8, 0xef, 0x2e, 0xad, 0x6f, 0x84, 0x4f}} , - {{0x2d, 0x2d, 0xf0, 0x1b, 0x7e, 0x2a, 0x6c, 0xf8, 0xa9, 0x6a, 0xe1, 0xf0, 0x99, 0xa1, 0x67, 0x9a, 0xd4, 0x13, 0xca, 0xca, 0xba, 0x27, 0x92, 0xaa, 0xa1, 0x5d, 0x50, 0xde, 0xcc, 0x40, 0x26, 0x0a}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x9f, 0x3e, 0xf2, 0xb2, 0x90, 0xce, 0xdb, 0x64, 0x3e, 0x03, 0xdd, 0x37, 0x36, 0x54, 0x70, 0x76, 0x24, 0xb5, 0x69, 0x03, 0xfc, 0xa0, 0x2b, 0x74, 0xb2, 0x05, 0x0e, 0xcc, 0xd8, 0x1f, 0x6a, 0x1f}} , - {{0x19, 0x5e, 0x60, 0x69, 0x58, 0x86, 0xa0, 0x31, 0xbd, 0x32, 0xe9, 0x2c, 0x5c, 0xd2, 0x85, 0xba, 0x40, 0x64, 0xa8, 0x74, 0xf8, 0x0e, 0x1c, 0xb3, 0xa9, 0x69, 0xe8, 0x1e, 0x40, 0x64, 0x99, 0x77}}}, -{{{0x6c, 0x32, 0x4f, 0xfd, 0xbb, 0x5c, 0xbb, 0x8d, 0x64, 0x66, 0x4a, 0x71, 0x1f, 0x79, 0xa3, 0xad, 0x8d, 0xf9, 0xd4, 0xec, 0xcf, 0x67, 0x70, 0xfa, 0x05, 0x4a, 0x0f, 0x6e, 0xaf, 0x87, 0x0a, 0x6f}} , - {{0xc6, 0x36, 0x6e, 0x6c, 0x8c, 0x24, 0x09, 0x60, 0xbe, 0x26, 0xd2, 0x4c, 0x5e, 0x17, 0xca, 0x5f, 0x1d, 0xcc, 0x87, 0xe8, 0x42, 0x6a, 0xcb, 0xcb, 0x7d, 0x92, 0x05, 0x35, 0x81, 0x13, 0x60, 0x6b}}}, -{{{0xf4, 0x15, 0xcd, 0x0f, 0x0a, 0xaf, 0x4e, 0x6b, 0x51, 0xfd, 0x14, 0xc4, 0x2e, 0x13, 0x86, 0x74, 0x44, 0xcb, 0x66, 0x6b, 0xb6, 0x9d, 0x74, 0x56, 0x32, 0xac, 0x8d, 0x8e, 0x8c, 0x8c, 0x8c, 0x39}} , - {{0xca, 0x59, 0x74, 0x1a, 0x11, 0xef, 0x6d, 0xf7, 0x39, 0x5c, 0x3b, 0x1f, 0xfa, 0xe3, 0x40, 0x41, 0x23, 0x9e, 0xf6, 0xd1, 0x21, 0xa2, 0xbf, 0xad, 0x65, 0x42, 0x6b, 0x59, 0x8a, 0xe8, 0xc5, 0x7f}}}, -{{{0x64, 0x05, 0x7a, 0x84, 0x4a, 0x13, 0xc3, 0xf6, 0xb0, 0x6e, 0x9a, 0x6b, 0x53, 0x6b, 0x32, 0xda, 0xd9, 0x74, 0x75, 0xc4, 0xba, 0x64, 0x3d, 0x3b, 0x08, 0xdd, 0x10, 0x46, 0xef, 0xc7, 0x90, 0x1f}} , - {{0x7b, 0x2f, 0x3a, 0xce, 0xc8, 0xa1, 0x79, 0x3c, 0x30, 0x12, 0x44, 0x28, 0xf6, 0xbc, 0xff, 0xfd, 0xf4, 0xc0, 0x97, 0xb0, 0xcc, 0xc3, 0x13, 0x7a, 0xb9, 0x9a, 0x16, 0xe4, 0xcb, 0x4c, 0x34, 0x63}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x07, 0x4e, 0xd3, 0x2d, 0x09, 0x33, 0x0e, 0xd2, 0x0d, 0xbe, 0x3e, 0xe7, 0xe4, 0xaa, 0xb7, 0x00, 0x8b, 0xe8, 0xad, 0xaa, 0x7a, 0x8d, 0x34, 0x28, 0xa9, 0x81, 0x94, 0xc5, 0xe7, 0x42, 0xac, 0x47}} , - {{0x24, 0x89, 0x7a, 0x8f, 0xb5, 0x9b, 0xf0, 0xc2, 0x03, 0x64, 0xd0, 0x1e, 0xf5, 0xa4, 0xb2, 0xf3, 0x74, 0xe9, 0x1a, 0x16, 0xfd, 0xcb, 0x15, 0xea, 0xeb, 0x10, 0x6c, 0x35, 0xd1, 0xc1, 0xa6, 0x28}}}, -{{{0xcc, 0xd5, 0x39, 0xfc, 0xa5, 0xa4, 0xad, 0x32, 0x15, 0xce, 0x19, 0xe8, 0x34, 0x2b, 0x1c, 0x60, 0x91, 0xfc, 0x05, 0xa9, 0xb3, 0xdc, 0x80, 0x29, 0xc4, 0x20, 0x79, 0x06, 0x39, 0xc0, 0xe2, 0x22}} , - {{0xbb, 0xa8, 0xe1, 0x89, 0x70, 0x57, 0x18, 0x54, 0x3c, 0xf6, 0x0d, 0x82, 0x12, 0x05, 0x87, 0x96, 0x06, 0x39, 0xe3, 0xf8, 0xb3, 0x95, 0xe5, 0xd7, 0x26, 0xbf, 0x09, 0x5a, 0x94, 0xf9, 0x1c, 0x63}}}, -{{{0x2b, 0x8c, 0x2d, 0x9a, 0x8b, 0x84, 0xf2, 0x56, 0xfb, 0xad, 0x2e, 0x7f, 0xb7, 0xfc, 0x30, 0xe1, 0x35, 0x89, 0xba, 0x4d, 0xa8, 0x6d, 0xce, 0x8c, 0x8b, 0x30, 0xe0, 0xda, 0x29, 0x18, 0x11, 0x17}} , - {{0x19, 0xa6, 0x5a, 0x65, 0x93, 0xc3, 0xb5, 0x31, 0x22, 0x4f, 0xf3, 0xf6, 0x0f, 0xeb, 0x28, 0xc3, 0x7c, 0xeb, 0xce, 0x86, 0xec, 0x67, 0x76, 0x6e, 0x35, 0x45, 0x7b, 0xd8, 0x6b, 0x92, 0x01, 0x65}}}, -{{{0x3d, 0xd5, 0x9a, 0x64, 0x73, 0x36, 0xb1, 0xd6, 0x86, 0x98, 0x42, 0x3f, 0x8a, 0xf1, 0xc7, 0xf5, 0x42, 0xa8, 0x9c, 0x52, 0xa8, 0xdc, 0xf9, 0x24, 0x3f, 0x4a, 0xa1, 0xa4, 0x5b, 0xe8, 0x62, 0x1a}} , - {{0xc5, 0xbd, 0xc8, 0x14, 0xd5, 0x0d, 0xeb, 0xe1, 0xa5, 0xe6, 0x83, 0x11, 0x09, 0x00, 0x1d, 0x55, 0x83, 0x51, 0x7e, 0x75, 0x00, 0x81, 0xb9, 0xcb, 0xd8, 0xc5, 0xe5, 0xa1, 0xd9, 0x17, 0x6d, 0x1f}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xea, 0xf9, 0xe4, 0xe9, 0xe1, 0x52, 0x3f, 0x51, 0x19, 0x0d, 0xdd, 0xd9, 0x9d, 0x93, 0x31, 0x87, 0x23, 0x09, 0xd5, 0x83, 0xeb, 0x92, 0x09, 0x76, 0x6e, 0xe3, 0xf8, 0xc0, 0xa2, 0x66, 0xb5, 0x36}} , - {{0x3a, 0xbb, 0x39, 0xed, 0x32, 0x02, 0xe7, 0x43, 0x7a, 0x38, 0x14, 0x84, 0xe3, 0x44, 0xd2, 0x5e, 0x94, 0xdd, 0x78, 0x89, 0x55, 0x4c, 0x73, 0x9e, 0xe1, 0xe4, 0x3e, 0x43, 0xd0, 0x4a, 0xde, 0x1b}}}, -{{{0xb2, 0xe7, 0x8f, 0xe3, 0xa3, 0xc5, 0xcb, 0x72, 0xee, 0x79, 0x41, 0xf8, 0xdf, 0xee, 0x65, 0xc5, 0x45, 0x77, 0x27, 0x3c, 0xbd, 0x58, 0xd3, 0x75, 0xe2, 0x04, 0x4b, 0xbb, 0x65, 0xf3, 0xc8, 0x0f}} , - {{0x24, 0x7b, 0x93, 0x34, 0xb5, 0xe2, 0x74, 0x48, 0xcd, 0xa0, 0x0b, 0x92, 0x97, 0x66, 0x39, 0xf4, 0xb0, 0xe2, 0x5d, 0x39, 0x6a, 0x5b, 0x45, 0x17, 0x78, 0x1e, 0xdb, 0x91, 0x81, 0x1c, 0xf9, 0x16}}}, -{{{0x16, 0xdf, 0xd1, 0x5a, 0xd5, 0xe9, 0x4e, 0x58, 0x95, 0x93, 0x5f, 0x51, 0x09, 0xc3, 0x2a, 0xc9, 0xd4, 0x55, 0x48, 0x79, 0xa4, 0xa3, 0xb2, 0xc3, 0x62, 0xaa, 0x8c, 0xe8, 0xad, 0x47, 0x39, 0x1b}} , - {{0x46, 0xda, 0x9e, 0x51, 0x3a, 0xe6, 0xd1, 0xa6, 0xbb, 0x4d, 0x7b, 0x08, 0xbe, 0x8c, 0xd5, 0xf3, 0x3f, 0xfd, 0xf7, 0x44, 0x80, 0x2d, 0x53, 0x4b, 0xd0, 0x87, 0x68, 0xc1, 0xb5, 0xd8, 0xf7, 0x07}}}, -{{{0xf4, 0x10, 0x46, 0xbe, 0xb7, 0xd2, 0xd1, 0xce, 0x5e, 0x76, 0xa2, 0xd7, 0x03, 0xdc, 0xe4, 0x81, 0x5a, 0xf6, 0x3c, 0xde, 0xae, 0x7a, 0x9d, 0x21, 0x34, 0xa5, 0xf6, 0xa9, 0x73, 0xe2, 0x8d, 0x60}} , - {{0xfa, 0x44, 0x71, 0xf6, 0x41, 0xd8, 0xc6, 0x58, 0x13, 0x37, 0xeb, 0x84, 0x0f, 0x96, 0xc7, 0xdc, 0xc8, 0xa9, 0x7a, 0x83, 0xb2, 0x2f, 0x31, 0xb1, 0x1a, 0xd8, 0x98, 0x3f, 0x11, 0xd0, 0x31, 0x3b}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x81, 0xd5, 0x34, 0x16, 0x01, 0xa3, 0x93, 0xea, 0x52, 0x94, 0xec, 0x93, 0xb7, 0x81, 0x11, 0x2d, 0x58, 0xf9, 0xb5, 0x0a, 0xaa, 0x4f, 0xf6, 0x2e, 0x3f, 0x36, 0xbf, 0x33, 0x5a, 0xe7, 0xd1, 0x08}} , - {{0x1a, 0xcf, 0x42, 0xae, 0xcc, 0xb5, 0x77, 0x39, 0xc4, 0x5b, 0x5b, 0xd0, 0x26, 0x59, 0x27, 0xd0, 0x55, 0x71, 0x12, 0x9d, 0x88, 0x3d, 0x9c, 0xea, 0x41, 0x6a, 0xf0, 0x50, 0x93, 0x93, 0xdd, 0x47}}}, -{{{0x6f, 0xc9, 0x51, 0x6d, 0x1c, 0xaa, 0xf5, 0xa5, 0x90, 0x3f, 0x14, 0xe2, 0x6e, 0x8e, 0x64, 0xfd, 0xac, 0xe0, 0x4e, 0x22, 0xe5, 0xc1, 0xbc, 0x29, 0x0a, 0x6a, 0x9e, 0xa1, 0x60, 0xcb, 0x2f, 0x0b}} , - {{0xdc, 0x39, 0x32, 0xf3, 0xa1, 0x44, 0xe9, 0xc5, 0xc3, 0x78, 0xfb, 0x95, 0x47, 0x34, 0x35, 0x34, 0xe8, 0x25, 0xde, 0x93, 0xc6, 0xb4, 0x76, 0x6d, 0x86, 0x13, 0xc6, 0xe9, 0x68, 0xb5, 0x01, 0x63}}}, -{{{0x1f, 0x9a, 0x52, 0x64, 0x97, 0xd9, 0x1c, 0x08, 0x51, 0x6f, 0x26, 0x9d, 0xaa, 0x93, 0x33, 0x43, 0xfa, 0x77, 0xe9, 0x62, 0x9b, 0x5d, 0x18, 0x75, 0xeb, 0x78, 0xf7, 0x87, 0x8f, 0x41, 0xb4, 0x4d}} , - {{0x13, 0xa8, 0x82, 0x3e, 0xe9, 0x13, 0xad, 0xeb, 0x01, 0xca, 0xcf, 0xda, 0xcd, 0xf7, 0x6c, 0xc7, 0x7a, 0xdc, 0x1e, 0x6e, 0xc8, 0x4e, 0x55, 0x62, 0x80, 0xea, 0x78, 0x0c, 0x86, 0xb9, 0x40, 0x51}}}, -{{{0x27, 0xae, 0xd3, 0x0d, 0x4c, 0x8f, 0x34, 0xea, 0x7d, 0x3c, 0xe5, 0x8a, 0xcf, 0x5b, 0x92, 0xd8, 0x30, 0x16, 0xb4, 0xa3, 0x75, 0xff, 0xeb, 0x27, 0xc8, 0x5c, 0x6c, 0xc2, 0xee, 0x6c, 0x21, 0x0b}} , - {{0xc3, 0xba, 0x12, 0x53, 0x2a, 0xaa, 0x77, 0xad, 0x19, 0x78, 0x55, 0x8a, 0x2e, 0x60, 0x87, 0xc2, 0x6e, 0x91, 0x38, 0x91, 0x3f, 0x7a, 0xc5, 0x24, 0x8f, 0x51, 0xc5, 0xde, 0xb0, 0x53, 0x30, 0x56}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x02, 0xfe, 0x54, 0x12, 0x18, 0xca, 0x7d, 0xa5, 0x68, 0x43, 0xa3, 0x6d, 0x14, 0x2a, 0x6a, 0xa5, 0x8e, 0x32, 0xe7, 0x63, 0x4f, 0xe3, 0xc6, 0x44, 0x3e, 0xab, 0x63, 0xca, 0x17, 0x86, 0x74, 0x3f}} , - {{0x1e, 0x64, 0xc1, 0x7d, 0x52, 0xdc, 0x13, 0x5a, 0xa1, 0x9c, 0x4e, 0xee, 0x99, 0x28, 0xbb, 0x4c, 0xee, 0xac, 0xa9, 0x1b, 0x89, 0xa2, 0x38, 0x39, 0x7b, 0xc4, 0x0f, 0x42, 0xe6, 0x89, 0xed, 0x0f}}}, -{{{0xf3, 0x3c, 0x8c, 0x80, 0x83, 0x10, 0x8a, 0x37, 0x50, 0x9c, 0xb4, 0xdf, 0x3f, 0x8c, 0xf7, 0x23, 0x07, 0xd6, 0xff, 0xa0, 0x82, 0x6c, 0x75, 0x3b, 0xe4, 0xb5, 0xbb, 0xe4, 0xe6, 0x50, 0xf0, 0x08}} , - {{0x62, 0xee, 0x75, 0x48, 0x92, 0x33, 0xf2, 0xf4, 0xad, 0x15, 0x7a, 0xa1, 0x01, 0x46, 0xa9, 0x32, 0x06, 0x88, 0xb6, 0x36, 0x47, 0x35, 0xb9, 0xb4, 0x42, 0x85, 0x76, 0xf0, 0x48, 0x00, 0x90, 0x38}}}, -{{{0x51, 0x15, 0x9d, 0xc3, 0x95, 0xd1, 0x39, 0xbb, 0x64, 0x9d, 0x15, 0x81, 0xc1, 0x68, 0xd0, 0xb6, 0xa4, 0x2c, 0x7d, 0x5e, 0x02, 0x39, 0x00, 0xe0, 0x3b, 0xa4, 0xcc, 0xca, 0x1d, 0x81, 0x24, 0x10}} , - {{0xe7, 0x29, 0xf9, 0x37, 0xd9, 0x46, 0x5a, 0xcd, 0x70, 0xfe, 0x4d, 0x5b, 0xbf, 0xa5, 0xcf, 0x91, 0xf4, 0xef, 0xee, 0x8a, 0x29, 0xd0, 0xe7, 0xc4, 0x25, 0x92, 0x8a, 0xff, 0x36, 0xfc, 0xe4, 0x49}}}, -{{{0xbd, 0x00, 0xb9, 0x04, 0x7d, 0x35, 0xfc, 0xeb, 0xd0, 0x0b, 0x05, 0x32, 0x52, 0x7a, 0x89, 0x24, 0x75, 0x50, 0xe1, 0x63, 0x02, 0x82, 0x8e, 0xe7, 0x85, 0x0c, 0xf2, 0x56, 0x44, 0x37, 0x83, 0x25}} , - {{0x8f, 0xa1, 0xce, 0xcb, 0x60, 0xda, 0x12, 0x02, 0x1e, 0x29, 0x39, 0x2a, 0x03, 0xb7, 0xeb, 0x77, 0x40, 0xea, 0xc9, 0x2b, 0x2c, 0xd5, 0x7d, 0x7e, 0x2c, 0xc7, 0x5a, 0xfd, 0xff, 0xc4, 0xd1, 0x62}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x1d, 0x88, 0x98, 0x5b, 0x4e, 0xfc, 0x41, 0x24, 0x05, 0xe6, 0x50, 0x2b, 0xae, 0x96, 0x51, 0xd9, 0x6b, 0x72, 0xb2, 0x33, 0x42, 0x98, 0x68, 0xbb, 0x10, 0x5a, 0x7a, 0x8c, 0x9d, 0x07, 0xb4, 0x05}} , - {{0x2f, 0x61, 0x9f, 0xd7, 0xa8, 0x3f, 0x83, 0x8c, 0x10, 0x69, 0x90, 0xe6, 0xcf, 0xd2, 0x63, 0xa3, 0xe4, 0x54, 0x7e, 0xe5, 0x69, 0x13, 0x1c, 0x90, 0x57, 0xaa, 0xe9, 0x53, 0x22, 0x43, 0x29, 0x23}}}, -{{{0xe5, 0x1c, 0xf8, 0x0a, 0xfd, 0x2d, 0x7e, 0xf5, 0xf5, 0x70, 0x7d, 0x41, 0x6b, 0x11, 0xfe, 0xbe, 0x99, 0xd1, 0x55, 0x29, 0x31, 0xbf, 0xc0, 0x97, 0x6c, 0xd5, 0x35, 0xcc, 0x5e, 0x8b, 0xd9, 0x69}} , - {{0x8e, 0x4e, 0x9f, 0x25, 0xf8, 0x81, 0x54, 0x2d, 0x0e, 0xd5, 0x54, 0x81, 0x9b, 0xa6, 0x92, 0xce, 0x4b, 0xe9, 0x8f, 0x24, 0x3b, 0xca, 0xe0, 0x44, 0xab, 0x36, 0xfe, 0xfb, 0x87, 0xd4, 0x26, 0x3e}}}, -{{{0x0f, 0x93, 0x9c, 0x11, 0xe7, 0xdb, 0xf1, 0xf0, 0x85, 0x43, 0x28, 0x15, 0x37, 0xdd, 0xde, 0x27, 0xdf, 0xad, 0x3e, 0x49, 0x4f, 0xe0, 0x5b, 0xf6, 0x80, 0x59, 0x15, 0x3c, 0x85, 0xb7, 0x3e, 0x12}} , - {{0xf5, 0xff, 0xcc, 0xf0, 0xb4, 0x12, 0x03, 0x5f, 0xc9, 0x84, 0xcb, 0x1d, 0x17, 0xe0, 0xbc, 0xcc, 0x03, 0x62, 0xa9, 0x8b, 0x94, 0xa6, 0xaa, 0x18, 0xcb, 0x27, 0x8d, 0x49, 0xa6, 0x17, 0x15, 0x07}}}, -{{{0xd9, 0xb6, 0xd4, 0x9d, 0xd4, 0x6a, 0xaf, 0x70, 0x07, 0x2c, 0x10, 0x9e, 0xbd, 0x11, 0xad, 0xe4, 0x26, 0x33, 0x70, 0x92, 0x78, 0x1c, 0x74, 0x9f, 0x75, 0x60, 0x56, 0xf4, 0x39, 0xa8, 0xa8, 0x62}} , - {{0x3b, 0xbf, 0x55, 0x35, 0x61, 0x8b, 0x44, 0x97, 0xe8, 0x3a, 0x55, 0xc1, 0xc8, 0x3b, 0xfd, 0x95, 0x29, 0x11, 0x60, 0x96, 0x1e, 0xcb, 0x11, 0x9d, 0xc2, 0x03, 0x8a, 0x1b, 0xc6, 0xd6, 0x45, 0x3d}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x7e, 0x0e, 0x50, 0xb2, 0xcc, 0x0d, 0x6b, 0xa6, 0x71, 0x5b, 0x42, 0xed, 0xbd, 0xaf, 0xac, 0xf0, 0xfc, 0x12, 0xa2, 0x3f, 0x4e, 0xda, 0xe8, 0x11, 0xf3, 0x23, 0xe1, 0x04, 0x62, 0x03, 0x1c, 0x4e}} , - {{0xc8, 0xb1, 0x1b, 0x6f, 0x73, 0x61, 0x3d, 0x27, 0x0d, 0x7d, 0x7a, 0x25, 0x5f, 0x73, 0x0e, 0x2f, 0x93, 0xf6, 0x24, 0xd8, 0x4f, 0x90, 0xac, 0xa2, 0x62, 0x0a, 0xf0, 0x61, 0xd9, 0x08, 0x59, 0x6a}}}, -{{{0x6f, 0x2d, 0x55, 0xf8, 0x2f, 0x8e, 0xf0, 0x18, 0x3b, 0xea, 0xdd, 0x26, 0x72, 0xd1, 0xf5, 0xfe, 0xe5, 0xb8, 0xe6, 0xd3, 0x10, 0x48, 0x46, 0x49, 0x3a, 0x9f, 0x5e, 0x45, 0x6b, 0x90, 0xe8, 0x7f}} , - {{0xd3, 0x76, 0x69, 0x33, 0x7b, 0xb9, 0x40, 0x70, 0xee, 0xa6, 0x29, 0x6b, 0xdd, 0xd0, 0x5d, 0x8d, 0xc1, 0x3e, 0x4a, 0xea, 0x37, 0xb1, 0x03, 0x02, 0x03, 0x35, 0xf1, 0x28, 0x9d, 0xff, 0x00, 0x13}}}, -{{{0x7a, 0xdb, 0x12, 0xd2, 0x8a, 0x82, 0x03, 0x1b, 0x1e, 0xaf, 0xf9, 0x4b, 0x9c, 0xbe, 0xae, 0x7c, 0xe4, 0x94, 0x2a, 0x23, 0xb3, 0x62, 0x86, 0xe7, 0xfd, 0x23, 0xaa, 0x99, 0xbd, 0x2b, 0x11, 0x6c}} , - {{0x8d, 0xa6, 0xd5, 0xac, 0x9d, 0xcc, 0x68, 0x75, 0x7f, 0xc3, 0x4d, 0x4b, 0xdd, 0x6c, 0xbb, 0x11, 0x5a, 0x60, 0xe5, 0xbd, 0x7d, 0x27, 0x8b, 0xda, 0xb4, 0x95, 0xf6, 0x03, 0x27, 0xa4, 0x92, 0x3f}}}, -{{{0x22, 0xd6, 0xb5, 0x17, 0x84, 0xbf, 0x12, 0xcc, 0x23, 0x14, 0x4a, 0xdf, 0x14, 0x31, 0xbc, 0xa1, 0xac, 0x6e, 0xab, 0xfa, 0x57, 0x11, 0x53, 0xb3, 0x27, 0xe6, 0xf9, 0x47, 0x33, 0x44, 0x34, 0x1e}} , - {{0x79, 0xfc, 0xa6, 0xb4, 0x0b, 0x35, 0x20, 0xc9, 0x4d, 0x22, 0x84, 0xc4, 0xa9, 0x20, 0xec, 0x89, 0x94, 0xba, 0x66, 0x56, 0x48, 0xb9, 0x87, 0x7f, 0xca, 0x1e, 0x06, 0xed, 0xa5, 0x55, 0x59, 0x29}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x56, 0xe1, 0xf5, 0xf1, 0xd5, 0xab, 0xa8, 0x2b, 0xae, 0x89, 0xf3, 0xcf, 0x56, 0x9f, 0xf2, 0x4b, 0x31, 0xbc, 0x18, 0xa9, 0x06, 0x5b, 0xbe, 0xb4, 0x61, 0xf8, 0xb2, 0x06, 0x9c, 0x81, 0xab, 0x4c}} , - {{0x1f, 0x68, 0x76, 0x01, 0x16, 0x38, 0x2b, 0x0f, 0x77, 0x97, 0x92, 0x67, 0x4e, 0x86, 0x6a, 0x8b, 0xe5, 0xe8, 0x0c, 0xf7, 0x36, 0x39, 0xb5, 0x33, 0xe6, 0xcf, 0x5e, 0xbd, 0x18, 0xfb, 0x10, 0x1f}}}, -{{{0x83, 0xf0, 0x0d, 0x63, 0xef, 0x53, 0x6b, 0xb5, 0x6b, 0xf9, 0x83, 0xcf, 0xde, 0x04, 0x22, 0x9b, 0x2c, 0x0a, 0xe0, 0xa5, 0xd8, 0xc7, 0x9c, 0xa5, 0xa3, 0xf6, 0x6f, 0xcf, 0x90, 0x6b, 0x68, 0x7c}} , - {{0x33, 0x15, 0xd7, 0x7f, 0x1a, 0xd5, 0x21, 0x58, 0xc4, 0x18, 0xa5, 0xf0, 0xcc, 0x73, 0xa8, 0xfd, 0xfa, 0x18, 0xd1, 0x03, 0x91, 0x8d, 0x52, 0xd2, 0xa3, 0xa4, 0xd3, 0xb1, 0xea, 0x1d, 0x0f, 0x00}}}, -{{{0xcc, 0x48, 0x83, 0x90, 0xe5, 0xfd, 0x3f, 0x84, 0xaa, 0xf9, 0x8b, 0x82, 0x59, 0x24, 0x34, 0x68, 0x4f, 0x1c, 0x23, 0xd9, 0xcc, 0x71, 0xe1, 0x7f, 0x8c, 0xaf, 0xf1, 0xee, 0x00, 0xb6, 0xa0, 0x77}} , - {{0xf5, 0x1a, 0x61, 0xf7, 0x37, 0x9d, 0x00, 0xf4, 0xf2, 0x69, 0x6f, 0x4b, 0x01, 0x85, 0x19, 0x45, 0x4d, 0x7f, 0x02, 0x7c, 0x6a, 0x05, 0x47, 0x6c, 0x1f, 0x81, 0x20, 0xd4, 0xe8, 0x50, 0x27, 0x72}}}, -{{{0x2c, 0x3a, 0xe5, 0xad, 0xf4, 0xdd, 0x2d, 0xf7, 0x5c, 0x44, 0xb5, 0x5b, 0x21, 0xa3, 0x89, 0x5f, 0x96, 0x45, 0xca, 0x4d, 0xa4, 0x21, 0x99, 0x70, 0xda, 0xc4, 0xc4, 0xa0, 0xe5, 0xf4, 0xec, 0x0a}} , - {{0x07, 0x68, 0x21, 0x65, 0xe9, 0x08, 0xa0, 0x0b, 0x6a, 0x4a, 0xba, 0xb5, 0x80, 0xaf, 0xd0, 0x1b, 0xc5, 0xf5, 0x4b, 0x73, 0x50, 0x60, 0x2d, 0x71, 0x69, 0x61, 0x0e, 0xc0, 0x20, 0x40, 0x30, 0x19}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xd0, 0x75, 0x57, 0x3b, 0xeb, 0x5c, 0x14, 0x56, 0x50, 0xc9, 0x4f, 0xb8, 0xb8, 0x1e, 0xa3, 0xf4, 0xab, 0xf5, 0xa9, 0x20, 0x15, 0x94, 0x82, 0xda, 0x96, 0x1c, 0x9b, 0x59, 0x8c, 0xff, 0xf4, 0x51}} , - {{0xc1, 0x3a, 0x86, 0xd7, 0xb0, 0x06, 0x84, 0x7f, 0x1b, 0xbd, 0xd4, 0x07, 0x78, 0x80, 0x2e, 0xb1, 0xb4, 0xee, 0x52, 0x38, 0xee, 0x9a, 0xf9, 0xf6, 0xf3, 0x41, 0x6e, 0xd4, 0x88, 0x95, 0xac, 0x35}}}, -{{{0x41, 0x97, 0xbf, 0x71, 0x6a, 0x9b, 0x72, 0xec, 0xf3, 0xf8, 0x6b, 0xe6, 0x0e, 0x6c, 0x69, 0xa5, 0x2f, 0x68, 0x52, 0xd8, 0x61, 0x81, 0xc0, 0x63, 0x3f, 0xa6, 0x3c, 0x13, 0x90, 0xe6, 0x8d, 0x56}} , - {{0xe8, 0x39, 0x30, 0x77, 0x23, 0xb1, 0xfd, 0x1b, 0x3d, 0x3e, 0x74, 0x4d, 0x7f, 0xae, 0x5b, 0x3a, 0xb4, 0x65, 0x0e, 0x3a, 0x43, 0xdc, 0xdc, 0x41, 0x47, 0xe6, 0xe8, 0x92, 0x09, 0x22, 0x48, 0x4c}}}, -{{{0x85, 0x57, 0x9f, 0xb5, 0xc8, 0x06, 0xb2, 0x9f, 0x47, 0x3f, 0xf0, 0xfa, 0xe6, 0xa9, 0xb1, 0x9b, 0x6f, 0x96, 0x7d, 0xf9, 0xa4, 0x65, 0x09, 0x75, 0x32, 0xa6, 0x6c, 0x7f, 0x47, 0x4b, 0x2f, 0x4f}} , - {{0x34, 0xe9, 0x59, 0x93, 0x9d, 0x26, 0x80, 0x54, 0xf2, 0xcc, 0x3c, 0xc2, 0x25, 0x85, 0xe3, 0x6a, 0xc1, 0x62, 0x04, 0xa7, 0x08, 0x32, 0x6d, 0xa1, 0x39, 0x84, 0x8a, 0x3b, 0x87, 0x5f, 0x11, 0x13}}}, -{{{0xda, 0x03, 0x34, 0x66, 0xc4, 0x0c, 0x73, 0x6e, 0xbc, 0x24, 0xb5, 0xf9, 0x70, 0x81, 0x52, 0xe9, 0xf4, 0x7c, 0x23, 0xdd, 0x9f, 0xb8, 0x46, 0xef, 0x1d, 0x22, 0x55, 0x7d, 0x71, 0xc4, 0x42, 0x33}} , - {{0xc5, 0x37, 0x69, 0x5b, 0xa8, 0xc6, 0x9d, 0xa4, 0xfc, 0x61, 0x6e, 0x68, 0x46, 0xea, 0xd7, 0x1c, 0x67, 0xd2, 0x7d, 0xfa, 0xf1, 0xcc, 0x54, 0x8d, 0x36, 0x35, 0xc9, 0x00, 0xdf, 0x6c, 0x67, 0x50}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x9a, 0x4d, 0x42, 0x29, 0x5d, 0xa4, 0x6b, 0x6f, 0xa8, 0x8a, 0x4d, 0x91, 0x7b, 0xd2, 0xdf, 0x36, 0xef, 0x01, 0x22, 0xc5, 0xcc, 0x8d, 0xeb, 0x58, 0x3d, 0xb3, 0x50, 0xfc, 0x8b, 0x97, 0x96, 0x33}} , - {{0x93, 0x33, 0x07, 0xc8, 0x4a, 0xca, 0xd0, 0xb1, 0xab, 0xbd, 0xdd, 0xa7, 0x7c, 0xac, 0x3e, 0x45, 0xcb, 0xcc, 0x07, 0x91, 0xbf, 0x35, 0x9d, 0xcb, 0x7d, 0x12, 0x3c, 0x11, 0x59, 0x13, 0xcf, 0x5c}}}, -{{{0x45, 0xb8, 0x41, 0xd7, 0xab, 0x07, 0x15, 0x00, 0x8e, 0xce, 0xdf, 0xb2, 0x43, 0x5c, 0x01, 0xdc, 0xf4, 0x01, 0x51, 0x95, 0x10, 0x5a, 0xf6, 0x24, 0x24, 0xa0, 0x19, 0x3a, 0x09, 0x2a, 0xaa, 0x3f}} , - {{0xdc, 0x8e, 0xeb, 0xc6, 0xbf, 0xdd, 0x11, 0x7b, 0xe7, 0x47, 0xe6, 0xce, 0xe7, 0xb6, 0xc5, 0xe8, 0x8a, 0xdc, 0x4b, 0x57, 0x15, 0x3b, 0x66, 0xca, 0x89, 0xa3, 0xfd, 0xac, 0x0d, 0xe1, 0x1d, 0x7a}}}, -{{{0x89, 0xef, 0xbf, 0x03, 0x75, 0xd0, 0x29, 0x50, 0xcb, 0x7d, 0xd6, 0xbe, 0xad, 0x5f, 0x7b, 0x00, 0x32, 0xaa, 0x98, 0xed, 0x3f, 0x8f, 0x92, 0xcb, 0x81, 0x56, 0x01, 0x63, 0x64, 0xa3, 0x38, 0x39}} , - {{0x8b, 0xa4, 0xd6, 0x50, 0xb4, 0xaa, 0x5d, 0x64, 0x64, 0x76, 0x2e, 0xa1, 0xa6, 0xb3, 0xb8, 0x7c, 0x7a, 0x56, 0xf5, 0x5c, 0x4e, 0x84, 0x5c, 0xfb, 0xdd, 0xca, 0x48, 0x8b, 0x48, 0xb9, 0xba, 0x34}}}, -{{{0xc5, 0xe3, 0xe8, 0xae, 0x17, 0x27, 0xe3, 0x64, 0x60, 0x71, 0x47, 0x29, 0x02, 0x0f, 0x92, 0x5d, 0x10, 0x93, 0xc8, 0x0e, 0xa1, 0xed, 0xba, 0xa9, 0x96, 0x1c, 0xc5, 0x76, 0x30, 0xcd, 0xf9, 0x30}} , - {{0x95, 0xb0, 0xbd, 0x8c, 0xbc, 0xa7, 0x4f, 0x7e, 0xfd, 0x4e, 0x3a, 0xbf, 0x5f, 0x04, 0x79, 0x80, 0x2b, 0x5a, 0x9f, 0x4f, 0x68, 0x21, 0x19, 0x71, 0xc6, 0x20, 0x01, 0x42, 0xaa, 0xdf, 0xae, 0x2c}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x90, 0x6e, 0x7e, 0x4b, 0x71, 0x93, 0xc0, 0x72, 0xed, 0xeb, 0x71, 0x24, 0x97, 0x26, 0x9c, 0xfe, 0xcb, 0x3e, 0x59, 0x19, 0xa8, 0x0f, 0x75, 0x7d, 0xbe, 0x18, 0xe6, 0x96, 0x1e, 0x95, 0x70, 0x60}} , - {{0x89, 0x66, 0x3e, 0x1d, 0x4c, 0x5f, 0xfe, 0xc0, 0x04, 0x43, 0xd6, 0x44, 0x19, 0xb5, 0xad, 0xc7, 0x22, 0xdc, 0x71, 0x28, 0x64, 0xde, 0x41, 0x38, 0x27, 0x8f, 0x2c, 0x6b, 0x08, 0xb8, 0xb8, 0x7b}}}, -{{{0x3d, 0x70, 0x27, 0x9d, 0xd9, 0xaf, 0xb1, 0x27, 0xaf, 0xe3, 0x5d, 0x1e, 0x3a, 0x30, 0x54, 0x61, 0x60, 0xe8, 0xc3, 0x26, 0x3a, 0xbc, 0x7e, 0xf5, 0x81, 0xdd, 0x64, 0x01, 0x04, 0xeb, 0xc0, 0x1e}} , - {{0xda, 0x2c, 0xa4, 0xd1, 0xa1, 0xc3, 0x5c, 0x6e, 0x32, 0x07, 0x1f, 0xb8, 0x0e, 0x19, 0x9e, 0x99, 0x29, 0x33, 0x9a, 0xae, 0x7a, 0xed, 0x68, 0x42, 0x69, 0x7c, 0x07, 0xb3, 0x38, 0x2c, 0xf6, 0x3d}}}, -{{{0x64, 0xaa, 0xb5, 0x88, 0x79, 0x65, 0x38, 0x8c, 0x94, 0xd6, 0x62, 0x37, 0x7d, 0x64, 0xcd, 0x3a, 0xeb, 0xff, 0xe8, 0x81, 0x09, 0xc7, 0x6a, 0x50, 0x09, 0x0d, 0x28, 0x03, 0x0d, 0x9a, 0x93, 0x0a}} , - {{0x42, 0xa3, 0xf1, 0xc5, 0xb4, 0x0f, 0xd8, 0xc8, 0x8d, 0x15, 0x31, 0xbd, 0xf8, 0x07, 0x8b, 0xcd, 0x08, 0x8a, 0xfb, 0x18, 0x07, 0xfe, 0x8e, 0x52, 0x86, 0xef, 0xbe, 0xec, 0x49, 0x52, 0x99, 0x08}}}, -{{{0x0f, 0xa9, 0xd5, 0x01, 0xaa, 0x48, 0x4f, 0x28, 0x66, 0x32, 0x1a, 0xba, 0x7c, 0xea, 0x11, 0x80, 0x17, 0x18, 0x9b, 0x56, 0x88, 0x25, 0x06, 0x69, 0x12, 0x2c, 0xea, 0x56, 0x69, 0x41, 0x24, 0x19}} , - {{0xde, 0x21, 0xf0, 0xda, 0x8a, 0xfb, 0xb1, 0xb8, 0xcd, 0xc8, 0x6a, 0x82, 0x19, 0x73, 0xdb, 0xc7, 0xcf, 0x88, 0xeb, 0x96, 0xee, 0x6f, 0xfb, 0x06, 0xd2, 0xcd, 0x7d, 0x7b, 0x12, 0x28, 0x8e, 0x0c}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x93, 0x44, 0x97, 0xce, 0x28, 0xff, 0x3a, 0x40, 0xc4, 0xf5, 0xf6, 0x9b, 0xf4, 0x6b, 0x07, 0x84, 0xfb, 0x98, 0xd8, 0xec, 0x8c, 0x03, 0x57, 0xec, 0x49, 0xed, 0x63, 0xb6, 0xaa, 0xff, 0x98, 0x28}} , - {{0x3d, 0x16, 0x35, 0xf3, 0x46, 0xbc, 0xb3, 0xf4, 0xc6, 0xb6, 0x4f, 0xfa, 0xf4, 0xa0, 0x13, 0xe6, 0x57, 0x45, 0x93, 0xb9, 0xbc, 0xd6, 0x59, 0xe7, 0x77, 0x94, 0x6c, 0xab, 0x96, 0x3b, 0x4f, 0x09}}}, -{{{0x5a, 0xf7, 0x6b, 0x01, 0x12, 0x4f, 0x51, 0xc1, 0x70, 0x84, 0x94, 0x47, 0xb2, 0x01, 0x6c, 0x71, 0xd7, 0xcc, 0x17, 0x66, 0x0f, 0x59, 0x5d, 0x5d, 0x10, 0x01, 0x57, 0x11, 0xf5, 0xdd, 0xe2, 0x34}} , - {{0x26, 0xd9, 0x1f, 0x5c, 0x58, 0xac, 0x8b, 0x03, 0xd2, 0xc3, 0x85, 0x0f, 0x3a, 0xc3, 0x7f, 0x6d, 0x8e, 0x86, 0xcd, 0x52, 0x74, 0x8f, 0x55, 0x77, 0x17, 0xb7, 0x8e, 0xb7, 0x88, 0xea, 0xda, 0x1b}}}, -{{{0xb6, 0xea, 0x0e, 0x40, 0x93, 0x20, 0x79, 0x35, 0x6a, 0x61, 0x84, 0x5a, 0x07, 0x6d, 0xf9, 0x77, 0x6f, 0xed, 0x69, 0x1c, 0x0d, 0x25, 0x76, 0xcc, 0xf0, 0xdb, 0xbb, 0xc5, 0xad, 0xe2, 0x26, 0x57}} , - {{0xcf, 0xe8, 0x0e, 0x6b, 0x96, 0x7d, 0xed, 0x27, 0xd1, 0x3c, 0xa9, 0xd9, 0x50, 0xa9, 0x98, 0x84, 0x5e, 0x86, 0xef, 0xd6, 0xf0, 0xf8, 0x0e, 0x89, 0x05, 0x2f, 0xd9, 0x5f, 0x15, 0x5f, 0x73, 0x79}}}, -{{{0xc8, 0x5c, 0x16, 0xfe, 0xed, 0x9f, 0x26, 0x56, 0xf6, 0x4b, 0x9f, 0xa7, 0x0a, 0x85, 0xfe, 0xa5, 0x8c, 0x87, 0xdd, 0x98, 0xce, 0x4e, 0xc3, 0x58, 0x55, 0xb2, 0x7b, 0x3d, 0xd8, 0x6b, 0xb5, 0x4c}} , - {{0x65, 0x38, 0xa0, 0x15, 0xfa, 0xa7, 0xb4, 0x8f, 0xeb, 0xc4, 0x86, 0x9b, 0x30, 0xa5, 0x5e, 0x4d, 0xea, 0x8a, 0x9a, 0x9f, 0x1a, 0xd8, 0x5b, 0x53, 0x14, 0x19, 0x25, 0x63, 0xb4, 0x6f, 0x1f, 0x5d}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xac, 0x8f, 0xbc, 0x1e, 0x7d, 0x8b, 0x5a, 0x0b, 0x8d, 0xaf, 0x76, 0x2e, 0x71, 0xe3, 0x3b, 0x6f, 0x53, 0x2f, 0x3e, 0x90, 0x95, 0xd4, 0x35, 0x14, 0x4f, 0x8c, 0x3c, 0xce, 0x57, 0x1c, 0x76, 0x49}} , - {{0xa8, 0x50, 0xe1, 0x61, 0x6b, 0x57, 0x35, 0xeb, 0x44, 0x0b, 0x0c, 0x6e, 0xf9, 0x25, 0x80, 0x74, 0xf2, 0x8f, 0x6f, 0x7a, 0x3e, 0x7f, 0x2d, 0xf3, 0x4e, 0x09, 0x65, 0x10, 0x5e, 0x03, 0x25, 0x32}}}, -{{{0xa9, 0x60, 0xdc, 0x0f, 0x64, 0xe5, 0x1d, 0xe2, 0x8d, 0x4f, 0x79, 0x2f, 0x0e, 0x24, 0x02, 0x00, 0x05, 0x77, 0x43, 0x25, 0x3d, 0x6a, 0xc7, 0xb7, 0xbf, 0x04, 0x08, 0x65, 0xf4, 0x39, 0x4b, 0x65}} , - {{0x96, 0x19, 0x12, 0x6b, 0x6a, 0xb7, 0xe3, 0xdc, 0x45, 0x9b, 0xdb, 0xb4, 0xa8, 0xae, 0xdc, 0xa8, 0x14, 0x44, 0x65, 0x62, 0xce, 0x34, 0x9a, 0x84, 0x18, 0x12, 0x01, 0xf1, 0xe2, 0x7b, 0xce, 0x50}}}, -{{{0x41, 0x21, 0x30, 0x53, 0x1b, 0x47, 0x01, 0xb7, 0x18, 0xd8, 0x82, 0x57, 0xbd, 0xa3, 0x60, 0xf0, 0x32, 0xf6, 0x5b, 0xf0, 0x30, 0x88, 0x91, 0x59, 0xfd, 0x90, 0xa2, 0xb9, 0x55, 0x93, 0x21, 0x34}} , - {{0x97, 0x67, 0x9e, 0xeb, 0x6a, 0xf9, 0x6e, 0xd6, 0x73, 0xe8, 0x6b, 0x29, 0xec, 0x63, 0x82, 0x00, 0xa8, 0x99, 0x1c, 0x1d, 0x30, 0xc8, 0x90, 0x52, 0x90, 0xb6, 0x6a, 0x80, 0x4e, 0xff, 0x4b, 0x51}}}, -{{{0x0f, 0x7d, 0x63, 0x8c, 0x6e, 0x5c, 0xde, 0x30, 0xdf, 0x65, 0xfa, 0x2e, 0xb0, 0xa3, 0x25, 0x05, 0x54, 0xbd, 0x25, 0xba, 0x06, 0xae, 0xdf, 0x8b, 0xd9, 0x1b, 0xea, 0x38, 0xb3, 0x05, 0x16, 0x09}} , - {{0xc7, 0x8c, 0xbf, 0x64, 0x28, 0xad, 0xf8, 0xa5, 0x5a, 0x6f, 0xc9, 0xba, 0xd5, 0x7f, 0xd5, 0xd6, 0xbd, 0x66, 0x2f, 0x3d, 0xaa, 0x54, 0xf6, 0xba, 0x32, 0x22, 0x9a, 0x1e, 0x52, 0x05, 0xf4, 0x1d}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xaa, 0x1f, 0xbb, 0xeb, 0xfe, 0xe4, 0x87, 0xfc, 0xb1, 0x2c, 0xb7, 0x88, 0xf4, 0xc6, 0xb9, 0xf5, 0x24, 0x46, 0xf2, 0xa5, 0x9f, 0x8f, 0x8a, 0x93, 0x70, 0x69, 0xd4, 0x56, 0xec, 0xfd, 0x06, 0x46}} , - {{0x4e, 0x66, 0xcf, 0x4e, 0x34, 0xce, 0x0c, 0xd9, 0xa6, 0x50, 0xd6, 0x5e, 0x95, 0xaf, 0xe9, 0x58, 0xfa, 0xee, 0x9b, 0xb8, 0xa5, 0x0f, 0x35, 0xe0, 0x43, 0x82, 0x6d, 0x65, 0xe6, 0xd9, 0x00, 0x0f}}}, -{{{0x7b, 0x75, 0x3a, 0xfc, 0x64, 0xd3, 0x29, 0x7e, 0xdd, 0x49, 0x9a, 0x59, 0x53, 0xbf, 0xb4, 0xa7, 0x52, 0xb3, 0x05, 0xab, 0xc3, 0xaf, 0x16, 0x1a, 0x85, 0x42, 0x32, 0xa2, 0x86, 0xfa, 0x39, 0x43}} , - {{0x0e, 0x4b, 0xa3, 0x63, 0x8a, 0xfe, 0xa5, 0x58, 0xf1, 0x13, 0xbd, 0x9d, 0xaa, 0x7f, 0x76, 0x40, 0x70, 0x81, 0x10, 0x75, 0x99, 0xbb, 0xbe, 0x0b, 0x16, 0xe9, 0xba, 0x62, 0x34, 0xcc, 0x07, 0x6d}}}, -{{{0xc3, 0xf1, 0xc6, 0x93, 0x65, 0xee, 0x0b, 0xbc, 0xea, 0x14, 0xf0, 0xc1, 0xf8, 0x84, 0x89, 0xc2, 0xc9, 0xd7, 0xea, 0x34, 0xca, 0xa7, 0xc4, 0x99, 0xd5, 0x50, 0x69, 0xcb, 0xd6, 0x21, 0x63, 0x7c}} , - {{0x99, 0xeb, 0x7c, 0x31, 0x73, 0x64, 0x67, 0x7f, 0x0c, 0x66, 0xaa, 0x8c, 0x69, 0x91, 0xe2, 0x26, 0xd3, 0x23, 0xe2, 0x76, 0x5d, 0x32, 0x52, 0xdf, 0x5d, 0xc5, 0x8f, 0xb7, 0x7c, 0x84, 0xb3, 0x70}}}, -{{{0xeb, 0x01, 0xc7, 0x36, 0x97, 0x4e, 0xb6, 0xab, 0x5f, 0x0d, 0x2c, 0xba, 0x67, 0x64, 0x55, 0xde, 0xbc, 0xff, 0xa6, 0xec, 0x04, 0xd3, 0x8d, 0x39, 0x56, 0x5e, 0xee, 0xf8, 0xe4, 0x2e, 0x33, 0x62}} , - {{0x65, 0xef, 0xb8, 0x9f, 0xc8, 0x4b, 0xa7, 0xfd, 0x21, 0x49, 0x9b, 0x92, 0x35, 0x82, 0xd6, 0x0a, 0x9b, 0xf2, 0x79, 0xf1, 0x47, 0x2f, 0x6a, 0x7e, 0x9f, 0xcf, 0x18, 0x02, 0x3c, 0xfb, 0x1b, 0x3e}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x2f, 0x8b, 0xc8, 0x40, 0x51, 0xd1, 0xac, 0x1a, 0x0b, 0xe4, 0xa9, 0xa2, 0x42, 0x21, 0x19, 0x2f, 0x7b, 0x97, 0xbf, 0xf7, 0x57, 0x6d, 0x3f, 0x3d, 0x4f, 0x0f, 0xe2, 0xb2, 0x81, 0x00, 0x9e, 0x7b}} , - {{0x8c, 0x85, 0x2b, 0xc4, 0xfc, 0xf1, 0xab, 0xe8, 0x79, 0x22, 0xc4, 0x84, 0x17, 0x3a, 0xfa, 0x86, 0xa6, 0x7d, 0xf9, 0xf3, 0x6f, 0x03, 0x57, 0x20, 0x4d, 0x79, 0xf9, 0x6e, 0x71, 0x54, 0x38, 0x09}}}, -{{{0x40, 0x29, 0x74, 0xa8, 0x2f, 0x5e, 0xf9, 0x79, 0xa4, 0xf3, 0x3e, 0xb9, 0xfd, 0x33, 0x31, 0xac, 0x9a, 0x69, 0x88, 0x1e, 0x77, 0x21, 0x2d, 0xf3, 0x91, 0x52, 0x26, 0x15, 0xb2, 0xa6, 0xcf, 0x7e}} , - {{0xc6, 0x20, 0x47, 0x6c, 0xa4, 0x7d, 0xcb, 0x63, 0xea, 0x5b, 0x03, 0xdf, 0x3e, 0x88, 0x81, 0x6d, 0xce, 0x07, 0x42, 0x18, 0x60, 0x7e, 0x7b, 0x55, 0xfe, 0x6a, 0xf3, 0xda, 0x5c, 0x8b, 0x95, 0x10}}}, -{{{0x62, 0xe4, 0x0d, 0x03, 0xb4, 0xd7, 0xcd, 0xfa, 0xbd, 0x46, 0xdf, 0x93, 0x71, 0x10, 0x2c, 0xa8, 0x3b, 0xb6, 0x09, 0x05, 0x70, 0x84, 0x43, 0x29, 0xa8, 0x59, 0xf5, 0x8e, 0x10, 0xe4, 0xd7, 0x20}} , - {{0x57, 0x82, 0x1c, 0xab, 0xbf, 0x62, 0x70, 0xe8, 0xc4, 0xcf, 0xf0, 0x28, 0x6e, 0x16, 0x3c, 0x08, 0x78, 0x89, 0x85, 0x46, 0x0f, 0xf6, 0x7f, 0xcf, 0xcb, 0x7e, 0xb8, 0x25, 0xe9, 0x5a, 0xfa, 0x03}}}, -{{{0xfb, 0x95, 0x92, 0x63, 0x50, 0xfc, 0x62, 0xf0, 0xa4, 0x5e, 0x8c, 0x18, 0xc2, 0x17, 0x24, 0xb7, 0x78, 0xc2, 0xa9, 0xe7, 0x6a, 0x32, 0xd6, 0x29, 0x85, 0xaf, 0xcb, 0x8d, 0x91, 0x13, 0xda, 0x6b}} , - {{0x36, 0x0a, 0xc2, 0xb6, 0x4b, 0xa5, 0x5d, 0x07, 0x17, 0x41, 0x31, 0x5f, 0x62, 0x46, 0xf8, 0x92, 0xf9, 0x66, 0x48, 0x73, 0xa6, 0x97, 0x0d, 0x7d, 0x88, 0xee, 0x62, 0xb1, 0x03, 0xa8, 0x3f, 0x2c}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x4a, 0xb1, 0x70, 0x8a, 0xa9, 0xe8, 0x63, 0x79, 0x00, 0xe2, 0x25, 0x16, 0xca, 0x4b, 0x0f, 0xa4, 0x66, 0xad, 0x19, 0x9f, 0x88, 0x67, 0x0c, 0x8b, 0xc2, 0x4a, 0x5b, 0x2b, 0x6d, 0x95, 0xaf, 0x19}} , - {{0x8b, 0x9d, 0xb6, 0xcc, 0x60, 0xb4, 0x72, 0x4f, 0x17, 0x69, 0x5a, 0x4a, 0x68, 0x34, 0xab, 0xa1, 0x45, 0x32, 0x3c, 0x83, 0x87, 0x72, 0x30, 0x54, 0x77, 0x68, 0xae, 0xfb, 0xb5, 0x8b, 0x22, 0x5e}}}, -{{{0xf1, 0xb9, 0x87, 0x35, 0xc5, 0xbb, 0xb9, 0xcf, 0xf5, 0xd6, 0xcd, 0xd5, 0x0c, 0x7c, 0x0e, 0xe6, 0x90, 0x34, 0xfb, 0x51, 0x42, 0x1e, 0x6d, 0xac, 0x9a, 0x46, 0xc4, 0x97, 0x29, 0x32, 0xbf, 0x45}} , - {{0x66, 0x9e, 0xc6, 0x24, 0xc0, 0xed, 0xa5, 0x5d, 0x88, 0xd4, 0xf0, 0x73, 0x97, 0x7b, 0xea, 0x7f, 0x42, 0xff, 0x21, 0xa0, 0x9b, 0x2f, 0x9a, 0xfd, 0x53, 0x57, 0x07, 0x84, 0x48, 0x88, 0x9d, 0x52}}}, -{{{0xc6, 0x96, 0x48, 0x34, 0x2a, 0x06, 0xaf, 0x94, 0x3d, 0xf4, 0x1a, 0xcf, 0xf2, 0xc0, 0x21, 0xc2, 0x42, 0x5e, 0xc8, 0x2f, 0x35, 0xa2, 0x3e, 0x29, 0xfa, 0x0c, 0x84, 0xe5, 0x89, 0x72, 0x7c, 0x06}} , - {{0x32, 0x65, 0x03, 0xe5, 0x89, 0xa6, 0x6e, 0xb3, 0x5b, 0x8e, 0xca, 0xeb, 0xfe, 0x22, 0x56, 0x8b, 0x5d, 0x14, 0x4b, 0x4d, 0xf9, 0xbe, 0xb5, 0xf5, 0xe6, 0x5c, 0x7b, 0x8b, 0xf4, 0x13, 0x11, 0x34}}}, -{{{0x07, 0xc6, 0x22, 0x15, 0xe2, 0x9c, 0x60, 0xa2, 0x19, 0xd9, 0x27, 0xae, 0x37, 0x4e, 0xa6, 0xc9, 0x80, 0xa6, 0x91, 0x8f, 0x12, 0x49, 0xe5, 0x00, 0x18, 0x47, 0xd1, 0xd7, 0x28, 0x22, 0x63, 0x39}} , - {{0xe8, 0xe2, 0x00, 0x7e, 0xf2, 0x9e, 0x1e, 0x99, 0x39, 0x95, 0x04, 0xbd, 0x1e, 0x67, 0x7b, 0xb2, 0x26, 0xac, 0xe6, 0xaa, 0xe2, 0x46, 0xd5, 0xe4, 0xe8, 0x86, 0xbd, 0xab, 0x7c, 0x55, 0x59, 0x6f}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x24, 0x64, 0x6e, 0x9b, 0x35, 0x71, 0x78, 0xce, 0x33, 0x03, 0x21, 0x33, 0x36, 0xf1, 0x73, 0x9b, 0xb9, 0x15, 0x8b, 0x2c, 0x69, 0xcf, 0x4d, 0xed, 0x4f, 0x4d, 0x57, 0x14, 0x13, 0x82, 0xa4, 0x4d}} , - {{0x65, 0x6e, 0x0a, 0xa4, 0x59, 0x07, 0x17, 0xf2, 0x6b, 0x4a, 0x1f, 0x6e, 0xf6, 0xb5, 0xbc, 0x62, 0xe4, 0xb6, 0xda, 0xa2, 0x93, 0xbc, 0x29, 0x05, 0xd2, 0xd2, 0x73, 0x46, 0x03, 0x16, 0x40, 0x31}}}, -{{{0x4c, 0x73, 0x6d, 0x15, 0xbd, 0xa1, 0x4d, 0x5c, 0x13, 0x0b, 0x24, 0x06, 0x98, 0x78, 0x1c, 0x5b, 0xeb, 0x1f, 0x18, 0x54, 0x43, 0xd9, 0x55, 0x66, 0xda, 0x29, 0x21, 0xe8, 0xb8, 0x3c, 0x42, 0x22}} , - {{0xb4, 0xcd, 0x08, 0x6f, 0x15, 0x23, 0x1a, 0x0b, 0x22, 0xed, 0xd1, 0xf1, 0xa7, 0xc7, 0x73, 0x45, 0xf3, 0x9e, 0xce, 0x76, 0xb7, 0xf6, 0x39, 0xb6, 0x8e, 0x79, 0xbe, 0xe9, 0x9b, 0xcf, 0x7d, 0x62}}}, -{{{0x92, 0x5b, 0xfc, 0x72, 0xfd, 0xba, 0xf1, 0xfd, 0xa6, 0x7c, 0x95, 0xe3, 0x61, 0x3f, 0xe9, 0x03, 0xd4, 0x2b, 0xd4, 0x20, 0xd9, 0xdb, 0x4d, 0x32, 0x3e, 0xf5, 0x11, 0x64, 0xe3, 0xb4, 0xbe, 0x32}} , - {{0x86, 0x17, 0x90, 0xe7, 0xc9, 0x1f, 0x10, 0xa5, 0x6a, 0x2d, 0x39, 0xd0, 0x3b, 0xc4, 0xa6, 0xe9, 0x59, 0x13, 0xda, 0x1a, 0xe6, 0xa0, 0xb9, 0x3c, 0x50, 0xb8, 0x40, 0x7c, 0x15, 0x36, 0x5a, 0x42}}}, -{{{0xb4, 0x0b, 0x32, 0xab, 0xdc, 0x04, 0x51, 0x55, 0x21, 0x1e, 0x0b, 0x75, 0x99, 0x89, 0x73, 0x35, 0x3a, 0x91, 0x2b, 0xfe, 0xe7, 0x49, 0xea, 0x76, 0xc1, 0xf9, 0x46, 0xb9, 0x53, 0x02, 0x23, 0x04}} , - {{0xfc, 0x5a, 0x1e, 0x1d, 0x74, 0x58, 0x95, 0xa6, 0x8f, 0x7b, 0x97, 0x3e, 0x17, 0x3b, 0x79, 0x2d, 0xa6, 0x57, 0xef, 0x45, 0x02, 0x0b, 0x4d, 0x6e, 0x9e, 0x93, 0x8d, 0x2f, 0xd9, 0x9d, 0xdb, 0x04}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xc0, 0xd7, 0x56, 0x97, 0x58, 0x91, 0xde, 0x09, 0x4f, 0x9f, 0xbe, 0x63, 0xb0, 0x83, 0x86, 0x43, 0x5d, 0xbc, 0xe0, 0xf3, 0xc0, 0x75, 0xbf, 0x8b, 0x8e, 0xaa, 0xf7, 0x8b, 0x64, 0x6e, 0xb0, 0x63}} , - {{0x16, 0xae, 0x8b, 0xe0, 0x9b, 0x24, 0x68, 0x5c, 0x44, 0xc2, 0xd0, 0x08, 0xb7, 0x7b, 0x62, 0xfd, 0x7f, 0xd8, 0xd4, 0xb7, 0x50, 0xfd, 0x2c, 0x1b, 0xbf, 0x41, 0x95, 0xd9, 0x8e, 0xd8, 0x17, 0x1b}}}, -{{{0x86, 0x55, 0x37, 0x8e, 0xc3, 0x38, 0x48, 0x14, 0xb5, 0x97, 0xd2, 0xa7, 0x54, 0x45, 0xf1, 0x35, 0x44, 0x38, 0x9e, 0xf1, 0x1b, 0xb6, 0x34, 0x00, 0x3c, 0x96, 0xee, 0x29, 0x00, 0xea, 0x2c, 0x0b}} , - {{0xea, 0xda, 0x99, 0x9e, 0x19, 0x83, 0x66, 0x6d, 0xe9, 0x76, 0x87, 0x50, 0xd1, 0xfd, 0x3c, 0x60, 0x87, 0xc6, 0x41, 0xd9, 0x8e, 0xdb, 0x5e, 0xde, 0xaa, 0x9a, 0xd3, 0x28, 0xda, 0x95, 0xea, 0x47}}}, -{{{0xd0, 0x80, 0xba, 0x19, 0xae, 0x1d, 0xa9, 0x79, 0xf6, 0x3f, 0xac, 0x5d, 0x6f, 0x96, 0x1f, 0x2a, 0xce, 0x29, 0xb2, 0xff, 0x37, 0xf1, 0x94, 0x8f, 0x0c, 0xb5, 0x28, 0xba, 0x9a, 0x21, 0xf6, 0x66}} , - {{0x02, 0xfb, 0x54, 0xb8, 0x05, 0xf3, 0x81, 0x52, 0x69, 0x34, 0x46, 0x9d, 0x86, 0x76, 0x8f, 0xd7, 0xf8, 0x6a, 0x66, 0xff, 0xe6, 0xa7, 0x90, 0xf7, 0x5e, 0xcd, 0x6a, 0x9b, 0x55, 0xfc, 0x9d, 0x48}}}, -{{{0xbd, 0xaa, 0x13, 0xe6, 0xcd, 0x45, 0x4a, 0xa4, 0x59, 0x0a, 0x64, 0xb1, 0x98, 0xd6, 0x34, 0x13, 0x04, 0xe6, 0x97, 0x94, 0x06, 0xcb, 0xd4, 0x4e, 0xbb, 0x96, 0xcd, 0xd1, 0x57, 0xd1, 0xe3, 0x06}} , - {{0x7a, 0x6c, 0x45, 0x27, 0xc4, 0x93, 0x7f, 0x7d, 0x7c, 0x62, 0x50, 0x38, 0x3a, 0x6b, 0xb5, 0x88, 0xc6, 0xd9, 0xf1, 0x78, 0x19, 0xb9, 0x39, 0x93, 0x3d, 0xc9, 0xe0, 0x9c, 0x3c, 0xce, 0xf5, 0x72}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x24, 0xea, 0x23, 0x7d, 0x56, 0x2c, 0xe2, 0x59, 0x0e, 0x85, 0x60, 0x04, 0x88, 0x5a, 0x74, 0x1e, 0x4b, 0xef, 0x13, 0xda, 0x4c, 0xff, 0x83, 0x45, 0x85, 0x3f, 0x08, 0x95, 0x2c, 0x20, 0x13, 0x1f}} , - {{0x48, 0x5f, 0x27, 0x90, 0x5c, 0x02, 0x42, 0xad, 0x78, 0x47, 0x5c, 0xb5, 0x7e, 0x08, 0x85, 0x00, 0xfa, 0x7f, 0xfd, 0xfd, 0xe7, 0x09, 0x11, 0xf2, 0x7e, 0x1b, 0x38, 0x6c, 0x35, 0x6d, 0x33, 0x66}}}, -{{{0x93, 0x03, 0x36, 0x81, 0xac, 0xe4, 0x20, 0x09, 0x35, 0x4c, 0x45, 0xb2, 0x1e, 0x4c, 0x14, 0x21, 0xe6, 0xe9, 0x8a, 0x7b, 0x8d, 0xfe, 0x1e, 0xc6, 0x3e, 0xc1, 0x35, 0xfa, 0xe7, 0x70, 0x4e, 0x1d}} , - {{0x61, 0x2e, 0xc2, 0xdd, 0x95, 0x57, 0xd1, 0xab, 0x80, 0xe8, 0x63, 0x17, 0xb5, 0x48, 0xe4, 0x8a, 0x11, 0x9e, 0x72, 0xbe, 0x85, 0x8d, 0x51, 0x0a, 0xf2, 0x9f, 0xe0, 0x1c, 0xa9, 0x07, 0x28, 0x7b}}}, -{{{0xbb, 0x71, 0x14, 0x5e, 0x26, 0x8c, 0x3d, 0xc8, 0xe9, 0x7c, 0xd3, 0xd6, 0xd1, 0x2f, 0x07, 0x6d, 0xe6, 0xdf, 0xfb, 0x79, 0xd6, 0x99, 0x59, 0x96, 0x48, 0x40, 0x0f, 0x3a, 0x7b, 0xb2, 0xa0, 0x72}} , - {{0x4e, 0x3b, 0x69, 0xc8, 0x43, 0x75, 0x51, 0x6c, 0x79, 0x56, 0xe4, 0xcb, 0xf7, 0xa6, 0x51, 0xc2, 0x2c, 0x42, 0x0b, 0xd4, 0x82, 0x20, 0x1c, 0x01, 0x08, 0x66, 0xd7, 0xbf, 0x04, 0x56, 0xfc, 0x02}}}, -{{{0x24, 0xe8, 0xb7, 0x60, 0xae, 0x47, 0x80, 0xfc, 0xe5, 0x23, 0xe7, 0xc2, 0xc9, 0x85, 0xe6, 0x98, 0xa0, 0x29, 0x4e, 0xe1, 0x84, 0x39, 0x2d, 0x95, 0x2c, 0xf3, 0x45, 0x3c, 0xff, 0xaf, 0x27, 0x4c}} , - {{0x6b, 0xa6, 0xf5, 0x4b, 0x11, 0xbd, 0xba, 0x5b, 0x9e, 0xc4, 0xa4, 0x51, 0x1e, 0xbe, 0xd0, 0x90, 0x3a, 0x9c, 0xc2, 0x26, 0xb6, 0x1e, 0xf1, 0x95, 0x7d, 0xc8, 0x6d, 0x52, 0xe6, 0x99, 0x2c, 0x5f}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x85, 0xe0, 0x24, 0x32, 0xb4, 0xd1, 0xef, 0xfc, 0x69, 0xa2, 0xbf, 0x8f, 0x72, 0x2c, 0x95, 0xf6, 0xe4, 0x6e, 0x7d, 0x90, 0xf7, 0x57, 0x81, 0xa0, 0xf7, 0xda, 0xef, 0x33, 0x07, 0xe3, 0x6b, 0x78}} , - {{0x36, 0x27, 0x3e, 0xc6, 0x12, 0x07, 0xab, 0x4e, 0xbe, 0x69, 0x9d, 0xb3, 0xbe, 0x08, 0x7c, 0x2a, 0x47, 0x08, 0xfd, 0xd4, 0xcd, 0x0e, 0x27, 0x34, 0x5b, 0x98, 0x34, 0x2f, 0x77, 0x5f, 0x3a, 0x65}}}, -{{{0x13, 0xaa, 0x2e, 0x4c, 0xf0, 0x22, 0xb8, 0x6c, 0xb3, 0x19, 0x4d, 0xeb, 0x6b, 0xd0, 0xa4, 0xc6, 0x9c, 0xdd, 0xc8, 0x5b, 0x81, 0x57, 0x89, 0xdf, 0x33, 0xa9, 0x68, 0x49, 0x80, 0xe4, 0xfe, 0x21}} , - {{0x00, 0x17, 0x90, 0x30, 0xe9, 0xd3, 0x60, 0x30, 0x31, 0xc2, 0x72, 0x89, 0x7a, 0x36, 0xa5, 0xbd, 0x39, 0x83, 0x85, 0x50, 0xa1, 0x5d, 0x6c, 0x41, 0x1d, 0xb5, 0x2c, 0x07, 0x40, 0x77, 0x0b, 0x50}}}, -{{{0x64, 0x34, 0xec, 0xc0, 0x9e, 0x44, 0x41, 0xaf, 0xa0, 0x36, 0x05, 0x6d, 0xea, 0x30, 0x25, 0x46, 0x35, 0x24, 0x9d, 0x86, 0xbd, 0x95, 0xf1, 0x6a, 0x46, 0xd7, 0x94, 0x54, 0xf9, 0x3b, 0xbd, 0x5d}} , - {{0x77, 0x5b, 0xe2, 0x37, 0xc7, 0xe1, 0x7c, 0x13, 0x8c, 0x9f, 0x7b, 0x7b, 0x2a, 0xce, 0x42, 0xa3, 0xb9, 0x2a, 0x99, 0xa8, 0xc0, 0xd8, 0x3c, 0x86, 0xb0, 0xfb, 0xe9, 0x76, 0x77, 0xf7, 0xf5, 0x56}}}, -{{{0xdf, 0xb3, 0x46, 0x11, 0x6e, 0x13, 0xb7, 0x28, 0x4e, 0x56, 0xdd, 0xf1, 0xac, 0xad, 0x58, 0xc3, 0xf8, 0x88, 0x94, 0x5e, 0x06, 0x98, 0xa1, 0xe4, 0x6a, 0xfb, 0x0a, 0x49, 0x5d, 0x8a, 0xfe, 0x77}} , - {{0x46, 0x02, 0xf5, 0xa5, 0xaf, 0xc5, 0x75, 0x6d, 0xba, 0x45, 0x35, 0x0a, 0xfe, 0xc9, 0xac, 0x22, 0x91, 0x8d, 0x21, 0x95, 0x33, 0x03, 0xc0, 0x8a, 0x16, 0xf3, 0x39, 0xe0, 0x01, 0x0f, 0x53, 0x3c}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x34, 0x75, 0x37, 0x1f, 0x34, 0x4e, 0xa9, 0x1d, 0x68, 0x67, 0xf8, 0x49, 0x98, 0x96, 0xfc, 0x4c, 0x65, 0x97, 0xf7, 0x02, 0x4a, 0x52, 0x6c, 0x01, 0xbd, 0x48, 0xbb, 0x1b, 0xed, 0xa4, 0xe2, 0x53}} , - {{0x59, 0xd5, 0x9b, 0x5a, 0xa2, 0x90, 0xd3, 0xb8, 0x37, 0x4c, 0x55, 0x82, 0x28, 0x08, 0x0f, 0x7f, 0xaa, 0x81, 0x65, 0xe0, 0x0c, 0x52, 0xc9, 0xa3, 0x32, 0x27, 0x64, 0xda, 0xfd, 0x34, 0x23, 0x5a}}}, -{{{0xb5, 0xb0, 0x0c, 0x4d, 0xb3, 0x7b, 0x23, 0xc8, 0x1f, 0x8a, 0x39, 0x66, 0xe6, 0xba, 0x4c, 0x10, 0x37, 0xca, 0x9c, 0x7c, 0x05, 0x9e, 0xff, 0xc0, 0xf8, 0x8e, 0xb1, 0x8f, 0x6f, 0x67, 0x18, 0x26}} , - {{0x4b, 0x41, 0x13, 0x54, 0x23, 0x1a, 0xa4, 0x4e, 0xa9, 0x8b, 0x1e, 0x4b, 0xfc, 0x15, 0x24, 0xbb, 0x7e, 0xcb, 0xb6, 0x1e, 0x1b, 0xf5, 0xf2, 0xc8, 0x56, 0xec, 0x32, 0xa2, 0x60, 0x5b, 0xa0, 0x2a}}}, -{{{0xa4, 0x29, 0x47, 0x86, 0x2e, 0x92, 0x4f, 0x11, 0x4f, 0xf3, 0xb2, 0x5c, 0xd5, 0x3e, 0xa6, 0xb9, 0xc8, 0xe2, 0x33, 0x11, 0x1f, 0x01, 0x8f, 0xb0, 0x9b, 0xc7, 0xa5, 0xff, 0x83, 0x0f, 0x1e, 0x28}} , - {{0x1d, 0x29, 0x7a, 0xa1, 0xec, 0x8e, 0xb5, 0xad, 0xea, 0x02, 0x68, 0x60, 0x74, 0x29, 0x1c, 0xa5, 0xcf, 0xc8, 0x3b, 0x7d, 0x8b, 0x2b, 0x7c, 0xad, 0xa4, 0x40, 0x17, 0x51, 0x59, 0x7c, 0x2e, 0x5d}}}, -{{{0x0a, 0x6c, 0x4f, 0xbc, 0x3e, 0x32, 0xe7, 0x4a, 0x1a, 0x13, 0xc1, 0x49, 0x38, 0xbf, 0xf7, 0xc2, 0xd3, 0x8f, 0x6b, 0xad, 0x52, 0xf7, 0xcf, 0xbc, 0x27, 0xcb, 0x40, 0x67, 0x76, 0xcd, 0x6d, 0x56}} , - {{0xe5, 0xb0, 0x27, 0xad, 0xbe, 0x9b, 0xf2, 0xb5, 0x63, 0xde, 0x3a, 0x23, 0x95, 0xb7, 0x0a, 0x7e, 0xf3, 0x9e, 0x45, 0x6f, 0x19, 0x39, 0x75, 0x8f, 0x39, 0x3d, 0x0f, 0xc0, 0x9f, 0xf1, 0xe9, 0x51}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x88, 0xaa, 0x14, 0x24, 0x86, 0x94, 0x11, 0x12, 0x3e, 0x1a, 0xb5, 0xcc, 0xbb, 0xe0, 0x9c, 0xd5, 0x9c, 0x6d, 0xba, 0x58, 0x72, 0x8d, 0xfb, 0x22, 0x7b, 0x9f, 0x7c, 0x94, 0x30, 0xb3, 0x51, 0x21}} , - {{0xf6, 0x74, 0x3d, 0xf2, 0xaf, 0xd0, 0x1e, 0x03, 0x7c, 0x23, 0x6b, 0xc9, 0xfc, 0x25, 0x70, 0x90, 0xdc, 0x9a, 0xa4, 0xfb, 0x49, 0xfc, 0x3d, 0x0a, 0x35, 0x38, 0x6f, 0xe4, 0x7e, 0x50, 0x01, 0x2a}}}, -{{{0xd6, 0xe3, 0x96, 0x61, 0x3a, 0xfd, 0xef, 0x9b, 0x1f, 0x90, 0xa4, 0x24, 0x14, 0x5b, 0xc8, 0xde, 0x50, 0xb1, 0x1d, 0xaf, 0xe8, 0x55, 0x8a, 0x87, 0x0d, 0xfe, 0xaa, 0x3b, 0x82, 0x2c, 0x8d, 0x7b}} , - {{0x85, 0x0c, 0xaf, 0xf8, 0x83, 0x44, 0x49, 0xd9, 0x45, 0xcf, 0xf7, 0x48, 0xd9, 0x53, 0xb4, 0xf1, 0x65, 0xa0, 0xe1, 0xc3, 0xb3, 0x15, 0xed, 0x89, 0x9b, 0x4f, 0x62, 0xb3, 0x57, 0xa5, 0x45, 0x1c}}}, -{{{0x8f, 0x12, 0xea, 0xaf, 0xd1, 0x1f, 0x79, 0x10, 0x0b, 0xf6, 0xa3, 0x7b, 0xea, 0xac, 0x8b, 0x57, 0x32, 0x62, 0xe7, 0x06, 0x12, 0x51, 0xa0, 0x3b, 0x43, 0x5e, 0xa4, 0x20, 0x78, 0x31, 0xce, 0x0d}} , - {{0x84, 0x7c, 0xc2, 0xa6, 0x91, 0x23, 0xce, 0xbd, 0xdc, 0xf9, 0xce, 0xd5, 0x75, 0x30, 0x22, 0xe6, 0xf9, 0x43, 0x62, 0x0d, 0xf7, 0x75, 0x9d, 0x7f, 0x8c, 0xff, 0x7d, 0xe4, 0x72, 0xac, 0x9f, 0x1c}}}, -{{{0x88, 0xc1, 0x99, 0xd0, 0x3c, 0x1c, 0x5d, 0xb4, 0xef, 0x13, 0x0f, 0x90, 0xb9, 0x36, 0x2f, 0x95, 0x95, 0xc6, 0xdc, 0xde, 0x0a, 0x51, 0xe2, 0x8d, 0xf3, 0xbc, 0x51, 0xec, 0xdf, 0xb1, 0xa2, 0x5f}} , - {{0x2e, 0x68, 0xa1, 0x23, 0x7d, 0x9b, 0x40, 0x69, 0x85, 0x7b, 0x42, 0xbf, 0x90, 0x4b, 0xd6, 0x40, 0x2f, 0xd7, 0x52, 0x52, 0xb2, 0x21, 0xde, 0x64, 0xbd, 0x88, 0xc3, 0x6d, 0xa5, 0xfa, 0x81, 0x3f}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xfb, 0xfd, 0x47, 0x7b, 0x8a, 0x66, 0x9e, 0x79, 0x2e, 0x64, 0x82, 0xef, 0xf7, 0x21, 0xec, 0xf6, 0xd8, 0x86, 0x09, 0x31, 0x7c, 0xdd, 0x03, 0x6a, 0x58, 0xa0, 0x77, 0xb7, 0x9b, 0x8c, 0x87, 0x1f}} , - {{0x55, 0x47, 0xe4, 0xa8, 0x3d, 0x55, 0x21, 0x34, 0xab, 0x1d, 0xae, 0xe0, 0xf4, 0xea, 0xdb, 0xc5, 0xb9, 0x58, 0xbf, 0xc4, 0x2a, 0x89, 0x31, 0x1a, 0xf4, 0x2d, 0xe1, 0xca, 0x37, 0x99, 0x47, 0x59}}}, -{{{0xc7, 0xca, 0x63, 0xc1, 0x49, 0xa9, 0x35, 0x45, 0x55, 0x7e, 0xda, 0x64, 0x32, 0x07, 0x50, 0xf7, 0x32, 0xac, 0xde, 0x75, 0x58, 0x9b, 0x11, 0xb2, 0x3a, 0x1f, 0xf5, 0xf7, 0x79, 0x04, 0xe6, 0x08}} , - {{0x46, 0xfa, 0x22, 0x4b, 0xfa, 0xe1, 0xfe, 0x96, 0xfc, 0x67, 0xba, 0x67, 0x97, 0xc4, 0xe7, 0x1b, 0x86, 0x90, 0x5f, 0xee, 0xf4, 0x5b, 0x11, 0xb2, 0xcd, 0xad, 0xee, 0xc2, 0x48, 0x6c, 0x2b, 0x1b}}}, -{{{0xe3, 0x39, 0x62, 0xb4, 0x4f, 0x31, 0x04, 0xc9, 0xda, 0xd5, 0x73, 0x51, 0x57, 0xc5, 0xb8, 0xf3, 0xa3, 0x43, 0x70, 0xe4, 0x61, 0x81, 0x84, 0xe2, 0xbb, 0xbf, 0x4f, 0x9e, 0xa4, 0x5e, 0x74, 0x06}} , - {{0x29, 0xac, 0xff, 0x27, 0xe0, 0x59, 0xbe, 0x39, 0x9c, 0x0d, 0x83, 0xd7, 0x10, 0x0b, 0x15, 0xb7, 0xe1, 0xc2, 0x2c, 0x30, 0x73, 0x80, 0x3a, 0x7d, 0x5d, 0xab, 0x58, 0x6b, 0xc1, 0xf0, 0xf4, 0x22}}}, -{{{0xfe, 0x7f, 0xfb, 0x35, 0x7d, 0xc6, 0x01, 0x23, 0x28, 0xc4, 0x02, 0xac, 0x1f, 0x42, 0xb4, 0x9d, 0xfc, 0x00, 0x94, 0xa5, 0xee, 0xca, 0xda, 0x97, 0x09, 0x41, 0x77, 0x87, 0x5d, 0x7b, 0x87, 0x78}} , - {{0xf5, 0xfb, 0x90, 0x2d, 0x81, 0x19, 0x9e, 0x2f, 0x6d, 0x85, 0x88, 0x8c, 0x40, 0x5c, 0x77, 0x41, 0x4d, 0x01, 0x19, 0x76, 0x60, 0xe8, 0x4c, 0x48, 0xe4, 0x33, 0x83, 0x32, 0x6c, 0xb4, 0x41, 0x03}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xff, 0x10, 0xc2, 0x09, 0x4f, 0x6e, 0xf4, 0xd2, 0xdf, 0x7e, 0xca, 0x7b, 0x1c, 0x1d, 0xba, 0xa3, 0xb6, 0xda, 0x67, 0x33, 0xd4, 0x87, 0x36, 0x4b, 0x11, 0x20, 0x05, 0xa6, 0x29, 0xc1, 0x87, 0x17}} , - {{0xf6, 0x96, 0xca, 0x2f, 0xda, 0x38, 0xa7, 0x1b, 0xfc, 0xca, 0x7d, 0xfe, 0x08, 0x89, 0xe2, 0x47, 0x2b, 0x6a, 0x5d, 0x4b, 0xfa, 0xa1, 0xb4, 0xde, 0xb6, 0xc2, 0x31, 0x51, 0xf5, 0xe0, 0xa4, 0x0b}}}, -{{{0x5c, 0xe5, 0xc6, 0x04, 0x8e, 0x2b, 0x57, 0xbe, 0x38, 0x85, 0x23, 0xcb, 0xb7, 0xbe, 0x4f, 0xa9, 0xd3, 0x6e, 0x12, 0xaa, 0xd5, 0xb2, 0x2e, 0x93, 0x29, 0x9a, 0x4a, 0x88, 0x18, 0x43, 0xf5, 0x01}} , - {{0x50, 0xfc, 0xdb, 0xa2, 0x59, 0x21, 0x8d, 0xbd, 0x7e, 0x33, 0xae, 0x2f, 0x87, 0x1a, 0xd0, 0x97, 0xc7, 0x0d, 0x4d, 0x63, 0x01, 0xef, 0x05, 0x84, 0xec, 0x40, 0xdd, 0xa8, 0x0a, 0x4f, 0x70, 0x0b}}}, -{{{0x41, 0x69, 0x01, 0x67, 0x5c, 0xd3, 0x8a, 0xc5, 0xcf, 0x3f, 0xd1, 0x57, 0xd1, 0x67, 0x3e, 0x01, 0x39, 0xb5, 0xcb, 0x81, 0x56, 0x96, 0x26, 0xb6, 0xc2, 0xe7, 0x5c, 0xfb, 0x63, 0x97, 0x58, 0x06}} , - {{0x0c, 0x0e, 0xf3, 0xba, 0xf0, 0xe5, 0xba, 0xb2, 0x57, 0x77, 0xc6, 0x20, 0x9b, 0x89, 0x24, 0xbe, 0xf2, 0x9c, 0x8a, 0xba, 0x69, 0xc1, 0xf1, 0xb0, 0x4f, 0x2a, 0x05, 0x9a, 0xee, 0x10, 0x7e, 0x36}}}, -{{{0x3f, 0x26, 0xe9, 0x40, 0xe9, 0x03, 0xad, 0x06, 0x69, 0x91, 0xe0, 0xd1, 0x89, 0x60, 0x84, 0x79, 0xde, 0x27, 0x6d, 0xe6, 0x76, 0xbd, 0xea, 0xe6, 0xae, 0x48, 0xc3, 0x67, 0xc0, 0x57, 0xcd, 0x2f}} , - {{0x7f, 0xc1, 0xdc, 0xb9, 0xc7, 0xbc, 0x86, 0x3d, 0x55, 0x4b, 0x28, 0x7a, 0xfb, 0x4d, 0xc7, 0xf8, 0xbc, 0x67, 0x2a, 0x60, 0x4d, 0x8f, 0x07, 0x0b, 0x1a, 0x17, 0xbf, 0xfa, 0xac, 0xa7, 0x3d, 0x1a}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x91, 0x3f, 0xed, 0x5e, 0x18, 0x78, 0x3f, 0x23, 0x2c, 0x0d, 0x8c, 0x44, 0x00, 0xe8, 0xfb, 0xe9, 0x8e, 0xd6, 0xd1, 0x36, 0x58, 0x57, 0x9e, 0xae, 0x4b, 0x5c, 0x0b, 0x07, 0xbc, 0x6b, 0x55, 0x2b}} , - {{0x6f, 0x4d, 0x17, 0xd7, 0xe1, 0x84, 0xd9, 0x78, 0xb1, 0x90, 0xfd, 0x2e, 0xb3, 0xb5, 0x19, 0x3f, 0x1b, 0xfa, 0xc0, 0x68, 0xb3, 0xdd, 0x00, 0x2e, 0x89, 0xbd, 0x7e, 0x80, 0x32, 0x13, 0xa0, 0x7b}}}, -{{{0x1a, 0x6f, 0x40, 0xaf, 0x44, 0x44, 0xb0, 0x43, 0x8f, 0x0d, 0xd0, 0x1e, 0xc4, 0x0b, 0x19, 0x5d, 0x8e, 0xfe, 0xc1, 0xf3, 0xc5, 0x5c, 0x91, 0xf8, 0x04, 0x4e, 0xbe, 0x90, 0xb4, 0x47, 0x5c, 0x3f}} , - {{0xb0, 0x3b, 0x2c, 0xf3, 0xfe, 0x32, 0x71, 0x07, 0x3f, 0xaa, 0xba, 0x45, 0x60, 0xa8, 0x8d, 0xea, 0x54, 0xcb, 0x39, 0x10, 0xb4, 0xf2, 0x8b, 0xd2, 0x14, 0x82, 0x42, 0x07, 0x8e, 0xe9, 0x7c, 0x53}}}, -{{{0xb0, 0xae, 0xc1, 0x8d, 0xc9, 0x8f, 0xb9, 0x7a, 0x77, 0xef, 0xba, 0x79, 0xa0, 0x3c, 0xa8, 0xf5, 0x6a, 0xe2, 0x3f, 0x5d, 0x00, 0xe3, 0x4b, 0x45, 0x24, 0x7b, 0x43, 0x78, 0x55, 0x1d, 0x2b, 0x1e}} , - {{0x01, 0xb8, 0xd6, 0x16, 0x67, 0xa0, 0x15, 0xb9, 0xe1, 0x58, 0xa4, 0xa7, 0x31, 0x37, 0x77, 0x2f, 0x8b, 0x12, 0x9f, 0xf4, 0x3f, 0xc7, 0x36, 0x66, 0xd2, 0xa8, 0x56, 0xf7, 0x7f, 0x74, 0xc6, 0x41}}}, -{{{0x5d, 0xf8, 0xb4, 0xa8, 0x30, 0xdd, 0xcc, 0x38, 0xa5, 0xd3, 0xca, 0xd8, 0xd1, 0xf8, 0xb2, 0x31, 0x91, 0xd4, 0x72, 0x05, 0x57, 0x4a, 0x3b, 0x82, 0x4a, 0xc6, 0x68, 0x20, 0xe2, 0x18, 0x41, 0x61}} , - {{0x19, 0xd4, 0x8d, 0x47, 0x29, 0x12, 0x65, 0xb0, 0x11, 0x78, 0x47, 0xb5, 0xcb, 0xa3, 0xa5, 0xfa, 0x05, 0x85, 0x54, 0xa9, 0x33, 0x97, 0x8d, 0x2b, 0xc2, 0xfe, 0x99, 0x35, 0x28, 0xe5, 0xeb, 0x63}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xb1, 0x3f, 0x3f, 0xef, 0xd8, 0xf4, 0xfc, 0xb3, 0xa0, 0x60, 0x50, 0x06, 0x2b, 0x29, 0x52, 0x70, 0x15, 0x0b, 0x24, 0x24, 0xf8, 0x5f, 0x79, 0x18, 0xcc, 0xff, 0x89, 0x99, 0x84, 0xa1, 0xae, 0x13}} , - {{0x44, 0x1f, 0xb8, 0xc2, 0x01, 0xc1, 0x30, 0x19, 0x55, 0x05, 0x60, 0x10, 0xa4, 0x6c, 0x2d, 0x67, 0x70, 0xe5, 0x25, 0x1b, 0xf2, 0xbf, 0xdd, 0xfb, 0x70, 0x2b, 0xa1, 0x8c, 0x9c, 0x94, 0x84, 0x08}}}, -{{{0xe7, 0xc4, 0x43, 0x4d, 0xc9, 0x2b, 0x69, 0x5d, 0x1d, 0x3c, 0xaf, 0xbb, 0x43, 0x38, 0x4e, 0x98, 0x3d, 0xed, 0x0d, 0x21, 0x03, 0xfd, 0xf0, 0x99, 0x47, 0x04, 0xb0, 0x98, 0x69, 0x55, 0x72, 0x0f}} , - {{0x5e, 0xdf, 0x15, 0x53, 0x3b, 0x86, 0x80, 0xb0, 0xf1, 0x70, 0x68, 0x8f, 0x66, 0x7c, 0x0e, 0x49, 0x1a, 0xd8, 0x6b, 0xfe, 0x4e, 0xef, 0xca, 0x47, 0xd4, 0x03, 0xc1, 0x37, 0x50, 0x9c, 0xc1, 0x16}}}, -{{{0xcd, 0x24, 0xc6, 0x3e, 0x0c, 0x82, 0x9b, 0x91, 0x2b, 0x61, 0x4a, 0xb2, 0x0f, 0x88, 0x55, 0x5f, 0x5a, 0x57, 0xff, 0xe5, 0x74, 0x0b, 0x13, 0x43, 0x00, 0xd8, 0x6b, 0xcf, 0xd2, 0x15, 0x03, 0x2c}} , - {{0xdc, 0xff, 0x15, 0x61, 0x2f, 0x4a, 0x2f, 0x62, 0xf2, 0x04, 0x2f, 0xb5, 0x0c, 0xb7, 0x1e, 0x3f, 0x74, 0x1a, 0x0f, 0xd7, 0xea, 0xcd, 0xd9, 0x7d, 0xf6, 0x12, 0x0e, 0x2f, 0xdb, 0x5a, 0x3b, 0x16}}}, -{{{0x1b, 0x37, 0x47, 0xe3, 0xf5, 0x9e, 0xea, 0x2c, 0x2a, 0xe7, 0x82, 0x36, 0xf4, 0x1f, 0x81, 0x47, 0x92, 0x4b, 0x69, 0x0e, 0x11, 0x8c, 0x5d, 0x53, 0x5b, 0x81, 0x27, 0x08, 0xbc, 0xa0, 0xae, 0x25}} , - {{0x69, 0x32, 0xa1, 0x05, 0x11, 0x42, 0x00, 0xd2, 0x59, 0xac, 0x4d, 0x62, 0x8b, 0x13, 0xe2, 0x50, 0x5d, 0xa0, 0x9d, 0x9b, 0xfd, 0xbb, 0x12, 0x41, 0x75, 0x41, 0x9e, 0xcc, 0xdc, 0xc7, 0xdc, 0x5d}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xd9, 0xe3, 0x38, 0x06, 0x46, 0x70, 0x82, 0x5e, 0x28, 0x49, 0x79, 0xff, 0x25, 0xd2, 0x4e, 0x29, 0x8d, 0x06, 0xb0, 0x23, 0xae, 0x9b, 0x66, 0xe4, 0x7d, 0xc0, 0x70, 0x91, 0xa3, 0xfc, 0xec, 0x4e}} , - {{0x62, 0x12, 0x37, 0x6a, 0x30, 0xf6, 0x1e, 0xfb, 0x14, 0x5c, 0x0d, 0x0e, 0xb7, 0x81, 0x6a, 0xe7, 0x08, 0x05, 0xac, 0xaa, 0x38, 0x46, 0xe2, 0x73, 0xea, 0x4b, 0x07, 0x81, 0x43, 0x7c, 0x9e, 0x5e}}}, -{{{0xfc, 0xf9, 0x21, 0x4f, 0x2e, 0x76, 0x9b, 0x1f, 0x28, 0x60, 0x77, 0x43, 0x32, 0x9d, 0xbe, 0x17, 0x30, 0x2a, 0xc6, 0x18, 0x92, 0x66, 0x62, 0x30, 0x98, 0x40, 0x11, 0xa6, 0x7f, 0x18, 0x84, 0x28}} , - {{0x3f, 0xab, 0xd3, 0xf4, 0x8a, 0x76, 0xa1, 0x3c, 0xca, 0x2d, 0x49, 0xc3, 0xea, 0x08, 0x0b, 0x85, 0x17, 0x2a, 0xc3, 0x6c, 0x08, 0xfd, 0x57, 0x9f, 0x3d, 0x5f, 0xdf, 0x67, 0x68, 0x42, 0x00, 0x32}}}, -{{{0x51, 0x60, 0x1b, 0x06, 0x4f, 0x8a, 0x21, 0xba, 0x38, 0xa8, 0xba, 0xd6, 0x40, 0xf6, 0xe9, 0x9b, 0x76, 0x4d, 0x56, 0x21, 0x5b, 0x0a, 0x9b, 0x2e, 0x4f, 0x3d, 0x81, 0x32, 0x08, 0x9f, 0x97, 0x5b}} , - {{0xe5, 0x44, 0xec, 0x06, 0x9d, 0x90, 0x79, 0x9f, 0xd3, 0xe0, 0x79, 0xaf, 0x8f, 0x10, 0xfd, 0xdd, 0x04, 0xae, 0x27, 0x97, 0x46, 0x33, 0x79, 0xea, 0xb8, 0x4e, 0xca, 0x5a, 0x59, 0x57, 0xe1, 0x0e}}}, -{{{0x1a, 0xda, 0xf3, 0xa5, 0x41, 0x43, 0x28, 0xfc, 0x7e, 0xe7, 0x71, 0xea, 0xc6, 0x3b, 0x59, 0xcc, 0x2e, 0xd3, 0x40, 0xec, 0xb3, 0x13, 0x6f, 0x44, 0xcd, 0x13, 0xb2, 0x37, 0xf2, 0x6e, 0xd9, 0x1c}} , - {{0xe3, 0xdb, 0x60, 0xcd, 0x5c, 0x4a, 0x18, 0x0f, 0xef, 0x73, 0x36, 0x71, 0x8c, 0xf6, 0x11, 0xb4, 0xd8, 0xce, 0x17, 0x5e, 0x4f, 0x26, 0x77, 0x97, 0x5f, 0xcb, 0xef, 0x91, 0xeb, 0x6a, 0x62, 0x7a}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x18, 0x4a, 0xa2, 0x97, 0x08, 0x81, 0x2d, 0x83, 0xc4, 0xcc, 0xf0, 0x83, 0x7e, 0xec, 0x0d, 0x95, 0x4c, 0x5b, 0xfb, 0xfa, 0x98, 0x80, 0x4a, 0x66, 0x56, 0x0c, 0x51, 0xb3, 0xf2, 0x04, 0x5d, 0x27}} , - {{0x3b, 0xb9, 0xb8, 0x06, 0x5a, 0x2e, 0xfe, 0xc3, 0x82, 0x37, 0x9c, 0xa3, 0x11, 0x1f, 0x9c, 0xa6, 0xda, 0x63, 0x48, 0x9b, 0xad, 0xde, 0x2d, 0xa6, 0xbc, 0x6e, 0x32, 0xda, 0x27, 0x65, 0xdd, 0x57}}}, -{{{0x84, 0x4f, 0x37, 0x31, 0x7d, 0x2e, 0xbc, 0xad, 0x87, 0x07, 0x2a, 0x6b, 0x37, 0xfc, 0x5f, 0xeb, 0x4e, 0x75, 0x35, 0xa6, 0xde, 0xab, 0x0a, 0x19, 0x3a, 0xb7, 0xb1, 0xef, 0x92, 0x6a, 0x3b, 0x3c}} , - {{0x3b, 0xb2, 0x94, 0x6d, 0x39, 0x60, 0xac, 0xee, 0xe7, 0x81, 0x1a, 0x3b, 0x76, 0x87, 0x5c, 0x05, 0x94, 0x2a, 0x45, 0xb9, 0x80, 0xe9, 0x22, 0xb1, 0x07, 0xcb, 0x40, 0x9e, 0x70, 0x49, 0x6d, 0x12}}}, -{{{0xfd, 0x18, 0x78, 0x84, 0xa8, 0x4c, 0x7d, 0x6e, 0x59, 0xa6, 0xe5, 0x74, 0xf1, 0x19, 0xa6, 0x84, 0x2e, 0x51, 0xc1, 0x29, 0x13, 0xf2, 0x14, 0x6b, 0x5d, 0x53, 0x51, 0xf7, 0xef, 0xbf, 0x01, 0x22}} , - {{0xa4, 0x4b, 0x62, 0x4c, 0xe6, 0xfd, 0x72, 0x07, 0xf2, 0x81, 0xfc, 0xf2, 0xbd, 0x12, 0x7c, 0x68, 0x76, 0x2a, 0xba, 0xf5, 0x65, 0xb1, 0x1f, 0x17, 0x0a, 0x38, 0xb0, 0xbf, 0xc0, 0xf8, 0xf4, 0x2a}}}, -{{{0x55, 0x60, 0x55, 0x5b, 0xe4, 0x1d, 0x71, 0x4c, 0x9d, 0x5b, 0x9f, 0x70, 0xa6, 0x85, 0x9a, 0x2c, 0xa0, 0xe2, 0x32, 0x48, 0xce, 0x9e, 0x2a, 0xa5, 0x07, 0x3b, 0xc7, 0x6c, 0x86, 0x77, 0xde, 0x3c}} , - {{0xf7, 0x18, 0x7a, 0x96, 0x7e, 0x43, 0x57, 0xa9, 0x55, 0xfc, 0x4e, 0xb6, 0x72, 0x00, 0xf2, 0xe4, 0xd7, 0x52, 0xd3, 0xd3, 0xb6, 0x85, 0xf6, 0x71, 0xc7, 0x44, 0x3f, 0x7f, 0xd7, 0xb3, 0xf2, 0x79}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x46, 0xca, 0xa7, 0x55, 0x7b, 0x79, 0xf3, 0xca, 0x5a, 0x65, 0xf6, 0xed, 0x50, 0x14, 0x7b, 0xe4, 0xc4, 0x2a, 0x65, 0x9e, 0xe2, 0xf9, 0xca, 0xa7, 0x22, 0x26, 0x53, 0xcb, 0x21, 0x5b, 0xa7, 0x31}} , - {{0x90, 0xd7, 0xc5, 0x26, 0x08, 0xbd, 0xb0, 0x53, 0x63, 0x58, 0xc3, 0x31, 0x5e, 0x75, 0x46, 0x15, 0x91, 0xa6, 0xf8, 0x2f, 0x1a, 0x08, 0x65, 0x88, 0x2f, 0x98, 0x04, 0xf1, 0x7c, 0x6e, 0x00, 0x77}}}, -{{{0x81, 0x21, 0x61, 0x09, 0xf6, 0x4e, 0xf1, 0x92, 0xee, 0x63, 0x61, 0x73, 0x87, 0xc7, 0x54, 0x0e, 0x42, 0x4b, 0xc9, 0x47, 0xd1, 0xb8, 0x7e, 0x91, 0x75, 0x37, 0x99, 0x28, 0xb8, 0xdd, 0x7f, 0x50}} , - {{0x89, 0x8f, 0xc0, 0xbe, 0x5d, 0xd6, 0x9f, 0xa0, 0xf0, 0x9d, 0x81, 0xce, 0x3a, 0x7b, 0x98, 0x58, 0xbb, 0xd7, 0x78, 0xc8, 0x3f, 0x13, 0xf1, 0x74, 0x19, 0xdf, 0xf8, 0x98, 0x89, 0x5d, 0xfa, 0x5f}}}, -{{{0x9e, 0x35, 0x85, 0x94, 0x47, 0x1f, 0x90, 0x15, 0x26, 0xd0, 0x84, 0xed, 0x8a, 0x80, 0xf7, 0x63, 0x42, 0x86, 0x27, 0xd7, 0xf4, 0x75, 0x58, 0xdc, 0x9c, 0xc0, 0x22, 0x7e, 0x20, 0x35, 0xfd, 0x1f}} , - {{0x68, 0x0e, 0x6f, 0x97, 0xba, 0x70, 0xbb, 0xa3, 0x0e, 0xe5, 0x0b, 0x12, 0xf4, 0xa2, 0xdc, 0x47, 0xf8, 0xe6, 0xd0, 0x23, 0x6c, 0x33, 0xa8, 0x99, 0x46, 0x6e, 0x0f, 0x44, 0xba, 0x76, 0x48, 0x0f}}}, -{{{0xa3, 0x2a, 0x61, 0x37, 0xe2, 0x59, 0x12, 0x0e, 0x27, 0xba, 0x64, 0x43, 0xae, 0xc0, 0x42, 0x69, 0x79, 0xa4, 0x1e, 0x29, 0x8b, 0x15, 0xeb, 0xf8, 0xaf, 0xd4, 0xa2, 0x68, 0x33, 0xb5, 0x7a, 0x24}} , - {{0x2c, 0x19, 0x33, 0xdd, 0x1b, 0xab, 0xec, 0x01, 0xb0, 0x23, 0xf8, 0x42, 0x2b, 0x06, 0x88, 0xea, 0x3d, 0x2d, 0x00, 0x2a, 0x78, 0x45, 0x4d, 0x38, 0xed, 0x2e, 0x2e, 0x44, 0x49, 0xed, 0xcb, 0x33}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xa0, 0x68, 0xe8, 0x41, 0x8f, 0x91, 0xf8, 0x11, 0x13, 0x90, 0x2e, 0xa7, 0xab, 0x30, 0xef, 0xad, 0xa0, 0x61, 0x00, 0x88, 0xef, 0xdb, 0xce, 0x5b, 0x5c, 0xbb, 0x62, 0xc8, 0x56, 0xf9, 0x00, 0x73}} , - {{0x3f, 0x60, 0xc1, 0x82, 0x2d, 0xa3, 0x28, 0x58, 0x24, 0x9e, 0x9f, 0xe3, 0x70, 0xcc, 0x09, 0x4e, 0x1a, 0x3f, 0x11, 0x11, 0x15, 0x07, 0x3c, 0xa4, 0x41, 0xe0, 0x65, 0xa3, 0x0a, 0x41, 0x6d, 0x11}}}, -{{{0x31, 0x40, 0x01, 0x52, 0x56, 0x94, 0x5b, 0x28, 0x8a, 0xaa, 0x52, 0xee, 0xd8, 0x0a, 0x05, 0x8d, 0xcd, 0xb5, 0xaa, 0x2e, 0x38, 0xaa, 0xb7, 0x87, 0xf7, 0x2b, 0xfb, 0x04, 0xcb, 0x84, 0x3d, 0x54}} , - {{0x20, 0xef, 0x59, 0xde, 0xa4, 0x2b, 0x93, 0x6e, 0x2e, 0xec, 0x42, 0x9a, 0xd4, 0x2d, 0xf4, 0x46, 0x58, 0x27, 0x2b, 0x18, 0x8f, 0x83, 0x3d, 0x69, 0x9e, 0xd4, 0x3e, 0xb6, 0xc5, 0xfd, 0x58, 0x03}}}, -{{{0x33, 0x89, 0xc9, 0x63, 0x62, 0x1c, 0x17, 0xb4, 0x60, 0xc4, 0x26, 0x68, 0x09, 0xc3, 0x2e, 0x37, 0x0f, 0x7b, 0xb4, 0x9c, 0xb6, 0xf9, 0xfb, 0xd4, 0x51, 0x78, 0xc8, 0x63, 0xea, 0x77, 0x47, 0x07}} , - {{0x32, 0xb4, 0x18, 0x47, 0x79, 0xcb, 0xd4, 0x5a, 0x07, 0x14, 0x0f, 0xa0, 0xd5, 0xac, 0xd0, 0x41, 0x40, 0xab, 0x61, 0x23, 0xe5, 0x2a, 0x2a, 0x6f, 0xf7, 0xa8, 0xd4, 0x76, 0xef, 0xe7, 0x45, 0x6c}}}, -{{{0xa1, 0x5e, 0x60, 0x4f, 0xfb, 0xe1, 0x70, 0x6a, 0x1f, 0x55, 0x4f, 0x09, 0xb4, 0x95, 0x33, 0x36, 0xc6, 0x81, 0x01, 0x18, 0x06, 0x25, 0x27, 0xa4, 0xb4, 0x24, 0xa4, 0x86, 0x03, 0x4c, 0xac, 0x02}} , - {{0x77, 0x38, 0xde, 0xd7, 0x60, 0x48, 0x07, 0xf0, 0x74, 0xa8, 0xff, 0x54, 0xe5, 0x30, 0x43, 0xff, 0x77, 0xfb, 0x21, 0x07, 0xff, 0xb2, 0x07, 0x6b, 0xe4, 0xe5, 0x30, 0xfc, 0x19, 0x6c, 0xa3, 0x01}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x13, 0xc5, 0x2c, 0xac, 0xd3, 0x83, 0x82, 0x7c, 0x29, 0xf7, 0x05, 0xa5, 0x00, 0xb6, 0x1f, 0x86, 0x55, 0xf4, 0xd6, 0x2f, 0x0c, 0x99, 0xd0, 0x65, 0x9b, 0x6b, 0x46, 0x0d, 0x43, 0xf8, 0x16, 0x28}} , - {{0x1e, 0x7f, 0xb4, 0x74, 0x7e, 0xb1, 0x89, 0x4f, 0x18, 0x5a, 0xab, 0x64, 0x06, 0xdf, 0x45, 0x87, 0xe0, 0x6a, 0xc6, 0xf0, 0x0e, 0xc9, 0x24, 0x35, 0x38, 0xea, 0x30, 0x54, 0xb4, 0xc4, 0x52, 0x54}}}, -{{{0xe9, 0x9f, 0xdc, 0x3f, 0xc1, 0x89, 0x44, 0x74, 0x27, 0xe4, 0xc1, 0x90, 0xff, 0x4a, 0xa7, 0x3c, 0xee, 0xcd, 0xf4, 0x1d, 0x25, 0x94, 0x7f, 0x63, 0x16, 0x48, 0xbc, 0x64, 0xfe, 0x95, 0xc4, 0x0c}} , - {{0x8b, 0x19, 0x75, 0x6e, 0x03, 0x06, 0x5e, 0x6a, 0x6f, 0x1a, 0x8c, 0xe3, 0xd3, 0x28, 0xf2, 0xe0, 0xb9, 0x7a, 0x43, 0x69, 0xe6, 0xd3, 0xc0, 0xfe, 0x7e, 0x97, 0xab, 0x6c, 0x7b, 0x8e, 0x13, 0x42}}}, -{{{0xd4, 0xca, 0x70, 0x3d, 0xab, 0xfb, 0x5f, 0x5e, 0x00, 0x0c, 0xcc, 0x77, 0x22, 0xf8, 0x78, 0x55, 0xae, 0x62, 0x35, 0xfb, 0x9a, 0xc6, 0x03, 0xe4, 0x0c, 0xee, 0xab, 0xc7, 0xc0, 0x89, 0x87, 0x54}} , - {{0x32, 0xad, 0xae, 0x85, 0x58, 0x43, 0xb8, 0xb1, 0xe6, 0x3e, 0x00, 0x9c, 0x78, 0x88, 0x56, 0xdb, 0x9c, 0xfc, 0x79, 0xf6, 0xf9, 0x41, 0x5f, 0xb7, 0xbc, 0x11, 0xf9, 0x20, 0x36, 0x1c, 0x53, 0x2b}}}, -{{{0x5a, 0x20, 0x5b, 0xa1, 0xa5, 0x44, 0x91, 0x24, 0x02, 0x63, 0x12, 0x64, 0xb8, 0x55, 0xf6, 0xde, 0x2c, 0xdb, 0x47, 0xb8, 0xc6, 0x0a, 0xc3, 0x00, 0x78, 0x93, 0xd8, 0xf5, 0xf5, 0x18, 0x28, 0x0a}} , - {{0xd6, 0x1b, 0x9a, 0x6c, 0xe5, 0x46, 0xea, 0x70, 0x96, 0x8d, 0x4e, 0x2a, 0x52, 0x21, 0x26, 0x4b, 0xb1, 0xbb, 0x0f, 0x7c, 0xa9, 0x9b, 0x04, 0xbb, 0x51, 0x08, 0xf1, 0x9a, 0xa4, 0x76, 0x7c, 0x18}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xfa, 0x94, 0xf7, 0x40, 0xd0, 0xd7, 0xeb, 0xa9, 0x82, 0x36, 0xd5, 0x15, 0xb9, 0x33, 0x7a, 0xbf, 0x8a, 0xf2, 0x63, 0xaa, 0x37, 0xf5, 0x59, 0xac, 0xbd, 0xbb, 0x32, 0x36, 0xbe, 0x73, 0x99, 0x38}} , - {{0x2c, 0xb3, 0xda, 0x7a, 0xd8, 0x3d, 0x99, 0xca, 0xd2, 0xf4, 0xda, 0x99, 0x8e, 0x4f, 0x98, 0xb7, 0xf4, 0xae, 0x3e, 0x9f, 0x8e, 0x35, 0x60, 0xa4, 0x33, 0x75, 0xa4, 0x04, 0x93, 0xb1, 0x6b, 0x4d}}}, -{{{0x97, 0x9d, 0xa8, 0xcd, 0x97, 0x7b, 0x9d, 0xb9, 0xe7, 0xa5, 0xef, 0xfd, 0xa8, 0x42, 0x6b, 0xc3, 0x62, 0x64, 0x7d, 0xa5, 0x1b, 0xc9, 0x9e, 0xd2, 0x45, 0xb9, 0xee, 0x03, 0xb0, 0xbf, 0xc0, 0x68}} , - {{0xed, 0xb7, 0x84, 0x2c, 0xf6, 0xd3, 0xa1, 0x6b, 0x24, 0x6d, 0x87, 0x56, 0x97, 0x59, 0x79, 0x62, 0x9f, 0xac, 0xed, 0xf3, 0xc9, 0x89, 0x21, 0x2e, 0x04, 0xb3, 0xcc, 0x2f, 0xbe, 0xd6, 0x0a, 0x4b}}}, -{{{0x39, 0x61, 0x05, 0xed, 0x25, 0x89, 0x8b, 0x5d, 0x1b, 0xcb, 0x0c, 0x55, 0xf4, 0x6a, 0x00, 0x8a, 0x46, 0xe8, 0x1e, 0xc6, 0x83, 0xc8, 0x5a, 0x76, 0xdb, 0xcc, 0x19, 0x7a, 0xcc, 0x67, 0x46, 0x0b}} , - {{0x53, 0xcf, 0xc2, 0xa1, 0xad, 0x6a, 0xf3, 0xcd, 0x8f, 0xc9, 0xde, 0x1c, 0xf8, 0x6c, 0x8f, 0xf8, 0x76, 0x42, 0xe7, 0xfe, 0xb2, 0x72, 0x21, 0x0a, 0x66, 0x74, 0x8f, 0xb7, 0xeb, 0xe4, 0x6f, 0x01}}}, -{{{0x22, 0x8c, 0x6b, 0xbe, 0xfc, 0x4d, 0x70, 0x62, 0x6e, 0x52, 0x77, 0x99, 0x88, 0x7e, 0x7b, 0x57, 0x7a, 0x0d, 0xfe, 0xdc, 0x72, 0x92, 0xf1, 0x68, 0x1d, 0x97, 0xd7, 0x7c, 0x8d, 0x53, 0x10, 0x37}} , - {{0x53, 0x88, 0x77, 0x02, 0xca, 0x27, 0xa8, 0xe5, 0x45, 0xe2, 0xa8, 0x48, 0x2a, 0xab, 0x18, 0xca, 0xea, 0x2d, 0x2a, 0x54, 0x17, 0x37, 0x32, 0x09, 0xdc, 0xe0, 0x4a, 0xb7, 0x7d, 0x82, 0x10, 0x7d}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x8a, 0x64, 0x1e, 0x14, 0x0a, 0x57, 0xd4, 0xda, 0x5c, 0x96, 0x9b, 0x01, 0x4c, 0x67, 0xbf, 0x8b, 0x30, 0xfe, 0x08, 0xdb, 0x0d, 0xd5, 0xa8, 0xd7, 0x09, 0x11, 0x85, 0xa2, 0xd3, 0x45, 0xfb, 0x7e}} , - {{0xda, 0x8c, 0xc2, 0xd0, 0xac, 0x18, 0xe8, 0x52, 0x36, 0xd4, 0x21, 0xa3, 0xdd, 0x57, 0x22, 0x79, 0xb7, 0xf8, 0x71, 0x9d, 0xc6, 0x91, 0x70, 0x86, 0x56, 0xbf, 0xa1, 0x11, 0x8b, 0x19, 0xe1, 0x0f}}}, -{{{0x18, 0x32, 0x98, 0x2c, 0x8f, 0x91, 0xae, 0x12, 0xf0, 0x8c, 0xea, 0xf3, 0x3c, 0xb9, 0x5d, 0xe4, 0x69, 0xed, 0xb2, 0x47, 0x18, 0xbd, 0xce, 0x16, 0x52, 0x5c, 0x23, 0xe2, 0xa5, 0x25, 0x52, 0x5d}} , - {{0xb9, 0xb1, 0xe7, 0x5d, 0x4e, 0xbc, 0xee, 0xbb, 0x40, 0x81, 0x77, 0x82, 0x19, 0xab, 0xb5, 0xc6, 0xee, 0xab, 0x5b, 0x6b, 0x63, 0x92, 0x8a, 0x34, 0x8d, 0xcd, 0xee, 0x4f, 0x49, 0xe5, 0xc9, 0x7e}}}, -{{{0x21, 0xac, 0x8b, 0x22, 0xcd, 0xc3, 0x9a, 0xe9, 0x5e, 0x78, 0xbd, 0xde, 0xba, 0xad, 0xab, 0xbf, 0x75, 0x41, 0x09, 0xc5, 0x58, 0xa4, 0x7d, 0x92, 0xb0, 0x7f, 0xf2, 0xa1, 0xd1, 0xc0, 0xb3, 0x6d}} , - {{0x62, 0x4f, 0xd0, 0x75, 0x77, 0xba, 0x76, 0x77, 0xd7, 0xb8, 0xd8, 0x92, 0x6f, 0x98, 0x34, 0x3d, 0xd6, 0x4e, 0x1c, 0x0f, 0xf0, 0x8f, 0x2e, 0xf1, 0xb3, 0xbd, 0xb1, 0xb9, 0xec, 0x99, 0xb4, 0x07}}}, -{{{0x60, 0x57, 0x2e, 0x9a, 0x72, 0x1d, 0x6b, 0x6e, 0x58, 0x33, 0x24, 0x8c, 0x48, 0x39, 0x46, 0x8e, 0x89, 0x6a, 0x88, 0x51, 0x23, 0x62, 0xb5, 0x32, 0x09, 0x36, 0xe3, 0x57, 0xf5, 0x98, 0xde, 0x6f}} , - {{0x8b, 0x2c, 0x00, 0x48, 0x4a, 0xf9, 0x5b, 0x87, 0x69, 0x52, 0xe5, 0x5b, 0xd1, 0xb1, 0xe5, 0x25, 0x25, 0xe0, 0x9c, 0xc2, 0x13, 0x44, 0xe8, 0xb9, 0x0a, 0x70, 0xad, 0xbd, 0x0f, 0x51, 0x94, 0x69}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xa2, 0xdc, 0xab, 0xa9, 0x25, 0x2d, 0xac, 0x5f, 0x03, 0x33, 0x08, 0xe7, 0x7e, 0xfe, 0x95, 0x36, 0x3c, 0x5b, 0x3a, 0xd3, 0x05, 0x82, 0x1c, 0x95, 0x2d, 0xd8, 0x77, 0x7e, 0x02, 0xd9, 0x5b, 0x70}} , - {{0xc2, 0xfe, 0x1b, 0x0c, 0x67, 0xcd, 0xd6, 0xe0, 0x51, 0x8e, 0x2c, 0xe0, 0x79, 0x88, 0xf0, 0xcf, 0x41, 0x4a, 0xad, 0x23, 0xd4, 0x46, 0xca, 0x94, 0xa1, 0xc3, 0xeb, 0x28, 0x06, 0xfa, 0x17, 0x14}}}, -{{{0x7b, 0xaa, 0x70, 0x0a, 0x4b, 0xfb, 0xf5, 0xbf, 0x80, 0xc5, 0xcf, 0x08, 0x7a, 0xdd, 0xa1, 0xf4, 0x9d, 0x54, 0x50, 0x53, 0x23, 0x77, 0x23, 0xf5, 0x34, 0xa5, 0x22, 0xd1, 0x0d, 0x96, 0x2e, 0x47}} , - {{0xcc, 0xb7, 0x32, 0x89, 0x57, 0xd0, 0x98, 0x75, 0xe4, 0x37, 0x99, 0xa9, 0xe8, 0xba, 0xed, 0xba, 0xeb, 0xc7, 0x4f, 0x15, 0x76, 0x07, 0x0c, 0x4c, 0xef, 0x9f, 0x52, 0xfc, 0x04, 0x5d, 0x58, 0x10}}}, -{{{0xce, 0x82, 0xf0, 0x8f, 0x79, 0x02, 0xa8, 0xd1, 0xda, 0x14, 0x09, 0x48, 0xee, 0x8a, 0x40, 0x98, 0x76, 0x60, 0x54, 0x5a, 0xde, 0x03, 0x24, 0xf5, 0xe6, 0x2f, 0xe1, 0x03, 0xbf, 0x68, 0x82, 0x7f}} , - {{0x64, 0xe9, 0x28, 0xc7, 0xa4, 0xcf, 0x2a, 0xf9, 0x90, 0x64, 0x72, 0x2c, 0x8b, 0xeb, 0xec, 0xa0, 0xf2, 0x7d, 0x35, 0xb5, 0x90, 0x4d, 0x7f, 0x5b, 0x4a, 0x49, 0xe4, 0xb8, 0x3b, 0xc8, 0xa1, 0x2f}}}, -{{{0x8b, 0xc5, 0xcc, 0x3d, 0x69, 0xa6, 0xa1, 0x18, 0x44, 0xbc, 0x4d, 0x77, 0x37, 0xc7, 0x86, 0xec, 0x0c, 0xc9, 0xd6, 0x44, 0xa9, 0x23, 0x27, 0xb9, 0x03, 0x34, 0xa7, 0x0a, 0xd5, 0xc7, 0x34, 0x37}} , - {{0xf9, 0x7e, 0x3e, 0x66, 0xee, 0xf9, 0x99, 0x28, 0xff, 0xad, 0x11, 0xd8, 0xe2, 0x66, 0xc5, 0xcd, 0x0f, 0x0d, 0x0b, 0x6a, 0xfc, 0x7c, 0x24, 0xa8, 0x4f, 0xa8, 0x5e, 0x80, 0x45, 0x8b, 0x6c, 0x41}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xef, 0x1e, 0xec, 0xf7, 0x8d, 0x77, 0xf2, 0xea, 0xdb, 0x60, 0x03, 0x21, 0xc0, 0xff, 0x5e, 0x67, 0xc3, 0x71, 0x0b, 0x21, 0xb4, 0x41, 0xa0, 0x68, 0x38, 0xc6, 0x01, 0xa3, 0xd3, 0x51, 0x3c, 0x3c}} , - {{0x92, 0xf8, 0xd6, 0x4b, 0xef, 0x42, 0x13, 0xb2, 0x4a, 0xc4, 0x2e, 0x72, 0x3f, 0xc9, 0x11, 0xbd, 0x74, 0x02, 0x0e, 0xf5, 0x13, 0x9d, 0x83, 0x1a, 0x1b, 0xd5, 0x54, 0xde, 0xc4, 0x1e, 0x16, 0x6c}}}, -{{{0x27, 0x52, 0xe4, 0x63, 0xaa, 0x94, 0xe6, 0xc3, 0x28, 0x9c, 0xc6, 0x56, 0xac, 0xfa, 0xb6, 0xbd, 0xe2, 0xcc, 0x76, 0xc6, 0x27, 0x27, 0xa2, 0x8e, 0x78, 0x2b, 0x84, 0x72, 0x10, 0xbd, 0x4e, 0x2a}} , - {{0xea, 0xa7, 0x23, 0xef, 0x04, 0x61, 0x80, 0x50, 0xc9, 0x6e, 0xa5, 0x96, 0xd1, 0xd1, 0xc8, 0xc3, 0x18, 0xd7, 0x2d, 0xfd, 0x26, 0xbd, 0xcb, 0x7b, 0x92, 0x51, 0x0e, 0x4a, 0x65, 0x57, 0xb8, 0x49}}}, -{{{0xab, 0x55, 0x36, 0xc3, 0xec, 0x63, 0x55, 0x11, 0x55, 0xf6, 0xa5, 0xc7, 0x01, 0x5f, 0xfe, 0x79, 0xd8, 0x0a, 0xf7, 0x03, 0xd8, 0x98, 0x99, 0xf5, 0xd0, 0x00, 0x54, 0x6b, 0x66, 0x28, 0xf5, 0x25}} , - {{0x7a, 0x8d, 0xa1, 0x5d, 0x70, 0x5d, 0x51, 0x27, 0xee, 0x30, 0x65, 0x56, 0x95, 0x46, 0xde, 0xbd, 0x03, 0x75, 0xb4, 0x57, 0x59, 0x89, 0xeb, 0x02, 0x9e, 0xcc, 0x89, 0x19, 0xa7, 0xcb, 0x17, 0x67}}}, -{{{0x6a, 0xeb, 0xfc, 0x9a, 0x9a, 0x10, 0xce, 0xdb, 0x3a, 0x1c, 0x3c, 0x6a, 0x9d, 0xea, 0x46, 0xbc, 0x45, 0x49, 0xac, 0xe3, 0x41, 0x12, 0x7c, 0xf0, 0xf7, 0x4f, 0xf9, 0xf7, 0xff, 0x2c, 0x89, 0x04}} , - {{0x30, 0x31, 0x54, 0x1a, 0x46, 0xca, 0xe6, 0xc6, 0xcb, 0xe2, 0xc3, 0xc1, 0x8b, 0x75, 0x81, 0xbe, 0xee, 0xf8, 0xa3, 0x11, 0x1c, 0x25, 0xa3, 0xa7, 0x35, 0x51, 0x55, 0xe2, 0x25, 0xaa, 0xe2, 0x3a}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xb4, 0x48, 0x10, 0x9f, 0x8a, 0x09, 0x76, 0xfa, 0xf0, 0x7a, 0xb0, 0x70, 0xf7, 0x83, 0x80, 0x52, 0x84, 0x2b, 0x26, 0xa2, 0xc4, 0x5d, 0x4f, 0xba, 0xb1, 0xc8, 0x40, 0x0d, 0x78, 0x97, 0xc4, 0x60}} , - {{0xd4, 0xb1, 0x6c, 0x08, 0xc7, 0x40, 0x38, 0x73, 0x5f, 0x0b, 0xf3, 0x76, 0x5d, 0xb2, 0xa5, 0x2f, 0x57, 0x57, 0x07, 0xed, 0x08, 0xa2, 0x6c, 0x4f, 0x08, 0x02, 0xb5, 0x0e, 0xee, 0x44, 0xfa, 0x22}}}, -{{{0x0f, 0x00, 0x3f, 0xa6, 0x04, 0x19, 0x56, 0x65, 0x31, 0x7f, 0x8b, 0xeb, 0x0d, 0xe1, 0x47, 0x89, 0x97, 0x16, 0x53, 0xfa, 0x81, 0xa7, 0xaa, 0xb2, 0xbf, 0x67, 0xeb, 0x72, 0x60, 0x81, 0x0d, 0x48}} , - {{0x7e, 0x13, 0x33, 0xcd, 0xa8, 0x84, 0x56, 0x1e, 0x67, 0xaf, 0x6b, 0x43, 0xac, 0x17, 0xaf, 0x16, 0xc0, 0x52, 0x99, 0x49, 0x5b, 0x87, 0x73, 0x7e, 0xb5, 0x43, 0xda, 0x6b, 0x1d, 0x0f, 0x2d, 0x55}}}, -{{{0xe9, 0x58, 0x1f, 0xff, 0x84, 0x3f, 0x93, 0x1c, 0xcb, 0xe1, 0x30, 0x69, 0xa5, 0x75, 0x19, 0x7e, 0x14, 0x5f, 0xf8, 0xfc, 0x09, 0xdd, 0xa8, 0x78, 0x9d, 0xca, 0x59, 0x8b, 0xd1, 0x30, 0x01, 0x13}} , - {{0xff, 0x76, 0x03, 0xc5, 0x4b, 0x89, 0x99, 0x70, 0x00, 0x59, 0x70, 0x9c, 0xd5, 0xd9, 0x11, 0x89, 0x5a, 0x46, 0xfe, 0xef, 0xdc, 0xd9, 0x55, 0x2b, 0x45, 0xa7, 0xb0, 0x2d, 0xfb, 0x24, 0xc2, 0x29}}}, -{{{0x38, 0x06, 0xf8, 0x0b, 0xac, 0x82, 0xc4, 0x97, 0x2b, 0x90, 0xe0, 0xf7, 0xa8, 0xab, 0x6c, 0x08, 0x80, 0x66, 0x90, 0x46, 0xf7, 0x26, 0x2d, 0xf8, 0xf1, 0xc4, 0x6b, 0x4a, 0x82, 0x98, 0x8e, 0x37}} , - {{0x8e, 0xb4, 0xee, 0xb8, 0xd4, 0x3f, 0xb2, 0x1b, 0xe0, 0x0a, 0x3d, 0x75, 0x34, 0x28, 0xa2, 0x8e, 0xc4, 0x92, 0x7b, 0xfe, 0x60, 0x6e, 0x6d, 0xb8, 0x31, 0x1d, 0x62, 0x0d, 0x78, 0x14, 0x42, 0x11}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x5e, 0xa8, 0xd8, 0x04, 0x9b, 0x73, 0xc9, 0xc9, 0xdc, 0x0d, 0x73, 0xbf, 0x0a, 0x0a, 0x73, 0xff, 0x18, 0x1f, 0x9c, 0x51, 0xaa, 0xc6, 0xf1, 0x83, 0x25, 0xfd, 0xab, 0xa3, 0x11, 0xd3, 0x01, 0x24}} , - {{0x4d, 0xe3, 0x7e, 0x38, 0x62, 0x5e, 0x64, 0xbb, 0x2b, 0x53, 0xb5, 0x03, 0x68, 0xc4, 0xf2, 0x2b, 0x5a, 0x03, 0x32, 0x99, 0x4a, 0x41, 0x9a, 0xe1, 0x1a, 0xae, 0x8c, 0x48, 0xf3, 0x24, 0x32, 0x65}}}, -{{{0xe8, 0xdd, 0xad, 0x3a, 0x8c, 0xea, 0xf4, 0xb3, 0xb2, 0xe5, 0x73, 0xf2, 0xed, 0x8b, 0xbf, 0xed, 0xb1, 0x0c, 0x0c, 0xfb, 0x2b, 0xf1, 0x01, 0x48, 0xe8, 0x26, 0x03, 0x8e, 0x27, 0x4d, 0x96, 0x72}} , - {{0xc8, 0x09, 0x3b, 0x60, 0xc9, 0x26, 0x4d, 0x7c, 0xf2, 0x9c, 0xd4, 0xa1, 0x3b, 0x26, 0xc2, 0x04, 0x33, 0x44, 0x76, 0x3c, 0x02, 0xbb, 0x11, 0x42, 0x0c, 0x22, 0xb7, 0xc6, 0xe1, 0xac, 0xb4, 0x0e}}}, -{{{0x6f, 0x85, 0xe7, 0xef, 0xde, 0x67, 0x30, 0xfc, 0xbf, 0x5a, 0xe0, 0x7b, 0x7a, 0x2a, 0x54, 0x6b, 0x5d, 0x62, 0x85, 0xa1, 0xf8, 0x16, 0x88, 0xec, 0x61, 0xb9, 0x96, 0xb5, 0xef, 0x2d, 0x43, 0x4d}} , - {{0x7c, 0x31, 0x33, 0xcc, 0xe4, 0xcf, 0x6c, 0xff, 0x80, 0x47, 0x77, 0xd1, 0xd8, 0xe9, 0x69, 0x97, 0x98, 0x7f, 0x20, 0x57, 0x1d, 0x1d, 0x4f, 0x08, 0x27, 0xc8, 0x35, 0x57, 0x40, 0xc6, 0x21, 0x0c}}}, -{{{0xd2, 0x8e, 0x9b, 0xfa, 0x42, 0x8e, 0xdf, 0x8f, 0xc7, 0x86, 0xf9, 0xa4, 0xca, 0x70, 0x00, 0x9d, 0x21, 0xbf, 0xec, 0x57, 0x62, 0x30, 0x58, 0x8c, 0x0d, 0x35, 0xdb, 0x5d, 0x8b, 0x6a, 0xa0, 0x5a}} , - {{0xc1, 0x58, 0x7c, 0x0d, 0x20, 0xdd, 0x11, 0x26, 0x5f, 0x89, 0x3b, 0x97, 0x58, 0xf8, 0x8b, 0xe3, 0xdf, 0x32, 0xe2, 0xfc, 0xd8, 0x67, 0xf2, 0xa5, 0x37, 0x1e, 0x6d, 0xec, 0x7c, 0x27, 0x20, 0x79}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xd0, 0xe9, 0xc0, 0xfa, 0x95, 0x45, 0x23, 0x96, 0xf1, 0x2c, 0x79, 0x25, 0x14, 0xce, 0x40, 0x14, 0x44, 0x2c, 0x36, 0x50, 0xd9, 0x63, 0x56, 0xb7, 0x56, 0x3b, 0x9e, 0xa7, 0xef, 0x89, 0xbb, 0x0e}} , - {{0xce, 0x7f, 0xdc, 0x0a, 0xcc, 0x82, 0x1c, 0x0a, 0x78, 0x71, 0xe8, 0x74, 0x8d, 0x01, 0x30, 0x0f, 0xa7, 0x11, 0x4c, 0xdf, 0x38, 0xd7, 0xa7, 0x0d, 0xf8, 0x48, 0x52, 0x00, 0x80, 0x7b, 0x5f, 0x0e}}}, -{{{0x25, 0x83, 0xe6, 0x94, 0x7b, 0x81, 0xb2, 0x91, 0xae, 0x0e, 0x05, 0xc9, 0xa3, 0x68, 0x2d, 0xd9, 0x88, 0x25, 0x19, 0x2a, 0x61, 0x61, 0x21, 0x97, 0x15, 0xa1, 0x35, 0xa5, 0x46, 0xc8, 0xa2, 0x0e}} , - {{0x1b, 0x03, 0x0d, 0x8b, 0x5a, 0x1b, 0x97, 0x4b, 0xf2, 0x16, 0x31, 0x3d, 0x1f, 0x33, 0xa0, 0x50, 0x3a, 0x18, 0xbe, 0x13, 0xa1, 0x76, 0xc1, 0xba, 0x1b, 0xf1, 0x05, 0x7b, 0x33, 0xa8, 0x82, 0x3b}}}, -{{{0xba, 0x36, 0x7b, 0x6d, 0xa9, 0xea, 0x14, 0x12, 0xc5, 0xfa, 0x91, 0x00, 0xba, 0x9b, 0x99, 0xcc, 0x56, 0x02, 0xe9, 0xa0, 0x26, 0x40, 0x66, 0x8c, 0xc4, 0xf8, 0x85, 0x33, 0x68, 0xe7, 0x03, 0x20}} , - {{0x50, 0x5b, 0xff, 0xa9, 0xb2, 0xf1, 0xf1, 0x78, 0xcf, 0x14, 0xa4, 0xa9, 0xfc, 0x09, 0x46, 0x94, 0x54, 0x65, 0x0d, 0x9c, 0x5f, 0x72, 0x21, 0xe2, 0x97, 0xa5, 0x2d, 0x81, 0xce, 0x4a, 0x5f, 0x79}}}, -{{{0x3d, 0x5f, 0x5c, 0xd2, 0xbc, 0x7d, 0x77, 0x0e, 0x2a, 0x6d, 0x22, 0x45, 0x84, 0x06, 0xc4, 0xdd, 0xc6, 0xa6, 0xc6, 0xd7, 0x49, 0xad, 0x6d, 0x87, 0x91, 0x0e, 0x3a, 0x67, 0x1d, 0x2c, 0x1d, 0x56}} , - {{0xfe, 0x7a, 0x74, 0xcf, 0xd4, 0xd2, 0xe5, 0x19, 0xde, 0xd0, 0xdb, 0x70, 0x23, 0x69, 0xe6, 0x6d, 0xec, 0xec, 0xcc, 0x09, 0x33, 0x6a, 0x77, 0xdc, 0x6b, 0x22, 0x76, 0x5d, 0x92, 0x09, 0xac, 0x2d}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x23, 0x15, 0x17, 0xeb, 0xd3, 0xdb, 0x12, 0x5e, 0x01, 0xf0, 0x91, 0xab, 0x2c, 0x41, 0xce, 0xac, 0xed, 0x1b, 0x4b, 0x2d, 0xbc, 0xdb, 0x17, 0x66, 0x89, 0x46, 0xad, 0x4b, 0x1e, 0x6f, 0x0b, 0x14}} , - {{0x11, 0xce, 0xbf, 0xb6, 0x77, 0x2d, 0x48, 0x22, 0x18, 0x4f, 0xa3, 0x5d, 0x4a, 0xb0, 0x70, 0x12, 0x3e, 0x54, 0xd7, 0xd8, 0x0e, 0x2b, 0x27, 0xdc, 0x53, 0xff, 0xca, 0x8c, 0x59, 0xb3, 0x4e, 0x44}}}, -{{{0x07, 0x76, 0x61, 0x0f, 0x66, 0xb2, 0x21, 0x39, 0x7e, 0xc0, 0xec, 0x45, 0x28, 0x82, 0xa1, 0x29, 0x32, 0x44, 0x35, 0x13, 0x5e, 0x61, 0x5e, 0x54, 0xcb, 0x7c, 0xef, 0xf6, 0x41, 0xcf, 0x9f, 0x0a}} , - {{0xdd, 0xf9, 0xda, 0x84, 0xc3, 0xe6, 0x8a, 0x9f, 0x24, 0xd2, 0x96, 0x5d, 0x39, 0x6f, 0x58, 0x8c, 0xc1, 0x56, 0x93, 0xab, 0xb5, 0x79, 0x3b, 0xd2, 0xa8, 0x73, 0x16, 0xed, 0xfa, 0xb4, 0x2f, 0x73}}}, -{{{0x8b, 0xb1, 0x95, 0xe5, 0x92, 0x50, 0x35, 0x11, 0x76, 0xac, 0xf4, 0x4d, 0x24, 0xc3, 0x32, 0xe6, 0xeb, 0xfe, 0x2c, 0x87, 0xc4, 0xf1, 0x56, 0xc4, 0x75, 0x24, 0x7a, 0x56, 0x85, 0x5a, 0x3a, 0x13}} , - {{0x0d, 0x16, 0xac, 0x3c, 0x4a, 0x58, 0x86, 0x3a, 0x46, 0x7f, 0x6c, 0xa3, 0x52, 0x6e, 0x37, 0xe4, 0x96, 0x9c, 0xe9, 0x5c, 0x66, 0x41, 0x67, 0xe4, 0xfb, 0x79, 0x0c, 0x05, 0xf6, 0x64, 0xd5, 0x7c}}}, -{{{0x28, 0xc1, 0xe1, 0x54, 0x73, 0xf2, 0xbf, 0x76, 0x74, 0x19, 0x19, 0x1b, 0xe4, 0xb9, 0xa8, 0x46, 0x65, 0x73, 0xf3, 0x77, 0x9b, 0x29, 0x74, 0x5b, 0xc6, 0x89, 0x6c, 0x2c, 0x7c, 0xf8, 0xb3, 0x0f}} , - {{0xf7, 0xd5, 0xe9, 0x74, 0x5d, 0xb8, 0x25, 0x16, 0xb5, 0x30, 0xbc, 0x84, 0xc5, 0xf0, 0xad, 0xca, 0x12, 0x28, 0xbc, 0x9d, 0xd4, 0xfa, 0x82, 0xe6, 0xe3, 0xbf, 0xa2, 0x15, 0x2c, 0xd4, 0x34, 0x10}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x61, 0xb1, 0x46, 0xba, 0x0e, 0x31, 0xa5, 0x67, 0x6c, 0x7f, 0xd6, 0xd9, 0x27, 0x85, 0x0f, 0x79, 0x14, 0xc8, 0x6c, 0x2f, 0x5f, 0x5b, 0x9c, 0x35, 0x3d, 0x38, 0x86, 0x77, 0x65, 0x55, 0x6a, 0x7b}} , - {{0xd3, 0xb0, 0x3a, 0x66, 0x60, 0x1b, 0x43, 0xf1, 0x26, 0x58, 0x99, 0x09, 0x8f, 0x2d, 0xa3, 0x14, 0x71, 0x85, 0xdb, 0xed, 0xf6, 0x26, 0xd5, 0x61, 0x9a, 0x73, 0xac, 0x0e, 0xea, 0xac, 0xb7, 0x0c}}}, -{{{0x5e, 0xf4, 0xe5, 0x17, 0x0e, 0x10, 0x9f, 0xe7, 0x43, 0x5f, 0x67, 0x5c, 0xac, 0x4b, 0xe5, 0x14, 0x41, 0xd2, 0xbf, 0x48, 0xf5, 0x14, 0xb0, 0x71, 0xc6, 0x61, 0xc1, 0xb2, 0x70, 0x58, 0xd2, 0x5a}} , - {{0x2d, 0xba, 0x16, 0x07, 0x92, 0x94, 0xdc, 0xbd, 0x50, 0x2b, 0xc9, 0x7f, 0x42, 0x00, 0xba, 0x61, 0xed, 0xf8, 0x43, 0xed, 0xf5, 0xf9, 0x40, 0x60, 0xb2, 0xb0, 0x82, 0xcb, 0xed, 0x75, 0xc7, 0x65}}}, -{{{0x80, 0xba, 0x0d, 0x09, 0x40, 0xa7, 0x39, 0xa6, 0x67, 0x34, 0x7e, 0x66, 0xbe, 0x56, 0xfb, 0x53, 0x78, 0xc4, 0x46, 0xe8, 0xed, 0x68, 0x6c, 0x7f, 0xce, 0xe8, 0x9f, 0xce, 0xa2, 0x64, 0x58, 0x53}} , - {{0xe8, 0xc1, 0xa9, 0xc2, 0x7b, 0x59, 0x21, 0x33, 0xe2, 0x43, 0x73, 0x2b, 0xac, 0x2d, 0xc1, 0x89, 0x3b, 0x15, 0xe2, 0xd5, 0xc0, 0x97, 0x8a, 0xfd, 0x6f, 0x36, 0x33, 0xb7, 0xb9, 0xc3, 0x88, 0x09}}}, -{{{0xd0, 0xb6, 0x56, 0x30, 0x5c, 0xae, 0xb3, 0x75, 0x44, 0xa4, 0x83, 0x51, 0x6e, 0x01, 0x65, 0xef, 0x45, 0x76, 0xe6, 0xf5, 0xa2, 0x0d, 0xd4, 0x16, 0x3b, 0x58, 0x2f, 0xf2, 0x2f, 0x36, 0x18, 0x3f}} , - {{0xfd, 0x2f, 0xe0, 0x9b, 0x1e, 0x8c, 0xc5, 0x18, 0xa9, 0xca, 0xd4, 0x2b, 0x35, 0xb6, 0x95, 0x0a, 0x9f, 0x7e, 0xfb, 0xc4, 0xef, 0x88, 0x7b, 0x23, 0x43, 0xec, 0x2f, 0x0d, 0x0f, 0x7a, 0xfc, 0x5c}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x8d, 0xd2, 0xda, 0xc7, 0x44, 0xd6, 0x7a, 0xdb, 0x26, 0x7d, 0x1d, 0xb8, 0xe1, 0xde, 0x9d, 0x7a, 0x7d, 0x17, 0x7e, 0x1c, 0x37, 0x04, 0x8d, 0x2d, 0x7c, 0x5e, 0x18, 0x38, 0x1e, 0xaf, 0xc7, 0x1b}} , - {{0x33, 0x48, 0x31, 0x00, 0x59, 0xf6, 0xf2, 0xca, 0x0f, 0x27, 0x1b, 0x63, 0x12, 0x7e, 0x02, 0x1d, 0x49, 0xc0, 0x5d, 0x79, 0x87, 0xef, 0x5e, 0x7a, 0x2f, 0x1f, 0x66, 0x55, 0xd8, 0x09, 0xd9, 0x61}}}, -{{{0x54, 0x83, 0x02, 0x18, 0x82, 0x93, 0x99, 0x07, 0xd0, 0xa7, 0xda, 0xd8, 0x75, 0x89, 0xfa, 0xf2, 0xd9, 0xa3, 0xb8, 0x6b, 0x5a, 0x35, 0x28, 0xd2, 0x6b, 0x59, 0xc2, 0xf8, 0x45, 0xe2, 0xbc, 0x06}} , - {{0x65, 0xc0, 0xa3, 0x88, 0x51, 0x95, 0xfc, 0x96, 0x94, 0x78, 0xe8, 0x0d, 0x8b, 0x41, 0xc9, 0xc2, 0x58, 0x48, 0x75, 0x10, 0x2f, 0xcd, 0x2a, 0xc9, 0xa0, 0x6d, 0x0f, 0xdd, 0x9c, 0x98, 0x26, 0x3d}}}, -{{{0x2f, 0x66, 0x29, 0x1b, 0x04, 0x89, 0xbd, 0x7e, 0xee, 0x6e, 0xdd, 0xb7, 0x0e, 0xef, 0xb0, 0x0c, 0xb4, 0xfc, 0x7f, 0xc2, 0xc9, 0x3a, 0x3c, 0x64, 0xef, 0x45, 0x44, 0xaf, 0x8a, 0x90, 0x65, 0x76}} , - {{0xa1, 0x4c, 0x70, 0x4b, 0x0e, 0xa0, 0x83, 0x70, 0x13, 0xa4, 0xaf, 0xb8, 0x38, 0x19, 0x22, 0x65, 0x09, 0xb4, 0x02, 0x4f, 0x06, 0xf8, 0x17, 0xce, 0x46, 0x45, 0xda, 0x50, 0x7c, 0x8a, 0xd1, 0x4e}}}, -{{{0xf7, 0xd4, 0x16, 0x6c, 0x4e, 0x95, 0x9d, 0x5d, 0x0f, 0x91, 0x2b, 0x52, 0xfe, 0x5c, 0x34, 0xe5, 0x30, 0xe6, 0xa4, 0x3b, 0xf3, 0xf3, 0x34, 0x08, 0xa9, 0x4a, 0xa0, 0xb5, 0x6e, 0xb3, 0x09, 0x0a}} , - {{0x26, 0xd9, 0x5e, 0xa3, 0x0f, 0xeb, 0xa2, 0xf3, 0x20, 0x3b, 0x37, 0xd4, 0xe4, 0x9e, 0xce, 0x06, 0x3d, 0x53, 0xed, 0xae, 0x2b, 0xeb, 0xb6, 0x24, 0x0a, 0x11, 0xa3, 0x0f, 0xd6, 0x7f, 0xa4, 0x3a}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xdb, 0x9f, 0x2c, 0xfc, 0xd6, 0xb2, 0x1e, 0x2e, 0x52, 0x7a, 0x06, 0x87, 0x2d, 0x86, 0x72, 0x2b, 0x6d, 0x90, 0x77, 0x46, 0x43, 0xb5, 0x7a, 0xf8, 0x60, 0x7d, 0x91, 0x60, 0x5b, 0x9d, 0x9e, 0x07}} , - {{0x97, 0x87, 0xc7, 0x04, 0x1c, 0x38, 0x01, 0x39, 0x58, 0xc7, 0x85, 0xa3, 0xfc, 0x64, 0x00, 0x64, 0x25, 0xa2, 0xbf, 0x50, 0x94, 0xca, 0x26, 0x31, 0x45, 0x0a, 0x24, 0xd2, 0x51, 0x29, 0x51, 0x16}}}, -{{{0x4d, 0x4a, 0xd7, 0x98, 0x71, 0x57, 0xac, 0x7d, 0x8b, 0x37, 0xbd, 0x63, 0xff, 0x87, 0xb1, 0x49, 0x95, 0x20, 0x7c, 0xcf, 0x7c, 0x59, 0xc4, 0x91, 0x9c, 0xef, 0xd0, 0xdb, 0x60, 0x09, 0x9d, 0x46}} , - {{0xcb, 0x78, 0x94, 0x90, 0xe4, 0x45, 0xb3, 0xf6, 0xd9, 0xf6, 0x57, 0x74, 0xd5, 0xf8, 0x83, 0x4f, 0x39, 0xc9, 0xbd, 0x88, 0xc2, 0x57, 0x21, 0x1f, 0x24, 0x32, 0x68, 0xf8, 0xc7, 0x21, 0x5f, 0x0b}}}, -{{{0x2a, 0x36, 0x68, 0xfc, 0x5f, 0xb6, 0x4f, 0xa5, 0xe3, 0x9d, 0x24, 0x2f, 0xc0, 0x93, 0x61, 0xcf, 0xf8, 0x0a, 0xed, 0xe1, 0xdb, 0x27, 0xec, 0x0e, 0x14, 0x32, 0x5f, 0x8e, 0xa1, 0x62, 0x41, 0x16}} , - {{0x95, 0x21, 0x01, 0xce, 0x95, 0x5b, 0x0e, 0x57, 0xc7, 0xb9, 0x62, 0xb5, 0x28, 0xca, 0x11, 0xec, 0xb4, 0x46, 0x06, 0x73, 0x26, 0xff, 0xfb, 0x66, 0x7d, 0xee, 0x5f, 0xb2, 0x56, 0xfd, 0x2a, 0x08}}}, -{{{0x92, 0x67, 0x77, 0x56, 0xa1, 0xff, 0xc4, 0xc5, 0x95, 0xf0, 0xe3, 0x3a, 0x0a, 0xca, 0x94, 0x4d, 0x9e, 0x7e, 0x3d, 0xb9, 0x6e, 0xb6, 0xb0, 0xce, 0xa4, 0x30, 0x89, 0x99, 0xe9, 0xad, 0x11, 0x59}} , - {{0xf6, 0x48, 0x95, 0xa1, 0x6f, 0x5f, 0xb7, 0xa5, 0xbb, 0x30, 0x00, 0x1c, 0xd2, 0x8a, 0xd6, 0x25, 0x26, 0x1b, 0xb2, 0x0d, 0x37, 0x6a, 0x05, 0xf4, 0x9d, 0x3e, 0x17, 0x2a, 0x43, 0xd2, 0x3a, 0x06}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x32, 0x99, 0x93, 0xd1, 0x9a, 0x72, 0xf3, 0xa9, 0x16, 0xbd, 0xb4, 0x4c, 0xdd, 0xf9, 0xd4, 0xb2, 0x64, 0x9a, 0xd3, 0x05, 0xe4, 0xa3, 0x73, 0x1c, 0xcb, 0x7e, 0x57, 0x67, 0xff, 0x04, 0xb3, 0x10}} , - {{0xb9, 0x4b, 0xa4, 0xad, 0xd0, 0x6d, 0x61, 0x23, 0xb4, 0xaf, 0x34, 0xa9, 0xaa, 0x65, 0xec, 0xd9, 0x69, 0xe3, 0x85, 0xcd, 0xcc, 0xe7, 0xb0, 0x9b, 0x41, 0xc1, 0x1c, 0xf9, 0xa0, 0xfa, 0xb7, 0x13}}}, -{{{0x04, 0xfd, 0x88, 0x3c, 0x0c, 0xd0, 0x09, 0x52, 0x51, 0x4f, 0x06, 0x19, 0xcc, 0xc3, 0xbb, 0xde, 0x80, 0xc5, 0x33, 0xbc, 0xf9, 0xf3, 0x17, 0x36, 0xdd, 0xc6, 0xde, 0xe8, 0x9b, 0x5d, 0x79, 0x1b}} , - {{0x65, 0x0a, 0xbe, 0x51, 0x57, 0xad, 0x50, 0x79, 0x08, 0x71, 0x9b, 0x07, 0x95, 0x8f, 0xfb, 0xae, 0x4b, 0x38, 0xba, 0xcf, 0x53, 0x2a, 0x86, 0x1e, 0xc0, 0x50, 0x5c, 0x67, 0x1b, 0xf6, 0x87, 0x6c}}}, -{{{0x4f, 0x00, 0xb2, 0x66, 0x55, 0xed, 0x4a, 0xed, 0x8d, 0xe1, 0x66, 0x18, 0xb2, 0x14, 0x74, 0x8d, 0xfd, 0x1a, 0x36, 0x0f, 0x26, 0x5c, 0x8b, 0x89, 0xf3, 0xab, 0xf2, 0xf3, 0x24, 0x67, 0xfd, 0x70}} , - {{0xfd, 0x4e, 0x2a, 0xc1, 0x3a, 0xca, 0x8f, 0x00, 0xd8, 0xec, 0x74, 0x67, 0xef, 0x61, 0xe0, 0x28, 0xd0, 0x96, 0xf4, 0x48, 0xde, 0x81, 0xe3, 0xef, 0xdc, 0xaa, 0x7d, 0xf3, 0xb6, 0x55, 0xa6, 0x65}}}, -{{{0xeb, 0xcb, 0xc5, 0x70, 0x91, 0x31, 0x10, 0x93, 0x0d, 0xc8, 0xd0, 0xef, 0x62, 0xe8, 0x6f, 0x82, 0xe3, 0x69, 0x3d, 0x91, 0x7f, 0x31, 0xe1, 0x26, 0x35, 0x3c, 0x4a, 0x2f, 0xab, 0xc4, 0x9a, 0x5e}} , - {{0xab, 0x1b, 0xb5, 0xe5, 0x2b, 0xc3, 0x0e, 0x29, 0xb0, 0xd0, 0x73, 0xe6, 0x4f, 0x64, 0xf2, 0xbc, 0xe4, 0xe4, 0xe1, 0x9a, 0x52, 0x33, 0x2f, 0xbd, 0xcc, 0x03, 0xee, 0x8a, 0xfa, 0x00, 0x5f, 0x50}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xf6, 0xdb, 0x0d, 0x22, 0x3d, 0xb5, 0x14, 0x75, 0x31, 0xf0, 0x81, 0xe2, 0xb9, 0x37, 0xa2, 0xa9, 0x84, 0x11, 0x9a, 0x07, 0xb5, 0x53, 0x89, 0x78, 0xa9, 0x30, 0x27, 0xa1, 0xf1, 0x4e, 0x5c, 0x2e}} , - {{0x8b, 0x00, 0x54, 0xfb, 0x4d, 0xdc, 0xcb, 0x17, 0x35, 0x40, 0xff, 0xb7, 0x8c, 0xfe, 0x4a, 0xe4, 0x4e, 0x99, 0x4e, 0xa8, 0x74, 0x54, 0x5d, 0x5c, 0x96, 0xa3, 0x12, 0x55, 0x36, 0x31, 0x17, 0x5c}}}, -{{{0xce, 0x24, 0xef, 0x7b, 0x86, 0xf2, 0x0f, 0x77, 0xe8, 0x5c, 0x7d, 0x87, 0x38, 0x2d, 0xef, 0xaf, 0xf2, 0x8c, 0x72, 0x2e, 0xeb, 0xb6, 0x55, 0x4b, 0x6e, 0xf1, 0x4e, 0x8a, 0x0e, 0x9a, 0x6c, 0x4c}} , - {{0x25, 0xea, 0x86, 0xc2, 0xd1, 0x4f, 0xb7, 0x3e, 0xa8, 0x5c, 0x8d, 0x66, 0x81, 0x25, 0xed, 0xc5, 0x4c, 0x05, 0xb9, 0xd8, 0xd6, 0x70, 0xbe, 0x73, 0x82, 0xe8, 0xa1, 0xe5, 0x1e, 0x71, 0xd5, 0x26}}}, -{{{0x4e, 0x6d, 0xc3, 0xa7, 0x4f, 0x22, 0x45, 0x26, 0xa2, 0x7e, 0x16, 0xf7, 0xf7, 0x63, 0xdc, 0x86, 0x01, 0x2a, 0x71, 0x38, 0x5c, 0x33, 0xc3, 0xce, 0x30, 0xff, 0xf9, 0x2c, 0x91, 0x71, 0x8a, 0x72}} , - {{0x8c, 0x44, 0x09, 0x28, 0xd5, 0x23, 0xc9, 0x8f, 0xf3, 0x84, 0x45, 0xc6, 0x9a, 0x5e, 0xff, 0xd2, 0xc7, 0x57, 0x93, 0xa3, 0xc1, 0x69, 0xdd, 0x62, 0x0f, 0xda, 0x5c, 0x30, 0x59, 0x5d, 0xe9, 0x4c}}}, -{{{0x92, 0x7e, 0x50, 0x27, 0x72, 0xd7, 0x0c, 0xd6, 0x69, 0x96, 0x81, 0x35, 0x84, 0x94, 0x35, 0x8b, 0x6c, 0xaa, 0x62, 0x86, 0x6e, 0x1c, 0x15, 0xf3, 0x6c, 0xb3, 0xff, 0x65, 0x1b, 0xa2, 0x9b, 0x59}} , - {{0xe2, 0xa9, 0x65, 0x88, 0xc4, 0x50, 0xfa, 0xbb, 0x3b, 0x6e, 0x5f, 0x44, 0x01, 0xca, 0x97, 0xd4, 0xdd, 0xf6, 0xcd, 0x3f, 0x3f, 0xe5, 0x97, 0x67, 0x2b, 0x8c, 0x66, 0x0f, 0x35, 0x9b, 0xf5, 0x07}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xf1, 0x59, 0x27, 0xd8, 0xdb, 0x5a, 0x11, 0x5e, 0x82, 0xf3, 0x38, 0xff, 0x1c, 0xed, 0xfe, 0x3f, 0x64, 0x54, 0x3f, 0x7f, 0xd1, 0x81, 0xed, 0xef, 0x65, 0xc5, 0xcb, 0xfd, 0xe1, 0x80, 0xcd, 0x11}} , - {{0xe0, 0xdb, 0x22, 0x28, 0xe6, 0xff, 0x61, 0x9d, 0x41, 0x14, 0x2d, 0x3b, 0x26, 0x22, 0xdf, 0xf1, 0x34, 0x81, 0xe9, 0x45, 0xee, 0x0f, 0x98, 0x8b, 0xa6, 0x3f, 0xef, 0xf7, 0x43, 0x19, 0xf1, 0x43}}}, -{{{0xee, 0xf3, 0x00, 0xa1, 0x50, 0xde, 0xc0, 0xb6, 0x01, 0xe3, 0x8c, 0x3c, 0x4d, 0x31, 0xd2, 0xb0, 0x58, 0xcd, 0xed, 0x10, 0x4a, 0x7a, 0xef, 0x80, 0xa9, 0x19, 0x32, 0xf3, 0xd8, 0x33, 0x8c, 0x06}} , - {{0xcb, 0x7d, 0x4f, 0xff, 0x30, 0xd8, 0x12, 0x3b, 0x39, 0x1c, 0x06, 0xf9, 0x4c, 0x34, 0x35, 0x71, 0xb5, 0x16, 0x94, 0x67, 0xdf, 0xee, 0x11, 0xde, 0xa4, 0x1d, 0x88, 0x93, 0x35, 0xa9, 0x32, 0x10}}}, -{{{0xe9, 0xc3, 0xbc, 0x7b, 0x5c, 0xfc, 0xb2, 0xf9, 0xc9, 0x2f, 0xe5, 0xba, 0x3a, 0x0b, 0xab, 0x64, 0x38, 0x6f, 0x5b, 0x4b, 0x93, 0xda, 0x64, 0xec, 0x4d, 0x3d, 0xa0, 0xf5, 0xbb, 0xba, 0x47, 0x48}} , - {{0x60, 0xbc, 0x45, 0x1f, 0x23, 0xa2, 0x3b, 0x70, 0x76, 0xe6, 0x97, 0x99, 0x4f, 0x77, 0x54, 0x67, 0x30, 0x9a, 0xe7, 0x66, 0xd6, 0xcd, 0x2e, 0x51, 0x24, 0x2c, 0x42, 0x4a, 0x11, 0xfe, 0x6f, 0x7e}}}, -{{{0x87, 0xc0, 0xb1, 0xf0, 0xa3, 0x6f, 0x0c, 0x93, 0xa9, 0x0a, 0x72, 0xef, 0x5c, 0xbe, 0x65, 0x35, 0xa7, 0x6a, 0x4e, 0x2c, 0xbf, 0x21, 0x23, 0xe8, 0x2f, 0x97, 0xc7, 0x3e, 0xc8, 0x17, 0xac, 0x1e}} , - {{0x7b, 0xef, 0x21, 0xe5, 0x40, 0xcc, 0x1e, 0xdc, 0xd6, 0xbd, 0x97, 0x7a, 0x7c, 0x75, 0x86, 0x7a, 0x25, 0x5a, 0x6e, 0x7c, 0xe5, 0x51, 0x3c, 0x1b, 0x5b, 0x82, 0x9a, 0x07, 0x60, 0xa1, 0x19, 0x04}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x96, 0x88, 0xa6, 0xab, 0x8f, 0xe3, 0x3a, 0x49, 0xf8, 0xfe, 0x34, 0xe7, 0x6a, 0xb2, 0xfe, 0x40, 0x26, 0x74, 0x57, 0x4c, 0xf6, 0xd4, 0x99, 0xce, 0x5d, 0x7b, 0x2f, 0x67, 0xd6, 0x5a, 0xe4, 0x4e}} , - {{0x5c, 0x82, 0xb3, 0xbd, 0x55, 0x25, 0xf6, 0x6a, 0x93, 0xa4, 0x02, 0xc6, 0x7d, 0x5c, 0xb1, 0x2b, 0x5b, 0xff, 0xfb, 0x56, 0xf8, 0x01, 0x41, 0x90, 0xc6, 0xb6, 0xac, 0x4f, 0xfe, 0xa7, 0x41, 0x70}}}, -{{{0xdb, 0xfa, 0x9b, 0x2c, 0xd4, 0x23, 0x67, 0x2c, 0x8a, 0x63, 0x6c, 0x07, 0x26, 0x48, 0x4f, 0xc2, 0x03, 0xd2, 0x53, 0x20, 0x28, 0xed, 0x65, 0x71, 0x47, 0xa9, 0x16, 0x16, 0x12, 0xbc, 0x28, 0x33}} , - {{0x39, 0xc0, 0xfa, 0xfa, 0xcd, 0x33, 0x43, 0xc7, 0x97, 0x76, 0x9b, 0x93, 0x91, 0x72, 0xeb, 0xc5, 0x18, 0x67, 0x4c, 0x11, 0xf0, 0xf4, 0xe5, 0x73, 0xb2, 0x5c, 0x1b, 0xc2, 0x26, 0x3f, 0xbf, 0x2b}}}, -{{{0x86, 0xe6, 0x8c, 0x1d, 0xdf, 0xca, 0xfc, 0xd5, 0xf8, 0x3a, 0xc3, 0x44, 0x72, 0xe6, 0x78, 0x9d, 0x2b, 0x97, 0xf8, 0x28, 0x45, 0xb4, 0x20, 0xc9, 0x2a, 0x8c, 0x67, 0xaa, 0x11, 0xc5, 0x5b, 0x2f}} , - {{0x17, 0x0f, 0x86, 0x52, 0xd7, 0x9d, 0xc3, 0x44, 0x51, 0x76, 0x32, 0x65, 0xb4, 0x37, 0x81, 0x99, 0x46, 0x37, 0x62, 0xed, 0xcf, 0x64, 0x9d, 0x72, 0x40, 0x7a, 0x4c, 0x0b, 0x76, 0x2a, 0xfb, 0x56}}}, -{{{0x33, 0xa7, 0x90, 0x7c, 0xc3, 0x6f, 0x17, 0xa5, 0xa0, 0x67, 0x72, 0x17, 0xea, 0x7e, 0x63, 0x14, 0x83, 0xde, 0xc1, 0x71, 0x2d, 0x41, 0x32, 0x7a, 0xf3, 0xd1, 0x2b, 0xd8, 0x2a, 0xa6, 0x46, 0x36}} , - {{0xac, 0xcc, 0x6b, 0x7c, 0xf9, 0xb8, 0x8b, 0x08, 0x5c, 0xd0, 0x7d, 0x8f, 0x73, 0xea, 0x20, 0xda, 0x86, 0xca, 0x00, 0xc7, 0xad, 0x73, 0x4d, 0xe9, 0xe8, 0xa9, 0xda, 0x1f, 0x03, 0x06, 0xdd, 0x24}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x9c, 0xb2, 0x61, 0x0a, 0x98, 0x2a, 0xa5, 0xd7, 0xee, 0xa9, 0xac, 0x65, 0xcb, 0x0a, 0x1e, 0xe2, 0xbe, 0xdc, 0x85, 0x59, 0x0f, 0x9c, 0xa6, 0x57, 0x34, 0xa5, 0x87, 0xeb, 0x7b, 0x1e, 0x0c, 0x3c}} , - {{0x2f, 0xbd, 0x84, 0x63, 0x0d, 0xb5, 0xa0, 0xf0, 0x4b, 0x9e, 0x93, 0xc6, 0x34, 0x9a, 0x34, 0xff, 0x73, 0x19, 0x2f, 0x6e, 0x54, 0x45, 0x2c, 0x92, 0x31, 0x76, 0x34, 0xf1, 0xb2, 0x26, 0xe8, 0x74}}}, -{{{0x0a, 0x67, 0x90, 0x6d, 0x0c, 0x4c, 0xcc, 0xc0, 0xe6, 0xbd, 0xa7, 0x5e, 0x55, 0x8c, 0xcd, 0x58, 0x9b, 0x11, 0xa2, 0xbb, 0x4b, 0xb1, 0x43, 0x04, 0x3c, 0x55, 0xed, 0x23, 0xfe, 0xcd, 0xb1, 0x53}} , - {{0x05, 0xfb, 0x75, 0xf5, 0x01, 0xaf, 0x38, 0x72, 0x58, 0xfc, 0x04, 0x29, 0x34, 0x7a, 0x67, 0xa2, 0x08, 0x50, 0x6e, 0xd0, 0x2b, 0x73, 0xd5, 0xb8, 0xe4, 0x30, 0x96, 0xad, 0x45, 0xdf, 0xa6, 0x5c}}}, -{{{0x0d, 0x88, 0x1a, 0x90, 0x7e, 0xdc, 0xd8, 0xfe, 0xc1, 0x2f, 0x5d, 0x67, 0xee, 0x67, 0x2f, 0xed, 0x6f, 0x55, 0x43, 0x5f, 0x87, 0x14, 0x35, 0x42, 0xd3, 0x75, 0xae, 0xd5, 0xd3, 0x85, 0x1a, 0x76}} , - {{0x87, 0xc8, 0xa0, 0x6e, 0xe1, 0xb0, 0xad, 0x6a, 0x4a, 0x34, 0x71, 0xed, 0x7c, 0xd6, 0x44, 0x03, 0x65, 0x4a, 0x5c, 0x5c, 0x04, 0xf5, 0x24, 0x3f, 0xb0, 0x16, 0x5e, 0x8c, 0xb2, 0xd2, 0xc5, 0x20}}}, -{{{0x98, 0x83, 0xc2, 0x37, 0xa0, 0x41, 0xa8, 0x48, 0x5c, 0x5f, 0xbf, 0xc8, 0xfa, 0x24, 0xe0, 0x59, 0x2c, 0xbd, 0xf6, 0x81, 0x7e, 0x88, 0xe6, 0xca, 0x04, 0xd8, 0x5d, 0x60, 0xbb, 0x74, 0xa7, 0x0b}} , - {{0x21, 0x13, 0x91, 0xbf, 0x77, 0x7a, 0x33, 0xbc, 0xe9, 0x07, 0x39, 0x0a, 0xdd, 0x7d, 0x06, 0x10, 0x9a, 0xee, 0x47, 0x73, 0x1b, 0x15, 0x5a, 0xfb, 0xcd, 0x4d, 0xd0, 0xd2, 0x3a, 0x01, 0xba, 0x54}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x48, 0xd5, 0x39, 0x4a, 0x0b, 0x20, 0x6a, 0x43, 0xa0, 0x07, 0x82, 0x5e, 0x49, 0x7c, 0xc9, 0x47, 0xf1, 0x7c, 0x37, 0xb9, 0x23, 0xef, 0x6b, 0x46, 0x45, 0x8c, 0x45, 0x76, 0xdf, 0x14, 0x6b, 0x6e}} , - {{0x42, 0xc9, 0xca, 0x29, 0x4c, 0x76, 0x37, 0xda, 0x8a, 0x2d, 0x7c, 0x3a, 0x58, 0xf2, 0x03, 0xb4, 0xb5, 0xb9, 0x1a, 0x13, 0x2d, 0xde, 0x5f, 0x6b, 0x9d, 0xba, 0x52, 0xc9, 0x5d, 0xb3, 0xf3, 0x30}}}, -{{{0x4c, 0x6f, 0xfe, 0x6b, 0x0c, 0x62, 0xd7, 0x48, 0x71, 0xef, 0xb1, 0x85, 0x79, 0xc0, 0xed, 0x24, 0xb1, 0x08, 0x93, 0x76, 0x8e, 0xf7, 0x38, 0x8e, 0xeb, 0xfe, 0x80, 0x40, 0xaf, 0x90, 0x64, 0x49}} , - {{0x4a, 0x88, 0xda, 0xc1, 0x98, 0x44, 0x3c, 0x53, 0x4e, 0xdb, 0x4b, 0xb9, 0x12, 0x5f, 0xcd, 0x08, 0x04, 0xef, 0x75, 0xe7, 0xb1, 0x3a, 0xe5, 0x07, 0xfa, 0xca, 0x65, 0x7b, 0x72, 0x10, 0x64, 0x7f}}}, -{{{0x3d, 0x81, 0xf0, 0xeb, 0x16, 0xfd, 0x58, 0x33, 0x8d, 0x7c, 0x1a, 0xfb, 0x20, 0x2c, 0x8a, 0xee, 0x90, 0xbb, 0x33, 0x6d, 0x45, 0xe9, 0x8e, 0x99, 0x85, 0xe1, 0x08, 0x1f, 0xc5, 0xf1, 0xb5, 0x46}} , - {{0xe4, 0xe7, 0x43, 0x4b, 0xa0, 0x3f, 0x2b, 0x06, 0xba, 0x17, 0xae, 0x3d, 0xe6, 0xce, 0xbd, 0xb8, 0xed, 0x74, 0x11, 0x35, 0xec, 0x96, 0xfe, 0x31, 0xe3, 0x0e, 0x7a, 0x4e, 0xc9, 0x1d, 0xcb, 0x20}}}, -{{{0xe0, 0x67, 0xe9, 0x7b, 0xdb, 0x96, 0x5c, 0xb0, 0x32, 0xd0, 0x59, 0x31, 0x90, 0xdc, 0x92, 0x97, 0xac, 0x09, 0x38, 0x31, 0x0f, 0x7e, 0xd6, 0x5d, 0xd0, 0x06, 0xb6, 0x1f, 0xea, 0xf0, 0x5b, 0x07}} , - {{0x81, 0x9f, 0xc7, 0xde, 0x6b, 0x41, 0x22, 0x35, 0x14, 0x67, 0x77, 0x3e, 0x90, 0x81, 0xb0, 0xd9, 0x85, 0x4c, 0xca, 0x9b, 0x3f, 0x04, 0x59, 0xd6, 0xaa, 0x17, 0xc3, 0x88, 0x34, 0x37, 0xba, 0x43}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x4c, 0xb6, 0x69, 0xc8, 0x81, 0x95, 0x94, 0x33, 0x92, 0x34, 0xe9, 0x3c, 0x84, 0x0d, 0x3d, 0x5a, 0x37, 0x9c, 0x22, 0xa0, 0xaa, 0x65, 0xce, 0xb4, 0xc2, 0x2d, 0x66, 0x67, 0x02, 0xff, 0x74, 0x10}} , - {{0x22, 0xb0, 0xd5, 0xe6, 0xc7, 0xef, 0xb1, 0xa7, 0x13, 0xda, 0x60, 0xb4, 0x80, 0xc1, 0x42, 0x7d, 0x10, 0x70, 0x97, 0x04, 0x4d, 0xda, 0x23, 0x89, 0xc2, 0x0e, 0x68, 0xcb, 0xde, 0xe0, 0x9b, 0x29}}}, -{{{0x33, 0xfe, 0x42, 0x2a, 0x36, 0x2b, 0x2e, 0x36, 0x64, 0x5c, 0x8b, 0xcc, 0x81, 0x6a, 0x15, 0x08, 0xa1, 0x27, 0xe8, 0x57, 0xe5, 0x78, 0x8e, 0xf2, 0x58, 0x19, 0x12, 0x42, 0xae, 0xc4, 0x63, 0x3e}} , - {{0x78, 0x96, 0x9c, 0xa7, 0xca, 0x80, 0xae, 0x02, 0x85, 0xb1, 0x7c, 0x04, 0x5c, 0xc1, 0x5b, 0x26, 0xc1, 0xba, 0xed, 0xa5, 0x59, 0x70, 0x85, 0x8c, 0x8c, 0xe8, 0x87, 0xac, 0x6a, 0x28, 0x99, 0x35}}}, -{{{0x9f, 0x04, 0x08, 0x28, 0xbe, 0x87, 0xda, 0x80, 0x28, 0x38, 0xde, 0x9f, 0xcd, 0xe4, 0xe3, 0x62, 0xfb, 0x2e, 0x46, 0x8d, 0x01, 0xb3, 0x06, 0x51, 0xd4, 0x19, 0x3b, 0x11, 0xfa, 0xe2, 0xad, 0x1e}} , - {{0xa0, 0x20, 0x99, 0x69, 0x0a, 0xae, 0xa3, 0x70, 0x4e, 0x64, 0x80, 0xb7, 0x85, 0x9c, 0x87, 0x54, 0x43, 0x43, 0x55, 0x80, 0x6d, 0x8d, 0x7c, 0xa9, 0x64, 0xca, 0x6c, 0x2e, 0x21, 0xd8, 0xc8, 0x6c}}}, -{{{0x91, 0x4a, 0x07, 0xad, 0x08, 0x75, 0xc1, 0x4f, 0xa4, 0xb2, 0xc3, 0x6f, 0x46, 0x3e, 0xb1, 0xce, 0x52, 0xab, 0x67, 0x09, 0x54, 0x48, 0x6b, 0x6c, 0xd7, 0x1d, 0x71, 0x76, 0xcb, 0xff, 0xdd, 0x31}} , - {{0x36, 0x88, 0xfa, 0xfd, 0xf0, 0x36, 0x6f, 0x07, 0x74, 0x88, 0x50, 0xd0, 0x95, 0x38, 0x4a, 0x48, 0x2e, 0x07, 0x64, 0x97, 0x11, 0x76, 0x01, 0x1a, 0x27, 0x4d, 0x8e, 0x25, 0x9a, 0x9b, 0x1c, 0x22}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xbe, 0x57, 0xbd, 0x0e, 0x0f, 0xac, 0x5e, 0x76, 0xa3, 0x71, 0xad, 0x2b, 0x10, 0x45, 0x02, 0xec, 0x59, 0xd5, 0x5d, 0xa9, 0x44, 0xcc, 0x25, 0x4c, 0xb3, 0x3c, 0x5b, 0x69, 0x07, 0x55, 0x26, 0x6b}} , - {{0x30, 0x6b, 0xd4, 0xa7, 0x51, 0x29, 0xe3, 0xf9, 0x7a, 0x75, 0x2a, 0x82, 0x2f, 0xd6, 0x1d, 0x99, 0x2b, 0x80, 0xd5, 0x67, 0x1e, 0x15, 0x9d, 0xca, 0xfd, 0xeb, 0xac, 0x97, 0x35, 0x09, 0x7f, 0x3f}}}, -{{{0x35, 0x0d, 0x34, 0x0a, 0xb8, 0x67, 0x56, 0x29, 0x20, 0xf3, 0x19, 0x5f, 0xe2, 0x83, 0x42, 0x73, 0x53, 0xa8, 0xc5, 0x02, 0x19, 0x33, 0xb4, 0x64, 0xbd, 0xc3, 0x87, 0x8c, 0xd7, 0x76, 0xed, 0x25}} , - {{0x47, 0x39, 0x37, 0x76, 0x0d, 0x1d, 0x0c, 0xf5, 0x5a, 0x6d, 0x43, 0x88, 0x99, 0x15, 0xb4, 0x52, 0x0f, 0x2a, 0xb3, 0xb0, 0x3f, 0xa6, 0xb3, 0x26, 0xb3, 0xc7, 0x45, 0xf5, 0x92, 0x5f, 0x9b, 0x17}}}, -{{{0x9d, 0x23, 0xbd, 0x15, 0xfe, 0x52, 0x52, 0x15, 0x26, 0x79, 0x86, 0xba, 0x06, 0x56, 0x66, 0xbb, 0x8c, 0x2e, 0x10, 0x11, 0xd5, 0x4a, 0x18, 0x52, 0xda, 0x84, 0x44, 0xf0, 0x3e, 0xe9, 0x8c, 0x35}} , - {{0xad, 0xa0, 0x41, 0xec, 0xc8, 0x4d, 0xb9, 0xd2, 0x6e, 0x96, 0x4e, 0x5b, 0xc5, 0xc2, 0xa0, 0x1b, 0xcf, 0x0c, 0xbf, 0x17, 0x66, 0x57, 0xc1, 0x17, 0x90, 0x45, 0x71, 0xc2, 0xe1, 0x24, 0xeb, 0x27}}}, -{{{0x2c, 0xb9, 0x42, 0xa4, 0xaf, 0x3b, 0x42, 0x0e, 0xc2, 0x0f, 0xf2, 0xea, 0x83, 0xaf, 0x9a, 0x13, 0x17, 0xb0, 0xbd, 0x89, 0x17, 0xe3, 0x72, 0xcb, 0x0e, 0x76, 0x7e, 0x41, 0x63, 0x04, 0x88, 0x71}} , - {{0x75, 0x78, 0x38, 0x86, 0x57, 0xdd, 0x9f, 0xee, 0x54, 0x70, 0x65, 0xbf, 0xf1, 0x2c, 0xe0, 0x39, 0x0d, 0xe3, 0x89, 0xfd, 0x8e, 0x93, 0x4f, 0x43, 0xdc, 0xd5, 0x5b, 0xde, 0xf9, 0x98, 0xe5, 0x7b}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xe7, 0x3b, 0x65, 0x11, 0xdf, 0xb2, 0xf2, 0x63, 0x94, 0x12, 0x6f, 0x5c, 0x9e, 0x77, 0xc1, 0xb6, 0xd8, 0xab, 0x58, 0x7a, 0x1d, 0x95, 0x73, 0xdd, 0xe7, 0xe3, 0x6f, 0xf2, 0x03, 0x1d, 0xdb, 0x76}} , - {{0xae, 0x06, 0x4e, 0x2c, 0x52, 0x1b, 0xbc, 0x5a, 0x5a, 0xa5, 0xbe, 0x27, 0xbd, 0xeb, 0xe1, 0x14, 0x17, 0x68, 0x26, 0x07, 0x03, 0xd1, 0x18, 0x0b, 0xdf, 0xf1, 0x06, 0x5c, 0xa6, 0x1b, 0xb9, 0x24}}}, -{{{0xc5, 0x66, 0x80, 0x13, 0x0e, 0x48, 0x8c, 0x87, 0x31, 0x84, 0xb4, 0x60, 0xed, 0xc5, 0xec, 0xb6, 0xc5, 0x05, 0x33, 0x5f, 0x2f, 0x7d, 0x40, 0xb6, 0x32, 0x1d, 0x38, 0x74, 0x1b, 0xf1, 0x09, 0x3d}} , - {{0xd4, 0x69, 0x82, 0xbc, 0x8d, 0xf8, 0x34, 0x36, 0x75, 0x55, 0x18, 0x55, 0x58, 0x3c, 0x79, 0xaf, 0x26, 0x80, 0xab, 0x9b, 0x95, 0x00, 0xf1, 0xcb, 0xda, 0xc1, 0x9f, 0xf6, 0x2f, 0xa2, 0xf4, 0x45}}}, -{{{0x17, 0xbe, 0xeb, 0x85, 0xed, 0x9e, 0xcd, 0x56, 0xf5, 0x17, 0x45, 0x42, 0xb4, 0x1f, 0x44, 0x4c, 0x05, 0x74, 0x15, 0x47, 0x00, 0xc6, 0x6a, 0x3d, 0x24, 0x09, 0x0d, 0x58, 0xb1, 0x42, 0xd7, 0x04}} , - {{0x8d, 0xbd, 0xa3, 0xc4, 0x06, 0x9b, 0x1f, 0x90, 0x58, 0x60, 0x74, 0xb2, 0x00, 0x3b, 0x3c, 0xd2, 0xda, 0x82, 0xbb, 0x10, 0x90, 0x69, 0x92, 0xa9, 0xb4, 0x30, 0x81, 0xe3, 0x7c, 0xa8, 0x89, 0x45}}}, -{{{0x3f, 0xdc, 0x05, 0xcb, 0x41, 0x3c, 0xc8, 0x23, 0x04, 0x2c, 0x38, 0x99, 0xe3, 0x68, 0x55, 0xf9, 0xd3, 0x32, 0xc7, 0xbf, 0xfa, 0xd4, 0x1b, 0x5d, 0xde, 0xdc, 0x10, 0x42, 0xc0, 0x42, 0xd9, 0x75}} , - {{0x2d, 0xab, 0x35, 0x4e, 0x87, 0xc4, 0x65, 0x97, 0x67, 0x24, 0xa4, 0x47, 0xad, 0x3f, 0x8e, 0xf3, 0xcb, 0x31, 0x17, 0x77, 0xc5, 0xe2, 0xd7, 0x8f, 0x3c, 0xc1, 0xcd, 0x56, 0x48, 0xc1, 0x6c, 0x69}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x14, 0xae, 0x5f, 0x88, 0x7b, 0xa5, 0x90, 0xdf, 0x10, 0xb2, 0x8b, 0x5e, 0x24, 0x17, 0xc3, 0xa3, 0xd4, 0x0f, 0x92, 0x61, 0x1a, 0x19, 0x5a, 0xad, 0x76, 0xbd, 0xd8, 0x1c, 0xdd, 0xe0, 0x12, 0x6d}} , - {{0x8e, 0xbd, 0x70, 0x8f, 0x02, 0xa3, 0x24, 0x4d, 0x5a, 0x67, 0xc4, 0xda, 0xf7, 0x20, 0x0f, 0x81, 0x5b, 0x7a, 0x05, 0x24, 0x67, 0x83, 0x0b, 0x2a, 0x80, 0xe7, 0xfd, 0x74, 0x4b, 0x9e, 0x5c, 0x0d}}}, -{{{0x94, 0xd5, 0x5f, 0x1f, 0xa2, 0xfb, 0xeb, 0xe1, 0x07, 0x34, 0xf8, 0x20, 0xad, 0x81, 0x30, 0x06, 0x2d, 0xa1, 0x81, 0x95, 0x36, 0xcf, 0x11, 0x0b, 0xaf, 0xc1, 0x2b, 0x9a, 0x6c, 0x55, 0xc1, 0x16}} , - {{0x36, 0x4f, 0xf1, 0x5e, 0x74, 0x35, 0x13, 0x28, 0xd7, 0x11, 0xcf, 0xb8, 0xde, 0x93, 0xb3, 0x05, 0xb8, 0xb5, 0x73, 0xe9, 0xeb, 0xad, 0x19, 0x1e, 0x89, 0x0f, 0x8b, 0x15, 0xd5, 0x8c, 0xe3, 0x23}}}, -{{{0x33, 0x79, 0xe7, 0x18, 0xe6, 0x0f, 0x57, 0x93, 0x15, 0xa0, 0xa7, 0xaa, 0xc4, 0xbf, 0x4f, 0x30, 0x74, 0x95, 0x5e, 0x69, 0x4a, 0x5b, 0x45, 0xe4, 0x00, 0xeb, 0x23, 0x74, 0x4c, 0xdf, 0x6b, 0x45}} , - {{0x97, 0x29, 0x6c, 0xc4, 0x42, 0x0b, 0xdd, 0xc0, 0x29, 0x5c, 0x9b, 0x34, 0x97, 0xd0, 0xc7, 0x79, 0x80, 0x63, 0x74, 0xe4, 0x8e, 0x37, 0xb0, 0x2b, 0x7c, 0xe8, 0x68, 0x6c, 0xc3, 0x82, 0x97, 0x57}}}, -{{{0x22, 0xbe, 0x83, 0xb6, 0x4b, 0x80, 0x6b, 0x43, 0x24, 0x5e, 0xef, 0x99, 0x9b, 0xa8, 0xfc, 0x25, 0x8d, 0x3b, 0x03, 0x94, 0x2b, 0x3e, 0xe7, 0x95, 0x76, 0x9b, 0xcc, 0x15, 0xdb, 0x32, 0xe6, 0x66}} , - {{0x84, 0xf0, 0x4a, 0x13, 0xa6, 0xd6, 0xfa, 0x93, 0x46, 0x07, 0xf6, 0x7e, 0x5c, 0x6d, 0x5e, 0xf6, 0xa6, 0xe7, 0x48, 0xf0, 0x06, 0xea, 0xff, 0x90, 0xc1, 0xcc, 0x4c, 0x19, 0x9c, 0x3c, 0x4e, 0x53}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x2a, 0x50, 0xe3, 0x07, 0x15, 0x59, 0xf2, 0x8b, 0x81, 0xf2, 0xf3, 0xd3, 0x6c, 0x99, 0x8c, 0x70, 0x67, 0xec, 0xcc, 0xee, 0x9e, 0x59, 0x45, 0x59, 0x7d, 0x47, 0x75, 0x69, 0xf5, 0x24, 0x93, 0x5d}} , - {{0x6a, 0x4f, 0x1b, 0xbe, 0x6b, 0x30, 0xcf, 0x75, 0x46, 0xe3, 0x7b, 0x9d, 0xfc, 0xcd, 0xd8, 0x5c, 0x1f, 0xb4, 0xc8, 0xe2, 0x24, 0xec, 0x1a, 0x28, 0x05, 0x32, 0x57, 0xfd, 0x3c, 0x5a, 0x98, 0x10}}}, -{{{0xa3, 0xdb, 0xf7, 0x30, 0xd8, 0xc2, 0x9a, 0xe1, 0xd3, 0xce, 0x22, 0xe5, 0x80, 0x1e, 0xd9, 0xe4, 0x1f, 0xab, 0xc0, 0x71, 0x1a, 0x86, 0x0e, 0x27, 0x99, 0x5b, 0xfa, 0x76, 0x99, 0xb0, 0x08, 0x3c}} , - {{0x2a, 0x93, 0xd2, 0x85, 0x1b, 0x6a, 0x5d, 0xa6, 0xee, 0xd1, 0xd1, 0x33, 0xbd, 0x6a, 0x36, 0x73, 0x37, 0x3a, 0x44, 0xb4, 0xec, 0xa9, 0x7a, 0xde, 0x83, 0x40, 0xd7, 0xdf, 0x28, 0xba, 0xa2, 0x30}}}, -{{{0xd3, 0xb5, 0x6d, 0x05, 0x3f, 0x9f, 0xf3, 0x15, 0x8d, 0x7c, 0xca, 0xc9, 0xfc, 0x8a, 0x7c, 0x94, 0xb0, 0x63, 0x36, 0x9b, 0x78, 0xd1, 0x91, 0x1f, 0x93, 0xd8, 0x57, 0x43, 0xde, 0x76, 0xa3, 0x43}} , - {{0x9b, 0x35, 0xe2, 0xa9, 0x3d, 0x32, 0x1e, 0xbb, 0x16, 0x28, 0x70, 0xe9, 0x45, 0x2f, 0x8f, 0x70, 0x7f, 0x08, 0x7e, 0x53, 0xc4, 0x7a, 0xbf, 0xf7, 0xe1, 0xa4, 0x6a, 0xd8, 0xac, 0x64, 0x1b, 0x11}}}, -{{{0xb2, 0xeb, 0x47, 0x46, 0x18, 0x3e, 0x1f, 0x99, 0x0c, 0xcc, 0xf1, 0x2c, 0xe0, 0xe7, 0x8f, 0xe0, 0x01, 0x7e, 0x65, 0xb8, 0x0c, 0xd0, 0xfb, 0xc8, 0xb9, 0x90, 0x98, 0x33, 0x61, 0x3b, 0xd8, 0x27}} , - {{0xa0, 0xbe, 0x72, 0x3a, 0x50, 0x4b, 0x74, 0xab, 0x01, 0xc8, 0x93, 0xc5, 0xe4, 0xc7, 0x08, 0x6c, 0xb4, 0xca, 0xee, 0xeb, 0x8e, 0xd7, 0x4e, 0x26, 0xc6, 0x1d, 0xe2, 0x71, 0xaf, 0x89, 0xa0, 0x2a}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x98, 0x0b, 0xe4, 0xde, 0xdb, 0xa8, 0xfa, 0x82, 0x74, 0x06, 0x52, 0x6d, 0x08, 0x52, 0x8a, 0xff, 0x62, 0xc5, 0x6a, 0x44, 0x0f, 0x51, 0x8c, 0x1f, 0x6e, 0xb6, 0xc6, 0x2c, 0x81, 0xd3, 0x76, 0x46}} , - {{0xf4, 0x29, 0x74, 0x2e, 0x80, 0xa7, 0x1a, 0x8f, 0xf6, 0xbd, 0xd6, 0x8e, 0xbf, 0xc1, 0x95, 0x2a, 0xeb, 0xa0, 0x7f, 0x45, 0xa0, 0x50, 0x14, 0x05, 0xb1, 0x57, 0x4c, 0x74, 0xb7, 0xe2, 0x89, 0x7d}}}, -{{{0x07, 0xee, 0xa7, 0xad, 0xb7, 0x09, 0x0b, 0x49, 0x4e, 0xbf, 0xca, 0xe5, 0x21, 0xe6, 0xe6, 0xaf, 0xd5, 0x67, 0xf3, 0xce, 0x7e, 0x7c, 0x93, 0x7b, 0x5a, 0x10, 0x12, 0x0e, 0x6c, 0x06, 0x11, 0x75}} , - {{0xd5, 0xfc, 0x86, 0xa3, 0x3b, 0xa3, 0x3e, 0x0a, 0xfb, 0x0b, 0xf7, 0x36, 0xb1, 0x5b, 0xda, 0x70, 0xb7, 0x00, 0xa7, 0xda, 0x88, 0x8f, 0x84, 0xa8, 0xbc, 0x1c, 0x39, 0xb8, 0x65, 0xf3, 0x4d, 0x60}}}, -{{{0x96, 0x9d, 0x31, 0xf4, 0xa2, 0xbe, 0x81, 0xb9, 0xa5, 0x59, 0x9e, 0xba, 0x07, 0xbe, 0x74, 0x58, 0xd8, 0xeb, 0xc5, 0x9f, 0x3d, 0xd1, 0xf4, 0xae, 0xce, 0x53, 0xdf, 0x4f, 0xc7, 0x2a, 0x89, 0x4d}} , - {{0x29, 0xd8, 0xf2, 0xaa, 0xe9, 0x0e, 0xf7, 0x2e, 0x5f, 0x9d, 0x8a, 0x5b, 0x09, 0xed, 0xc9, 0x24, 0x22, 0xf4, 0x0f, 0x25, 0x8f, 0x1c, 0x84, 0x6e, 0x34, 0x14, 0x6c, 0xea, 0xb3, 0x86, 0x5d, 0x04}}}, -{{{0x07, 0x98, 0x61, 0xe8, 0x6a, 0xd2, 0x81, 0x49, 0x25, 0xd5, 0x5b, 0x18, 0xc7, 0x35, 0x52, 0x51, 0xa4, 0x46, 0xad, 0x18, 0x0d, 0xc9, 0x5f, 0x18, 0x91, 0x3b, 0xb4, 0xc0, 0x60, 0x59, 0x8d, 0x66}} , - {{0x03, 0x1b, 0x79, 0x53, 0x6e, 0x24, 0xae, 0x57, 0xd9, 0x58, 0x09, 0x85, 0x48, 0xa2, 0xd3, 0xb5, 0xe2, 0x4d, 0x11, 0x82, 0xe6, 0x86, 0x3c, 0xe9, 0xb1, 0x00, 0x19, 0xc2, 0x57, 0xf7, 0x66, 0x7a}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x0f, 0xe3, 0x89, 0x03, 0xd7, 0x22, 0x95, 0x9f, 0xca, 0xb4, 0x8d, 0x9e, 0x6d, 0x97, 0xff, 0x8d, 0x21, 0x59, 0x07, 0xef, 0x03, 0x2d, 0x5e, 0xf8, 0x44, 0x46, 0xe7, 0x85, 0x80, 0xc5, 0x89, 0x50}} , - {{0x8b, 0xd8, 0x53, 0x86, 0x24, 0x86, 0x29, 0x52, 0x01, 0xfa, 0x20, 0xc3, 0x4e, 0x95, 0xcb, 0xad, 0x7b, 0x34, 0x94, 0x30, 0xb7, 0x7a, 0xfa, 0x96, 0x41, 0x60, 0x2b, 0xcb, 0x59, 0xb9, 0xca, 0x50}}}, -{{{0xc2, 0x5b, 0x9b, 0x78, 0x23, 0x1b, 0x3a, 0x88, 0x94, 0x5f, 0x0a, 0x9b, 0x98, 0x2b, 0x6e, 0x53, 0x11, 0xf6, 0xff, 0xc6, 0x7d, 0x42, 0xcc, 0x02, 0x80, 0x40, 0x0d, 0x1e, 0xfb, 0xaf, 0x61, 0x07}} , - {{0xb0, 0xe6, 0x2f, 0x81, 0x70, 0xa1, 0x2e, 0x39, 0x04, 0x7c, 0xc4, 0x2c, 0x87, 0x45, 0x4a, 0x5b, 0x69, 0x97, 0xac, 0x6d, 0x2c, 0x10, 0x42, 0x7c, 0x3b, 0x15, 0x70, 0x60, 0x0e, 0x11, 0x6d, 0x3a}}}, -{{{0x9b, 0x18, 0x80, 0x5e, 0xdb, 0x05, 0xbd, 0xc6, 0xb7, 0x3c, 0xc2, 0x40, 0x4d, 0x5d, 0xce, 0x97, 0x8a, 0x34, 0x15, 0xab, 0x28, 0x5d, 0x10, 0xf0, 0x37, 0x0c, 0xcc, 0x16, 0xfa, 0x1f, 0x33, 0x0d}} , - {{0x19, 0xf9, 0x35, 0xaa, 0x59, 0x1a, 0x0c, 0x5c, 0x06, 0xfc, 0x6a, 0x0b, 0x97, 0x53, 0x36, 0xfc, 0x2a, 0xa5, 0x5a, 0x9b, 0x30, 0xef, 0x23, 0xaf, 0x39, 0x5d, 0x9a, 0x6b, 0x75, 0x57, 0x48, 0x0b}}}, -{{{0x26, 0xdc, 0x76, 0x3b, 0xfc, 0xf9, 0x9c, 0x3f, 0x89, 0x0b, 0x62, 0x53, 0xaf, 0x83, 0x01, 0x2e, 0xbc, 0x6a, 0xc6, 0x03, 0x0d, 0x75, 0x2a, 0x0d, 0xe6, 0x94, 0x54, 0xcf, 0xb3, 0xe5, 0x96, 0x25}} , - {{0xfe, 0x82, 0xb1, 0x74, 0x31, 0x8a, 0xa7, 0x6f, 0x56, 0xbd, 0x8d, 0xf4, 0xe0, 0x94, 0x51, 0x59, 0xde, 0x2c, 0x5a, 0xf4, 0x84, 0x6b, 0x4a, 0x88, 0x93, 0xc0, 0x0c, 0x9a, 0xac, 0xa7, 0xa0, 0x68}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x25, 0x0d, 0xd6, 0xc7, 0x23, 0x47, 0x10, 0xad, 0xc7, 0x08, 0x5c, 0x87, 0x87, 0x93, 0x98, 0x18, 0xb8, 0xd3, 0x9c, 0xac, 0x5a, 0x3d, 0xc5, 0x75, 0xf8, 0x49, 0x32, 0x14, 0xcc, 0x51, 0x96, 0x24}} , - {{0x65, 0x9c, 0x5d, 0xf0, 0x37, 0x04, 0xf0, 0x34, 0x69, 0x2a, 0xf0, 0xa5, 0x64, 0xca, 0xde, 0x2b, 0x5b, 0x15, 0x10, 0xd2, 0xab, 0x06, 0xdd, 0xc4, 0xb0, 0xb6, 0x5b, 0xc1, 0x17, 0xdf, 0x8f, 0x02}}}, -{{{0xbd, 0x59, 0x3d, 0xbf, 0x5c, 0x31, 0x44, 0x2c, 0x32, 0x94, 0x04, 0x60, 0x84, 0x0f, 0xad, 0x00, 0xb6, 0x8f, 0xc9, 0x1d, 0xcc, 0x5c, 0xa2, 0x49, 0x0e, 0x50, 0x91, 0x08, 0x9a, 0x43, 0x55, 0x05}} , - {{0x5d, 0x93, 0x55, 0xdf, 0x9b, 0x12, 0x19, 0xec, 0x93, 0x85, 0x42, 0x9e, 0x66, 0x0f, 0x9d, 0xaf, 0x99, 0xaf, 0x26, 0x89, 0xbc, 0x61, 0xfd, 0xff, 0xce, 0x4b, 0xf4, 0x33, 0x95, 0xc9, 0x35, 0x58}}}, -{{{0x12, 0x55, 0xf9, 0xda, 0xcb, 0x44, 0xa7, 0xdc, 0x57, 0xe2, 0xf9, 0x9a, 0xe6, 0x07, 0x23, 0x60, 0x54, 0xa7, 0x39, 0xa5, 0x9b, 0x84, 0x56, 0x6e, 0xaa, 0x8b, 0x8f, 0xb0, 0x2c, 0x87, 0xaf, 0x67}} , - {{0x00, 0xa9, 0x4c, 0xb2, 0x12, 0xf8, 0x32, 0xa8, 0x7a, 0x00, 0x4b, 0x49, 0x32, 0xba, 0x1f, 0x5d, 0x44, 0x8e, 0x44, 0x7a, 0xdc, 0x11, 0xfb, 0x39, 0x08, 0x57, 0x87, 0xa5, 0x12, 0x42, 0x93, 0x0e}}}, -{{{0x17, 0xb4, 0xae, 0x72, 0x59, 0xd0, 0xaa, 0xa8, 0x16, 0x8b, 0x63, 0x11, 0xb3, 0x43, 0x04, 0xda, 0x0c, 0xa8, 0xb7, 0x68, 0xdd, 0x4e, 0x54, 0xe7, 0xaf, 0x5d, 0x5d, 0x05, 0x76, 0x36, 0xec, 0x0d}} , - {{0x6d, 0x7c, 0x82, 0x32, 0x38, 0x55, 0x57, 0x74, 0x5b, 0x7d, 0xc3, 0xc4, 0xfb, 0x06, 0x29, 0xf0, 0x13, 0x55, 0x54, 0xc6, 0xa7, 0xdc, 0x4c, 0x9f, 0x98, 0x49, 0x20, 0xa8, 0xc3, 0x8d, 0xfa, 0x48}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x87, 0x47, 0x9d, 0xe9, 0x25, 0xd5, 0xe3, 0x47, 0x78, 0xdf, 0x85, 0xa7, 0x85, 0x5e, 0x7a, 0x4c, 0x5f, 0x79, 0x1a, 0xf3, 0xa2, 0xb2, 0x28, 0xa0, 0x9c, 0xdd, 0x30, 0x40, 0xd4, 0x38, 0xbd, 0x28}} , - {{0xfc, 0xbb, 0xd5, 0x78, 0x6d, 0x1d, 0xd4, 0x99, 0xb4, 0xaa, 0x44, 0x44, 0x7a, 0x1b, 0xd8, 0xfe, 0xb4, 0x99, 0xb9, 0xcc, 0xe7, 0xc4, 0xd3, 0x3a, 0x73, 0x83, 0x41, 0x5c, 0x40, 0xd7, 0x2d, 0x55}}}, -{{{0x26, 0xe1, 0x7b, 0x5f, 0xe5, 0xdc, 0x3f, 0x7d, 0xa1, 0xa7, 0x26, 0x44, 0x22, 0x23, 0xc0, 0x8f, 0x7d, 0xf1, 0xb5, 0x11, 0x47, 0x7b, 0x19, 0xd4, 0x75, 0x6f, 0x1e, 0xa5, 0x27, 0xfe, 0xc8, 0x0e}} , - {{0xd3, 0x11, 0x3d, 0xab, 0xef, 0x2c, 0xed, 0xb1, 0x3d, 0x7c, 0x32, 0x81, 0x6b, 0xfe, 0xf8, 0x1c, 0x3c, 0x7b, 0xc0, 0x61, 0xdf, 0xb8, 0x75, 0x76, 0x7f, 0xaa, 0xd8, 0x93, 0xaf, 0x3d, 0xe8, 0x3d}}}, -{{{0xfd, 0x5b, 0x4e, 0x8d, 0xb6, 0x7e, 0x82, 0x9b, 0xef, 0xce, 0x04, 0x69, 0x51, 0x52, 0xff, 0xef, 0xa0, 0x52, 0xb5, 0x79, 0x17, 0x5e, 0x2f, 0xde, 0xd6, 0x3c, 0x2d, 0xa0, 0x43, 0xb4, 0x0b, 0x19}} , - {{0xc0, 0x61, 0x48, 0x48, 0x17, 0xf4, 0x9e, 0x18, 0x51, 0x2d, 0xea, 0x2f, 0xf2, 0xf2, 0xe0, 0xa3, 0x14, 0xb7, 0x8b, 0x3a, 0x30, 0xf5, 0x81, 0xc1, 0x5d, 0x71, 0x39, 0x62, 0x55, 0x1f, 0x60, 0x5a}}}, -{{{0xe5, 0x89, 0x8a, 0x76, 0x6c, 0xdb, 0x4d, 0x0a, 0x5b, 0x72, 0x9d, 0x59, 0x6e, 0x63, 0x63, 0x18, 0x7c, 0xe3, 0xfa, 0xe2, 0xdb, 0xa1, 0x8d, 0xf4, 0xa5, 0xd7, 0x16, 0xb2, 0xd0, 0xb3, 0x3f, 0x39}} , - {{0xce, 0x60, 0x09, 0x6c, 0xf5, 0x76, 0x17, 0x24, 0x80, 0x3a, 0x96, 0xc7, 0x94, 0x2e, 0xf7, 0x6b, 0xef, 0xb5, 0x05, 0x96, 0xef, 0xd3, 0x7b, 0x51, 0xda, 0x05, 0x44, 0x67, 0xbc, 0x07, 0x21, 0x4e}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xe9, 0x73, 0x6f, 0x21, 0xb9, 0xde, 0x22, 0x7d, 0xeb, 0x97, 0x31, 0x10, 0xa3, 0xea, 0xe1, 0xc6, 0x37, 0xeb, 0x8f, 0x43, 0x58, 0xde, 0x41, 0x64, 0x0e, 0x3e, 0x07, 0x99, 0x3d, 0xf1, 0xdf, 0x1e}} , - {{0xf8, 0xad, 0x43, 0xc2, 0x17, 0x06, 0xe2, 0xe4, 0xa9, 0x86, 0xcd, 0x18, 0xd7, 0x78, 0xc8, 0x74, 0x66, 0xd2, 0x09, 0x18, 0xa5, 0xf1, 0xca, 0xa6, 0x62, 0x92, 0xc1, 0xcb, 0x00, 0xeb, 0x42, 0x2e}}}, -{{{0x7b, 0x34, 0x24, 0x4c, 0xcf, 0x38, 0xe5, 0x6c, 0x0a, 0x01, 0x2c, 0x22, 0x0b, 0x24, 0x38, 0xad, 0x24, 0x7e, 0x19, 0xf0, 0x6c, 0xf9, 0x31, 0xf4, 0x35, 0x11, 0xf6, 0x46, 0x33, 0x3a, 0x23, 0x59}} , - {{0x20, 0x0b, 0xa1, 0x08, 0x19, 0xad, 0x39, 0x54, 0xea, 0x3e, 0x23, 0x09, 0xb6, 0xe2, 0xd2, 0xbc, 0x4d, 0xfc, 0x9c, 0xf0, 0x13, 0x16, 0x22, 0x3f, 0xb9, 0xd2, 0x11, 0x86, 0x90, 0x55, 0xce, 0x3c}}}, -{{{0xc4, 0x0b, 0x4b, 0x62, 0x99, 0x37, 0x84, 0x3f, 0x74, 0xa2, 0xf9, 0xce, 0xe2, 0x0b, 0x0f, 0x2a, 0x3d, 0xa3, 0xe3, 0xdb, 0x5a, 0x9d, 0x93, 0xcc, 0xa5, 0xef, 0x82, 0x91, 0x1d, 0xe6, 0x6c, 0x68}} , - {{0xa3, 0x64, 0x17, 0x9b, 0x8b, 0xc8, 0x3a, 0x61, 0xe6, 0x9d, 0xc6, 0xed, 0x7b, 0x03, 0x52, 0x26, 0x9d, 0x3a, 0xb3, 0x13, 0xcc, 0x8a, 0xfd, 0x2c, 0x1a, 0x1d, 0xed, 0x13, 0xd0, 0x55, 0x57, 0x0e}}}, -{{{0x1a, 0xea, 0xbf, 0xfd, 0x4a, 0x3c, 0x8e, 0xec, 0x29, 0x7e, 0x77, 0x77, 0x12, 0x99, 0xd7, 0x84, 0xf9, 0x55, 0x7f, 0xf1, 0x8b, 0xb4, 0xd2, 0x95, 0xa3, 0x8d, 0xf0, 0x8a, 0xa7, 0xeb, 0x82, 0x4b}} , - {{0x2c, 0x28, 0xf4, 0x3a, 0xf6, 0xde, 0x0a, 0xe0, 0x41, 0x44, 0x23, 0xf8, 0x3f, 0x03, 0x64, 0x9f, 0xc3, 0x55, 0x4c, 0xc6, 0xc1, 0x94, 0x1c, 0x24, 0x5d, 0x5f, 0x92, 0x45, 0x96, 0x57, 0x37, 0x14}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xc1, 0xcd, 0x90, 0x66, 0xb9, 0x76, 0xa0, 0x5b, 0xa5, 0x85, 0x75, 0x23, 0xf9, 0x89, 0xa5, 0x82, 0xb2, 0x6f, 0xb1, 0xeb, 0xc4, 0x69, 0x6f, 0x18, 0x5a, 0xed, 0x94, 0x3d, 0x9d, 0xd9, 0x2c, 0x1a}} , - {{0x35, 0xb0, 0xe6, 0x73, 0x06, 0xb7, 0x37, 0xe0, 0xf8, 0xb0, 0x22, 0xe8, 0xd2, 0xed, 0x0b, 0xef, 0xe6, 0xc6, 0x5a, 0x99, 0x9e, 0x1a, 0x9f, 0x04, 0x97, 0xe4, 0x4d, 0x0b, 0xbe, 0xba, 0x44, 0x40}}}, -{{{0xc1, 0x56, 0x96, 0x91, 0x5f, 0x1f, 0xbb, 0x54, 0x6f, 0x88, 0x89, 0x0a, 0xb2, 0xd6, 0x41, 0x42, 0x6a, 0x82, 0xee, 0x14, 0xaa, 0x76, 0x30, 0x65, 0x0f, 0x67, 0x39, 0xa6, 0x51, 0x7c, 0x49, 0x24}} , - {{0x35, 0xa3, 0x78, 0xd1, 0x11, 0x0f, 0x75, 0xd3, 0x70, 0x46, 0xdb, 0x20, 0x51, 0xcb, 0x92, 0x80, 0x54, 0x10, 0x74, 0x36, 0x86, 0xa9, 0xd7, 0xa3, 0x08, 0x78, 0xf1, 0x01, 0x29, 0xf8, 0x80, 0x3b}}}, -{{{0xdb, 0xa7, 0x9d, 0x9d, 0xbf, 0xa0, 0xcc, 0xed, 0x53, 0xa2, 0xa2, 0x19, 0x39, 0x48, 0x83, 0x19, 0x37, 0x58, 0xd1, 0x04, 0x28, 0x40, 0xf7, 0x8a, 0xc2, 0x08, 0xb7, 0xa5, 0x42, 0xcf, 0x53, 0x4c}} , - {{0xa7, 0xbb, 0xf6, 0x8e, 0xad, 0xdd, 0xf7, 0x90, 0xdd, 0x5f, 0x93, 0x89, 0xae, 0x04, 0x37, 0xe6, 0x9a, 0xb7, 0xe8, 0xc0, 0xdf, 0x16, 0x2a, 0xbf, 0xc4, 0x3a, 0x3c, 0x41, 0xd5, 0x89, 0x72, 0x5a}}}, -{{{0x1f, 0x96, 0xff, 0x34, 0x2c, 0x13, 0x21, 0xcb, 0x0a, 0x89, 0x85, 0xbe, 0xb3, 0x70, 0x9e, 0x1e, 0xde, 0x97, 0xaf, 0x96, 0x30, 0xf7, 0x48, 0x89, 0x40, 0x8d, 0x07, 0xf1, 0x25, 0xf0, 0x30, 0x58}} , - {{0x1e, 0xd4, 0x93, 0x57, 0xe2, 0x17, 0xe7, 0x9d, 0xab, 0x3c, 0x55, 0x03, 0x82, 0x2f, 0x2b, 0xdb, 0x56, 0x1e, 0x30, 0x2e, 0x24, 0x47, 0x6e, 0xe6, 0xff, 0x33, 0x24, 0x2c, 0x75, 0x51, 0xd4, 0x67}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0x2b, 0x06, 0xd9, 0xa1, 0x5d, 0xe1, 0xf4, 0xd1, 0x1e, 0x3c, 0x9a, 0xc6, 0x29, 0x2b, 0x13, 0x13, 0x78, 0xc0, 0xd8, 0x16, 0x17, 0x2d, 0x9e, 0xa9, 0xc9, 0x79, 0x57, 0xab, 0x24, 0x91, 0x92, 0x19}} , - {{0x69, 0xfb, 0xa1, 0x9c, 0xa6, 0x75, 0x49, 0x7d, 0x60, 0x73, 0x40, 0x42, 0xc4, 0x13, 0x0a, 0x95, 0x79, 0x1e, 0x04, 0x83, 0x94, 0x99, 0x9b, 0x1e, 0x0c, 0xe8, 0x1f, 0x54, 0xef, 0xcb, 0xc0, 0x52}}}, -{{{0x14, 0x89, 0x73, 0xa1, 0x37, 0x87, 0x6a, 0x7a, 0xcf, 0x1d, 0xd9, 0x2e, 0x1a, 0x67, 0xed, 0x74, 0xc0, 0xf0, 0x9c, 0x33, 0xdd, 0xdf, 0x08, 0xbf, 0x7b, 0xd1, 0x66, 0xda, 0xe6, 0xc9, 0x49, 0x08}} , - {{0xe9, 0xdd, 0x5e, 0x55, 0xb0, 0x0a, 0xde, 0x21, 0x4c, 0x5a, 0x2e, 0xd4, 0x80, 0x3a, 0x57, 0x92, 0x7a, 0xf1, 0xc4, 0x2c, 0x40, 0xaf, 0x2f, 0xc9, 0x92, 0x03, 0xe5, 0x5a, 0xbc, 0xdc, 0xf4, 0x09}}}, -{{{0xf3, 0xe1, 0x2b, 0x7c, 0x05, 0x86, 0x80, 0x93, 0x4a, 0xad, 0xb4, 0x8f, 0x7e, 0x99, 0x0c, 0xfd, 0xcd, 0xef, 0xd1, 0xff, 0x2c, 0x69, 0x34, 0x13, 0x41, 0x64, 0xcf, 0x3b, 0xd0, 0x90, 0x09, 0x1e}} , - {{0x9d, 0x45, 0xd6, 0x80, 0xe6, 0x45, 0xaa, 0xf4, 0x15, 0xaa, 0x5c, 0x34, 0x87, 0x99, 0xa2, 0x8c, 0x26, 0x84, 0x62, 0x7d, 0xb6, 0x29, 0xc0, 0x52, 0xea, 0xf5, 0x81, 0x18, 0x0f, 0x35, 0xa9, 0x0e}}}, -{{{0xe7, 0x20, 0x72, 0x7c, 0x6d, 0x94, 0x5f, 0x52, 0x44, 0x54, 0xe3, 0xf1, 0xb2, 0xb0, 0x36, 0x46, 0x0f, 0xae, 0x92, 0xe8, 0x70, 0x9d, 0x6e, 0x79, 0xb1, 0xad, 0x37, 0xa9, 0x5f, 0xc0, 0xde, 0x03}} , - {{0x15, 0x55, 0x37, 0xc6, 0x1c, 0x27, 0x1c, 0x6d, 0x14, 0x4f, 0xca, 0xa4, 0xc4, 0x88, 0x25, 0x46, 0x39, 0xfc, 0x5a, 0xe5, 0xfe, 0x29, 0x11, 0x69, 0xf5, 0x72, 0x84, 0x4d, 0x78, 0x9f, 0x94, 0x15}}}, -{{{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}}, - {{0x01, 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}}}, -{{{0xec, 0xd3, 0xff, 0x57, 0x0b, 0xb0, 0xb2, 0xdc, 0xf8, 0x4f, 0xe2, 0x12, 0xd5, 0x36, 0xbe, 0x6b, 0x09, 0x43, 0x6d, 0xa3, 0x4d, 0x90, 0x2d, 0xb8, 0x74, 0xe8, 0x71, 0x45, 0x19, 0x8b, 0x0c, 0x6a}} , - {{0xb8, 0x42, 0x1c, 0x03, 0xad, 0x2c, 0x03, 0x8e, 0xac, 0xd7, 0x98, 0x29, 0x13, 0xc6, 0x02, 0x29, 0xb5, 0xd4, 0xe7, 0xcf, 0xcc, 0x8b, 0x83, 0xec, 0x35, 0xc7, 0x9c, 0x74, 0xb7, 0xad, 0x85, 0x5f}}}, -{{{0x78, 0x84, 0xe1, 0x56, 0x45, 0x69, 0x68, 0x5a, 0x4f, 0xb8, 0xb1, 0x29, 0xff, 0x33, 0x03, 0x31, 0xb7, 0xcb, 0x96, 0x25, 0xe6, 0xe6, 0x41, 0x98, 0x1a, 0xbb, 0x03, 0x56, 0xf2, 0xb2, 0x91, 0x34}} , - {{0x2c, 0x6c, 0xf7, 0x66, 0xa4, 0x62, 0x6b, 0x39, 0xb3, 0xba, 0x65, 0xd3, 0x1c, 0xf8, 0x11, 0xaa, 0xbe, 0xdc, 0x80, 0x59, 0x87, 0xf5, 0x7b, 0xe5, 0xe3, 0xb3, 0x3e, 0x39, 0xda, 0xbe, 0x88, 0x09}}}, -{{{0x8b, 0xf1, 0xa0, 0xf5, 0xdc, 0x29, 0xb4, 0xe2, 0x07, 0xc6, 0x7a, 0x00, 0xd0, 0x89, 0x17, 0x51, 0xd4, 0xbb, 0xd4, 0x22, 0xea, 0x7e, 0x7d, 0x7c, 0x24, 0xea, 0xf2, 0xe8, 0x22, 0x12, 0x95, 0x06}} , - {{0xda, 0x7c, 0xa4, 0x0c, 0xf4, 0xba, 0x6e, 0xe1, 0x89, 0xb5, 0x59, 0xca, 0xf1, 0xc0, 0x29, 0x36, 0x09, 0x44, 0xe2, 0x7f, 0xd1, 0x63, 0x15, 0x99, 0xea, 0x25, 0xcf, 0x0c, 0x9d, 0xc0, 0x44, 0x6f}}}, -{{{0x1d, 0x86, 0x4e, 0xcf, 0xf7, 0x37, 0x10, 0x25, 0x8f, 0x12, 0xfb, 0x19, 0xfb, 0xe0, 0xed, 0x10, 0xc8, 0xe2, 0xf5, 0x75, 0xb1, 0x33, 0xc0, 0x96, 0x0d, 0xfb, 0x15, 0x6c, 0x0d, 0x07, 0x5f, 0x05}} , - {{0x69, 0x3e, 0x47, 0x97, 0x2c, 0xaf, 0x52, 0x7c, 0x78, 0x83, 0xad, 0x1b, 0x39, 0x82, 0x2f, 0x02, 0x6f, 0x47, 0xdb, 0x2a, 0xb0, 0xe1, 0x91, 0x99, 0x55, 0xb8, 0x99, 0x3a, 0xa0, 0x44, 0x11, 0x51}}} -}; - -static inline void p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p) -{ - fe25519_mul(&r->x, &p->x, &p->t); - fe25519_mul(&r->y, &p->y, &p->z); - fe25519_mul(&r->z, &p->z, &p->t); -} - -static inline void p1p1_to_p2_2(ge25519_p3 *r, const ge25519_p1p1 *p) -{ - fe25519_mul(&r->x, &p->x, &p->t); - fe25519_mul(&r->y, &p->y, &p->z); - fe25519_mul(&r->z, &p->z, &p->t); -} - -static inline void p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p) -{ - p1p1_to_p2_2(r, p); - fe25519_mul(&r->t, &p->x, &p->y); -} - -static void ge25519_mixadd2(ge25519_p3 *r, const ge25519_aff *q) -{ - fe25519 a,b,t1,t2,c,d,e,f,g,h,qt; - fe25519_mul(&qt, &q->x, &q->y); - fe25519_sub(&a, &r->y, &r->x); /* A = (Y1-X1)*(Y2-X2) */ - fe25519_add(&b, &r->y, &r->x); /* B = (Y1+X1)*(Y2+X2) */ - fe25519_sub(&t1, &q->y, &q->x); - fe25519_add(&t2, &q->y, &q->x); - fe25519_mul(&a, &a, &t1); - fe25519_mul(&b, &b, &t2); - fe25519_sub(&e, &b, &a); /* E = B-A */ - fe25519_add(&h, &b, &a); /* H = B+A */ - fe25519_mul(&c, &r->t, &qt); /* C = T1*k*T2 */ - fe25519_mul(&c, &c, &ge25519_ec2d); - fe25519_add(&d, &r->z, &r->z); /* D = Z1*2 */ - fe25519_sub(&f, &d, &c); /* F = D-C */ - fe25519_add(&g, &d, &c); /* G = D+C */ - fe25519_mul(&r->x, &e, &f); - fe25519_mul(&r->y, &h, &g); - fe25519_mul(&r->z, &g, &f); - fe25519_mul(&r->t, &e, &h); -} - -static void add_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_p3 *q) -{ - fe25519 a, b, c, d, t; - - fe25519_sub(&a, &p->y, &p->x); /* A = (Y1-X1)*(Y2-X2) */ - fe25519_sub(&t, &q->y, &q->x); - fe25519_mul(&a, &a, &t); - fe25519_add(&b, &p->x, &p->y); /* B = (Y1+X1)*(Y2+X2) */ - fe25519_add(&t, &q->x, &q->y); - fe25519_mul(&b, &b, &t); - fe25519_mul(&c, &p->t, &q->t); /* C = T1*k*T2 */ - fe25519_mul(&c, &c, &ge25519_ec2d); - fe25519_mul(&d, &p->z, &q->z); /* D = Z1*2*Z2 */ - fe25519_add(&d, &d, &d); - fe25519_sub(&r->x, &b, &a); /* E = B-A */ - fe25519_sub(&r->t, &d, &c); /* F = D-C */ - fe25519_add(&r->z, &d, &c); /* G = D+C */ - fe25519_add(&r->y, &b, &a); /* H = B+A */ -} - -/* See http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd */ -static void dbl_p1p1(ge25519_p1p1 *r, const ge25519_p2 *p) -{ - fe25519 a,b,c,d; - fe25519_square(&a, &p->x); - fe25519_square(&b, &p->y); - fe25519_square(&c, &p->z); - fe25519_add(&c, &c, &c); - fe25519_neg(&d, &a); - - fe25519_add(&r->x, &p->x, &p->y); - fe25519_square(&r->x, &r->x); - fe25519_sub(&r->x, &r->x, &a); - fe25519_sub(&r->x, &r->x, &b); - fe25519_add(&r->z, &d, &b); - fe25519_sub(&r->t, &r->z, &c); - fe25519_sub(&r->y, &d, &b); -} - -/* Constant-time version of: if(b) r = p */ -static inline void cmov_aff(ge25519_aff *r, const ge25519_aff *p, unsigned char b) -{ - fe25519_cmov(&r->x, &p->x, b); - fe25519_cmov(&r->y, &p->y, b); -} - -static inline unsigned char equal(signed char b,signed char c) -{ - unsigned char ub = b; - unsigned char uc = c; - unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ - crypto_uint32 y = x; /* 0: yes; 1..255: no */ - y -= 1; /* 4294967295: yes; 0..254: no */ - y >>= 31; /* 1: yes; 0: no */ - return (unsigned char)y; -} - -static inline unsigned char negative(signed char b) -{ - unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ - x >>= 63; /* 1: yes; 0: no */ - return (unsigned char)x; -} - -static inline void choose_t(ge25519_aff *t, unsigned long long pos, signed char b) -{ - /* constant time */ - fe25519 v; - *t = ge25519_base_multiples_affine[5*pos+0]; - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+1],equal(b,1) | equal(b,-1)); - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+2],equal(b,2) | equal(b,-2)); - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+3],equal(b,3) | equal(b,-3)); - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+4],equal(b,-4)); - fe25519_neg(&v, &t->x); - fe25519_cmov(&t->x, &v, negative(b)); -} - -static inline void setneutral(ge25519 *r) -{ - fe25519_setzero(&r->x); - fe25519_setone(&r->y); - fe25519_setone(&r->z); - fe25519_setzero(&r->t); -} - -/* return 0 on success, -1 otherwise */ -static int ge25519_unpackneg_vartime(ge25519_p3 *r, const unsigned char p[32]) -{ - unsigned char par; - fe25519 t, chk, num, den, den2, den4, den6; - fe25519_setone(&r->z); - par = p[31] >> 7; - fe25519_unpack(&r->y, p); - fe25519_square(&num, &r->y); /* x = y^2 */ - fe25519_mul(&den, &num, &ge25519_ecd); /* den = dy^2 */ - fe25519_sub(&num, &num, &r->z); /* x = y^2-1 */ - fe25519_add(&den, &r->z, &den); /* den = dy^2+1 */ - - /* Computation of sqrt(num/den) */ - /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ - fe25519_square(&den2, &den); - fe25519_square(&den4, &den2); - fe25519_mul(&den6, &den4, &den2); - fe25519_mul(&t, &den6, &num); - fe25519_mul(&t, &t, &den); - - fe25519_pow2523(&t, &t); - /* 2. computation of r->x = t * num * den^3 */ - fe25519_mul(&t, &t, &num); - fe25519_mul(&t, &t, &den); - fe25519_mul(&t, &t, &den); - fe25519_mul(&r->x, &t, &den); - - /* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: */ - fe25519_square(&chk, &r->x); - fe25519_mul(&chk, &chk, &den); - if (!fe25519_iseq_vartime(&chk, &num)) - fe25519_mul(&r->x, &r->x, &ge25519_sqrtm1); - - /* 4. Now we have one of the two square roots, except if input was not a square */ - fe25519_square(&chk, &r->x); - fe25519_mul(&chk, &chk, &den); - if (!fe25519_iseq_vartime(&chk, &num)) - return -1; - - /* 5. Choose the desired square root according to parity: */ - if(fe25519_getparity(&r->x) != (1-par)) - fe25519_neg(&r->x, &r->x); - - fe25519_mul(&r->t, &r->x, &r->y); - return 0; -} - -static inline void ge25519_pack(unsigned char r[32], const ge25519_p3 *p) -{ - fe25519 tx, ty, zi; - fe25519_invert(&zi, &p->z); - fe25519_mul(&tx, &p->x, &zi); - fe25519_mul(&ty, &p->y, &zi); - fe25519_pack(r, &ty); - r[31] ^= fe25519_getparity(&tx) << 7; -} - -#if 0 -static int ge25519_isneutral_vartime(const ge25519_p3 *p) -{ - int ret = 1; - if(!fe25519_iszero(&p->x)) ret = 0; - if(!fe25519_iseq_vartime(&p->y, &p->z)) ret = 0; - return ret; -} -#endif - -/* computes [s1]p1 + [s2]p2 */ -static void ge25519_double_scalarmult_vartime(ge25519_p3 *r, const ge25519_p3 *p1, const sc25519 *s1, const ge25519_p3 *p2, const sc25519 *s2) -{ - ge25519_p1p1 tp1p1; - ge25519_p3 pre[16]; - char *pre5 = (char *)(&(pre[5])); // eliminate type punning warning - unsigned char b[127]; - int i; - - /* precomputation s2 s1 */ - setneutral(pre); /* 00 00 */ - pre[1] = *p1; /* 00 01 */ - dbl_p1p1(&tp1p1,(ge25519_p2 *)p1); p1p1_to_p3( &pre[2], &tp1p1); /* 00 10 */ - add_p1p1(&tp1p1,&pre[1], &pre[2]); p1p1_to_p3( &pre[3], &tp1p1); /* 00 11 */ - pre[4] = *p2; /* 01 00 */ - add_p1p1(&tp1p1,&pre[1], &pre[4]); p1p1_to_p3( &pre[5], &tp1p1); /* 01 01 */ - add_p1p1(&tp1p1,&pre[2], &pre[4]); p1p1_to_p3( &pre[6], &tp1p1); /* 01 10 */ - add_p1p1(&tp1p1,&pre[3], &pre[4]); p1p1_to_p3( &pre[7], &tp1p1); /* 01 11 */ - dbl_p1p1(&tp1p1,(ge25519_p2 *)p2); p1p1_to_p3( &pre[8], &tp1p1); /* 10 00 */ - add_p1p1(&tp1p1,&pre[1], &pre[8]); p1p1_to_p3( &pre[9], &tp1p1); /* 10 01 */ - dbl_p1p1(&tp1p1,(ge25519_p2 *)pre5); p1p1_to_p3(&pre[10], &tp1p1); /* 10 10 */ - add_p1p1(&tp1p1,&pre[3], &pre[8]); p1p1_to_p3(&pre[11], &tp1p1); /* 10 11 */ - add_p1p1(&tp1p1,&pre[4], &pre[8]); p1p1_to_p3(&pre[12], &tp1p1); /* 11 00 */ - add_p1p1(&tp1p1,&pre[1],&pre[12]); p1p1_to_p3(&pre[13], &tp1p1); /* 11 01 */ - add_p1p1(&tp1p1,&pre[2],&pre[12]); p1p1_to_p3(&pre[14], &tp1p1); /* 11 10 */ - add_p1p1(&tp1p1,&pre[3],&pre[12]); p1p1_to_p3(&pre[15], &tp1p1); /* 11 11 */ - - sc25519_2interleave2(b,s1,s2); - - /* scalar multiplication */ - *r = pre[b[126]]; - for(i=125;i>=0;i--) - { - dbl_p1p1(&tp1p1, (ge25519_p2 *)r); - p1p1_to_p2((ge25519_p2 *) r, &tp1p1); - dbl_p1p1(&tp1p1, (ge25519_p2 *)r); - if(b[i]!=0) - { - p1p1_to_p3(r, &tp1p1); - add_p1p1(&tp1p1, r, &pre[b[i]]); - } - if(i != 0) p1p1_to_p2((ge25519_p2 *)r, &tp1p1); - else p1p1_to_p3(r, &tp1p1); - } -} - -static inline void ge25519_scalarmult_base(ge25519_p3 *r, const sc25519 *s) -{ - signed char b[85]; - int i; - ge25519_aff t; - sc25519_window3(b,s); - - choose_t((ge25519_aff *)r, 0, b[0]); - fe25519_setone(&r->z); - fe25519_mul(&r->t, &r->x, &r->y); - for(i=1;i<85;i++) - { - choose_t(&t, (unsigned long long) i, b[i]); - ge25519_mixadd2(r, &t); - } -} - -static inline void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen) -{ - unsigned long long i; - - for (i = 0;i < 32;++i) playground[i] = sm[i]; - for (i = 32;i < 64;++i) playground[i] = pk[i-32]; - for (i = 64;i < smlen;++i) playground[i] = sm[i]; - - //crypto_hash_sha512(hram,playground,smlen); - SHA512::hash(hram,playground,(unsigned int)smlen); -} - -// This is the original sign and verify code -- the versions in sign() and -// verify() below the fold are slightly modified in terms of how they behave -// in relation to the message, but the algorithms are the same. - -#if 0 -int crypto_sign_keypair( - unsigned char *pk, - unsigned char *sk - ) -{ - sc25519 scsk; - ge25519 gepk; - unsigned char extsk[64]; - int i; - - randombytes(sk, 32); - crypto_hash_sha512(extsk, sk, 32); - extsk[0] &= 248; - extsk[31] &= 127; - extsk[31] |= 64; - - sc25519_from32bytes(&scsk,extsk); - - ge25519_scalarmult_base(&gepk, &scsk); - ge25519_pack(pk, &gepk); - for(i=0;i<32;i++) - sk[32 + i] = pk[i]; - return 0; -} - -static int crypto_sign( - unsigned char *sm,unsigned long long *smlen, - const unsigned char *m,unsigned long long mlen, - const unsigned char *sk - ) -{ - sc25519 sck, scs, scsk; - ge25519 ger; - unsigned char r[32]; - unsigned char s[32]; - unsigned char extsk[64]; - unsigned long long i; - unsigned char hmg[crypto_hash_sha512_BYTES]; - unsigned char hram[crypto_hash_sha512_BYTES]; - - crypto_hash_sha512(extsk, sk, 32); - extsk[0] &= 248; - extsk[31] &= 127; - extsk[31] |= 64; - - *smlen = mlen+64; - for(i=0;i. - */ - -#ifndef ZT_C25519_HPP -#define ZT_C25519_HPP - -#include "Array.hpp" -#include "Utils.hpp" - -namespace ZeroTier { - -#define ZT_C25519_PUBLIC_KEY_LEN 64 -#define ZT_C25519_PRIVATE_KEY_LEN 64 -#define ZT_C25519_SIGNATURE_LEN 96 - -/** - * A combined Curve25519 ECDH and Ed25519 signature engine - */ -class C25519 -{ -public: - /** - * Public key (both crypto and signing) - */ - typedef Array Public; // crypto key, signing key (both 32 bytes) - - /** - * Private key (both crypto and signing) - */ - typedef Array Private; // crypto key, signing key (both 32 bytes) - - /** - * Message signature - */ - typedef Array Signature; - - /** - * Public/private key pair - */ - typedef struct { - Public pub; - Private priv; - } Pair; - - /** - * Generate a C25519 elliptic curve key pair - */ - static inline Pair generate() - throw() - { - Pair kp; - Utils::getSecureRandom(kp.priv.data,(unsigned int)kp.priv.size()); - _calcPubDH(kp); - _calcPubED(kp); - return kp; - } - - /** - * Generate a key pair satisfying a condition - * - * This begins with a random keypair from a random secret key and then - * iteratively increments the random secret until cond(kp) returns true. - * This is used to compute key pairs in which the public key, its hash - * or some other aspect of it satisfies some condition, such as for a - * hashcash criteria. - * - * @param cond Condition function or function object - * @return Key pair where cond(kp) returns true - * @tparam F Type of 'cond' - */ - template - static inline Pair generateSatisfying(F cond) - throw() - { - Pair kp; - void *const priv = (void *)kp.priv.data; - Utils::getSecureRandom(priv,(unsigned int)kp.priv.size()); - _calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv - do { - ++(((uint64_t *)priv)[1]); - --(((uint64_t *)priv)[2]); - _calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied - } while (!cond(kp)); - return kp; - } - - /** - * Perform C25519 ECC key agreement - * - * Actual key bytes are generated from one or more SHA-512 digests of - * the raw result of key agreement. - * - * @param mine My private key - * @param their Their public key - * @param keybuf Buffer to fill - * @param keylen Number of key bytes to generate - */ - static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen) - throw(); - static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen) - throw() - { - agree(mine.priv,their,keybuf,keylen); - } - - /** - * Sign a message with a sender's key pair - * - * This takes the SHA-521 of msg[] and then signs the first 32 bytes of this - * digest, returning it and the 64-byte ed25519 signature in signature[]. - * This results in a signature that verifies both the signer's authenticity - * and the integrity of the message. - * - * This is based on the original ed25519 code from NaCl and the SUPERCOP - * cipher benchmark suite, but with the modification that it always - * produces a signature of fixed 96-byte length based on the hash of an - * arbitrary-length message. - * - * @param myPrivate My private key - * @param myPublic My public key - * @param msg Message to sign - * @param len Length of message in bytes - * @param signature Buffer to fill with signature -- MUST be 96 bytes in length - */ - static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature) - throw(); - static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature) - throw() - { - sign(mine.priv,mine.pub,msg,len,signature); - } - - /** - * Sign a message with a sender's key pair - * - * @param myPrivate My private key - * @param myPublic My public key - * @param msg Message to sign - * @param len Length of message in bytes - * @return Signature - */ - static inline Signature sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len) - throw() - { - Signature sig; - sign(myPrivate,myPublic,msg,len,sig.data); - return sig; - } - static inline Signature sign(const Pair &mine,const void *msg,unsigned int len) - throw() - { - Signature sig; - sign(mine.priv,mine.pub,msg,len,sig.data); - return sig; - } - - /** - * Verify a message's signature - * - * @param their Public key to verify against - * @param msg Message to verify signature integrity against - * @param len Length of message in bytes - * @param signature 96-byte signature - * @return True if signature is valid and the message is authentic and unmodified - */ - static bool verify(const Public &their,const void *msg,unsigned int len,const void *signature) - throw(); - - /** - * Verify a message's signature - * - * @param their Public key to verify against - * @param msg Message to verify signature integrity against - * @param len Length of message in bytes - * @param signature 96-byte signature - * @return True if signature is valid and the message is authentic and unmodified - */ - static inline bool verify(const Public &their,const void *msg,unsigned int len,const Signature &signature) - throw() - { - return verify(their,msg,len,signature.data); - } - -private: - // derive first 32 bytes of kp.pub from first 32 bytes of kp.priv - // this is the ECDH key - static void _calcPubDH(Pair &kp) - throw(); - - // derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv - // this is the Ed25519 sign/verify key - static void _calcPubED(Pair &kp) - throw(); -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Capability.cpp b/zto/node/Capability.cpp deleted file mode 100644 index c178e56..0000000 --- a/zto/node/Capability.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Capability.hpp" -#include "RuntimeEnvironment.hpp" -#include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Network.hpp" - -namespace ZeroTier { - -int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const -{ - try { - // There must be at least one entry, and sanity check for bad chain max length - if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) - return -1; - - // Validate all entries in chain of custody - Buffer<(sizeof(Capability) * 2)> tmp; - this->serialize(tmp,true); - for(unsigned int c=0;c<_maxCustodyChainLength;++c) { - if (c == 0) { - if ((!_custody[c].to)||(!_custody[c].from)||(_custody[c].from != Network::controllerFor(_nwid))) - return -1; // the first entry must be present and from the network's controller - } else { - if (!_custody[c].to) - return 0; // all previous entries were valid, so we are valid - else if ((!_custody[c].from)||(_custody[c].from != _custody[c-1].to)) - return -1; // otherwise if we have another entry it must be from the previous holder in the chain - } - - const Identity id(RR->topology->getIdentity(tPtr,_custody[c].from)); - if (id) { - if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) - return -1; - } else { - RR->sw->requestWhois(tPtr,_custody[c].from); - return 1; - } - } - - // We reached max custody chain length and everything was valid - return 0; - } catch ( ... ) {} - return -1; -} - -} // namespace ZeroTier diff --git a/zto/node/Capability.hpp b/zto/node/Capability.hpp deleted file mode 100644 index 5ef6c99..0000000 --- a/zto/node/Capability.hpp +++ /dev/null @@ -1,469 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_CAPABILITY_HPP -#define ZT_CAPABILITY_HPP - -#include -#include -#include - -#include "Constants.hpp" -#include "Address.hpp" -#include "C25519.hpp" -#include "Utils.hpp" -#include "Buffer.hpp" -#include "Identity.hpp" -#include "../include/ZeroTierOne.h" - -namespace ZeroTier { - -class RuntimeEnvironment; - -/** - * A set of grouped and signed network flow rules - * - * On the sending side the sender does the following for each packet: - * - * (1) Evaluates its capabilities in ascending order of ID to determine - * which capability allows it to transmit this packet. - * (2) If it has not done so lately, it then sends this capability to the - * receving peer ("presents" it). - * (3) The sender then sends the packet. - * - * On the receiving side the receiver evaluates the capabilities presented - * by the sender. If any valid un-expired capability allows this packet it - * is accepted. - * - * Note that this is after evaluation of network scope rules and only if - * network scope rules do not deliver an explicit match. - * - * Capabilities support a chain of custody. This is currently unused but - * in the future would allow the publication of capabilities that can be - * handed off between nodes. Limited transferrability of capabilities is - * a feature of true capability based security. - */ -class Capability -{ -public: - Capability() - { - memset(this,0,sizeof(Capability)); - } - - /** - * @param id Capability ID - * @param nwid Network ID - * @param ts Timestamp (at controller) - * @param mccl Maximum custody chain length (1 to create non-transferrable capability) - * @param rules Network flow rules for this capability - * @param ruleCount Number of flow rules - */ - Capability(uint32_t id,uint64_t nwid,uint64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) - { - memset(this,0,sizeof(Capability)); - _nwid = nwid; - _ts = ts; - _id = id; - _maxCustodyChainLength = (mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1; - _ruleCount = (ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES; - if (_ruleCount) - memcpy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount); - } - - /** - * @return Rules -- see ruleCount() for size of array - */ - inline const ZT_VirtualNetworkRule *rules() const { return _rules; } - - /** - * @return Number of rules in rules() - */ - inline unsigned int ruleCount() const { return _ruleCount; } - - /** - * @return ID and evaluation order of this capability in network - */ - inline uint32_t id() const { return _id; } - - /** - * @return Network ID for which this capability was issued - */ - inline uint64_t networkId() const { return _nwid; } - - /** - * @return Timestamp - */ - inline uint64_t timestamp() const { return _ts; } - - /** - * @return Last 'to' address in chain of custody - */ - inline Address issuedTo() const - { - Address i2; - for(unsigned int i=0;i tmp; - this->serialize(tmp,true); - _custody[i].to = to; - _custody[i].from = from.address(); - _custody[i].signature = from.sign(tmp.data(),tmp.size()); - return true; - } - } - } catch ( ... ) {} - return false; - } - - /** - * Verify this capability's chain of custody and signatures - * - * @param RR Runtime environment to provide for peer lookup, etc. - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; - - template - static inline void serializeRules(Buffer &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) - { - for(unsigned int i=0;i - static inline void deserializeRules(const Buffer &b,unsigned int &p,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,const unsigned int maxRuleCount) - { - while ((ruleCount < maxRuleCount)&&(p < b.size())) { - rules[ruleCount].t = (uint8_t)b[p++]; - const unsigned int fieldLen = (unsigned int)b[p++]; - switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) { - default: - break; - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_WATCH: - case ZT_NETWORK_RULE_ACTION_REDIRECT: - rules[ruleCount].v.fwd.address = b.template at(p); - rules[ruleCount].v.fwd.flags = b.template at(p + 8); - rules[ruleCount].v.fwd.length = b.template at(p + 12); - break; - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - rules[ruleCount].v.zt = Address(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - rules[ruleCount].v.vlanId = b.template at(p); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - rules[ruleCount].v.vlanPcp = (uint8_t)b[p]; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - rules[ruleCount].v.vlanDei = (uint8_t)b[p]; - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - memcpy(rules[ruleCount].v.mac,b.field(p,6),6); - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - memcpy(&(rules[ruleCount].v.ipv4.ip),b.field(p,4),4); - rules[ruleCount].v.ipv4.mask = (uint8_t)b[p + 4]; - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - memcpy(rules[ruleCount].v.ipv6.ip,b.field(p,16),16); - rules[ruleCount].v.ipv6.mask = (uint8_t)b[p + 16]; - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - rules[ruleCount].v.ipTos.mask = (uint8_t)b[p]; - rules[ruleCount].v.ipTos.value[0] = (uint8_t)b[p+1]; - rules[ruleCount].v.ipTos.value[1] = (uint8_t)b[p+2]; - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - rules[ruleCount].v.ipProtocol = (uint8_t)b[p]; - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - rules[ruleCount].v.etherType = b.template at(p); - break; - case ZT_NETWORK_RULE_MATCH_ICMP: - rules[ruleCount].v.icmp.type = (uint8_t)b[p]; - rules[ruleCount].v.icmp.code = (uint8_t)b[p+1]; - rules[ruleCount].v.icmp.flags = (uint8_t)b[p+2]; - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - rules[ruleCount].v.port[0] = b.template at(p); - rules[ruleCount].v.port[1] = b.template at(p + 2); - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: - rules[ruleCount].v.characteristics = b.template at(p); - break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - rules[ruleCount].v.frameSize[0] = b.template at(p); - rules[ruleCount].v.frameSize[1] = b.template at(p + 2); - break; - case ZT_NETWORK_RULE_MATCH_RANDOM: - rules[ruleCount].v.randomProbability = b.template at(p); - break; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: - case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: - case ZT_NETWORK_RULE_MATCH_TAG_SENDER: - case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: - rules[ruleCount].v.tag.id = b.template at(p); - rules[ruleCount].v.tag.value = b.template at(p + 4); - break; - } - p += fieldLen; - ++ruleCount; - } - } - - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - // These are the same between Tag and Capability - b.append(_nwid); - b.append(_ts); - b.append(_id); - - b.append((uint16_t)_ruleCount); - serializeRules(b,_rules,_ruleCount); - b.append((uint8_t)_maxCustodyChainLength); - - if (!forSign) { - for(unsigned int i=0;;++i) { - if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) { - _custody[i].to.appendTo(b); - _custody[i].from.appendTo(b); - b.append((uint8_t)1); // 1 == Ed25519 signature - b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature - b.append(_custody[i].signature.data,ZT_C25519_SIGNATURE_LEN); - } else { - b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain - break; - } - } - } - - // This is the size of any additional fields, currently 0. - b.append((uint16_t)0); - - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - memset(this,0,sizeof(Capability)); - - unsigned int p = startAt; - - _nwid = b.template at(p); p += 8; - _ts = b.template at(p); p += 8; - _id = b.template at(p); p += 4; - - const unsigned int rc = b.template at(p); p += 2; - if (rc > ZT_MAX_CAPABILITY_RULES) - throw std::runtime_error("rule overflow"); - deserializeRules(b,p,_rules,_ruleCount,rc); - - _maxCustodyChainLength = (unsigned int)b[p++]; - if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) - throw std::runtime_error("invalid max custody chain length"); - - for(unsigned int i=0;;++i) { - const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; - if (!to) - break; - if ((i >= _maxCustodyChainLength)||(i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) - throw std::runtime_error("unterminated custody chain"); - _custody[i].to = to; - _custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; - if (b[p++] == 1) { - if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) - throw std::runtime_error("invalid signature"); - p += 2; - memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; - } else { - p += 2 + b.template at(p); - } - } - - p += 2 + b.template at(p); - if (p > b.size()) - throw std::runtime_error("extended field overflow"); - - return (p - startAt); - } - - // Provides natural sort order by ID - inline bool operator<(const Capability &c) const { return (_id < c._id); } - - inline bool operator==(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) == 0); } - inline bool operator!=(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) != 0); } - -private: - uint64_t _nwid; - uint64_t _ts; - uint32_t _id; - - unsigned int _maxCustodyChainLength; - - unsigned int _ruleCount; - ZT_VirtualNetworkRule _rules[ZT_MAX_CAPABILITY_RULES]; - - struct { - Address to; - Address from; - C25519::Signature signature; - } _custody[ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH]; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/CertificateOfMembership.cpp b/zto/node/CertificateOfMembership.cpp deleted file mode 100644 index 9bf7021..0000000 --- a/zto/node/CertificateOfMembership.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "CertificateOfMembership.hpp" -#include "RuntimeEnvironment.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Network.hpp" - -namespace ZeroTier { - -void CertificateOfMembership::setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta) -{ - _signedBy.zero(); - - for(unsigned int i=0;i<_qualifierCount;++i) { - if (_qualifiers[i].id == id) { - _qualifiers[i].value = value; - _qualifiers[i].maxDelta = maxDelta; - return; - } - } - - if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { - _qualifiers[_qualifierCount].id = id; - _qualifiers[_qualifierCount].value = value; - _qualifiers[_qualifierCount].maxDelta = maxDelta; - ++_qualifierCount; - std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount])); - } -} - -#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF - -std::string CertificateOfMembership::toString() const -{ - std::string s; - - s.append("1:"); // COM_UINT64_ED25519 - - uint64_t *const buf = new uint64_t[_qualifierCount * 3]; - try { - unsigned int ptr = 0; - for(unsigned int i=0;i<_qualifierCount;++i) { - buf[ptr++] = Utils::hton(_qualifiers[i].id); - buf[ptr++] = Utils::hton(_qualifiers[i].value); - buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); - } - s.append(Utils::hex(buf,ptr * sizeof(uint64_t))); - delete [] buf; - } catch ( ... ) { - delete [] buf; - throw; - } - - s.push_back(':'); - - s.append(_signedBy.toString()); - - if (_signedBy) { - s.push_back(':'); - s.append(Utils::hex(_signature.data,(unsigned int)_signature.size())); - } - - return s; -} - -void CertificateOfMembership::fromString(const char *s) -{ - _qualifierCount = 0; - _signedBy.zero(); - memset(_signature.data,0,_signature.size()); - - if (!*s) - return; - - unsigned int colonAt = 0; - while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt; - - if (!((colonAt == 1)&&(s[0] == '1'))) // COM_UINT64_ED25519? - return; - - s += colonAt + 1; - colonAt = 0; - while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt; - - if (colonAt) { - const unsigned int buflen = colonAt / 2; - char *const buf = new char[buflen]; - unsigned int bufactual = Utils::unhex(s,colonAt,buf,buflen); - char *bufptr = buf; - try { - while (bufactual >= 24) { - if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { - _qualifiers[_qualifierCount].id = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; - _qualifiers[_qualifierCount].value = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; - _qualifiers[_qualifierCount].maxDelta = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; - ++_qualifierCount; - } else { - bufptr += 24; - } - bufactual -= 24; - } - } catch ( ... ) {} - delete [] buf; - } - - if (s[colonAt]) { - s += colonAt + 1; - colonAt = 0; - while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt; - - if (colonAt) { - char addrbuf[ZT_ADDRESS_LENGTH]; - if (Utils::unhex(s,colonAt,addrbuf,sizeof(addrbuf)) == ZT_ADDRESS_LENGTH) - _signedBy.setTo(addrbuf,ZT_ADDRESS_LENGTH); - - if ((_signedBy)&&(s[colonAt])) { - s += colonAt + 1; - colonAt = 0; - while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt; - if (colonAt) { - if (Utils::unhex(s,colonAt,_signature.data,(unsigned int)_signature.size()) != _signature.size()) - _signedBy.zero(); - } else { - _signedBy.zero(); - } - } else { - _signedBy.zero(); - } - } - } - - std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount])); -} - -#endif // ZT_SUPPORT_OLD_STYLE_NETCONF - -bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) const -{ - unsigned int myidx = 0; - unsigned int otheridx = 0; - - if ((_qualifierCount == 0)||(other._qualifierCount == 0)) - return false; - - while (myidx < _qualifierCount) { - // Fail if we're at the end of other, since this means the field is - // missing. - if (otheridx >= other._qualifierCount) - return false; - - // Seek to corresponding tuple in other, ignoring tuples that - // we may not have. If we run off the end of other, the tuple is - // missing. This works because tuples are sorted by ID. - while (other._qualifiers[otheridx].id != _qualifiers[myidx].id) { - ++otheridx; - if (otheridx >= other._qualifierCount) - return false; - } - - // Compare to determine if the absolute value of the difference - // between these two parameters is within our maxDelta. - const uint64_t a = _qualifiers[myidx].value; - const uint64_t b = other._qualifiers[myidx].value; - if (((a >= b) ? (a - b) : (b - a)) > _qualifiers[myidx].maxDelta) - return false; - - ++myidx; - } - - return true; -} - -bool CertificateOfMembership::sign(const Identity &with) -{ - uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; - unsigned int ptr = 0; - for(unsigned int i=0;i<_qualifierCount;++i) { - buf[ptr++] = Utils::hton(_qualifiers[i].id); - buf[ptr++] = Utils::hton(_qualifiers[i].value); - buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); - } - - try { - _signature = with.sign(buf,ptr * sizeof(uint64_t)); - _signedBy = with.address(); - return true; - } catch ( ... ) { - _signedBy.zero(); - return false; - } -} - -int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const -{ - if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) - return -1; - - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); - return 1; - } - - uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; - unsigned int ptr = 0; - for(unsigned int i=0;i<_qualifierCount;++i) { - buf[ptr++] = Utils::hton(_qualifiers[i].id); - buf[ptr++] = Utils::hton(_qualifiers[i].value); - buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); - } - return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1); -} - -} // namespace ZeroTier diff --git a/zto/node/CertificateOfMembership.hpp b/zto/node/CertificateOfMembership.hpp deleted file mode 100644 index ae976b5..0000000 --- a/zto/node/CertificateOfMembership.hpp +++ /dev/null @@ -1,358 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP -#define ZT_CERTIFICATEOFMEMBERSHIP_HPP - -#include -#include - -#include -#include -#include - -#include "Constants.hpp" -#include "Buffer.hpp" -#include "Address.hpp" -#include "C25519.hpp" -#include "Identity.hpp" -#include "Utils.hpp" - -/** - * Maximum number of qualifiers allowed in a COM (absolute max: 65535) - */ -#define ZT_NETWORK_COM_MAX_QUALIFIERS 8 - -namespace ZeroTier { - -class RuntimeEnvironment; - -/** - * Certificate of network membership - * - * The COM contains a sorted set of three-element tuples called qualifiers. - * These contain an id, a value, and a maximum delta. - * - * The ID is arbitrary and should be assigned using a scheme that makes - * every ID globally unique. IDs beneath 65536 are reserved for global - * assignment by ZeroTier Networks. - * - * The value's meaning is ID-specific and isn't important here. What's - * important is the value and the third member of the tuple: the maximum - * delta. The maximum delta is the maximum difference permitted between - * values for a given ID between certificates for the two certificates to - * themselves agree. - * - * Network membership is checked by checking whether a peer's certificate - * agrees with your own. The timestamp provides the fundamental criterion-- - * each member of a private network must constantly obtain new certificates - * often enough to stay within the max delta for this qualifier. But other - * criteria could be added in the future for very special behaviors, things - * like latitude and longitude for instance. - * - * This is a memcpy()'able structure and is safe (in a crash sense) to modify - * without locks. - */ -class CertificateOfMembership -{ -public: - /** - * Reserved qualifier IDs - * - * IDs below 1024 are reserved for use as standard IDs. Others are available - * for user-defined use. - * - * Addition of new required fields requires that code in hasRequiredFields - * be updated as well. - */ - enum ReservedId - { - /** - * Timestamp of certificate - */ - COM_RESERVED_ID_TIMESTAMP = 0, - - /** - * Network ID for which certificate was issued - */ - COM_RESERVED_ID_NETWORK_ID = 1, - - /** - * ZeroTier address to whom certificate was issued - */ - COM_RESERVED_ID_ISSUED_TO = 2 - }; - - /** - * Create an empty certificate of membership - */ - CertificateOfMembership() - { - memset(this,0,sizeof(CertificateOfMembership)); - } - - CertificateOfMembership(const CertificateOfMembership &c) - { - memcpy(this,&c,sizeof(CertificateOfMembership)); - } - - /** - * Create from required fields common to all networks - * - * @param timestamp Timestamp of certificate - * @param timestampMaxDelta Maximum variation between timestamps on this net - * @param nwid Network ID - * @param issuedTo Certificate recipient - */ - CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo) - { - _qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP; - _qualifiers[0].value = timestamp; - _qualifiers[0].maxDelta = timestampMaxDelta; - _qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID; - _qualifiers[1].value = nwid; - _qualifiers[1].maxDelta = 0; - _qualifiers[2].id = COM_RESERVED_ID_ISSUED_TO; - _qualifiers[2].value = issuedTo.toInt(); - _qualifiers[2].maxDelta = 0xffffffffffffffffULL; - _qualifierCount = 3; - memset(_signature.data,0,_signature.size()); - } - - inline CertificateOfMembership &operator=(const CertificateOfMembership &c) - { - memcpy(this,&c,sizeof(CertificateOfMembership)); - return *this; - } - - /** - * Create from binary-serialized COM in buffer - * - * @param b Buffer to deserialize from - * @param startAt Position to start in buffer - */ - template - CertificateOfMembership(const Buffer &b,unsigned int startAt = 0) - { - deserialize(b,startAt); - } - - /** - * @return True if there's something here - */ - inline operator bool() const throw() { return (_qualifierCount != 0); } - - /** - * @return Timestamp for this cert and maximum delta for timestamp - */ - inline std::pair timestamp() const - { - for(unsigned int i=0;i<_qualifierCount;++i) { - if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) - return std::pair(_qualifiers[i].value,_qualifiers[i].maxDelta); - } - return std::pair(0ULL,0ULL); - } - - /** - * @return Address to which this cert was issued - */ - inline Address issuedTo() const - { - for(unsigned int i=0;i<_qualifierCount;++i) { - if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) - return Address(_qualifiers[i].value); - } - return Address(); - } - - /** - * @return Network ID for which this cert was issued - */ - inline uint64_t networkId() const - { - for(unsigned int i=0;i<_qualifierCount;++i) { - if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) - return _qualifiers[i].value; - } - return 0ULL; - } - - /** - * Add or update a qualifier in this certificate - * - * Any signature is invalidated and signedBy is set to null. - * - * @param id Qualifier ID - * @param value Qualifier value - * @param maxDelta Qualifier maximum allowed difference (absolute value of difference) - */ - void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta); - inline void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); } - -#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF - /** - * @return String-serialized representation of this certificate - */ - std::string toString() const; - - /** - * Set this certificate equal to the hex-serialized string - * - * Invalid strings will result in invalid or undefined certificate - * contents. These will subsequently fail validation and comparison. - * Empty strings will result in an empty certificate. - * - * @param s String to deserialize - */ - void fromString(const char *s); -#endif // ZT_SUPPORT_OLD_STYLE_NETCONF - - /** - * Compare two certificates for parameter agreement - * - * This compares this certificate with the other and returns true if all - * paramters in this cert are present in the other and if they agree to - * within this cert's max delta value for each given parameter. - * - * Tuples present in other but not in this cert are ignored, but any - * tuples present in this cert but not in other result in 'false'. - * - * @param other Cert to compare with - * @return True if certs agree and 'other' may be communicated with - */ - bool agreesWith(const CertificateOfMembership &other) const; - - /** - * Sign this certificate - * - * @param with Identity to sign with, must include private key - * @return True if signature was successful - */ - bool sign(const Identity &with); - - /** - * Verify this COM and its signature - * - * @param RR Runtime environment for looking up peers - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; - - /** - * @return True if signed - */ - inline bool isSigned() const throw() { return (_signedBy); } - - /** - * @return Address that signed this certificate or null address if none - */ - inline const Address &signedBy() const throw() { return _signedBy; } - - template - inline void serialize(Buffer &b) const - { - b.append((uint8_t)1); - b.append((uint16_t)_qualifierCount); - for(unsigned int i=0;i<_qualifierCount;++i) { - b.append(_qualifiers[i].id); - b.append(_qualifiers[i].value); - b.append(_qualifiers[i].maxDelta); - } - _signedBy.appendTo(b); - if (_signedBy) - b.append(_signature.data,(unsigned int)_signature.size()); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; - - _qualifierCount = 0; - _signedBy.zero(); - - if (b[p++] != 1) - throw std::invalid_argument("invalid object"); - - unsigned int numq = b.template at(p); p += sizeof(uint16_t); - uint64_t lastId = 0; - for(unsigned int i=0;i(p); - if (qid < lastId) - throw std::invalid_argument("qualifiers not sorted"); - else lastId = qid; - if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { - _qualifiers[_qualifierCount].id = qid; - _qualifiers[_qualifierCount].value = b.template at(p + 8); - _qualifiers[_qualifierCount].maxDelta = b.template at(p + 16); - p += 24; - ++_qualifierCount; - } else { - throw std::invalid_argument("too many qualifiers"); - } - } - - _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; - - if (_signedBy) { - memcpy(_signature.data,b.field(p,(unsigned int)_signature.size()),_signature.size()); - p += (unsigned int)_signature.size(); - } - - return (p - startAt); - } - - inline bool operator==(const CertificateOfMembership &c) const - throw() - { - if (_signedBy != c._signedBy) - return false; - if (_qualifierCount != c._qualifierCount) - return false; - for(unsigned int i=0;i<_qualifierCount;++i) { - const _Qualifier &a = _qualifiers[i]; - const _Qualifier &b = c._qualifiers[i]; - if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta)) - return false; - } - return (_signature == c._signature); - } - inline bool operator!=(const CertificateOfMembership &c) const throw() { return (!(*this == c)); } - -private: - struct _Qualifier - { - _Qualifier() : id(0),value(0),maxDelta(0) {} - uint64_t id; - uint64_t value; - uint64_t maxDelta; - inline bool operator<(const _Qualifier &q) const throw() { return (id < q.id); } // sort order - }; - - Address _signedBy; - _Qualifier _qualifiers[ZT_NETWORK_COM_MAX_QUALIFIERS]; - unsigned int _qualifierCount; - C25519::Signature _signature; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/CertificateOfOwnership.cpp b/zto/node/CertificateOfOwnership.cpp deleted file mode 100644 index 2bd181e..0000000 --- a/zto/node/CertificateOfOwnership.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "CertificateOfOwnership.hpp" -#include "RuntimeEnvironment.hpp" -#include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Network.hpp" - -namespace ZeroTier { - -int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) const -{ - if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) - return -1; - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); - return 1; - } - try { - Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp; - this->serialize(tmp,true); - return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); - } catch ( ... ) { - return -1; - } -} - -bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const void *v,unsigned int l) const -{ - for(unsigned int i=0,j=_thingCount;i(v)[k] != _thingValues[i][k]) - break; - ++k; - } - if (k == l) - return true; - } - } - return false; -} - -} // namespace ZeroTier diff --git a/zto/node/CertificateOfOwnership.hpp b/zto/node/CertificateOfOwnership.hpp deleted file mode 100644 index 8c47582..0000000 --- a/zto/node/CertificateOfOwnership.hpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP -#define ZT_CERTIFICATEOFOWNERSHIP_HPP - -#include -#include -#include -#include - -#include "Constants.hpp" -#include "C25519.hpp" -#include "Address.hpp" -#include "Identity.hpp" -#include "Buffer.hpp" -#include "InetAddress.hpp" -#include "MAC.hpp" - -// Max things per CertificateOfOwnership -#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS 16 - -// Maximum size of a thing's value field in bytes -#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE 16 - -namespace ZeroTier { - -class RuntimeEnvironment; - -/** - * Certificate indicating ownership of a network identifier - */ -class CertificateOfOwnership -{ -public: - enum Thing - { - THING_NULL = 0, - THING_MAC_ADDRESS = 1, - THING_IPV4_ADDRESS = 2, - THING_IPV6_ADDRESS = 3 - }; - - CertificateOfOwnership() - { - memset(this,0,sizeof(CertificateOfOwnership)); - } - - CertificateOfOwnership(const uint64_t nwid,const uint64_t ts,const Address &issuedTo,const uint32_t id) : - _networkId(nwid), - _ts(ts), - _flags(0), - _id(id), - _thingCount(0), - _issuedTo(issuedTo) - { - } - - inline uint64_t networkId() const { return _networkId; } - inline uint64_t timestamp() const { return _ts; } - inline uint32_t id() const { return _id; } - inline unsigned int thingCount() const { return (unsigned int)_thingCount; } - - inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; } - inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; } - - inline const Address &issuedTo() const { return _issuedTo; } - - inline bool owns(const InetAddress &ip) const - { - if (ip.ss_family == AF_INET) - return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast(&ip)->sin_addr.s_addr),4); - if (ip.ss_family == AF_INET6) - return this->_owns(THING_IPV6_ADDRESS,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); - return false; - } - - inline bool owns(const MAC &mac) const - { - uint8_t tmp[6]; - mac.copyTo(tmp,6); - return this->_owns(THING_MAC_ADDRESS,tmp,6); - } - - inline void addThing(const InetAddress &ip) - { - if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return; - if (ip.ss_family == AF_INET) { - _thingTypes[_thingCount] = THING_IPV4_ADDRESS; - memcpy(_thingValues[_thingCount],&(reinterpret_cast(&ip)->sin_addr.s_addr),4); - ++_thingCount; - } else if (ip.ss_family == AF_INET6) { - _thingTypes[_thingCount] = THING_IPV6_ADDRESS; - memcpy(_thingValues[_thingCount],reinterpret_cast(&ip)->sin6_addr.s6_addr,16); - ++_thingCount; - } - } - - inline void addThing(const MAC &mac) - { - if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return; - _thingTypes[_thingCount] = THING_MAC_ADDRESS; - mac.copyTo(_thingValues[_thingCount],6); - ++_thingCount; - } - - /** - * @param signer Signing identity, must have private key - * @return True if signature was successful - */ - inline bool sign(const Identity &signer) - { - if (signer.hasPrivate()) { - Buffer tmp; - _signedBy = signer.address(); - this->serialize(tmp,true); - _signature = signer.sign(tmp.data(),tmp.size()); - return true; - } - return false; - } - - /** - * @param RR Runtime environment to allow identity lookup for signedBy - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; - - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - b.append(_networkId); - b.append(_ts); - b.append(_flags); - b.append(_id); - b.append((uint16_t)_thingCount); - for(unsigned int i=0,j=_thingCount;i - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; - - memset(this,0,sizeof(CertificateOfOwnership)); - - _networkId = b.template at(p); p += 8; - _ts = b.template at(p); p += 8; - _flags = b.template at(p); p += 8; - _id = b.template at(p); p += 4; - _thingCount = b.template at(p); p += 2; - for(unsigned int i=0,j=_thingCount;i(p) != ZT_C25519_SIGNATURE_LEN) - throw std::runtime_error("invalid signature length"); - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; - } else { - p += 2 + b.template at(p); - } - - p += 2 + b.template at(p); - if (p > b.size()) - throw std::runtime_error("extended field overflow"); - - return (p - startAt); - } - - // Provides natural sort order by ID - inline bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); } - - inline bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); } - inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); } - -private: - bool _owns(const Thing &t,const void *v,unsigned int l) const; - - uint64_t _networkId; - uint64_t _ts; - uint64_t _flags; - uint32_t _id; - uint16_t _thingCount; - uint8_t _thingTypes[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS]; - uint8_t _thingValues[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS][ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE]; - Address _issuedTo; - Address _signedBy; - C25519::Signature _signature; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/CertificateOfRepresentation.hpp b/zto/node/CertificateOfRepresentation.hpp deleted file mode 100644 index 02e961c..0000000 --- a/zto/node/CertificateOfRepresentation.hpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_CERTIFICATEOFREPRESENTATION_HPP -#define ZT_CERTIFICATEOFREPRESENTATION_HPP - -#include "Constants.hpp" -#include "Address.hpp" -#include "C25519.hpp" -#include "Identity.hpp" -#include "Buffer.hpp" - -/** - * Maximum number of addresses allowed in a COR - */ -#define ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES ZT_MAX_UPSTREAMS - -namespace ZeroTier { - -/** - * A signed enumeration of a node's roots (planet and moons) - * - * This is sent as part of HELLO and attests to which roots a node trusts - * to represent it on the network. Federated roots (moons) can send these - * further upstream to tell global roots which nodes they represent, making - * them reachable via federated roots if they are not reachable directly. - * - * As of 1.2.0 this is sent but not used. Right now nodes still always - * announce to planetary roots no matter what. In the future this can be - * used to implement even better fault tolerance for federation for the - * no roots are reachable case as well as a "privacy mode" where federated - * roots can shield nodes entirely and p2p connectivity behind them can - * be disabled. This will be desirable for a number of use cases. - */ -class CertificateOfRepresentation -{ -public: - CertificateOfRepresentation() - { - memset(this,0,sizeof(CertificateOfRepresentation)); - } - - inline uint64_t timestamp() const { return _timestamp; } - inline const Address &representative(const unsigned int i) const { return _reps[i]; } - inline unsigned int repCount() const { return _repCount; } - - inline void clear() - { - memset(this,0,sizeof(CertificateOfRepresentation)); - } - - /** - * Add a representative if space remains - * - * @param r Representative to add - * @return True if representative was added - */ - inline bool addRepresentative(const Address &r) - { - if (_repCount < ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) { - _reps[_repCount++] = r; - return true; - } - return false; - } - - /** - * Sign this COR with my identity - * - * @param myIdentity This node's identity - * @param ts COR timestamp for establishing new vs. old - */ - inline void sign(const Identity &myIdentity,const uint64_t ts) - { - _timestamp = ts; - Buffer tmp; - this->serialize(tmp,true); - _signature = myIdentity.sign(tmp.data(),tmp.size()); - } - - /** - * Verify this COR's signature - * - * @param senderIdentity Identity of sender of COR - * @return True if COR is valid - */ - inline bool verify(const Identity &senderIdentity) - { - try { - Buffer tmp; - this->serialize(tmp,true); - return senderIdentity.verify(tmp.data(),tmp.size(),_signature.data,ZT_C25519_SIGNATURE_LEN); - } catch ( ... ) { - return false; - } - } - - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - b.append((uint64_t)_timestamp); - b.append((uint16_t)_repCount); - for(unsigned int i=0;i<_repCount;++i) - _reps[i].appendTo(b); - - if (!forSign) { - b.append((uint8_t)1); // 1 == Ed25519 signature - b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); - } - - b.append((uint16_t)0); // size of any additional fields, currently 0 - - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - clear(); - - unsigned int p = startAt; - - _timestamp = b.template at(p); p += 8; - const unsigned int rc = b.template at(p); p += 2; - for(unsigned int i=0;i ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) ? ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES : rc; - - if (b[p++] == 1) { - if (b.template at(p) == ZT_C25519_SIGNATURE_LEN) { - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); - p += ZT_C25519_SIGNATURE_LEN; - } else throw std::runtime_error("invalid signature"); - } else { - p += 2 + b.template at(p); - } - - p += 2 + b.template at(p); - if (p > b.size()) - throw std::runtime_error("extended field overflow"); - - return (p - startAt); - } - -private: - uint64_t _timestamp; - Address _reps[ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES]; - unsigned int _repCount; - C25519::Signature _signature; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Cluster.cpp b/zto/node/Cluster.cpp deleted file mode 100644 index 54206f9..0000000 --- a/zto/node/Cluster.cpp +++ /dev/null @@ -1,1034 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifdef ZT_ENABLE_CLUSTER - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "../version.h" - -#include "Cluster.hpp" -#include "RuntimeEnvironment.hpp" -#include "MulticastGroup.hpp" -#include "CertificateOfMembership.hpp" -#include "Salsa20.hpp" -#include "Poly1305.hpp" -#include "Identity.hpp" -#include "Topology.hpp" -#include "Packet.hpp" -#include "Switch.hpp" -#include "Node.hpp" -#include "Network.hpp" -#include "Array.hpp" - -namespace ZeroTier { - -static inline double _dist3d(int x1,int y1,int z1,int x2,int y2,int z2) - throw() -{ - double dx = ((double)x2 - (double)x1); - double dy = ((double)y2 - (double)y1); - double dz = ((double)z2 - (double)z1); - return sqrt((dx * dx) + (dy * dy) + (dz * dz)); -} - -// An entry in _ClusterSendQueue -struct _ClusterSendQueueEntry -{ - uint64_t timestamp; - Address fromPeerAddress; - Address toPeerAddress; - // if we ever support larger transport MTUs this must be increased - unsigned char data[ZT_CLUSTER_SEND_QUEUE_DATA_MAX]; - unsigned int len; - bool unite; -}; - -// A multi-index map with entry memory pooling -- this allows our queue to -// be O(log(N)) and is complex enough that it makes the code a lot cleaner -// to break it out from Cluster. -class _ClusterSendQueue -{ -public: - _ClusterSendQueue() : - _poolCount(0) {} - ~_ClusterSendQueue() {} // memory is automatically freed when _chunks is destroyed - - inline void enqueue(uint64_t now,const Address &from,const Address &to,const void *data,unsigned int len,bool unite) - { - if (len > ZT_CLUSTER_SEND_QUEUE_DATA_MAX) - return; - - Mutex::Lock _l(_lock); - - // Delete oldest queue entry for this sender if this enqueue() would take them over the per-sender limit - { - std::set< std::pair >::iterator qi(_bySrc.lower_bound(std::pair(from,(_ClusterSendQueueEntry *)0))); - std::set< std::pair >::iterator oldest(qi); - unsigned long countForSender = 0; - while ((qi != _bySrc.end())&&(qi->first == from)) { - if (qi->second->timestamp < oldest->second->timestamp) - oldest = qi; - ++countForSender; - ++qi; - } - if (countForSender >= ZT_CLUSTER_MAX_QUEUE_PER_SENDER) { - _byDest.erase(std::pair(oldest->second->toPeerAddress,oldest->second)); - _pool[_poolCount++] = oldest->second; - _bySrc.erase(oldest); - } - } - - _ClusterSendQueueEntry *e; - if (_poolCount > 0) { - e = _pool[--_poolCount]; - } else { - if (_chunks.size() >= ZT_CLUSTER_MAX_QUEUE_CHUNKS) - return; // queue is totally full! - _chunks.push_back(Array<_ClusterSendQueueEntry,ZT_CLUSTER_QUEUE_CHUNK_SIZE>()); - e = &(_chunks.back().data[0]); - for(unsigned int i=1;itimestamp = now; - e->fromPeerAddress = from; - e->toPeerAddress = to; - memcpy(e->data,data,len); - e->len = len; - e->unite = unite; - - _bySrc.insert(std::pair(from,e)); - _byDest.insert(std::pair(to,e)); - } - - inline void expire(uint64_t now) - { - Mutex::Lock _l(_lock); - for(std::set< std::pair >::iterator qi(_bySrc.begin());qi!=_bySrc.end();) { - if ((now - qi->second->timestamp) > ZT_CLUSTER_QUEUE_EXPIRATION) { - _byDest.erase(std::pair(qi->second->toPeerAddress,qi->second)); - _pool[_poolCount++] = qi->second; - _bySrc.erase(qi++); - } else ++qi; - } - } - - /** - * Get and dequeue entries for a given destination address - * - * After use these entries must be returned with returnToPool()! - * - * @param dest Destination address - * @param results Array to fill with results - * @param maxResults Size of results[] in pointers - * @return Number of actual results returned - */ - inline unsigned int getByDest(const Address &dest,_ClusterSendQueueEntry **results,unsigned int maxResults) - { - unsigned int count = 0; - Mutex::Lock _l(_lock); - std::set< std::pair >::iterator qi(_byDest.lower_bound(std::pair(dest,(_ClusterSendQueueEntry *)0))); - while ((qi != _byDest.end())&&(qi->first == dest)) { - _bySrc.erase(std::pair(qi->second->fromPeerAddress,qi->second)); - results[count++] = qi->second; - if (count == maxResults) - break; - _byDest.erase(qi++); - } - return count; - } - - /** - * Return entries to pool after use - * - * @param entries Array of entries - * @param count Number of entries - */ - inline void returnToPool(_ClusterSendQueueEntry **entries,unsigned int count) - { - Mutex::Lock _l(_lock); - for(unsigned int i=0;i > _chunks; - _ClusterSendQueueEntry *_pool[ZT_CLUSTER_QUEUE_CHUNK_SIZE * ZT_CLUSTER_MAX_QUEUE_CHUNKS]; - unsigned long _poolCount; - std::set< std::pair > _bySrc; - std::set< std::pair > _byDest; - Mutex _lock; -}; - -Cluster::Cluster( - const RuntimeEnvironment *renv, - uint16_t id, - const std::vector &zeroTierPhysicalEndpoints, - int32_t x, - int32_t y, - int32_t z, - void (*sendFunction)(void *,unsigned int,const void *,unsigned int), - void *sendFunctionArg, - int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), - void *addressToLocationFunctionArg) : - RR(renv), - _sendQueue(new _ClusterSendQueue()), - _sendFunction(sendFunction), - _sendFunctionArg(sendFunctionArg), - _addressToLocationFunction(addressToLocationFunction), - _addressToLocationFunctionArg(addressToLocationFunctionArg), - _x(x), - _y(y), - _z(z), - _id(id), - _zeroTierPhysicalEndpoints(zeroTierPhysicalEndpoints), - _members(new _Member[ZT_CLUSTER_MAX_MEMBERS]), - _lastFlushed(0), - _lastCleanedRemotePeers(0), - _lastCleanedQueue(0) -{ - uint16_t stmp[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)]; - - // Generate master secret by hashing the secret from our Identity key pair - RR->identity.sha512PrivateKey(_masterSecret); - - // Generate our inbound message key, which is the master secret XORed with our ID and hashed twice - memcpy(stmp,_masterSecret,sizeof(stmp)); - stmp[0] ^= Utils::hton(id); - SHA512::hash(stmp,stmp,sizeof(stmp)); - SHA512::hash(stmp,stmp,sizeof(stmp)); - memcpy(_key,stmp,sizeof(_key)); - Utils::burn(stmp,sizeof(stmp)); -} - -Cluster::~Cluster() -{ - Utils::burn(_masterSecret,sizeof(_masterSecret)); - Utils::burn(_key,sizeof(_key)); - delete [] _members; - delete _sendQueue; -} - -void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) -{ - Buffer dmsg; - { - // FORMAT: <[16] iv><[8] MAC><... data> - if ((len < 24)||(len > ZT_CLUSTER_MAX_MESSAGE_LENGTH)) - return; - - // 16-byte IV: first 8 bytes XORed with key, last 8 bytes used as Salsa20 64-bit IV - char keytmp[32]; - memcpy(keytmp,_key,32); - for(int i=0;i<8;++i) - keytmp[i] ^= reinterpret_cast(msg)[i]; - Salsa20 s20(keytmp,256,reinterpret_cast(msg) + 8); - Utils::burn(keytmp,sizeof(keytmp)); - - // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard") - char polykey[ZT_POLY1305_KEY_LEN]; - memset(polykey,0,sizeof(polykey)); - s20.crypt12(polykey,polykey,sizeof(polykey)); - - // Compute 16-byte MAC - char mac[ZT_POLY1305_MAC_LEN]; - Poly1305::compute(mac,reinterpret_cast(msg) + 24,len - 24,polykey); - - // Check first 8 bytes of MAC against 64-bit MAC in stream - if (!Utils::secureEq(mac,reinterpret_cast(msg) + 16,8)) - return; - - // Decrypt! - dmsg.setSize(len - 24); - s20.crypt12(reinterpret_cast(msg) + 24,const_cast(dmsg.data()),dmsg.size()); - } - - if (dmsg.size() < 4) - return; - const uint16_t fromMemberId = dmsg.at(0); - unsigned int ptr = 2; - if (fromMemberId == _id) // sanity check: we don't talk to ourselves - return; - const uint16_t toMemberId = dmsg.at(ptr); - ptr += 2; - if (toMemberId != _id) // sanity check: message not for us? - return; - - { // make sure sender is actually considered a member - Mutex::Lock _l3(_memberIds_m); - if (std::find(_memberIds.begin(),_memberIds.end(),fromMemberId) == _memberIds.end()) - return; - } - - try { - while (ptr < dmsg.size()) { - const unsigned int mlen = dmsg.at(ptr); ptr += 2; - const unsigned int nextPtr = ptr + mlen; - if (nextPtr > dmsg.size()) - break; - - int mtype = -1; - try { - switch((StateMessageType)(mtype = (int)dmsg[ptr++])) { - default: - break; - - case CLUSTER_MESSAGE_ALIVE: { - _Member &m = _members[fromMemberId]; - Mutex::Lock mlck(m.lock); - ptr += 7; // skip version stuff, not used yet - m.x = dmsg.at(ptr); ptr += 4; - m.y = dmsg.at(ptr); ptr += 4; - m.z = dmsg.at(ptr); ptr += 4; - ptr += 8; // skip local clock, not used - m.load = dmsg.at(ptr); ptr += 8; - m.peers = dmsg.at(ptr); ptr += 8; - ptr += 8; // skip flags, unused -#ifdef ZT_TRACE - std::string addrs; -#endif - unsigned int physicalAddressCount = dmsg[ptr++]; - m.zeroTierPhysicalEndpoints.clear(); - for(unsigned int i=0;i 0) - addrs.push_back(','); - addrs.append(m.zeroTierPhysicalEndpoints.back().toString()); - } -#endif - } -#ifdef ZT_TRACE - if ((RR->node->now() - m.lastReceivedAliveAnnouncement) >= ZT_CLUSTER_TIMEOUT) { - TRACE("[%u] I'm alive! peers close to %d,%d,%d can be redirected to: %s",(unsigned int)fromMemberId,m.x,m.y,m.z,addrs.c_str()); - } -#endif - m.lastReceivedAliveAnnouncement = RR->node->now(); - } break; - - case CLUSTER_MESSAGE_HAVE_PEER: { - Identity id; - ptr += id.deserialize(dmsg,ptr); - if (id) { - { - Mutex::Lock _l(_remotePeers_m); - _RemotePeer &rp = _remotePeers[std::pair(id.address(),(unsigned int)fromMemberId)]; - if (!rp.lastHavePeerReceived) { - RR->topology->saveIdentity((void *)0,id); - RR->identity.agree(id,rp.key,ZT_PEER_SECRET_KEY_LENGTH); - } - rp.lastHavePeerReceived = RR->node->now(); - } - - _ClusterSendQueueEntry *q[16384]; // 16384 is "tons" - unsigned int qc = _sendQueue->getByDest(id.address(),q,16384); - for(unsigned int i=0;irelayViaCluster(q[i]->fromPeerAddress,q[i]->toPeerAddress,q[i]->data,q[i]->len,q[i]->unite); - _sendQueue->returnToPool(q,qc); - - TRACE("[%u] has %s (retried %u queued sends)",(unsigned int)fromMemberId,id.address().toString().c_str(),qc); - } - } break; - - case CLUSTER_MESSAGE_WANT_PEER: { - const Address zeroTierAddress(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH; - SharedPtr peer(RR->topology->getPeerNoCache(zeroTierAddress)); - if ( (peer) && (peer->hasLocalClusterOptimalPath(RR->node->now())) ) { - Buffer<1024> buf; - peer->identity().serialize(buf); - Mutex::Lock _l2(_members[fromMemberId].lock); - _send(fromMemberId,CLUSTER_MESSAGE_HAVE_PEER,buf.data(),buf.size()); - } - } break; - - case CLUSTER_MESSAGE_REMOTE_PACKET: { - const unsigned int plen = dmsg.at(ptr); ptr += 2; - if (plen) { - Packet remotep(dmsg.field(ptr,plen),plen); ptr += plen; - //TRACE("remote %s from %s via %u (%u bytes)",Packet::verbString(remotep.verb()),remotep.source().toString().c_str(),fromMemberId,plen); - switch(remotep.verb()) { - case Packet::VERB_WHOIS: _doREMOTE_WHOIS(fromMemberId,remotep); break; - case Packet::VERB_MULTICAST_GATHER: _doREMOTE_MULTICAST_GATHER(fromMemberId,remotep); break; - default: break; // ignore things we don't care about across cluster - } - } - } break; - - case CLUSTER_MESSAGE_PROXY_UNITE: { - const Address localPeerAddress(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH; - const Address remotePeerAddress(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH; - const unsigned int numRemotePeerPaths = dmsg[ptr++]; - InetAddress remotePeerPaths[256]; // size is 8-bit, so 256 is max - for(unsigned int i=0;inode->now(); - SharedPtr localPeer(RR->topology->getPeerNoCache(localPeerAddress)); - if ((localPeer)&&(numRemotePeerPaths > 0)) { - InetAddress bestLocalV4,bestLocalV6; - localPeer->getRendezvousAddresses(now,bestLocalV4,bestLocalV6); - - InetAddress bestRemoteV4,bestRemoteV6; - for(unsigned int i=0;iidentity.address(),Packet::VERB_RENDEZVOUS); - rendezvousForLocal.append((uint8_t)0); - remotePeerAddress.appendTo(rendezvousForLocal); - - Buffer<2048> rendezvousForRemote; - remotePeerAddress.appendTo(rendezvousForRemote); - rendezvousForRemote.append((uint8_t)Packet::VERB_RENDEZVOUS); - rendezvousForRemote.addSize(2); // space for actual packet payload length - rendezvousForRemote.append((uint8_t)0); // flags == 0 - localPeerAddress.appendTo(rendezvousForRemote); - - bool haveMatch = false; - if ((bestLocalV6)&&(bestRemoteV6)) { - haveMatch = true; - - rendezvousForLocal.append((uint16_t)bestRemoteV6.port()); - rendezvousForLocal.append((uint8_t)16); - rendezvousForLocal.append(bestRemoteV6.rawIpData(),16); - - rendezvousForRemote.append((uint16_t)bestLocalV6.port()); - rendezvousForRemote.append((uint8_t)16); - rendezvousForRemote.append(bestLocalV6.rawIpData(),16); - rendezvousForRemote.setAt(ZT_ADDRESS_LENGTH + 1,(uint16_t)(9 + 16)); - } else if ((bestLocalV4)&&(bestRemoteV4)) { - haveMatch = true; - - rendezvousForLocal.append((uint16_t)bestRemoteV4.port()); - rendezvousForLocal.append((uint8_t)4); - rendezvousForLocal.append(bestRemoteV4.rawIpData(),4); - - rendezvousForRemote.append((uint16_t)bestLocalV4.port()); - rendezvousForRemote.append((uint8_t)4); - rendezvousForRemote.append(bestLocalV4.rawIpData(),4); - rendezvousForRemote.setAt(ZT_ADDRESS_LENGTH + 1,(uint16_t)(9 + 4)); - } - - if (haveMatch) { - { - Mutex::Lock _l2(_members[fromMemberId].lock); - _send(fromMemberId,CLUSTER_MESSAGE_PROXY_SEND,rendezvousForRemote.data(),rendezvousForRemote.size()); - } - RR->sw->send((void *)0,rendezvousForLocal,true); - } - } - } break; - - case CLUSTER_MESSAGE_PROXY_SEND: { - const Address rcpt(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH; - const Packet::Verb verb = (Packet::Verb)dmsg[ptr++]; - const unsigned int len = dmsg.at(ptr); ptr += 2; - Packet outp(rcpt,RR->identity.address(),verb); - outp.append(dmsg.field(ptr,len),len); ptr += len; - RR->sw->send((void *)0,outp,true); - //TRACE("[%u] proxy send %s to %s length %u",(unsigned int)fromMemberId,Packet::verbString(verb),rcpt.toString().c_str(),len); - } break; - - case CLUSTER_MESSAGE_NETWORK_CONFIG: { - const SharedPtr network(RR->node->network(dmsg.at(ptr))); - if (network) { - // Copy into a Packet just to conform to Network API. Eventually - // will want to refactor. - network->handleConfigChunk((void *)0,0,Address(),Buffer(dmsg),ptr); - } - } break; - } - } catch ( ... ) { - TRACE("invalid message of size %u type %d (inner decode), discarding",mlen,mtype); - // drop invalids - } - - ptr = nextPtr; - } - } catch ( ... ) { - TRACE("invalid message (outer loop), discarding"); - // drop invalids - } -} - -void Cluster::broadcastHavePeer(const Identity &id) -{ - Buffer<1024> buf; - id.serialize(buf); - Mutex::Lock _l(_memberIds_m); - for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { - Mutex::Lock _l2(_members[*mid].lock); - _send(*mid,CLUSTER_MESSAGE_HAVE_PEER,buf.data(),buf.size()); - } -} - -void Cluster::broadcastNetworkConfigChunk(const void *chunk,unsigned int len) -{ - Mutex::Lock _l(_memberIds_m); - for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { - Mutex::Lock _l2(_members[*mid].lock); - _send(*mid,CLUSTER_MESSAGE_NETWORK_CONFIG,chunk,len); - } -} - -int Cluster::checkSendViaCluster(const Address &toPeerAddress,uint64_t &mostRecentTs,void *peerSecret) -{ - const uint64_t now = RR->node->now(); - mostRecentTs = 0; - int mostRecentMemberId = -1; - { - Mutex::Lock _l2(_remotePeers_m); - std::map< std::pair,_RemotePeer >::const_iterator rpe(_remotePeers.lower_bound(std::pair(toPeerAddress,0))); - for(;;) { - if ((rpe == _remotePeers.end())||(rpe->first.first != toPeerAddress)) - break; - else if (rpe->second.lastHavePeerReceived > mostRecentTs) { - mostRecentTs = rpe->second.lastHavePeerReceived; - memcpy(peerSecret,rpe->second.key,ZT_PEER_SECRET_KEY_LENGTH); - mostRecentMemberId = (int)rpe->first.second; - } - ++rpe; - } - } - - const uint64_t ageOfMostRecentHavePeerAnnouncement = now - mostRecentTs; - if (ageOfMostRecentHavePeerAnnouncement >= (ZT_PEER_ACTIVITY_TIMEOUT / 3)) { - if (ageOfMostRecentHavePeerAnnouncement >= ZT_PEER_ACTIVITY_TIMEOUT) - mostRecentMemberId = -1; - - bool sendWantPeer = true; - { - Mutex::Lock _l(_remotePeers_m); - _RemotePeer &rp = _remotePeers[std::pair(toPeerAddress,(unsigned int)_id)]; - if ((now - rp.lastSentWantPeer) >= ZT_CLUSTER_WANT_PEER_EVERY) { - rp.lastSentWantPeer = now; - } else { - sendWantPeer = false; // don't flood WANT_PEER - } - } - if (sendWantPeer) { - char tmp[ZT_ADDRESS_LENGTH]; - toPeerAddress.copyTo(tmp,ZT_ADDRESS_LENGTH); - { - Mutex::Lock _l(_memberIds_m); - for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { - Mutex::Lock _l2(_members[*mid].lock); - _send(*mid,CLUSTER_MESSAGE_WANT_PEER,tmp,ZT_ADDRESS_LENGTH); - } - } - } - } - - return mostRecentMemberId; -} - -bool Cluster::sendViaCluster(int mostRecentMemberId,const Address &toPeerAddress,const void *data,unsigned int len) -{ - if ((mostRecentMemberId < 0)||(mostRecentMemberId >= ZT_CLUSTER_MAX_MEMBERS)) // sanity check - return false; - Mutex::Lock _l2(_members[mostRecentMemberId].lock); - for(std::vector::const_iterator i1(_zeroTierPhysicalEndpoints.begin());i1!=_zeroTierPhysicalEndpoints.end();++i1) { - for(std::vector::const_iterator i2(_members[mostRecentMemberId].zeroTierPhysicalEndpoints.begin());i2!=_members[mostRecentMemberId].zeroTierPhysicalEndpoints.end();++i2) { - if (i1->ss_family == i2->ss_family) { - TRACE("sendViaCluster sending %u bytes to %s by way of %u (%s->%s)",len,toPeerAddress.toString().c_str(),(unsigned int)mostRecentMemberId,i1->toString().c_str(),i2->toString().c_str()); - RR->node->putPacket((void *)0,*i1,*i2,data,len); - return true; - } - } - } - return false; -} - -void Cluster::relayViaCluster(const Address &fromPeerAddress,const Address &toPeerAddress,const void *data,unsigned int len,bool unite) -{ - if (len > ZT_PROTO_MAX_PACKET_LENGTH) // sanity check - return; - - const uint64_t now = RR->node->now(); - - uint64_t mostRecentTs = 0; - int mostRecentMemberId = -1; - { - Mutex::Lock _l2(_remotePeers_m); - std::map< std::pair,_RemotePeer >::const_iterator rpe(_remotePeers.lower_bound(std::pair(toPeerAddress,0))); - for(;;) { - if ((rpe == _remotePeers.end())||(rpe->first.first != toPeerAddress)) - break; - else if (rpe->second.lastHavePeerReceived > mostRecentTs) { - mostRecentTs = rpe->second.lastHavePeerReceived; - mostRecentMemberId = (int)rpe->first.second; - } - ++rpe; - } - } - - const uint64_t ageOfMostRecentHavePeerAnnouncement = now - mostRecentTs; - if (ageOfMostRecentHavePeerAnnouncement >= (ZT_PEER_ACTIVITY_TIMEOUT / 3)) { - // Enqueue and wait if peer seems alive, but do WANT_PEER to refresh homing - const bool enqueueAndWait = ((ageOfMostRecentHavePeerAnnouncement >= ZT_PEER_ACTIVITY_TIMEOUT)||(mostRecentMemberId < 0)); - - // Poll everyone with WANT_PEER if the age of our most recent entry is - // approaching expiration (or has expired, or does not exist). - bool sendWantPeer = true; - { - Mutex::Lock _l(_remotePeers_m); - _RemotePeer &rp = _remotePeers[std::pair(toPeerAddress,(unsigned int)_id)]; - if ((now - rp.lastSentWantPeer) >= ZT_CLUSTER_WANT_PEER_EVERY) { - rp.lastSentWantPeer = now; - } else { - sendWantPeer = false; // don't flood WANT_PEER - } - } - if (sendWantPeer) { - char tmp[ZT_ADDRESS_LENGTH]; - toPeerAddress.copyTo(tmp,ZT_ADDRESS_LENGTH); - { - Mutex::Lock _l(_memberIds_m); - for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { - Mutex::Lock _l2(_members[*mid].lock); - _send(*mid,CLUSTER_MESSAGE_WANT_PEER,tmp,ZT_ADDRESS_LENGTH); - } - } - } - - // If there isn't a good place to send via, then enqueue this for retrying - // later and return after having broadcasted a WANT_PEER. - if (enqueueAndWait) { - TRACE("relayViaCluster %s -> %s enqueueing to wait for HAVE_PEER",fromPeerAddress.toString().c_str(),toPeerAddress.toString().c_str()); - _sendQueue->enqueue(now,fromPeerAddress,toPeerAddress,data,len,unite); - return; - } - } - - if (mostRecentMemberId >= 0) { - Buffer<1024> buf; - if (unite) { - InetAddress v4,v6; - if (fromPeerAddress) { - SharedPtr fromPeer(RR->topology->getPeerNoCache(fromPeerAddress)); - if (fromPeer) - fromPeer->getRendezvousAddresses(now,v4,v6); - } - uint8_t addrCount = 0; - if (v4) - ++addrCount; - if (v6) - ++addrCount; - if (addrCount) { - toPeerAddress.appendTo(buf); - fromPeerAddress.appendTo(buf); - buf.append(addrCount); - if (v4) - v4.serialize(buf); - if (v6) - v6.serialize(buf); - } - } - - { - Mutex::Lock _l2(_members[mostRecentMemberId].lock); - if (buf.size() > 0) - _send(mostRecentMemberId,CLUSTER_MESSAGE_PROXY_UNITE,buf.data(),buf.size()); - - for(std::vector::const_iterator i1(_zeroTierPhysicalEndpoints.begin());i1!=_zeroTierPhysicalEndpoints.end();++i1) { - for(std::vector::const_iterator i2(_members[mostRecentMemberId].zeroTierPhysicalEndpoints.begin());i2!=_members[mostRecentMemberId].zeroTierPhysicalEndpoints.end();++i2) { - if (i1->ss_family == i2->ss_family) { - TRACE("relayViaCluster relaying %u bytes from %s to %s by way of %u (%s->%s)",len,fromPeerAddress.toString().c_str(),toPeerAddress.toString().c_str(),(unsigned int)mostRecentMemberId,i1->toString().c_str(),i2->toString().c_str()); - RR->node->putPacket((void *)0,*i1,*i2,data,len); - return; - } - } - } - - TRACE("relayViaCluster relaying %u bytes from %s to %s by way of %u failed: no common endpoints with the same address family!",len,fromPeerAddress.toString().c_str(),toPeerAddress.toString().c_str(),(unsigned int)mostRecentMemberId); - } - } -} - -void Cluster::sendDistributedQuery(const Packet &pkt) -{ - Buffer<4096> buf; - buf.append((uint16_t)pkt.size()); - buf.append(pkt.data(),pkt.size()); - Mutex::Lock _l(_memberIds_m); - for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { - Mutex::Lock _l2(_members[*mid].lock); - _send(*mid,CLUSTER_MESSAGE_REMOTE_PACKET,buf.data(),buf.size()); - } -} - -void Cluster::doPeriodicTasks() -{ - const uint64_t now = RR->node->now(); - - if ((now - _lastFlushed) >= ZT_CLUSTER_FLUSH_PERIOD) { - _lastFlushed = now; - - Mutex::Lock _l(_memberIds_m); - for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { - Mutex::Lock _l2(_members[*mid].lock); - - if ((now - _members[*mid].lastAnnouncedAliveTo) >= ((ZT_CLUSTER_TIMEOUT / 2) - 1000)) { - _members[*mid].lastAnnouncedAliveTo = now; - - Buffer<2048> alive; - alive.append((uint16_t)ZEROTIER_ONE_VERSION_MAJOR); - alive.append((uint16_t)ZEROTIER_ONE_VERSION_MINOR); - alive.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - alive.append((uint8_t)ZT_PROTO_VERSION); - if (_addressToLocationFunction) { - alive.append((int32_t)_x); - alive.append((int32_t)_y); - alive.append((int32_t)_z); - } else { - alive.append((int32_t)0); - alive.append((int32_t)0); - alive.append((int32_t)0); - } - alive.append((uint64_t)now); - alive.append((uint64_t)0); // TODO: compute and send load average - alive.append((uint64_t)RR->topology->countActive(now)); - alive.append((uint64_t)0); // unused/reserved flags - alive.append((uint8_t)_zeroTierPhysicalEndpoints.size()); - for(std::vector::const_iterator pe(_zeroTierPhysicalEndpoints.begin());pe!=_zeroTierPhysicalEndpoints.end();++pe) - pe->serialize(alive); - _send(*mid,CLUSTER_MESSAGE_ALIVE,alive.data(),alive.size()); - } - - _flush(*mid); - } - } - - if ((now - _lastCleanedRemotePeers) >= (ZT_PEER_ACTIVITY_TIMEOUT * 2)) { - _lastCleanedRemotePeers = now; - - Mutex::Lock _l(_remotePeers_m); - for(std::map< std::pair,_RemotePeer >::iterator rp(_remotePeers.begin());rp!=_remotePeers.end();) { - if ((now - rp->second.lastHavePeerReceived) >= ZT_PEER_ACTIVITY_TIMEOUT) - _remotePeers.erase(rp++); - else ++rp; - } - } - - if ((now - _lastCleanedQueue) >= ZT_CLUSTER_QUEUE_EXPIRATION) { - _lastCleanedQueue = now; - _sendQueue->expire(now); - } -} - -void Cluster::addMember(uint16_t memberId) -{ - if ((memberId >= ZT_CLUSTER_MAX_MEMBERS)||(memberId == _id)) - return; - - Mutex::Lock _l2(_members[memberId].lock); - - { - Mutex::Lock _l(_memberIds_m); - if (std::find(_memberIds.begin(),_memberIds.end(),memberId) != _memberIds.end()) - return; - _memberIds.push_back(memberId); - std::sort(_memberIds.begin(),_memberIds.end()); - } - - _members[memberId].clear(); - - // Generate this member's message key from the master and its ID - uint16_t stmp[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)]; - memcpy(stmp,_masterSecret,sizeof(stmp)); - stmp[0] ^= Utils::hton(memberId); - SHA512::hash(stmp,stmp,sizeof(stmp)); - SHA512::hash(stmp,stmp,sizeof(stmp)); - memcpy(_members[memberId].key,stmp,sizeof(_members[memberId].key)); - Utils::burn(stmp,sizeof(stmp)); - - // Prepare q - _members[memberId].q.clear(); - char iv[16]; - Utils::getSecureRandom(iv,16); - _members[memberId].q.append(iv,16); - _members[memberId].q.addSize(8); // room for MAC - _members[memberId].q.append((uint16_t)_id); - _members[memberId].q.append((uint16_t)memberId); -} - -void Cluster::removeMember(uint16_t memberId) -{ - Mutex::Lock _l(_memberIds_m); - std::vector newMemberIds; - for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { - if (*mid != memberId) - newMemberIds.push_back(*mid); - } - _memberIds = newMemberIds; -} - -bool Cluster::findBetterEndpoint(InetAddress &redirectTo,const Address &peerAddress,const InetAddress &peerPhysicalAddress,bool offload) -{ - if (_addressToLocationFunction) { - // Pick based on location if it can be determined - int px = 0,py = 0,pz = 0; - if (_addressToLocationFunction(_addressToLocationFunctionArg,reinterpret_cast(&peerPhysicalAddress),&px,&py,&pz) == 0) { - TRACE("no geolocation data for %s",peerPhysicalAddress.toIpString().c_str()); - return false; - } - - // Find member closest to this peer - const uint64_t now = RR->node->now(); - std::vector best; - const double currentDistance = _dist3d(_x,_y,_z,px,py,pz); - double bestDistance = (offload ? 2147483648.0 : currentDistance); -#ifdef ZT_TRACE - unsigned int bestMember = _id; -#endif - { - Mutex::Lock _l(_memberIds_m); - for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { - _Member &m = _members[*mid]; - Mutex::Lock _ml(m.lock); - - // Consider member if it's alive and has sent us a location and one or more physical endpoints to send peers to - if ( ((now - m.lastReceivedAliveAnnouncement) < ZT_CLUSTER_TIMEOUT) && ((m.x != 0)||(m.y != 0)||(m.z != 0)) && (m.zeroTierPhysicalEndpoints.size() > 0) ) { - const double mdist = _dist3d(m.x,m.y,m.z,px,py,pz); - if (mdist < bestDistance) { - bestDistance = mdist; -#ifdef ZT_TRACE - bestMember = *mid; -#endif - best = m.zeroTierPhysicalEndpoints; - } - } - } - } - - // Redirect to a closer member if it has a ZeroTier endpoint address in the same ss_family - for(std::vector::const_iterator a(best.begin());a!=best.end();++a) { - if (a->ss_family == peerPhysicalAddress.ss_family) { - TRACE("%s at [%d,%d,%d] is %f from us but %f from %u, can redirect to %s",peerAddress.toString().c_str(),px,py,pz,currentDistance,bestDistance,bestMember,a->toString().c_str()); - redirectTo = *a; - return true; - } - } - TRACE("%s at [%d,%d,%d] is %f from us, no better endpoints found",peerAddress.toString().c_str(),px,py,pz,currentDistance); - return false; - } else { - // TODO: pick based on load if no location info? - return false; - } -} - -bool Cluster::isClusterPeerFrontplane(const InetAddress &ip) const -{ - Mutex::Lock _l(_memberIds_m); - for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { - Mutex::Lock _l2(_members[*mid].lock); - for(std::vector::const_iterator i2(_members[*mid].zeroTierPhysicalEndpoints.begin());i2!=_members[*mid].zeroTierPhysicalEndpoints.end();++i2) { - if (ip == *i2) - return true; - } - } - return false; -} - -void Cluster::status(ZT_ClusterStatus &status) const -{ - const uint64_t now = RR->node->now(); - memset(&status,0,sizeof(ZT_ClusterStatus)); - - status.myId = _id; - - { - ZT_ClusterMemberStatus *const s = &(status.members[status.clusterSize++]); - s->id = _id; - s->alive = 1; - s->x = _x; - s->y = _y; - s->z = _z; - s->load = 0; // TODO - s->peers = RR->topology->countActive(now); - for(std::vector::const_iterator ep(_zeroTierPhysicalEndpoints.begin());ep!=_zeroTierPhysicalEndpoints.end();++ep) { - if (s->numZeroTierPhysicalEndpoints >= ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES) // sanity check - break; - memcpy(&(s->zeroTierPhysicalEndpoints[s->numZeroTierPhysicalEndpoints++]),&(*ep),sizeof(struct sockaddr_storage)); - } - } - - { - Mutex::Lock _l1(_memberIds_m); - for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { - if (status.clusterSize >= ZT_CLUSTER_MAX_MEMBERS) // sanity check - break; - - _Member &m = _members[*mid]; - Mutex::Lock ml(m.lock); - - ZT_ClusterMemberStatus *const s = &(status.members[status.clusterSize++]); - s->id = *mid; - s->msSinceLastHeartbeat = (unsigned int)std::min((uint64_t)(~((unsigned int)0)),(now - m.lastReceivedAliveAnnouncement)); - s->alive = (s->msSinceLastHeartbeat < ZT_CLUSTER_TIMEOUT) ? 1 : 0; - s->x = m.x; - s->y = m.y; - s->z = m.z; - s->load = m.load; - s->peers = m.peers; - for(std::vector::const_iterator ep(m.zeroTierPhysicalEndpoints.begin());ep!=m.zeroTierPhysicalEndpoints.end();++ep) { - if (s->numZeroTierPhysicalEndpoints >= ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES) // sanity check - break; - memcpy(&(s->zeroTierPhysicalEndpoints[s->numZeroTierPhysicalEndpoints++]),&(*ep),sizeof(struct sockaddr_storage)); - } - } - } -} - -void Cluster::_send(uint16_t memberId,StateMessageType type,const void *msg,unsigned int len) -{ - if ((len + 3) > (ZT_CLUSTER_MAX_MESSAGE_LENGTH - (24 + 2 + 2))) // sanity check - return; - _Member &m = _members[memberId]; - // assumes m.lock is locked! - if ((m.q.size() + len + 3) > ZT_CLUSTER_MAX_MESSAGE_LENGTH) - _flush(memberId); - m.q.append((uint16_t)(len + 1)); - m.q.append((uint8_t)type); - m.q.append(msg,len); -} - -void Cluster::_flush(uint16_t memberId) -{ - _Member &m = _members[memberId]; - // assumes m.lock is locked! - if (m.q.size() > (24 + 2 + 2)) { // 16-byte IV + 8-byte MAC + 2 byte from-member-ID + 2 byte to-member-ID - // Create key from member's key and IV - char keytmp[32]; - memcpy(keytmp,m.key,32); - for(int i=0;i<8;++i) - keytmp[i] ^= m.q[i]; - Salsa20 s20(keytmp,256,m.q.field(8,8)); - Utils::burn(keytmp,sizeof(keytmp)); - - // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard") - char polykey[ZT_POLY1305_KEY_LEN]; - memset(polykey,0,sizeof(polykey)); - s20.crypt12(polykey,polykey,sizeof(polykey)); - - // Encrypt m.q in place - s20.crypt12(reinterpret_cast(m.q.data()) + 24,const_cast(reinterpret_cast(m.q.data())) + 24,m.q.size() - 24); - - // Add MAC for authentication (encrypt-then-MAC) - char mac[ZT_POLY1305_MAC_LEN]; - Poly1305::compute(mac,reinterpret_cast(m.q.data()) + 24,m.q.size() - 24,polykey); - memcpy(m.q.field(16,8),mac,8); - - // Send! - _sendFunction(_sendFunctionArg,memberId,m.q.data(),m.q.size()); - - // Prepare for more - m.q.clear(); - char iv[16]; - Utils::getSecureRandom(iv,16); - m.q.append(iv,16); - m.q.addSize(8); // room for MAC - m.q.append((uint16_t)_id); // from member ID - m.q.append((uint16_t)memberId); // to member ID - } -} - -void Cluster::_doREMOTE_WHOIS(uint64_t fromMemberId,const Packet &remotep) -{ - if (remotep.payloadLength() >= ZT_ADDRESS_LENGTH) { - Identity queried(RR->topology->getIdentity((void *)0,Address(remotep.payload(),ZT_ADDRESS_LENGTH))); - if (queried) { - Buffer<1024> routp; - remotep.source().appendTo(routp); - routp.append((uint8_t)Packet::VERB_OK); - routp.addSize(2); // space for length - routp.append((uint8_t)Packet::VERB_WHOIS); - routp.append(remotep.packetId()); - queried.serialize(routp); - routp.setAt(ZT_ADDRESS_LENGTH + 1,(uint16_t)(routp.size() - ZT_ADDRESS_LENGTH - 3)); - - TRACE("responding to remote WHOIS from %s @ %u with identity of %s",remotep.source().toString().c_str(),(unsigned int)fromMemberId,queried.address().toString().c_str()); - Mutex::Lock _l2(_members[fromMemberId].lock); - _send(fromMemberId,CLUSTER_MESSAGE_PROXY_SEND,routp.data(),routp.size()); - } - } -} - -void Cluster::_doREMOTE_MULTICAST_GATHER(uint64_t fromMemberId,const Packet &remotep) -{ - const uint64_t nwid = remotep.at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); - const MulticastGroup mg(MAC(remotep.field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),remotep.at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); - unsigned int gatherLimit = remotep.at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); - const Address remotePeerAddress(remotep.source()); - - if (gatherLimit) { - Buffer routp; - remotePeerAddress.appendTo(routp); - routp.append((uint8_t)Packet::VERB_OK); - routp.addSize(2); // space for length - routp.append((uint8_t)Packet::VERB_MULTICAST_GATHER); - routp.append(remotep.packetId()); - routp.append(nwid); - mg.mac().appendTo(routp); - routp.append((uint32_t)mg.adi()); - - if (gatherLimit > ((ZT_CLUSTER_MAX_MESSAGE_LENGTH - 80) / 5)) - gatherLimit = ((ZT_CLUSTER_MAX_MESSAGE_LENGTH - 80) / 5); - if (RR->mc->gather(remotePeerAddress,nwid,mg,routp,gatherLimit)) { - routp.setAt(ZT_ADDRESS_LENGTH + 1,(uint16_t)(routp.size() - ZT_ADDRESS_LENGTH - 3)); - - TRACE("responding to remote MULTICAST_GATHER from %s @ %u with %u bytes",remotePeerAddress.toString().c_str(),(unsigned int)fromMemberId,routp.size()); - Mutex::Lock _l2(_members[fromMemberId].lock); - _send(fromMemberId,CLUSTER_MESSAGE_PROXY_SEND,routp.data(),routp.size()); - } - } -} - -} // namespace ZeroTier - -#endif // ZT_ENABLE_CLUSTER diff --git a/zto/node/Cluster.hpp b/zto/node/Cluster.hpp deleted file mode 100644 index 08e32a9..0000000 --- a/zto/node/Cluster.hpp +++ /dev/null @@ -1,455 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_CLUSTER_HPP -#define ZT_CLUSTER_HPP - -#ifdef ZT_ENABLE_CLUSTER - -#include - -#include "Constants.hpp" -#include "../include/ZeroTierOne.h" -#include "Address.hpp" -#include "InetAddress.hpp" -#include "SHA512.hpp" -#include "Utils.hpp" -#include "Buffer.hpp" -#include "Mutex.hpp" -#include "SharedPtr.hpp" -#include "Hashtable.hpp" -#include "Packet.hpp" -#include "SharedPtr.hpp" - -/** - * Timeout for cluster members being considered "alive" - * - * A cluster member is considered dead and will no longer have peers - * redirected to it if we have not heard a heartbeat in this long. - */ -#define ZT_CLUSTER_TIMEOUT 5000 - -/** - * Desired period between doPeriodicTasks() in milliseconds - */ -#define ZT_CLUSTER_PERIODIC_TASK_PERIOD 20 - -/** - * How often to flush outgoing message queues (maximum interval) - */ -#define ZT_CLUSTER_FLUSH_PERIOD ZT_CLUSTER_PERIODIC_TASK_PERIOD - -/** - * Maximum number of queued outgoing packets per sender address - */ -#define ZT_CLUSTER_MAX_QUEUE_PER_SENDER 16 - -/** - * Expiration time for send queue entries - */ -#define ZT_CLUSTER_QUEUE_EXPIRATION 3000 - -/** - * Chunk size for allocating queue entries - * - * Queue entries are allocated in chunks of this many and are added to a pool. - * ZT_CLUSTER_MAX_QUEUE_GLOBAL must be evenly divisible by this. - */ -#define ZT_CLUSTER_QUEUE_CHUNK_SIZE 32 - -/** - * Maximum number of chunks to ever allocate - * - * This is a global sanity limit to prevent resource exhaustion attacks. It - * works out to about 600mb of RAM. You'll never see this on a normal edge - * node. We're unlikely to see this on a root server unless someone is DOSing - * us. In that case cluster relaying will be affected but other functions - * should continue to operate normally. - */ -#define ZT_CLUSTER_MAX_QUEUE_CHUNKS 8194 - -/** - * Max data per queue entry - */ -#define ZT_CLUSTER_SEND_QUEUE_DATA_MAX 1500 - -/** - * We won't send WANT_PEER to other members more than every (ms) per recipient - */ -#define ZT_CLUSTER_WANT_PEER_EVERY 1000 - -namespace ZeroTier { - -class RuntimeEnvironment; -class MulticastGroup; -class Peer; -class Identity; - -// Internal class implemented inside Cluster.cpp -class _ClusterSendQueue; - -/** - * Multi-homing cluster state replication and packet relaying - * - * Multi-homing means more than one node sharing the same ZeroTier identity. - * There is nothing in the protocol to prevent this, but to make it work well - * requires the devices sharing an identity to cooperate and share some - * information. - * - * There are three use cases we want to fulfill: - * - * (1) Multi-homing of root servers with handoff for efficient routing, - * HA, and load balancing across many commodity nodes. - * (2) Multi-homing of network controllers for the same reason. - * (3) Multi-homing of nodes on virtual networks, such as domain servers - * and other important endpoints. - * - * These use cases are in order of escalating difficulty. The initial - * version of Cluster is aimed at satisfying the first, though you are - * free to try #2 and #3. - */ -class Cluster -{ -public: - /** - * State message types - */ - enum StateMessageType - { - CLUSTER_MESSAGE_NOP = 0, - - /** - * This cluster member is alive: - * <[2] version minor> - * <[2] version major> - * <[2] version revision> - * <[1] protocol version> - * <[4] X location (signed 32-bit)> - * <[4] Y location (signed 32-bit)> - * <[4] Z location (signed 32-bit)> - * <[8] local clock at this member> - * <[8] load average> - * <[8] number of peers> - * <[8] flags (currently unused, must be zero)> - * <[1] number of preferred ZeroTier endpoints> - * <[...] InetAddress(es) of preferred ZeroTier endpoint(s)> - * - * Cluster members constantly broadcast an alive heartbeat and will only - * receive peer redirects if they've done so within the timeout. - */ - CLUSTER_MESSAGE_ALIVE = 1, - - /** - * Cluster member has this peer: - * <[...] serialized identity of peer> - * - * This is typically sent in response to WANT_PEER but can also be pushed - * to prepopulate if this makes sense. - */ - CLUSTER_MESSAGE_HAVE_PEER = 2, - - /** - * Cluster member wants this peer: - * <[5] ZeroTier address of peer> - * - * Members that have a direct link to this peer will respond with - * HAVE_PEER. - */ - CLUSTER_MESSAGE_WANT_PEER = 3, - - /** - * A remote packet that we should also possibly respond to: - * <[2] 16-bit length of remote packet> - * <[...] remote packet payload> - * - * Cluster members may relay requests by relaying the request packet. - * These may include requests such as WHOIS and MULTICAST_GATHER. The - * packet must be already decrypted, decompressed, and authenticated. - * - * This can only be used for small request packets as per the cluster - * message size limit, but since these are the only ones in question - * this is fine. - * - * If a response is generated it is sent via PROXY_SEND. - */ - CLUSTER_MESSAGE_REMOTE_PACKET = 4, - - /** - * Request that VERB_RENDEZVOUS be sent to a peer that we have: - * <[5] ZeroTier address of peer on recipient's side> - * <[5] ZeroTier address of peer on sender's side> - * <[1] 8-bit number of sender's peer's active path addresses> - * <[...] series of serialized InetAddresses of sender's peer's paths> - * - * This requests that we perform NAT-t introduction between a peer that - * we have and one on the sender's side. The sender furnishes contact - * info for its peer, and we send VERB_RENDEZVOUS to both sides: to ours - * directly and with PROXY_SEND to theirs. - */ - CLUSTER_MESSAGE_PROXY_UNITE = 5, - - /** - * Request that a cluster member send a packet to a locally-known peer: - * <[5] ZeroTier address of recipient> - * <[1] packet verb> - * <[2] length of packet payload> - * <[...] packet payload> - * - * This differs from RELAY in that it requests the receiving cluster - * member to actually compose a ZeroTier Packet from itself to the - * provided recipient. RELAY simply says "please forward this blob." - * RELAY is used to implement peer-to-peer relaying with RENDEZVOUS, - * while PROXY_SEND is used to implement proxy sending (which right - * now is only used to send RENDEZVOUS). - */ - CLUSTER_MESSAGE_PROXY_SEND = 6, - - /** - * Replicate a network config for a network we belong to: - * <[...] network config chunk> - * - * This is used by clusters to avoid every member having to query - * for the same netconf for networks all members belong to. - * - * The first field of a network config chunk is the network ID, - * so this can be checked to look up the network on receipt. - */ - CLUSTER_MESSAGE_NETWORK_CONFIG = 7 - }; - - /** - * Construct a new cluster - */ - Cluster( - const RuntimeEnvironment *renv, - uint16_t id, - const std::vector &zeroTierPhysicalEndpoints, - int32_t x, - int32_t y, - int32_t z, - void (*sendFunction)(void *,unsigned int,const void *,unsigned int), - void *sendFunctionArg, - int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), - void *addressToLocationFunctionArg); - - ~Cluster(); - - /** - * @return This cluster member's ID - */ - inline uint16_t id() const throw() { return _id; } - - /** - * Handle an incoming intra-cluster message - * - * @param data Message data - * @param len Message length (max: ZT_CLUSTER_MAX_MESSAGE_LENGTH) - */ - void handleIncomingStateMessage(const void *msg,unsigned int len); - - /** - * Broadcast that we have a given peer - * - * This should be done when new peers are first contacted. - * - * @param id Identity of peer - */ - void broadcastHavePeer(const Identity &id); - - /** - * Broadcast a network config chunk to other members of cluster - * - * @param chunk Chunk data - * @param len Length of chunk - */ - void broadcastNetworkConfigChunk(const void *chunk,unsigned int len); - - /** - * If the cluster has this peer, prepare the packet to send via cluster - * - * Note that outp is only armored (or modified at all) if the return value is a member ID. - * - * @param toPeerAddress Value of outp.destination(), simply to save additional lookup - * @param ts Result: set to time of last HAVE_PEER from the cluster - * @param peerSecret Result: Buffer to fill with peer secret on valid return value, must be at least ZT_PEER_SECRET_KEY_LENGTH bytes - * @return -1 if cluster does not know this peer, or a member ID to pass to sendViaCluster() - */ - int checkSendViaCluster(const Address &toPeerAddress,uint64_t &mostRecentTs,void *peerSecret); - - /** - * Send data via cluster front plane (packet head or fragment) - * - * @param haveMemberId Member ID that has this peer as returned by prepSendviaCluster() - * @param toPeerAddress Destination peer address - * @param data Packet or packet fragment data - * @param len Length of packet or fragment - * @return True if packet was sent (and outp was modified via armoring) - */ - bool sendViaCluster(int haveMemberId,const Address &toPeerAddress,const void *data,unsigned int len); - - /** - * Relay a packet via the cluster - * - * This is used in the outgoing packet and relaying logic in Switch to - * relay packets to other cluster members. It isn't PROXY_SEND-- that is - * used internally in Cluster to send responses to peer queries. - * - * @param fromPeerAddress Source peer address (if known, should be NULL for fragments) - * @param toPeerAddress Destination peer address - * @param data Packet or packet fragment data - * @param len Length of packet or fragment - * @param unite If true, also request proxy unite across cluster - */ - void relayViaCluster(const Address &fromPeerAddress,const Address &toPeerAddress,const void *data,unsigned int len,bool unite); - - /** - * Send a distributed query to other cluster members - * - * Some queries such as WHOIS or MULTICAST_GATHER need a response from other - * cluster members. Replies (if any) will be sent back to the peer via - * PROXY_SEND across the cluster. - * - * @param pkt Packet to distribute - */ - void sendDistributedQuery(const Packet &pkt); - - /** - * Call every ~ZT_CLUSTER_PERIODIC_TASK_PERIOD milliseconds. - */ - void doPeriodicTasks(); - - /** - * Add a member ID to this cluster - * - * @param memberId Member ID - */ - void addMember(uint16_t memberId); - - /** - * Remove a member ID from this cluster - * - * @param memberId Member ID to remove - */ - void removeMember(uint16_t memberId); - - /** - * Find a better cluster endpoint for this peer (if any) - * - * @param redirectTo InetAddress to be set to a better endpoint (if there is one) - * @param peerAddress Address of peer to (possibly) redirect - * @param peerPhysicalAddress Physical address of peer's current best path (where packet was most recently received or getBestPath()->address()) - * @param offload Always redirect if possible -- can be used to offload peers during shutdown - * @return True if redirectTo was set to a new address, false if redirectTo was not modified - */ - bool findBetterEndpoint(InetAddress &redirectTo,const Address &peerAddress,const InetAddress &peerPhysicalAddress,bool offload); - - /** - * @param ip Address to check - * @return True if this is a cluster frontplane address (excluding our addresses) - */ - bool isClusterPeerFrontplane(const InetAddress &ip) const; - - /** - * Fill out ZT_ClusterStatus structure (from core API) - * - * @param status Reference to structure to hold result (anything there is replaced) - */ - void status(ZT_ClusterStatus &status) const; - -private: - void _send(uint16_t memberId,StateMessageType type,const void *msg,unsigned int len); - void _flush(uint16_t memberId); - - void _doREMOTE_WHOIS(uint64_t fromMemberId,const Packet &remotep); - void _doREMOTE_MULTICAST_GATHER(uint64_t fromMemberId,const Packet &remotep); - - // These are initialized in the constructor and remain immutable ------------ - uint16_t _masterSecret[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)]; - unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; - const RuntimeEnvironment *RR; - _ClusterSendQueue *const _sendQueue; - void (*_sendFunction)(void *,unsigned int,const void *,unsigned int); - void *_sendFunctionArg; - int (*_addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *); - void *_addressToLocationFunctionArg; - const int32_t _x; - const int32_t _y; - const int32_t _z; - const uint16_t _id; - const std::vector _zeroTierPhysicalEndpoints; - // end immutable fields ----------------------------------------------------- - - struct _Member - { - unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; - - uint64_t lastReceivedAliveAnnouncement; - uint64_t lastAnnouncedAliveTo; - - uint64_t load; - uint64_t peers; - int32_t x,y,z; - - std::vector zeroTierPhysicalEndpoints; - - Buffer q; - - Mutex lock; - - inline void clear() - { - lastReceivedAliveAnnouncement = 0; - lastAnnouncedAliveTo = 0; - load = 0; - peers = 0; - x = 0; - y = 0; - z = 0; - zeroTierPhysicalEndpoints.clear(); - q.clear(); - } - - _Member() { this->clear(); } - ~_Member() { Utils::burn(key,sizeof(key)); } - }; - _Member *const _members; - - std::vector _memberIds; - Mutex _memberIds_m; - - struct _RemotePeer - { - _RemotePeer() : lastHavePeerReceived(0),lastSentWantPeer(0) {} - ~_RemotePeer() { Utils::burn(key,ZT_PEER_SECRET_KEY_LENGTH); } - uint64_t lastHavePeerReceived; - uint64_t lastSentWantPeer; - uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; // secret key from identity agreement - }; - std::map< std::pair,_RemotePeer > _remotePeers; // we need ordered behavior and lower_bound here - Mutex _remotePeers_m; - - uint64_t _lastFlushed; - uint64_t _lastCleanedRemotePeers; - uint64_t _lastCleanedQueue; -}; - -} // namespace ZeroTier - -#endif // ZT_ENABLE_CLUSTER - -#endif diff --git a/zto/node/Constants.hpp b/zto/node/Constants.hpp deleted file mode 100644 index 410a245..0000000 --- a/zto/node/Constants.hpp +++ /dev/null @@ -1,457 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_CONSTANTS_HPP -#define ZT_CONSTANTS_HPP - -#include "../include/ZeroTierOne.h" - -// -// This include file also auto-detects and canonicalizes some environment -// information defines: -// -// __LINUX__ -// __APPLE__ -// __BSD__ (OSX also defines this) -// __UNIX_LIKE__ (Linux, BSD, etc.) -// __WINDOWS__ -// -// Also makes sure __BYTE_ORDER is defined reasonably. -// - -// Hack: make sure __GCC__ is defined on old GCC compilers -#ifndef __GCC__ -#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) -#define __GCC__ -#endif -#endif - -#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) -#ifndef __LINUX__ -#define __LINUX__ -#endif -#ifndef __UNIX_LIKE__ -#define __UNIX_LIKE__ -#endif -#include -#endif - -#ifdef __APPLE__ -#include -#ifndef __UNIX_LIKE__ -#define __UNIX_LIKE__ -#endif -#ifndef __BSD__ -#define __BSD__ -#endif -#include -#endif - -// Defined this macro to disable "type punning" on a number of targets that -// have issues with unaligned memory access. -#if defined(__arm__) || defined(__ARMEL__) || (defined(__APPLE__) && ( (defined(TARGET_OS_IPHONE) && (TARGET_OS_IPHONE != 0)) || (defined(TARGET_OS_WATCH) && (TARGET_OS_WATCH != 0)) || (defined(TARGET_IPHONE_SIMULATOR) && (TARGET_IPHONE_SIMULATOR != 0)) ) ) -#ifndef ZT_NO_TYPE_PUNNING -#define ZT_NO_TYPE_PUNNING -#endif -#endif - -#if defined(__FreeBSD__) || defined(__OpenBSD__) -#ifndef __UNIX_LIKE__ -#define __UNIX_LIKE__ -#endif -#ifndef __BSD__ -#define __BSD__ -#endif -#include -#ifndef __BYTE_ORDER -#define __BYTE_ORDER _BYTE_ORDER -#define __LITTLE_ENDIAN _LITTLE_ENDIAN -#define __BIG_ENDIAN _BIG_ENDIAN -#endif -#endif - -#if defined(_WIN32) || defined(_WIN64) -#ifndef __WINDOWS__ -#define __WINDOWS__ -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif -#pragma warning(disable : 4290) -#pragma warning(disable : 4996) -#pragma warning(disable : 4101) -#undef __UNIX_LIKE__ -#undef __BSD__ -#define ZT_PATH_SEPARATOR '\\' -#define ZT_PATH_SEPARATOR_S "\\" -#define ZT_EOL_S "\r\n" -#include -#include -#endif - -// Assume little endian if not defined -#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER)) -#undef __BYTE_ORDER -#undef __LITTLE_ENDIAN -#undef __BIG_ENDIAN -#define __BIG_ENDIAN 4321 -#define __LITTLE_ENDIAN 1234 -#define __BYTE_ORDER 1234 -#endif - -#ifdef __UNIX_LIKE__ -#define ZT_PATH_SEPARATOR '/' -#define ZT_PATH_SEPARATOR_S "/" -#define ZT_EOL_S "\n" -#endif - -#ifndef __BYTE_ORDER -#include -#endif - -/** - * Length of a ZeroTier address in bytes - */ -#define ZT_ADDRESS_LENGTH 5 - -/** - * Length of a hexadecimal ZeroTier address - */ -#define ZT_ADDRESS_LENGTH_HEX 10 - -/** - * Addresses beginning with this byte are reserved for the joy of in-band signaling - */ -#define ZT_ADDRESS_RESERVED_PREFIX 0xff - -/** - * Default payload MTU for UDP packets - * - * In the future we might support UDP path MTU discovery, but for now we - * set a maximum that is equal to 1500 minus 8 (for PPPoE overhead, common - * in some markets) minus 48 (IPv6 UDP overhead). - */ -#define ZT_UDP_DEFAULT_PAYLOAD_MTU 1444 - -/** - * Default MTU used for Ethernet tap device - */ -#define ZT_IF_MTU ZT_MAX_MTU - -/** - * Maximum number of packet fragments we'll support - * - * The actual spec allows 16, but this is the most we'll support right - * now. Packets with more than this many fragments are dropped. - */ -#define ZT_MAX_PACKET_FRAGMENTS 4 - -/** - * Size of RX queue - * - * This is about 2mb, and can be decreased for small devices. A queue smaller - * than about 4 is probably going to cause a lot of lost packets. - */ -#define ZT_RX_QUEUE_SIZE 64 - -/** - * RX queue entries older than this do not "exist" - */ -#define ZT_RX_QUEUE_EXPIRE 4000 - -/** - * Length of secret key in bytes -- 256-bit -- do not change - */ -#define ZT_PEER_SECRET_KEY_LENGTH 32 - -/** - * Minimum delay between timer task checks to prevent thrashing - */ -#define ZT_CORE_TIMER_TASK_GRANULARITY 500 - -/** - * How often Topology::clean() and Network::clean() and similar are called, in ms - */ -#define ZT_HOUSEKEEPING_PERIOD 120000 - -/** - * How long to remember peer records in RAM if they haven't been used - */ -#define ZT_PEER_IN_MEMORY_EXPIRATION 600000 - -/** - * Delay between WHOIS retries in ms - */ -#define ZT_WHOIS_RETRY_DELAY 1000 - -/** - * Maximum identity WHOIS retries (each attempt tries consulting a different peer) - */ -#define ZT_MAX_WHOIS_RETRIES 4 - -/** - * Transmit queue entry timeout - */ -#define ZT_TRANSMIT_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1)) - -/** - * Receive queue entry timeout - */ -#define ZT_RECEIVE_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1)) - -/** - * Maximum latency to allow for OK(HELLO) before packet is discarded - */ -#define ZT_HELLO_MAX_ALLOWABLE_LATENCY 60000 - -/** - * Maximum number of ZT hops allowed (this is not IP hops/TTL) - * - * The protocol allows up to 7, but we limit it to something smaller. - */ -#define ZT_RELAY_MAX_HOPS 3 - -/** - * Maximum number of upstreams to use (far more than we should ever need) - */ -#define ZT_MAX_UPSTREAMS 64 - -/** - * Expire time for multicast 'likes' and indirect multicast memberships in ms - */ -#define ZT_MULTICAST_LIKE_EXPIRE 600000 - -/** - * Period for multicast LIKE announcements - */ -#define ZT_MULTICAST_ANNOUNCE_PERIOD 120000 - -/** - * Delay between explicit MULTICAST_GATHER requests for a given multicast channel - */ -#define ZT_MULTICAST_EXPLICIT_GATHER_DELAY (ZT_MULTICAST_LIKE_EXPIRE / 10) - -/** - * Expiration for credentials presented for MULTICAST_LIKE or MULTICAST_GATHER (for non-network-members) - */ -#define ZT_MULTICAST_CREDENTIAL_EXPIRATON ZT_MULTICAST_LIKE_EXPIRE - -/** - * Timeout for outgoing multicasts - * - * This is how long we wait for explicit or implicit gather results. - */ -#define ZT_MULTICAST_TRANSMIT_TIMEOUT 5000 - -/** - * Delay between checks of peer pings, etc., and also related housekeeping tasks - */ -#define ZT_PING_CHECK_INVERVAL 5000 - -/** - * How frequently to send heartbeats over in-use paths - */ -#define ZT_PATH_HEARTBEAT_PERIOD 14000 - -/** - * Paths are considered inactive if they have not received traffic in this long - */ -#define ZT_PATH_ALIVE_TIMEOUT 45000 - -/** - * Minimum time between attempts to check dead paths to see if they can be re-awakened - */ -#define ZT_PATH_MIN_REACTIVATE_INTERVAL 2500 - -/** - * Do not accept HELLOs over a given path more often than this - */ -#define ZT_PATH_HELLO_RATE_LIMIT 1000 - -/** - * Delay between full-fledge pings of directly connected peers - */ -#define ZT_PEER_PING_PERIOD 60000 - -/** - * Paths are considered expired if they have not produced a real packet in this long - */ -#define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) - -/** - * Send a full HELLO every this often (ms) - */ -#define ZT_PEER_SEND_FULL_HELLO_EVERY (ZT_PEER_PING_PERIOD * 2) - -/** - * How often to retry expired paths that we're still remembering - */ -#define ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD (ZT_PEER_PING_PERIOD * 10) - -/** - * Timeout for overall peer activity (measured from last receive) - */ -#define ZT_PEER_ACTIVITY_TIMEOUT 500000 - -/** - * General rate limit timeout for multiple packet types (HELLO, etc.) - */ -#define ZT_PEER_GENERAL_INBOUND_RATE_LIMIT 500 - -/** - * General limit for max RTT for requests over the network - */ -#define ZT_GENERAL_RTT_LIMIT 5000 - -/** - * Delay between requests for updated network autoconf information - * - * Don't lengthen this as it affects things like QoS / uptime monitoring - * via ZeroTier Central. This is the heartbeat, basically. - */ -#define ZT_NETWORK_AUTOCONF_DELAY 60000 - -/** - * Minimum interval between attempts by relays to unite peers - * - * When a relay gets a packet destined for another peer, it sends both peers - * a RENDEZVOUS message no more than this often. This instructs the peers - * to attempt NAT-t and gives each the other's corresponding IP:port pair. - */ -#define ZT_MIN_UNITE_INTERVAL 30000 - -/** - * How often should peers try memorized or statically defined paths? - */ -#define ZT_TRY_MEMORIZED_PATH_INTERVAL 30000 - -/** - * Sanity limit on maximum bridge routes - * - * If the number of bridge routes exceeds this, we cull routes from the - * bridges with the most MACs behind them until it doesn't. This is a - * sanity limit to prevent memory-filling DOS attacks, nothing more. No - * physical LAN has anywhere even close to this many nodes. Note that this - * does not limit the size of ZT virtual LANs, only bridge routing. - */ -#define ZT_MAX_BRIDGE_ROUTES 67108864 - -/** - * If there is no known route, spam to up to this many active bridges - */ -#define ZT_MAX_BRIDGE_SPAM 32 - -/** - * Interval between direct path pushes in milliseconds - */ -#define ZT_DIRECT_PATH_PUSH_INTERVAL 120000 - -/** - * Time horizon for push direct paths cutoff - */ -#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000 - -/** - * Maximum number of direct path pushes within cutoff time - * - * This limits response to PUSH_DIRECT_PATHS to CUTOFF_LIMIT responses - * per CUTOFF_TIME milliseconds per peer to prevent this from being - * useful for DOS amplification attacks. - */ -#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5 - -/** - * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6) - */ -#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4 - -/** - * Time horizon for VERB_NETWORK_CREDENTIALS cutoff - */ -#define ZT_PEER_CREDENTIALS_CUTOFF_TIME 60000 - -/** - * Maximum number of VERB_NETWORK_CREDENTIALS within cutoff time - */ -#define ZT_PEER_CREDEITIALS_CUTOFF_LIMIT 15 - -/** - * WHOIS rate limit (we allow these to be pretty fast) - */ -#define ZT_PEER_WHOIS_RATE_LIMIT 100 - -/** - * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound - */ -#define ZT_PEER_GENERAL_RATE_LIMIT 1000 - -/** - * Don't do expensive identity validation more often than this - * - * IPv4 and IPv6 address prefixes are hashed down to 14-bit (0-16383) integers - * using the first 24 bits for IPv4 or the first 48 bits for IPv6. These are - * then rate limited to one identity validation per this often milliseconds. - */ -#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64) || defined(_M_AMD64)) -// AMD64 machines can do anywhere from one every 50ms to one every 10ms. This provides plenty of margin. -#define ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT 2000 -#else -#if (defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)) -// 32-bit Intel machines usually average about one every 100ms -#define ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT 5000 -#else -// This provides a safe margin for ARM, MIPS, etc. that usually average one every 250-400ms -#define ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT 10000 -#endif -#endif - -/** - * How long is a path or peer considered to have a trust relationship with us (for e.g. relay policy) since last trusted established packet? - */ -#define ZT_TRUST_EXPIRATION 600000 - -/** - * Enable support for older network configurations from older (pre-1.1.6) controllers - */ -#define ZT_SUPPORT_OLD_STYLE_NETCONF 1 - -/** - * Desired buffer size for UDP sockets (used in service and osdep but defined here) - */ -#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__)) -#define ZT_UDP_DESIRED_BUF_SIZE 1048576 -#else -#define ZT_UDP_DESIRED_BUF_SIZE 131072 -#endif - -/** - * Desired / recommended min stack size for threads (used on some platforms to reset thread stack size) - */ -#define ZT_THREAD_MIN_STACK_SIZE 1048576 - -/* Ethernet frame types that might be relevant to us */ -#define ZT_ETHERTYPE_IPV4 0x0800 -#define ZT_ETHERTYPE_ARP 0x0806 -#define ZT_ETHERTYPE_RARP 0x8035 -#define ZT_ETHERTYPE_ATALK 0x809b -#define ZT_ETHERTYPE_AARP 0x80f3 -#define ZT_ETHERTYPE_IPX_A 0x8137 -#define ZT_ETHERTYPE_IPX_B 0x8138 -#define ZT_ETHERTYPE_IPV6 0x86dd - -#endif diff --git a/zto/node/Dictionary.hpp b/zto/node/Dictionary.hpp deleted file mode 100644 index fa9e288..0000000 --- a/zto/node/Dictionary.hpp +++ /dev/null @@ -1,473 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_DICTIONARY_HPP -#define ZT_DICTIONARY_HPP - -#include "Constants.hpp" -#include "Utils.hpp" -#include "Buffer.hpp" -#include "Address.hpp" - -#include - -namespace ZeroTier { - -/** - * A small (in code and data) packed key=value store - * - * This stores data in the form of a compact blob that is sort of human - * readable (depending on whether you put binary data in it) and is backward - * compatible with older versions. Binary data is escaped such that the - * serialized form of a Dictionary is always a valid null-terminated C string. - * - * Keys are restricted: no binary data, no CR/LF, and no equals (=). If a key - * contains these characters it may not be retrievable. This is not checked. - * - * Lookup is via linear search and will be slow with a lot of keys. It's - * designed for small things. - * - * There is code to test and fuzz this in selftest.cpp. Fuzzing a blob of - * pointer tricks like this is important after any modifications. - * - * This is used for network configurations and for saving some things on disk - * in the ZeroTier One service code. - * - * @tparam C Dictionary max capacity in bytes - */ -template -class Dictionary -{ -public: - Dictionary() - { - _d[0] = (char)0; - } - - Dictionary(const char *s) - { - if (s) { - Utils::scopy(_d,sizeof(_d),s); - } else { - _d[0] = (char)0; - } - } - - Dictionary(const char *s,unsigned int len) - { - if (s) { - if (len > (C-1)) - len = C-1; - memcpy(_d,s,len); - _d[len] = (char)0; - } else { - _d[0] = (char)0; - } - } - - Dictionary(const Dictionary &d) - { - Utils::scopy(_d,sizeof(_d),d._d); - } - - inline Dictionary &operator=(const Dictionary &d) - { - Utils::scopy(_d,sizeof(_d),d._d); - return *this; - } - - /** - * Load a dictionary from a C-string - * - * @param s Dictionary in string form - * @return False if 's' was longer than our capacity - */ - inline bool load(const char *s) - { - if (s) { - return Utils::scopy(_d,sizeof(_d),s); - } else { - _d[0] = (char)0; - return true; - } - } - - /** - * Delete all entries - */ - inline void clear() - { - _d[0] = (char)0; - } - - /** - * @return Size of dictionary in bytes not including terminating NULL - */ - inline unsigned int sizeBytes() const - { - for(unsigned int i=0;i - inline bool get(const char *key,Buffer &dest) const - { - const int r = this->get(key,const_cast(reinterpret_cast(dest.data())),BC); - if (r >= 0) { - dest.setSize((unsigned int)r); - return true; - } else { - dest.clear(); - return false; - } - } - - /** - * Get a boolean value - * - * @param key Key to look up - * @param dfl Default value if not found in dictionary - * @return Boolean value of key or 'dfl' if not found - */ - bool getB(const char *key,bool dfl = false) const - { - char tmp[4]; - if (this->get(key,tmp,sizeof(tmp)) >= 0) - return ((*tmp == '1')||(*tmp == 't')||(*tmp == 'T')); - return dfl; - } - - /** - * Get an unsigned int64 stored as hex in the dictionary - * - * @param key Key to look up - * @param dfl Default value or 0 if unspecified - * @return Decoded hex UInt value or 'dfl' if not found - */ - inline uint64_t getUI(const char *key,uint64_t dfl = 0) const - { - char tmp[128]; - if (this->get(key,tmp,sizeof(tmp)) >= 1) - return Utils::hexStrToU64(tmp); - return dfl; - } - - /** - * Add a new key=value pair - * - * If the key is already present this will append another, but the first - * will always be returned by get(). This is not checked. If you want to - * ensure a key is not present use erase() first. - * - * Use the vlen parameter to add binary values. Nulls will be escaped. - * - * @param key Key -- nulls, CR/LF, and equals (=) are illegal characters - * @param value Value to set - * @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0 - * @return True if there was enough room to add this key=value pair - */ - inline bool add(const char *key,const char *value,int vlen = -1) - { - for(unsigned int i=0;i 0) { - _d[j++] = '\n'; - if (j == C) { - _d[i] = (char)0; - return false; - } - } - - const char *p = key; - while (*p) { - _d[j++] = *(p++); - if (j == C) { - _d[i] = (char)0; - return false; - } - } - - _d[j++] = '='; - if (j == C) { - _d[i] = (char)0; - return false; - } - - p = value; - int k = 0; - while ( ((vlen < 0)&&(*p)) || (k < vlen) ) { - switch(*p) { - case 0: - case '\r': - case '\n': - case '\\': - case '=': - _d[j++] = '\\'; - if (j == C) { - _d[i] = (char)0; - return false; - } - switch(*p) { - case 0: _d[j++] = '0'; break; - case '\r': _d[j++] = 'r'; break; - case '\n': _d[j++] = 'n'; break; - case '\\': _d[j++] = '\\'; break; - case '=': _d[j++] = 'e'; break; - } - if (j == C) { - _d[i] = (char)0; - return false; - } - break; - default: - _d[j++] = *p; - if (j == C) { - _d[i] = (char)0; - return false; - } - break; - } - ++p; - ++k; - } - - _d[j] = (char)0; - - return true; - } - } - return false; - } - - /** - * Add a boolean as a '1' or a '0' - */ - inline bool add(const char *key,bool value) - { - return this->add(key,(value) ? "1" : "0",1); - } - - /** - * Add a 64-bit integer (unsigned) as a hex value - */ - inline bool add(const char *key,uint64_t value) - { - char tmp[32]; - Utils::snprintf(tmp,sizeof(tmp),"%llx",(unsigned long long)value); - return this->add(key,tmp,-1); - } - - /** - * Add a 64-bit integer (unsigned) as a hex value - */ - inline bool add(const char *key,const Address &a) - { - char tmp[32]; - Utils::snprintf(tmp,sizeof(tmp),"%.10llx",(unsigned long long)a.toInt()); - return this->add(key,tmp,-1); - } - - /** - * Add a binary buffer's contents as a value - * - * @tparam BC Buffer capacity (usually inferred) - */ - template - inline bool add(const char *key,const Buffer &value) - { - return this->add(key,(const char *)value.data(),(int)value.size()); - } - - /** - * @param key Key to check - * @return True if key is present - */ - inline bool contains(const char *key) const - { - char tmp[2]; - return (this->get(key,tmp,2) >= 0); - } - - /** - * Erase a key from this dictionary - * - * Use this before add() to ensure that a key is replaced if it might - * already be present. - * - * @param key Key to erase - * @return True if key was found and erased - */ - inline bool erase(const char *key) - { - char d2[C]; - char *saveptr = (char *)0; - unsigned int d2ptr = 0; - bool found = false; - for(char *f=Utils::stok(_d,"\r\n",&saveptr);(f);f=Utils::stok((char *)0,"\r\n",&saveptr)) { - if (*f) { - const char *p = f; - const char *k = key; - while ((*k)&&(*p)) { - if (*k != *p) - break; - ++k; - ++p; - } - if (*k) { - p = f; - while (*p) - d2[d2ptr++] = *(p++); - d2[d2ptr++] = '\n'; - } else { - found = true; - } - } - } - d2[d2ptr++] = (char)0; - memcpy(_d,d2,d2ptr); - return found; - } - - /** - * @return Value of C template parameter - */ - inline unsigned int capacity() const { return C; } - - inline const char *data() const { return _d; } - inline char *unsafeData() { return _d; } - -private: - char _d[C]; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Hashtable.hpp b/zto/node/Hashtable.hpp deleted file mode 100644 index 66f2990..0000000 --- a/zto/node/Hashtable.hpp +++ /dev/null @@ -1,415 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_HASHTABLE_HPP -#define ZT_HASHTABLE_HPP - -#include -#include -#include - -#include -#include -#include -#include - -namespace ZeroTier { - -/** - * A minimal hash table implementation for the ZeroTier core - * - * This is not a drop-in replacement for STL containers, and has several - * limitations. Keys can be uint64_t or an object, and if the latter they - * must implement a method called hashCode() that returns an unsigned long - * value that is evenly distributed. - */ -template -class Hashtable -{ -private: - struct _Bucket - { - _Bucket(const K &k,const V &v) : k(k),v(v) {} - _Bucket(const K &k) : k(k),v() {} - _Bucket(const _Bucket &b) : k(b.k),v(b.v) {} - inline _Bucket &operator=(const _Bucket &b) { k = b.k; v = b.v; return *this; } - K k; - V v; - _Bucket *next; // must be set manually for each _Bucket - }; - -public: - /** - * A simple forward iterator (different from STL) - * - * It's safe to erase the last key, but not others. Don't use set() since that - * may rehash and invalidate the iterator. Note the erasing the key will destroy - * the targets of the pointers returned by next(). - */ - class Iterator - { - public: - /** - * @param ht Hash table to iterate over - */ - Iterator(Hashtable &ht) : - _idx(0), - _ht(&ht), - _b(ht._t[0]) - { - } - - /** - * @param kptr Pointer to set to point to next key - * @param vptr Pointer to set to point to next value - * @return True if kptr and vptr are set, false if no more entries - */ - inline bool next(K *&kptr,V *&vptr) - { - for(;;) { - if (_b) { - kptr = &(_b->k); - vptr = &(_b->v); - _b = _b->next; - return true; - } - ++_idx; - if (_idx >= _ht->_bc) - return false; - _b = _ht->_t[_idx]; - } - } - - private: - unsigned long _idx; - Hashtable *_ht; - _Bucket *_b; - }; - friend class Hashtable::Iterator; - - /** - * @param bc Initial capacity in buckets (default: 64, must be nonzero) - */ - Hashtable(unsigned long bc = 64) : - _t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))), - _bc(bc), - _s(0) - { - if (!_t) - throw std::bad_alloc(); - for(unsigned long i=0;i &ht) : - _t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * ht._bc))), - _bc(ht._bc), - _s(ht._s) - { - if (!_t) - throw std::bad_alloc(); - for(unsigned long i=0;i<_bc;++i) - _t[i] = (_Bucket *)0; - for(unsigned long i=0;i<_bc;++i) { - const _Bucket *b = ht._t[i]; - while (b) { - _Bucket *nb = new _Bucket(*b); - nb->next = _t[i]; - _t[i] = nb; - b = b->next; - } - } - } - - ~Hashtable() - { - this->clear(); - ::free(_t); - } - - inline Hashtable &operator=(const Hashtable &ht) - { - this->clear(); - if (ht._s) { - for(unsigned long i=0;iset(b->k,b->v); - b = b->next; - } - } - } - return *this; - } - - /** - * Erase all entries - */ - inline void clear() - { - if (_s) { - for(unsigned long i=0;i<_bc;++i) { - _Bucket *b = _t[i]; - while (b) { - _Bucket *const nb = b->next; - delete b; - b = nb; - } - _t[i] = (_Bucket *)0; - } - _s = 0; - } - } - - /** - * @return Vector of all keys - */ - inline typename std::vector keys() const - { - typename std::vector k; - if (_s) { - k.reserve(_s); - for(unsigned long i=0;i<_bc;++i) { - _Bucket *b = _t[i]; - while (b) { - k.push_back(b->k); - b = b->next; - } - } - } - return k; - } - - /** - * Append all keys (in unspecified order) to the supplied vector or list - * - * @param v Vector, list, or other compliant container - * @tparam Type of V (generally inferred) - */ - template - inline void appendKeys(C &v) const - { - if (_s) { - for(unsigned long i=0;i<_bc;++i) { - _Bucket *b = _t[i]; - while (b) { - v.push_back(b->k); - b = b->next; - } - } - } - } - - /** - * @return Vector of all entries (pairs of K,V) - */ - inline typename std::vector< std::pair > entries() const - { - typename std::vector< std::pair > k; - if (_s) { - k.reserve(_s); - for(unsigned long i=0;i<_bc;++i) { - _Bucket *b = _t[i]; - while (b) { - k.push_back(std::pair(b->k,b->v)); - b = b->next; - } - } - } - return k; - } - - /** - * @param k Key - * @return Pointer to value or NULL if not found - */ - inline V *get(const K &k) - { - _Bucket *b = _t[_hc(k) % _bc]; - while (b) { - if (b->k == k) - return &(b->v); - b = b->next; - } - return (V *)0; - } - inline const V *get(const K &k) const { return const_cast(this)->get(k); } - - /** - * @param k Key to check - * @return True if key is present - */ - inline bool contains(const K &k) const - { - _Bucket *b = _t[_hc(k) % _bc]; - while (b) { - if (b->k == k) - return true; - b = b->next; - } - return false; - } - - /** - * @param k Key - * @return True if value was present - */ - inline bool erase(const K &k) - { - const unsigned long bidx = _hc(k) % _bc; - _Bucket *lastb = (_Bucket *)0; - _Bucket *b = _t[bidx]; - while (b) { - if (b->k == k) { - if (lastb) - lastb->next = b->next; - else _t[bidx] = b->next; - delete b; - --_s; - return true; - } - lastb = b; - b = b->next; - } - return false; - } - - /** - * @param k Key - * @param v Value - * @return Reference to value in table - */ - inline V &set(const K &k,const V &v) - { - const unsigned long h = _hc(k); - unsigned long bidx = h % _bc; - - _Bucket *b = _t[bidx]; - while (b) { - if (b->k == k) { - b->v = v; - return b->v; - } - b = b->next; - } - - if (_s >= _bc) { - _grow(); - bidx = h % _bc; - } - - b = new _Bucket(k,v); - b->next = _t[bidx]; - _t[bidx] = b; - ++_s; - return b->v; - } - - /** - * @param k Key - * @return Value, possibly newly created - */ - inline V &operator[](const K &k) - { - const unsigned long h = _hc(k); - unsigned long bidx = h % _bc; - - _Bucket *b = _t[bidx]; - while (b) { - if (b->k == k) - return b->v; - b = b->next; - } - - if (_s >= _bc) { - _grow(); - bidx = h % _bc; - } - - b = new _Bucket(k); - b->next = _t[bidx]; - _t[bidx] = b; - ++_s; - return b->v; - } - - /** - * @return Number of entries - */ - inline unsigned long size() const throw() { return _s; } - - /** - * @return True if table is empty - */ - inline bool empty() const throw() { return (_s == 0); } - -private: - template - static inline unsigned long _hc(const O &obj) - { - return (unsigned long)obj.hashCode(); - } - static inline unsigned long _hc(const uint64_t i) - { - /* NOTE: this assumes that 'i' is evenly distributed, which is the case for - * packet IDs and network IDs -- the two use cases in ZT for uint64_t keys. - * These values are also greater than 0xffffffff so they'll map onto a full - * bucket count just fine no matter what happens. Normally you'd want to - * hash an integer key index in a hash table. */ - return (unsigned long)i; - } - static inline unsigned long _hc(const uint32_t i) - { - return ((unsigned long)i * (unsigned long)0x9e3779b1); - } - static inline unsigned long _hc(const uint16_t i) - { - return ((unsigned long)i * (unsigned long)0x9e3779b1); - } - - inline void _grow() - { - const unsigned long nc = _bc * 2; - _Bucket **nt = reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * nc)); - if (nt) { - for(unsigned long i=0;inext; - const unsigned long nidx = _hc(b->k) % nc; - b->next = nt[nidx]; - nt[nidx] = b; - b = nb; - } - } - ::free(_t); - _t = nt; - _bc = nc; - } - } - - _Bucket **_t; - unsigned long _bc; - unsigned long _s; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Identity.cpp b/zto/node/Identity.cpp deleted file mode 100644 index 89fdb83..0000000 --- a/zto/node/Identity.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include - -#include "Constants.hpp" -#include "Identity.hpp" -#include "SHA512.hpp" -#include "Salsa20.hpp" -#include "Utils.hpp" - -// These can't be changed without a new identity type. They define the -// parameters of the hashcash hashing/searching algorithm. - -#define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17 -#define ZT_IDENTITY_GEN_MEMORY 2097152 - -namespace ZeroTier { - -// A memory-hard composition of SHA-512 and Salsa20 for hashcash hashing -static inline void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *digest,void *genmem) -{ - // Digest publicKey[] to obtain initial digest - SHA512::hash(digest,publicKey,publicKeyBytes); - - // Initialize genmem[] using Salsa20 in a CBC-like configuration since - // ordinary Salsa20 is randomly seekable. This is good for a cipher - // but is not what we want for sequential memory-harndess. - memset(genmem,0,ZT_IDENTITY_GEN_MEMORY); - Salsa20 s20(digest,256,(char *)digest + 32); - s20.crypt20((char *)genmem,(char *)genmem,64); - for(unsigned long i=64;idata,(unsigned int)_privateKey->size())); - } - - return r; -} - -bool Identity::fromString(const char *str) -{ - if (!str) - return false; - - char *saveptr = (char *)0; - char tmp[1024]; - if (!Utils::scopy(tmp,sizeof(tmp),str)) - return false; - - delete _privateKey; - _privateKey = (C25519::Private *)0; - - int fno = 0; - for(char *f=Utils::stok(tmp,":",&saveptr);(f);f=Utils::stok((char *)0,":",&saveptr)) { - switch(fno++) { - case 0: - _address = Address(Utils::hexStrToU64(f)); - if (_address.isReserved()) - return false; - break; - case 1: - if ((f[0] != '0')||(f[1])) - return false; - break; - case 2: - if (Utils::unhex(f,_publicKey.data,(unsigned int)_publicKey.size()) != _publicKey.size()) - return false; - break; - case 3: - _privateKey = new C25519::Private(); - if (Utils::unhex(f,_privateKey->data,(unsigned int)_privateKey->size()) != _privateKey->size()) - return false; - break; - default: - return false; - } - } - if (fno < 3) - return false; - - return true; -} - -} // namespace ZeroTier diff --git a/zto/node/Identity.hpp b/zto/node/Identity.hpp deleted file mode 100644 index e452273..0000000 --- a/zto/node/Identity.hpp +++ /dev/null @@ -1,323 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_IDENTITY_HPP -#define ZT_IDENTITY_HPP - -#include -#include -#include - -#include "Constants.hpp" -#include "Array.hpp" -#include "Utils.hpp" -#include "Address.hpp" -#include "C25519.hpp" -#include "Buffer.hpp" -#include "SHA512.hpp" - -namespace ZeroTier { - -/** - * A ZeroTier identity - * - * An identity consists of a public key, a 40-bit ZeroTier address computed - * from that key in a collision-resistant fashion, and a self-signature. - * - * The address derivation algorithm makes it computationally very expensive to - * search for a different public key that duplicates an existing address. (See - * code for deriveAddress() for this algorithm.) - */ -class Identity -{ -public: - Identity() : - _privateKey((C25519::Private *)0) - { - } - - Identity(const Identity &id) : - _address(id._address), - _publicKey(id._publicKey), - _privateKey((id._privateKey) ? new C25519::Private(*(id._privateKey)) : (C25519::Private *)0) - { - } - - Identity(const char *str) - throw(std::invalid_argument) : - _privateKey((C25519::Private *)0) - { - if (!fromString(str)) - throw std::invalid_argument(std::string("invalid string-serialized identity: ") + str); - } - - Identity(const std::string &str) - throw(std::invalid_argument) : - _privateKey((C25519::Private *)0) - { - if (!fromString(str)) - throw std::invalid_argument(std::string("invalid string-serialized identity: ") + str); - } - - template - Identity(const Buffer &b,unsigned int startAt = 0) : - _privateKey((C25519::Private *)0) - { - deserialize(b,startAt); - } - - ~Identity() - { - delete _privateKey; - } - - inline Identity &operator=(const Identity &id) - { - _address = id._address; - _publicKey = id._publicKey; - if (id._privateKey) { - if (!_privateKey) - _privateKey = new C25519::Private(); - *_privateKey = *(id._privateKey); - } else { - delete _privateKey; - _privateKey = (C25519::Private *)0; - } - return *this; - } - - /** - * Generate a new identity (address, key pair) - * - * This is a time consuming operation. - */ - void generate(); - - /** - * Check the validity of this identity's pairing of key to address - * - * @return True if validation check passes - */ - bool locallyValidate() const; - - /** - * @return True if this identity contains a private key - */ - inline bool hasPrivate() const throw() { return (_privateKey != (C25519::Private *)0); } - - /** - * Compute the SHA512 hash of our private key (if we have one) - * - * @param sha Buffer to receive SHA512 (MUST be ZT_SHA512_DIGEST_LEN (64) bytes in length) - * @return True on success, false if no private key - */ - inline bool sha512PrivateKey(void *sha) const - { - if (_privateKey) { - SHA512::hash(sha,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN); - return true; - } - return false; - } - - /** - * Sign a message with this identity (private key required) - * - * @param data Data to sign - * @param len Length of data - */ - inline C25519::Signature sign(const void *data,unsigned int len) const - throw(std::runtime_error) - { - if (_privateKey) - return C25519::sign(*_privateKey,_publicKey,data,len); - throw std::runtime_error("sign() requires a private key"); - } - - /** - * Verify a message signature against this identity - * - * @param data Data to check - * @param len Length of data - * @param signature Signature bytes - * @param siglen Length of signature in bytes - * @return True if signature validates and data integrity checks - */ - inline bool verify(const void *data,unsigned int len,const void *signature,unsigned int siglen) const - { - if (siglen != ZT_C25519_SIGNATURE_LEN) - return false; - return C25519::verify(_publicKey,data,len,signature); - } - - /** - * Verify a message signature against this identity - * - * @param data Data to check - * @param len Length of data - * @param signature Signature - * @return True if signature validates and data integrity checks - */ - inline bool verify(const void *data,unsigned int len,const C25519::Signature &signature) const - { - return C25519::verify(_publicKey,data,len,signature); - } - - /** - * Shortcut method to perform key agreement with another identity - * - * This identity must have a private key. (Check hasPrivate()) - * - * @param id Identity to agree with - * @param key Result parameter to fill with key bytes - * @param klen Length of key in bytes - * @return Was agreement successful? - */ - inline bool agree(const Identity &id,void *key,unsigned int klen) const - { - if (_privateKey) { - C25519::agree(*_privateKey,id._publicKey,key,klen); - return true; - } - return false; - } - - /** - * @return This identity's address - */ - inline const Address &address() const throw() { return _address; } - - /** - * Serialize this identity (binary) - * - * @param b Destination buffer to append to - * @param includePrivate If true, include private key component (if present) (default: false) - * @throws std::out_of_range Buffer too small - */ - template - inline void serialize(Buffer &b,bool includePrivate = false) const - { - _address.appendTo(b); - b.append((uint8_t)0); // C25519/Ed25519 identity type - b.append(_publicKey.data,(unsigned int)_publicKey.size()); - if ((_privateKey)&&(includePrivate)) { - b.append((unsigned char)_privateKey->size()); - b.append(_privateKey->data,(unsigned int)_privateKey->size()); - } else b.append((unsigned char)0); - } - - /** - * Deserialize a binary serialized identity - * - * If an exception is thrown, the Identity object is left in an undefined - * state and should not be used. - * - * @param b Buffer containing serialized data - * @param startAt Index within buffer of serialized data (default: 0) - * @return Length of serialized data read from buffer - * @throws std::out_of_range Serialized data invalid - * @throws std::invalid_argument Serialized data invalid - */ - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - delete _privateKey; - _privateKey = (C25519::Private *)0; - - unsigned int p = startAt; - - _address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; - - if (b[p++] != 0) - throw std::invalid_argument("unsupported identity type"); - - memcpy(_publicKey.data,b.field(p,(unsigned int)_publicKey.size()),(unsigned int)_publicKey.size()); - p += (unsigned int)_publicKey.size(); - - unsigned int privateKeyLength = (unsigned int)b[p++]; - if (privateKeyLength) { - if (privateKeyLength != ZT_C25519_PRIVATE_KEY_LEN) - throw std::invalid_argument("invalid private key"); - _privateKey = new C25519::Private(); - memcpy(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN); - p += ZT_C25519_PRIVATE_KEY_LEN; - } - - return (p - startAt); - } - - /** - * Serialize to a more human-friendly string - * - * @param includePrivate If true, include private key (if it exists) - * @return ASCII string representation of identity - */ - std::string toString(bool includePrivate) const; - - /** - * Deserialize a human-friendly string - * - * Note: validation is for the format only. The locallyValidate() method - * must be used to check signature and address/key correspondence. - * - * @param str String to deserialize - * @return True if deserialization appears successful - */ - bool fromString(const char *str); - inline bool fromString(const std::string &str) { return fromString(str.c_str()); } - - /** - * @return C25519 public key - */ - inline const C25519::Public &publicKey() const { return _publicKey; } - - /** - * @return C25519 key pair (only returns valid pair if private key is present in this Identity object) - */ - inline const C25519::Pair privateKeyPair() const - { - C25519::Pair pair; - pair.pub = _publicKey; - if (_privateKey) - pair.priv = *_privateKey; - else memset(pair.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN); - return pair; - } - - /** - * @return True if this identity contains something - */ - inline operator bool() const throw() { return (_address); } - - inline bool operator==(const Identity &id) const throw() { return ((_address == id._address)&&(_publicKey == id._publicKey)); } - inline bool operator<(const Identity &id) const throw() { return ((_address < id._address)||((_address == id._address)&&(_publicKey < id._publicKey))); } - inline bool operator!=(const Identity &id) const throw() { return !(*this == id); } - inline bool operator>(const Identity &id) const throw() { return (id < *this); } - inline bool operator<=(const Identity &id) const throw() { return !(id < *this); } - inline bool operator>=(const Identity &id) const throw() { return !(*this < id); } - -private: - Address _address; - C25519::Public _publicKey; - C25519::Private *_privateKey; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/IncomingPacket.cpp b/zto/node/IncomingPacket.cpp deleted file mode 100644 index 52794fd..0000000 --- a/zto/node/IncomingPacket.cpp +++ /dev/null @@ -1,1473 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#include "../version.h" -#include "../include/ZeroTierOne.h" - -#include "Constants.hpp" -#include "RuntimeEnvironment.hpp" -#include "IncomingPacket.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Peer.hpp" -#include "NetworkController.hpp" -#include "SelfAwareness.hpp" -#include "Salsa20.hpp" -#include "SHA512.hpp" -#include "World.hpp" -#include "Cluster.hpp" -#include "Node.hpp" -#include "CertificateOfMembership.hpp" -#include "CertificateOfRepresentation.hpp" -#include "Capability.hpp" -#include "Tag.hpp" -#include "Revocation.hpp" - -namespace ZeroTier { - -bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) -{ - const Address sourceAddress(source()); - - try { - // Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear) - const unsigned int c = cipher(); - bool trusted = false; - if (c == ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH) { - // If this is marked as a packet via a trusted path, check source address and path ID. - // Obviously if no trusted paths are configured this always returns false and such - // packets are dropped on the floor. - if (RR->topology->shouldInboundPathBeTrusted(_path->address(),trustedPathId())) { - trusted = true; - TRACE("TRUSTED PATH packet approved from %s(%s), trusted path ID %llx",sourceAddress.toString().c_str(),_path->address().toString().c_str(),trustedPathId()); - } else { - TRACE("dropped packet from %s(%s), cipher set to trusted path mode but path %llx@%s is not trusted!",sourceAddress.toString().c_str(),_path->address().toString().c_str(),trustedPathId(),_path->address().toString().c_str()); - return true; - } - } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { - // Only HELLO is allowed in the clear, but will still have a MAC - return _doHELLO(RR,tPtr,false); - } - - const SharedPtr peer(RR->topology->getPeer(tPtr,sourceAddress)); - if (peer) { - if (!trusted) { - if (!dearmor(peer->key())) { - //fprintf(stderr,"dropped packet from %s(%s), MAC authentication failed (size: %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); - TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); - return true; - } - } - - if (!uncompress()) { - //fprintf(stderr,"dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); - TRACE("dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); - return true; - } - - const Packet::Verb v = verb(); - //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_path->address().toString().c_str()); - switch(v) { - //case Packet::VERB_NOP: - default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(tPtr,_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); - return true; - - case Packet::VERB_HELLO: return _doHELLO(RR,tPtr,true); - case Packet::VERB_ERROR: return _doERROR(RR,tPtr,peer); - case Packet::VERB_OK: return _doOK(RR,tPtr,peer); - case Packet::VERB_WHOIS: return _doWHOIS(RR,tPtr,peer); - case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,tPtr,peer); - case Packet::VERB_FRAME: return _doFRAME(RR,tPtr,peer); - case Packet::VERB_EXT_FRAME: return _doEXT_FRAME(RR,tPtr,peer); - case Packet::VERB_ECHO: return _doECHO(RR,tPtr,peer); - case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,tPtr,peer); - case Packet::VERB_NETWORK_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,tPtr,peer); - case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,tPtr,peer); - case Packet::VERB_NETWORK_CONFIG: return _doNETWORK_CONFIG(RR,tPtr,peer); - case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,tPtr,peer); - case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,tPtr,peer); - case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,tPtr,peer); - case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,tPtr,peer); - case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,tPtr,peer); - case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,tPtr,peer); - } - } else { - RR->sw->requestWhois(tPtr,sourceAddress); - return false; - } - } catch ( ... ) { - // Exceptions are more informatively caught in _do...() handlers but - // this outer try/catch will catch anything else odd. - TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",sourceAddress.toString().c_str(),_path->address().toString().c_str()); - return true; - } -} - -bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; - const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); - const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; - - //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); - - /* Security note: we do not gate doERROR() with expectingReplyTo() to - * avoid having to log every outgoing packet ID. Instead we put the - * logic to determine whether we should consider an ERROR in each - * error handler. In most cases these are only trusted in specific - * circumstances. */ - - switch(errorCode) { - - case Packet::ERROR_OBJ_NOT_FOUND: - // Object not found, currently only meaningful from network controllers. - if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == peer->address())) - network->setNotFound(); - } - break; - - case Packet::ERROR_UNSUPPORTED_OPERATION: - // This can be sent in response to any operation, though right now we only - // consider it meaningful from network controllers. This would indicate - // that the queried node does not support acting as a controller. - if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == peer->address())) - network->setNotFound(); - } - break; - - case Packet::ERROR_IDENTITY_COLLISION: - // FIXME: for federation this will need a payload with a signature or something. - if (RR->topology->isUpstream(peer->identity())) - RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); - break; - - case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { - // Peers can send this in response to frames if they do not have a recent enough COM from us - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - const uint64_t now = RR->node->now(); - if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) - network->pushCredentialsNow(tPtr,peer->address(),now); - } break; - - case Packet::ERROR_NETWORK_ACCESS_DENIED_: { - // Network controller: network access denied. - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == peer->address())) - network->setAccessDenied(); - } break; - - case Packet::ERROR_UNWANTED_MULTICAST: { - // Members of networks can use this error to indicate that they no longer - // want to receive multicasts on a given channel. - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->gate(tPtr,peer))) { - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); - TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); - RR->mc->remove(network->id(),mg,peer->address()); - } - } break; - - default: break; - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); - } catch ( ... ) { - TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated) -{ - try { - const uint64_t now = RR->node->now(); - - const uint64_t pid = packetId(); - const Address fromAddress(source()); - const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; - const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; - const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; - const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO_IDX_REVISION); - const uint64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); - Identity id; - unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); - - if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } - if (fromAddress != id.address()) { - TRACE("dropped HELLO from %s(%s): identity does not match packet source address",fromAddress.toString().c_str(),_path->address().toString().c_str()); - return true; - } - - SharedPtr peer(RR->topology->getPeer(tPtr,id.address())); - if (peer) { - // We already have an identity with this address -- check for collisions - if (!alreadyAuthenticated) { - if (peer->identity() != id) { - // Identity is different from the one we already have -- address collision - - // Check rate limits - if (!RR->node->rateGateIdentityVerification(now,_path->address())) - return true; - - uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; - if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { - if (dearmor(key)) { // ensure packet is authentic, otherwise drop - TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_path->address().toString().c_str()); - Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((uint8_t)Packet::VERB_HELLO); - outp.append((uint64_t)pid); - outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); - outp.armor(key,true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } else { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); - } - } else { - TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_path->address().toString().c_str()); - } - - return true; - } else { - // Identity is the same as the one we already have -- check packet integrity - - if (!dearmor(peer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } - - // Continue at // VALID - } - } // else if alreadyAuthenticated then continue at // VALID - } else { - // We don't already have an identity with this address -- validate and learn it - - // Sanity check: this basically can't happen - if (alreadyAuthenticated) { - TRACE("dropped HELLO from %s(%s): somehow already authenticated with unknown peer?",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } - - // Check rate limits - if (!RR->node->rateGateIdentityVerification(now,_path->address())) - return true; - - // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) - SharedPtr newPeer(new Peer(RR,RR->identity,id)); - if (!dearmor(newPeer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } - - // Check that identity's address is valid as per the derivation function - if (!id.locallyValidate()) { - TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } - - peer = RR->topology->addPeer(tPtr,newPeer); - - // Continue at // VALID - } - - // VALID -- if we made it here, packet passed identity and authenticity checks! - - // Get external surface address if present (was not in old versions) - InetAddress externalSurfaceAddress; - if (ptr < size()) { - ptr += externalSurfaceAddress.deserialize(*this,ptr); - if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(tPtr,id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); - } - - // Get primary planet world ID and world timestamp if present - uint64_t planetWorldId = 0; - uint64_t planetWorldTimestamp = 0; - if ((ptr + 16) <= size()) { - planetWorldId = at(ptr); ptr += 8; - planetWorldTimestamp = at(ptr); ptr += 8; - } - - std::vector< std::pair > moonIdsAndTimestamps; - if (ptr < size()) { - // Remainder of packet, if present, is encrypted - cryptField(peer->key(),ptr,size() - ptr); - - // Get moon IDs and timestamps if present - if ((ptr + 2) <= size()) { - const unsigned int numMoons = at(ptr); ptr += 2; - for(unsigned int i=0;i(at(ptr),at(ptr + 8))); - ptr += 16; - } - } - - // Handle COR if present (older versions don't send this) - if ((ptr + 2) <= size()) { - if (at(ptr) > 0) { - CertificateOfRepresentation cor; - ptr += 2; - ptr += cor.deserialize(*this,ptr); - } else ptr += 2; - } - } - - // Send OK(HELLO) with an echo of the packet's timestamp and some of the same - // information about us: version, sent-to address, etc. - - Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_HELLO); - outp.append((uint64_t)pid); - outp.append((uint64_t)timestamp); - outp.append((unsigned char)ZT_PROTO_VERSION); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); - outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - - if (protoVersion >= 5) { - _path->address().serialize(outp); - } else { - /* LEGACY COMPATIBILITY HACK: - * - * For a while now (since 1.0.3), ZeroTier has recognized changes in - * its network environment empirically by examining its external network - * address as reported by trusted peers. In versions prior to 1.1.0 - * (protocol version < 5), they did this by saving a snapshot of this - * information (in SelfAwareness.hpp) keyed by reporting device ID and - * address type. - * - * This causes problems when clustering is combined with symmetric NAT. - * Symmetric NAT remaps ports, so different endpoints in a cluster will - * report back different exterior addresses. Since the old code keys - * this by device ID and not sending physical address and compares the - * entire address including port, it constantly thinks its external - * surface is changing and resets connections when talking to a cluster. - * - * In new code we key by sending physical address and device and we also - * take the more conservative position of only interpreting changes in - * IP address (neglecting port) as a change in network topology that - * necessitates a reset. But we can make older clients work here by - * nulling out the port field. Since this info is only used for empirical - * detection of link changes, it doesn't break anything else. - */ - InetAddress tmpa(_path->address()); - tmpa.setPort(0); - tmpa.serialize(outp); - } - - const unsigned int worldUpdateSizeAt = outp.size(); - outp.addSize(2); // make room for 16-bit size field - if ((planetWorldId)&&(RR->topology->planetWorldTimestamp() > planetWorldTimestamp)&&(planetWorldId == RR->topology->planetWorldId())) { - RR->topology->planet().serialize(outp,false); - } - if (moonIdsAndTimestamps.size() > 0) { - std::vector moons(RR->topology->moons()); - for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { - for(std::vector< std::pair >::const_iterator i(moonIdsAndTimestamps.begin());i!=moonIdsAndTimestamps.end();++i) { - if (i->first == m->id()) { - if (m->timestamp() > i->second) - m->serialize(outp,false); - break; - } - } - } - } - outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); - - const unsigned int corSizeAt = outp.size(); - outp.addSize(2); - RR->topology->appendCertificateOfRepresentation(outp); - outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); - - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),now); - - peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; - const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - - if (!RR->node->expectingReplyTo(inRePacketId)) { - TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); - return true; - } - - //TRACE("%s(%s): OK(%s)",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); - - switch(inReVerb) { - - case Packet::VERB_HELLO: { - const uint64_t latency = RR->node->now() - at(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP); - if (latency > ZT_HELLO_MAX_ALLOWABLE_LATENCY) - return true; - - const unsigned int vProto = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION]; - const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION]; - const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION]; - const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION); - - if (vProto < ZT_PROTO_VERSION_MIN) { - TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_path->address().toString().c_str()); - return true; - } - - InetAddress externalSurfaceAddress; - unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; - - // Get reported external surface address if present - if (ptr < size()) - ptr += externalSurfaceAddress.deserialize(*this,ptr); - - // Handle planet or moon updates if present - if ((ptr + 2) <= size()) { - const unsigned int worldsLen = at(ptr); ptr += 2; - if (RR->topology->shouldAcceptWorldUpdateFrom(peer->address())) { - const unsigned int endOfWorlds = ptr + worldsLen; - while (ptr < endOfWorlds) { - World w; - ptr += w.deserialize(*this,ptr); - RR->topology->addWorld(tPtr,w,false); - } - } else { - ptr += worldsLen; - } - } - - // Handle certificate of representation if present - if ((ptr + 2) <= size()) { - if (at(ptr) > 0) { - CertificateOfRepresentation cor; - ptr += 2; - ptr += cor.deserialize(*this,ptr); - } else ptr += 2; - } - -#ifdef ZT_TRACE - const std::string tmp1(source().toString()); - const std::string tmp2(_path->address().toString()); - TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u",tmp1.c_str(),tmp2.c_str(),vMajor,vMinor,vRevision,latency); -#endif - - if (!hops()) - peer->addDirectLatencyMeasurment((unsigned int)latency); - peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); - - if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(tPtr,peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); - } break; - - case Packet::VERB_WHOIS: - if (RR->topology->isUpstream(peer->identity())) { - const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); - RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->addPeer(tPtr,SharedPtr(new Peer(RR,RR->identity,id)))); - } - break; - - case Packet::VERB_NETWORK_CONFIG_REQUEST: { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_OK_IDX_PAYLOAD))); - if (network) - network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); - } break; - - case Packet::VERB_MULTICAST_GATHER: { - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(nwid)); - if (network) { - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); - const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); - } - } break; - - case Packet::VERB_MULTICAST_FRAME: { - const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS]; - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); - - //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags); - - const SharedPtr network(RR->node->network(nwid)); - if (network) { - unsigned int offset = 0; - - if ((flags & 0x01) != 0) { // deprecated but still used by older peers - CertificateOfMembership com; - offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); - if (com) - network->addCredential(tPtr,com); - } - - if ((flags & 0x02) != 0) { - // OK(MULTICAST_FRAME) includes implicit gather results - offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; - unsigned int totalKnown = at(offset); offset += 4; - unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); - } - } - } break; - - default: break; - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); - } catch ( ... ) { - TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) { - TRACE("dropped WHOIS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); - return true; - } - - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_WHOIS); - outp.append(packetId()); - - unsigned int count = 0; - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; - while ((ptr + ZT_ADDRESS_LENGTH) <= size()) { - const Address addr(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - ptr += ZT_ADDRESS_LENGTH; - - const Identity id(RR->topology->getIdentity(tPtr,addr)); - if (id) { - id.serialize(outp,false); - ++count; - } else { - // Request unknown WHOIS from upstream from us (if we have one) - RR->sw->requestWhois(tPtr,addr); -#ifdef ZT_ENABLE_CLUSTER - // Distribute WHOIS queries across a cluster if we do not know the ID. - // This may result in duplicate OKs to the querying peer, which is fine. - if (RR->cluster) - RR->cluster->sendDistributedQuery(*this); -#endif - } - } - - if (count > 0) { - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - if (!RR->topology->isUpstream(peer->identity())) { - TRACE("RENDEZVOUS from %s ignored since source is not upstream",peer->address().toString().c_str()); - } else { - const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr rendezvousWith(RR->topology->getPeer(tPtr,with)); - if (rendezvousWith) { - const unsigned int port = at(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT); - const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; - if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { - const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localAddress(),atAddr)) { - RR->node->putPacket(tPtr,_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(tPtr,_path->localAddress(),atAddr,RR->node->now(),false,0); - TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - } else { - TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - } - } else { - TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str()); - } - } else { - TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); - } - } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(nwid)); - bool trustEstablished = false; - if (network) { - if (network->gate(tPtr,peer)) { - trustEstablished = true; - if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { - const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); - const MAC sourceMac(peer->address(),nwid); - const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) - RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); - } - } else { - TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - } - } else { - TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); - } catch ( ... ) { - TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const uint64_t nwid = at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(nwid)); - if (network) { - const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; - - unsigned int comLen = 0; - if ((flags & 0x01) != 0) { // inline COM with EXT_FRAME is deprecated but still used with old peers - CertificateOfMembership com; - comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM); - if (com) - network->addCredential(tPtr,com); - } - - if (!network->gate(tPtr,peer)) { - TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); - return true; - } - - if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { - const unsigned int etherType = at(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); - const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO); - const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM); - const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); - const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); - - if ((!from)||(from.isMulticast())||(from == network->mac())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC %s",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),from.toString().c_str()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay - return true; - } - - switch (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { - case 1: - if (from != MAC(peer->address(),nwid)) { - if (network->config().permitsBridging(peer->address())) { - network->learnBridgeRoute(from,peer->address()); - } else { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay - return true; - } - } else if (to != network->mac()) { - if (to.isMulticast()) { - if (network->config().multicastLimit == 0) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: network %.16llx does not allow multicast",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay - return true; - } - } else if (!network->config().permitsBridging(RR->identity.address())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay - return true; - } - } - // fall through -- 2 means accept regardless of bridging checks or other restrictions - case 2: - RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); - break; - } - } - - if ((flags & 0x10) != 0) { // ACK requested - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((uint8_t)Packet::VERB_EXT_FRAME); - outp.append((uint64_t)packetId()); - outp.append((uint64_t)nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); - } else { - TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); - } - } catch ( ... ) { - TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - if (!peer->rateGateEchoRequest(RR->node->now())) { - TRACE("dropped ECHO from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); - return true; - } - - const uint64_t pid = packetId(); - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_ECHO); - outp.append((uint64_t)pid); - if (size() > ZT_PACKET_IDX_PAYLOAD) - outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - - peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const uint64_t now = RR->node->now(); - - uint64_t authOnNetwork[256]; // cache for approved network IDs - unsigned int authOnNetworkCount = 0; - SharedPtr network; - bool trustEstablished = false; - - // Iterate through 18-byte network,MAC,ADI tuples - for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr(ptr); - - bool auth = false; - for(unsigned int i=0;iid() != nwid)) - network = RR->node->network(nwid); - const bool authOnNet = ((network)&&(network->gate(tPtr,peer))); - if (!authOnNet) - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - trustEstablished |= authOnNet; - if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { - auth = true; - if (authOnNetworkCount < 256) // sanity check, packets can't really be this big - authOnNetwork[authOnNetworkCount++] = nwid; - } - } - - if (auth) { - const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14)); - RR->mc->add(tPtr,now,nwid,group,peer->address()); - } - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); - } catch ( ... ) { - TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - if (!peer->rateGateCredentialsReceived(RR->node->now())) { - TRACE("dropped NETWORK_CREDENTIALS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); - return true; - } - - CertificateOfMembership com; - Capability cap; - Tag tag; - Revocation revocation; - CertificateOfOwnership coo; - bool trustEstablished = false; - - unsigned int p = ZT_PACKET_IDX_PAYLOAD; - while ((p < size())&&((*this)[p] != 0)) { - p += com.deserialize(*this,p); - if (com) { - const SharedPtr network(RR->node->network(com.networkId())); - if (network) { - switch (network->addCredential(tPtr,com)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } else RR->mc->addCredential(tPtr,com,false); - } - } - ++p; // skip trailing 0 after COMs if present - - if (p < size()) { // older ZeroTier versions do not send capabilities, tags, or revocations - const unsigned int numCapabilities = at(p); p += 2; - for(unsigned int i=0;i network(RR->node->network(cap.networkId())); - if (network) { - switch (network->addCredential(tPtr,cap)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } - } - - if (p >= size()) return true; - - const unsigned int numTags = at(p); p += 2; - for(unsigned int i=0;i network(RR->node->network(tag.networkId())); - if (network) { - switch (network->addCredential(tPtr,tag)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } - } - - if (p >= size()) return true; - - const unsigned int numRevocations = at(p); p += 2; - for(unsigned int i=0;i network(RR->node->network(revocation.networkId())); - if (network) { - switch(network->addCredential(tPtr,peer->address(),revocation)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } - } - - if (p >= size()) return true; - - const unsigned int numCoos = at(p); p += 2; - for(unsigned int i=0;i network(RR->node->network(coo.networkId())); - if (network) { - switch(network->addCredential(tPtr,coo)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } - } - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); - } catch (std::exception &exc) { - //fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); - TRACE("dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); - } catch ( ... ) { - //fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): unknown exception" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str()); - TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); - const unsigned int hopCount = hops(); - const uint64_t requestPacketId = packetId(); - - if (RR->localNetworkController) { - const unsigned int metaDataLength = (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN <= size()) ? at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN) : 0; - const char *metaDataBytes = (metaDataLength != 0) ? (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength) : (const char *)0; - const Dictionary metaData(metaDataBytes,metaDataLength); - RR->localNetworkController->request(nwid,(hopCount > 0) ? InetAddress() : _path->address(),requestPacketId,peer->identity(),metaData); - } else { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); - outp.append(nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } - - peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); - } catch (std::exception &exc) { - //fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); - } catch ( ... ) { - //fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str()); - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD))); - if (network) { - const uint64_t configUpdateId = network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD); - if (configUpdateId) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((uint8_t)Packet::VERB_ECHO); - outp.append((uint64_t)packetId()); - outp.append((uint64_t)network->id()); - outp.append((uint64_t)configUpdateId); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } - } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); - const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS]; - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); - const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); - - //TRACE("<address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str()); - - const SharedPtr network(RR->node->network(nwid)); - - if ((flags & 0x01) != 0) { - try { - CertificateOfMembership com; - com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM); - if (com) { - if (network) - network->addCredential(tPtr,com); - else RR->mc->addCredential(tPtr,com,false); - } - } catch ( ... ) { - TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str()); - } - } - - const bool trustEstablished = ((network)&&(network->gate(tPtr,peer))); - if (!trustEstablished) - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); - outp.append(packetId()); - outp.append(nwid); - mg.mac().appendTo(outp); - outp.append((uint32_t)mg.adi()); - const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); - if (gatheredLocally > 0) { - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } - - // If we are a member of a cluster, distribute this GATHER across it -#ifdef ZT_ENABLE_CLUSTER - if ((RR->cluster)&&(gatheredLocally < gatherLimit)) - RR->cluster->sendDistributedQuery(*this); -#endif - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); - } catch ( ... ) { - TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID); - const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS]; - - const SharedPtr network(RR->node->network(nwid)); - if (network) { - // Offset -- size of optional fields added to position of later fields - unsigned int offset = 0; - - if ((flags & 0x01) != 0) { - // This is deprecated but may still be sent by old peers - CertificateOfMembership com; - offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); - if (com) - network->addCredential(tPtr,com); - } - - if (!network->gate(tPtr,peer)) { - TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); - return true; - } - - if (network->config().multicastLimit == 0) { - TRACE("dropped MULTICAST_FRAME from %s(%s): network %.16llx does not allow multicast",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); - return true; - } - - unsigned int gatherLimit = 0; - if ((flags & 0x02) != 0) { - gatherLimit = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT); - offset += 4; - } - - MAC from; - if ((flags & 0x04) != 0) { - from.setTo(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC,6),6); - offset += 6; - } else { - from.fromAddress(peer->address(),nwid); - } - - const MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,6),6),at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI)); - const unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE); - const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); - - //TRACE("<address().toString().c_str(),flags,frameLen); - - if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { - if (!to.mac().isMulticast()) { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay - return true; - } - if ((!from)||(from.isMulticast())||(from == network->mac())) { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay - return true; - } - - if (from != MAC(peer->address(),nwid)) { - if (network->config().permitsBridging(peer->address())) { - network->learnBridgeRoute(from,peer->address()); - } else { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay - return true; - } - } - - const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); - if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { - RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); - } - } - - if (gatherLimit) { - Packet outp(source(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME); - outp.append(packetId()); - outp.append(nwid); - to.mac().appendTo(outp); - outp.append((uint32_t)to.adi()); - outp.append((unsigned char)0x02); // flag 0x02 = contains gather results - if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) { - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); - } else { - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); - } - } catch ( ... ) { - TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const uint64_t now = RR->node->now(); - - // First, subject this to a rate limit - if (!peer->rateGatePushDirectPaths(now)) { - TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); - return true; - } - - // Second, limit addresses by scope and type - uint8_t countPerScope[ZT_INETADDRESS_MAX_SCOPE+1][2]; // [][0] is v4, [][1] is v6 - memset(countPerScope,0,sizeof(countPerScope)); - - unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; - - while (count--) { // if ptr overflows Buffer will throw - // TODO: some flags are not yet implemented - - unsigned int flags = (*this)[ptr++]; - unsigned int extLen = at(ptr); ptr += 2; - ptr += extLen; // unused right now - unsigned int addrType = (*this)[ptr++]; - unsigned int addrLen = (*this)[ptr++]; - - switch(addrType) { - case 4: { - InetAddress a(field(ptr,4),4,at(ptr + 4)); - - bool redundant = false; - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimal(a); - } else { - redundant = peer->hasActivePathTo(now,a); - } - - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) { - if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); - } else { - TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); - } - } - } break; - case 6: { - InetAddress a(field(ptr,16),16,at(ptr + 16)); - - bool redundant = false; - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimal(a); - } else { - redundant = peer->hasActivePathTo(now,a); - } - - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) { - if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); - } else { - TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); - } - } - } break; - } - ptr += addrLen; - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const Address originatorAddress(field(ZT_PACKET_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - SharedPtr originator(RR->topology->getPeer(tPtr,originatorAddress)); - if (!originator) { - RR->sw->requestWhois(tPtr,originatorAddress); - return false; - } - - const unsigned int flags = at(ZT_PACKET_IDX_PAYLOAD + 5); - const uint64_t timestamp = at(ZT_PACKET_IDX_PAYLOAD + 7); - const uint64_t testId = at(ZT_PACKET_IDX_PAYLOAD + 15); - - // Tracks total length of variable length fields, initialized to originator credential length below - unsigned int vlf; - - // Originator credentials -- right now only a network ID for which the originator is controller or is authorized by controller is allowed - const unsigned int originatorCredentialLength = vlf = at(ZT_PACKET_IDX_PAYLOAD + 23); - uint64_t originatorCredentialNetworkId = 0; - if (originatorCredentialLength >= 1) { - switch((*this)[ZT_PACKET_IDX_PAYLOAD + 25]) { - case 0x01: { // 64-bit network ID, originator must be controller - if (originatorCredentialLength >= 9) - originatorCredentialNetworkId = at(ZT_PACKET_IDX_PAYLOAD + 26); - } break; - default: break; - } - } - - // Add length of "additional fields," which are currently unused - vlf += at(ZT_PACKET_IDX_PAYLOAD + 25 + vlf); - - // Verify signature -- only tests signed by their originators are allowed - const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); - if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { - TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); - return true; - } - vlf += signatureLength; - - // Save this length so we can copy the immutable parts of this test - // into the one we send along to next hops. - const unsigned int lengthOfSignedPortionAndSignature = 29 + vlf; - - // Add length of second "additional fields" section. - vlf += at(ZT_PACKET_IDX_PAYLOAD + 29 + vlf); - - uint64_t reportFlags = 0; - - // Check credentials (signature already verified) - if (originatorCredentialNetworkId) { - SharedPtr network(RR->node->network(originatorCredentialNetworkId)); - if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); - return true; - } - if (network->gate(tPtr,peer)) - reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH; - } else { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); - return true; - } - - const uint64_t now = RR->node->now(); - - unsigned int breadth = 0; - Address nextHop[256]; // breadth is a uin8_t, so this is the max - InetAddress nextHopBestPathAddress[256]; - unsigned int remainingHopsPtr = ZT_PACKET_IDX_PAYLOAD + 33 + vlf; - if ((ZT_PACKET_IDX_PAYLOAD + 31 + vlf) < size()) { - // unsigned int nextHopFlags = (*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf] - breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 32 + vlf]; - for(unsigned int h=0;h nhp(RR->topology->getPeer(tPtr,nextHop[h])); - if (nhp) { - SharedPtr nhbp(nhp->getBestPath(now,false)); - if ((nhbp)&&(nhbp->alive(now))) - nextHopBestPathAddress[h] = nhbp->address(); - } - } - } - - // Report back to originator, depending on flags and whether we are last hop - if ( ((flags & 0x01) != 0) || ((breadth == 0)&&((flags & 0x02) != 0)) ) { - Packet outp(originatorAddress,RR->identity.address(),Packet::VERB_CIRCUIT_TEST_REPORT); - outp.append((uint64_t)timestamp); - outp.append((uint64_t)testId); - outp.append((uint64_t)0); // field reserved for future use - outp.append((uint8_t)ZT_VENDOR_ZEROTIER); - outp.append((uint8_t)ZT_PROTO_VERSION); - outp.append((uint8_t)ZEROTIER_ONE_VERSION_MAJOR); - outp.append((uint8_t)ZEROTIER_ONE_VERSION_MINOR); - outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - outp.append((uint16_t)ZT_PLATFORM_UNSPECIFIED); - outp.append((uint16_t)ZT_ARCHITECTURE_UNSPECIFIED); - outp.append((uint16_t)0); // error code, currently unused - outp.append((uint64_t)reportFlags); - outp.append((uint64_t)packetId()); - peer->address().appendTo(outp); - outp.append((uint8_t)hops()); - _path->localAddress().serialize(outp); - _path->address().serialize(outp); - outp.append((uint16_t)_path->linkQuality()); - outp.append((uint8_t)breadth); - for(unsigned int h=0;hsw->send(tPtr,outp,true); - } - - // If there are next hops, forward the test along through the graph - if (breadth > 0) { - Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST); - outp.append(field(ZT_PACKET_IDX_PAYLOAD,lengthOfSignedPortionAndSignature),lengthOfSignedPortionAndSignature); - outp.append((uint16_t)0); // no additional fields - if (remainingHopsPtr < size()) - outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr); - - for(unsigned int h=0;hidentity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid - outp.newInitializationVector(); - outp.setDestination(nextHop[h]); - RR->sw->send(tPtr,outp,true); - } - } - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - ZT_CircuitTestReport report; - memset(&report,0,sizeof(report)); - - report.current = peer->address().toInt(); - report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); - report.testId = at(ZT_PACKET_IDX_PAYLOAD + 8); - report.timestamp = at(ZT_PACKET_IDX_PAYLOAD); - report.sourcePacketId = at(ZT_PACKET_IDX_PAYLOAD + 44); - report.flags = at(ZT_PACKET_IDX_PAYLOAD + 36); - report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58 - report.errorCode = at(ZT_PACKET_IDX_PAYLOAD + 34); - report.vendor = (enum ZT_Vendor)((*this)[ZT_PACKET_IDX_PAYLOAD + 24]); - report.protocolVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 25]; - report.majorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 26]; - report.minorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 27]; - report.revision = at(ZT_PACKET_IDX_PAYLOAD + 28); - report.platform = (enum ZT_Platform)at(ZT_PACKET_IDX_PAYLOAD + 30); - report.architecture = (enum ZT_Architecture)at(ZT_PACKET_IDX_PAYLOAD + 32); - - const unsigned int receivedOnLocalAddressLen = reinterpret_cast(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58); - const unsigned int receivedFromRemoteAddressLen = reinterpret_cast(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen); - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen; - if (report.protocolVersion >= 9) { - report.receivedFromLinkQuality = at(ptr); ptr += 2; - } else { - report.receivedFromLinkQuality = ZT_PATH_LINK_QUALITY_MAX; - ptr += at(ptr) + 2; // this field was once an 'extended field length' reserved field, which was always set to 0 - } - - report.nextHopCount = (*this)[ptr++]; - if (report.nextHopCount > ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) // sanity check, shouldn't be possible - report.nextHopCount = ZT_CIRCUIT_TEST_MAX_HOP_BREADTH; - for(unsigned int h=0;h(&(report.nextHops[h].physicalAddress))->deserialize(*this,ptr); - } - - RR->node->postCircuitTestReport(&report); - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - if (size() >= (ZT_PACKET_IDX_PAYLOAD + 8)) { - ZT_UserMessage um; - um.origin = peer->address().toInt(); - um.typeId = at(ZT_PACKET_IDX_PAYLOAD); - um.data = reinterpret_cast(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD + 8); - um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); - RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); - } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid) -{ - const uint64_t now = RR->node->now(); - if (peer->rateGateOutgoingComRequest(now)) { - Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((uint8_t)verb()); - outp.append(packetId()); - outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); - outp.append(nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),now); - } -} - -} // namespace ZeroTier diff --git a/zto/node/IncomingPacket.hpp b/zto/node/IncomingPacket.hpp deleted file mode 100644 index 3d4a2e0..0000000 --- a/zto/node/IncomingPacket.hpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_INCOMINGPACKET_HPP -#define ZT_INCOMINGPACKET_HPP - -#include - -#include "Packet.hpp" -#include "Path.hpp" -#include "Utils.hpp" -#include "MulticastGroup.hpp" -#include "Peer.hpp" - -/* - * The big picture: - * - * tryDecode gets called for a given fully-assembled packet until it returns - * true or the packet's time to live has been exceeded, in which case it is - * discarded as failed decode. Any exception thrown by tryDecode also causes - * the packet to be discarded. - * - * Thus a return of false from tryDecode() indicates that it should be called - * again. Logic is very simple as to when, and it's in doAnythingWaitingForPeer - * in Switch. This might be expanded to be more fine grained in the future. - * - * A return value of true indicates that the packet is done. tryDecode must - * never be called again after that. - */ - -namespace ZeroTier { - -class RuntimeEnvironment; -class Network; - -/** - * Subclass of packet that handles the decoding of it - */ -class IncomingPacket : public Packet -{ -public: - IncomingPacket() : - Packet(), - _receiveTime(0) - { - } - - /** - * Create a new packet-in-decode - * - * @param data Packet data - * @param len Packet length - * @param path Path over which packet arrived - * @param now Current time - * @throws std::out_of_range Range error processing packet - */ - IncomingPacket(const void *data,unsigned int len,const SharedPtr &path,uint64_t now) : - Packet(data,len), - _receiveTime(now), - _path(path) - { - } - - /** - * Init packet-in-decode in place - * - * @param data Packet data - * @param len Packet length - * @param path Path over which packet arrived - * @param now Current time - * @throws std::out_of_range Range error processing packet - */ - inline void init(const void *data,unsigned int len,const SharedPtr &path,uint64_t now) - { - copyFrom(data,len); - _receiveTime = now; - _path = path; - } - - /** - * Attempt to decode this packet - * - * Note that this returns 'true' if processing is complete. This says nothing - * about whether the packet was valid. A rejection is 'complete.' - * - * Once true is returned, this must not be called again. The packet's state - * may no longer be valid. - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return True if decoding and processing is complete, false if caller should try again - */ - bool tryDecode(const RuntimeEnvironment *RR,void *tPtr); - - /** - * @return Time of packet receipt / start of decode - */ - inline uint64_t receiveTime() const throw() { return _receiveTime; } - -private: - // These are called internally to handle packet contents once it has - // been authenticated, decrypted, decompressed, and classified. - bool _doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated); - bool _doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - - void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid); - - uint64_t _receiveTime; - SharedPtr _path; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/InetAddress.cpp b/zto/node/InetAddress.cpp deleted file mode 100644 index 7d22eea..0000000 --- a/zto/node/InetAddress.cpp +++ /dev/null @@ -1,473 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#include - -#include "Constants.hpp" -#include "InetAddress.hpp" -#include "Utils.hpp" - -namespace ZeroTier { - -const InetAddress InetAddress::LO4((const void *)("\x7f\x00\x00\x01"),4,0); -const InetAddress InetAddress::LO6((const void *)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"),16,0); - -InetAddress::IpScope InetAddress::ipScope() const - throw() -{ - switch(ss_family) { - - case AF_INET: { - const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr); - switch(ip >> 24) { - case 0x00: return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used) - case 0x06: return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army) - case 0x0a: return IP_SCOPE_PRIVATE; // 10.0.0.0/8 - case 0x0b: return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD) - case 0x15: return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN) - case 0x16: return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA) - case 0x19: return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense) - case 0x1a: return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA) - case 0x1c: return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North) - case 0x1d: return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA) - case 0x1e: return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA) - case 0x2c: return IP_SCOPE_PSEUDOPRIVATE; // 44.0.0.0/8 (Amateur Radio) - case 0x33: return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security) - case 0x37: return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD) - case 0x38: return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service) - case 0x64: - if ((ip & 0xffc00000) == 0x64400000) return IP_SCOPE_SHARED; // 100.64.0.0/10 - break; - case 0x7f: return IP_SCOPE_LOOPBACK; // 127.0.0.0/8 - case 0xa9: - if ((ip & 0xffff0000) == 0xa9fe0000) return IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16 - break; - case 0xac: - if ((ip & 0xfff00000) == 0xac100000) return IP_SCOPE_PRIVATE; // 172.16.0.0/12 - break; - case 0xc0: - if ((ip & 0xffff0000) == 0xc0a80000) return IP_SCOPE_PRIVATE; // 192.168.0.0/16 - break; - case 0xff: return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable) - } - switch(ip >> 28) { - case 0xe: return IP_SCOPE_MULTICAST; // 224.0.0.0/4 - case 0xf: return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable) - } - return IP_SCOPE_GLOBAL; - } break; - - case AF_INET6: { - const unsigned char *ip = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - if ((ip[0] & 0xf0) == 0xf0) { - if (ip[0] == 0xff) return IP_SCOPE_MULTICAST; // ff00::/8 - if ((ip[0] == 0xfe)&&((ip[1] & 0xc0) == 0x80)) { - unsigned int k = 2; - while ((!ip[k])&&(k < 15)) ++k; - if ((k == 15)&&(ip[15] == 0x01)) - return IP_SCOPE_LOOPBACK; // fe80::1/128 - else return IP_SCOPE_LINK_LOCAL; // fe80::/10 - } - if ((ip[0] & 0xfe) == 0xfc) return IP_SCOPE_PRIVATE; // fc00::/7 - } - unsigned int k = 0; - while ((!ip[k])&&(k < 15)) ++k; - if (k == 15) { // all 0's except last byte - if (ip[15] == 0x01) return IP_SCOPE_LOOPBACK; // ::1/128 - if (ip[15] == 0x00) return IP_SCOPE_NONE; // ::/128 - } - return IP_SCOPE_GLOBAL; - } break; - - } - - return IP_SCOPE_NONE; -} - -void InetAddress::set(const std::string &ip,unsigned int port) - throw() -{ - memset(this,0,sizeof(InetAddress)); - if (ip.find(':') != std::string::npos) { - struct sockaddr_in6 *sin6 = reinterpret_cast(this); - ss_family = AF_INET6; - sin6->sin6_port = Utils::hton((uint16_t)port); - if (inet_pton(AF_INET6,ip.c_str(),(void *)&(sin6->sin6_addr.s6_addr)) <= 0) - memset(this,0,sizeof(InetAddress)); - } else if (ip.find('.') != std::string::npos) { - struct sockaddr_in *sin = reinterpret_cast(this); - ss_family = AF_INET; - sin->sin_port = Utils::hton((uint16_t)port); - if (inet_pton(AF_INET,ip.c_str(),(void *)&(sin->sin_addr.s_addr)) <= 0) - memset(this,0,sizeof(InetAddress)); - } -} - -void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port) - throw() -{ - memset(this,0,sizeof(InetAddress)); - if (ipLen == 4) { - uint32_t ipb[1]; - memcpy(ipb,ipBytes,4); - ss_family = AF_INET; - reinterpret_cast(this)->sin_addr.s_addr = ipb[0]; - reinterpret_cast(this)->sin_port = Utils::hton((uint16_t)port); - } else if (ipLen == 16) { - ss_family = AF_INET6; - memcpy(reinterpret_cast(this)->sin6_addr.s6_addr,ipBytes,16); - reinterpret_cast(this)->sin6_port = Utils::hton((uint16_t)port); - } -} - -std::string InetAddress::toString() const -{ - char buf[128]; - switch(ss_family) { - case AF_INET: - Utils::snprintf(buf,sizeof(buf),"%d.%d.%d.%d/%d", - (int)(reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr)))[0], - (int)(reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr)))[1], - (int)(reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr)))[2], - (int)(reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr)))[3], - (int)Utils::ntoh((uint16_t)(reinterpret_cast(this)->sin_port)) - ); - return std::string(buf); - case AF_INET6: - Utils::snprintf(buf,sizeof(buf),"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%d", - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[0]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[1]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[2]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[3]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[4]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[5]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[6]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[7]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[8]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[9]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[10]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[11]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[12]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[13]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[14]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[15]), - (int)Utils::ntoh((uint16_t)(reinterpret_cast(this)->sin6_port)) - ); - return std::string(buf); - } - return std::string(); -} - -std::string InetAddress::toIpString() const -{ - char buf[128]; - switch(ss_family) { - case AF_INET: - Utils::snprintf(buf,sizeof(buf),"%d.%d.%d.%d", - (int)(reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr)))[0], - (int)(reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr)))[1], - (int)(reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr)))[2], - (int)(reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr)))[3] - ); - return std::string(buf); - case AF_INET6: - Utils::snprintf(buf,sizeof(buf),"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[0]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[1]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[2]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[3]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[4]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[5]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[6]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[7]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[8]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[9]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[10]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[11]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[12]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[13]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[14]), - (int)(reinterpret_cast(this)->sin6_addr.s6_addr[15]) - ); - return std::string(buf); - } - return std::string(); -} - -void InetAddress::fromString(const std::string &ipSlashPort) -{ - const std::size_t slashAt = ipSlashPort.find('/'); - if (slashAt == std::string::npos) { - set(ipSlashPort,0); - } else { - long p = strtol(ipSlashPort.substr(slashAt+1).c_str(),(char **)0,10); - if ((p > 0)&&(p <= 0xffff)) - set(ipSlashPort.substr(0,slashAt),(unsigned int)p); - else set(ipSlashPort.substr(0,slashAt),0); - } -} - -InetAddress InetAddress::netmask() const -{ - InetAddress r(*this); - switch(r.ss_family) { - case AF_INET: - reinterpret_cast(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits()))); - break; - case AF_INET6: { - uint64_t nm[2]; - const unsigned int bits = netmaskBits(); - if(bits) { - nm[0] = Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); - nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); - } - else { - nm[0] = 0; - nm[1] = 0; - } - memcpy(reinterpret_cast(&r)->sin6_addr.s6_addr,nm,16); - } break; - } - return r; -} - -InetAddress InetAddress::broadcast() const -{ - if (ss_family == AF_INET) { - InetAddress r(*this); - reinterpret_cast(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits())); - return r; - } - return InetAddress(); -} - -InetAddress InetAddress::network() const -{ - InetAddress r(*this); - switch(r.ss_family) { - case AF_INET: - reinterpret_cast(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits()))); - break; - case AF_INET6: { - uint64_t nm[2]; - const unsigned int bits = netmaskBits(); - memcpy(nm,reinterpret_cast(&r)->sin6_addr.s6_addr,16); - nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); - nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); - memcpy(reinterpret_cast(&r)->sin6_addr.s6_addr,nm,16); - } break; - } - return r; -} - -bool InetAddress::containsAddress(const InetAddress &addr) const -{ - if (addr.ss_family == ss_family) { - switch(ss_family) { - case AF_INET: { - const unsigned int bits = netmaskBits(); - if (bits == 0) - return true; - return ( (Utils::ntoh((uint32_t)reinterpret_cast(&addr)->sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr) >> (32 - bits)) ); - } - case AF_INET6: { - const InetAddress mask(netmask()); - const uint8_t *m = reinterpret_cast(reinterpret_cast(&mask)->sin6_addr.s6_addr); - const uint8_t *a = reinterpret_cast(reinterpret_cast(&addr)->sin6_addr.s6_addr); - const uint8_t *b = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - for(unsigned int i=0;i<16;++i) { - if ((a[i] & m[i]) != b[i]) - return false; - } - return true; - } - } - } - return false; -} - -bool InetAddress::isNetwork() const - throw() -{ - switch(ss_family) { - case AF_INET: { - unsigned int bits = netmaskBits(); - if (bits <= 0) - return false; - if (bits >= 32) - return false; - uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr); - return ((ip & (0xffffffff >> bits)) == 0); - } - case AF_INET6: { - unsigned int bits = netmaskBits(); - if (bits <= 0) - return false; - if (bits >= 128) - return false; - const unsigned char *ip = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - unsigned int p = bits / 8; - if ((ip[p++] & (0xff >> (bits % 8))) != 0) - return false; - while (p < 16) { - if (ip[p++]) - return false; - } - return true; - } - } - return false; -} - -bool InetAddress::operator==(const InetAddress &a) const - throw() -{ - if (ss_family == a.ss_family) { - switch(ss_family) { - case AF_INET: - return ( - (reinterpret_cast(this)->sin_port == reinterpret_cast(&a)->sin_port)&& - (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr)); - break; - case AF_INET6: - return ( - (reinterpret_cast(this)->sin6_port == reinterpret_cast(&a)->sin6_port)&& - (reinterpret_cast(this)->sin6_flowinfo == reinterpret_cast(&a)->sin6_flowinfo)&& - (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,16) == 0)&& - (reinterpret_cast(this)->sin6_scope_id == reinterpret_cast(&a)->sin6_scope_id)); - break; - default: - return (memcmp(this,&a,sizeof(InetAddress)) == 0); - } - } - return false; -} - -bool InetAddress::operator<(const InetAddress &a) const - throw() -{ - if (ss_family < a.ss_family) - return true; - else if (ss_family == a.ss_family) { - switch(ss_family) { - case AF_INET: - if (reinterpret_cast(this)->sin_port < reinterpret_cast(&a)->sin_port) - return true; - else if (reinterpret_cast(this)->sin_port == reinterpret_cast(&a)->sin_port) { - if (reinterpret_cast(this)->sin_addr.s_addr < reinterpret_cast(&a)->sin_addr.s_addr) - return true; - } - break; - case AF_INET6: - if (reinterpret_cast(this)->sin6_port < reinterpret_cast(&a)->sin6_port) - return true; - else if (reinterpret_cast(this)->sin6_port == reinterpret_cast(&a)->sin6_port) { - if (reinterpret_cast(this)->sin6_flowinfo < reinterpret_cast(&a)->sin6_flowinfo) - return true; - else if (reinterpret_cast(this)->sin6_flowinfo == reinterpret_cast(&a)->sin6_flowinfo) { - if (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,16) < 0) - return true; - else if (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,16) == 0) { - if (reinterpret_cast(this)->sin6_scope_id < reinterpret_cast(&a)->sin6_scope_id) - return true; - } - } - } - break; - default: - return (memcmp(this,&a,sizeof(InetAddress)) < 0); - } - } - return false; -} - -InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac) -{ - struct sockaddr_in6 sin6; - sin6.sin6_family = AF_INET6; - sin6.sin6_addr.s6_addr[0] = 0xfe; - sin6.sin6_addr.s6_addr[1] = 0x80; - sin6.sin6_addr.s6_addr[2] = 0x00; - sin6.sin6_addr.s6_addr[3] = 0x00; - sin6.sin6_addr.s6_addr[4] = 0x00; - sin6.sin6_addr.s6_addr[5] = 0x00; - sin6.sin6_addr.s6_addr[6] = 0x00; - sin6.sin6_addr.s6_addr[7] = 0x00; - sin6.sin6_addr.s6_addr[8] = mac[0] & 0xfd; - sin6.sin6_addr.s6_addr[9] = mac[1]; - sin6.sin6_addr.s6_addr[10] = mac[2]; - sin6.sin6_addr.s6_addr[11] = 0xff; - sin6.sin6_addr.s6_addr[12] = 0xfe; - sin6.sin6_addr.s6_addr[13] = mac[3]; - sin6.sin6_addr.s6_addr[14] = mac[4]; - sin6.sin6_addr.s6_addr[15] = mac[5]; - sin6.sin6_port = Utils::hton((uint16_t)64); - return InetAddress(sin6); -} - -InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress) -{ - InetAddress r; - struct sockaddr_in6 *const sin6 = reinterpret_cast(&r); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr.s6_addr[0] = 0xfd; - sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56); - sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48); - sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40); - sin6->sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32); - sin6->sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24); - sin6->sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16); - sin6->sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8); - sin6->sin6_addr.s6_addr[8] = (uint8_t)nwid; - sin6->sin6_addr.s6_addr[9] = 0x99; - sin6->sin6_addr.s6_addr[10] = 0x93; - sin6->sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32); - sin6->sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24); - sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16); - sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8); - sin6->sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress; - sin6->sin6_port = Utils::hton((uint16_t)88); // /88 includes 0xfd + network ID, discriminating by device ID below that - return r; -} - -InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress) -{ - nwid ^= (nwid >> 32); - InetAddress r; - struct sockaddr_in6 *const sin6 = reinterpret_cast(&r); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr.s6_addr[0] = 0xfc; - sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24); - sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16); - sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8); - sin6->sin6_addr.s6_addr[4] = (uint8_t)nwid; - sin6->sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32); - sin6->sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24); - sin6->sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16); - sin6->sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8); - sin6->sin6_addr.s6_addr[9] = (uint8_t)zeroTierAddress; - sin6->sin6_addr.s6_addr[15] = 0x01; - sin6->sin6_port = Utils::hton((uint16_t)40); - return r; -} - -} // namespace ZeroTier diff --git a/zto/node/InetAddress.hpp b/zto/node/InetAddress.hpp deleted file mode 100644 index c37fa62..0000000 --- a/zto/node/InetAddress.hpp +++ /dev/null @@ -1,601 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_INETADDRESS_HPP -#define ZT_INETADDRESS_HPP - -#include -#include -#include - -#include - -#include "Constants.hpp" -#include "../include/ZeroTierOne.h" -#include "Utils.hpp" -#include "MAC.hpp" -#include "Buffer.hpp" - -namespace ZeroTier { - -/** - * Maximum integer value of enum IpScope - */ -#define ZT_INETADDRESS_MAX_SCOPE 7 - -/** - * Extends sockaddr_storage with friendly C++ methods - * - * This is basically a "mixin" for sockaddr_storage. It adds methods and - * operators, but does not modify the structure. This can be cast to/from - * sockaddr_storage and used interchangeably. DO NOT change this by e.g. - * adding non-static fields, since much code depends on this identity. - */ -struct InetAddress : public sockaddr_storage -{ - /** - * Loopback IPv4 address (no port) - */ - static const InetAddress LO4; - - /** - * Loopback IPV6 address (no port) - */ - static const InetAddress LO6; - - /** - * IP address scope - * - * Note that these values are in ascending order of path preference and - * MUST remain that way or Path must be changed to reflect. Also be sure - * to change ZT_INETADDRESS_MAX_SCOPE if the max changes. - */ - enum IpScope - { - IP_SCOPE_NONE = 0, // NULL or not an IP address - IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs - IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc. - IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted" - IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others) - IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL - IP_SCOPE_SHARED = 6, // 100.64.0.0/10, shared space for e.g. carrier-grade NAT - IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc. - }; - - InetAddress() throw() { memset(this,0,sizeof(InetAddress)); } - InetAddress(const InetAddress &a) throw() { memcpy(this,&a,sizeof(InetAddress)); } - InetAddress(const InetAddress *a) throw() { memcpy(this,a,sizeof(InetAddress)); } - InetAddress(const struct sockaddr_storage &ss) throw() { *this = ss; } - InetAddress(const struct sockaddr_storage *ss) throw() { *this = ss; } - InetAddress(const struct sockaddr &sa) throw() { *this = sa; } - InetAddress(const struct sockaddr *sa) throw() { *this = sa; } - InetAddress(const struct sockaddr_in &sa) throw() { *this = sa; } - InetAddress(const struct sockaddr_in *sa) throw() { *this = sa; } - InetAddress(const struct sockaddr_in6 &sa) throw() { *this = sa; } - InetAddress(const struct sockaddr_in6 *sa) throw() { *this = sa; } - InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) throw() { this->set(ipBytes,ipLen,port); } - InetAddress(const uint32_t ipv4,unsigned int port) throw() { this->set(&ipv4,4,port); } - InetAddress(const std::string &ip,unsigned int port) throw() { this->set(ip,port); } - InetAddress(const std::string &ipSlashPort) throw() { this->fromString(ipSlashPort); } - InetAddress(const char *ipSlashPort) throw() { this->fromString(std::string(ipSlashPort)); } - - inline InetAddress &operator=(const InetAddress &a) - throw() - { - if (&a != this) - memcpy(this,&a,sizeof(InetAddress)); - return *this; - } - - inline InetAddress &operator=(const InetAddress *a) - throw() - { - if (a != this) - memcpy(this,a,sizeof(InetAddress)); - return *this; - } - - inline InetAddress &operator=(const struct sockaddr_storage &ss) - throw() - { - if (reinterpret_cast(&ss) != this) - memcpy(this,&ss,sizeof(InetAddress)); - return *this; - } - - inline InetAddress &operator=(const struct sockaddr_storage *ss) - throw() - { - if (reinterpret_cast(ss) != this) - memcpy(this,ss,sizeof(InetAddress)); - return *this; - } - - inline InetAddress &operator=(const struct sockaddr_in &sa) - throw() - { - if (reinterpret_cast(&sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,&sa,sizeof(struct sockaddr_in)); - } - return *this; - } - - inline InetAddress &operator=(const struct sockaddr_in *sa) - throw() - { - if (reinterpret_cast(sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,sa,sizeof(struct sockaddr_in)); - } - return *this; - } - - inline InetAddress &operator=(const struct sockaddr_in6 &sa) - throw() - { - if (reinterpret_cast(&sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,&sa,sizeof(struct sockaddr_in6)); - } - return *this; - } - - inline InetAddress &operator=(const struct sockaddr_in6 *sa) - throw() - { - if (reinterpret_cast(sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,sa,sizeof(struct sockaddr_in6)); - } - return *this; - } - - inline InetAddress &operator=(const struct sockaddr &sa) - throw() - { - if (reinterpret_cast(&sa) != this) { - memset(this,0,sizeof(InetAddress)); - switch(sa.sa_family) { - case AF_INET: - memcpy(this,&sa,sizeof(struct sockaddr_in)); - break; - case AF_INET6: - memcpy(this,&sa,sizeof(struct sockaddr_in6)); - break; - } - } - return *this; - } - - inline InetAddress &operator=(const struct sockaddr *sa) - throw() - { - if (reinterpret_cast(sa) != this) { - memset(this,0,sizeof(InetAddress)); - switch(sa->sa_family) { - case AF_INET: - memcpy(this,sa,sizeof(struct sockaddr_in)); - break; - case AF_INET6: - memcpy(this,sa,sizeof(struct sockaddr_in6)); - break; - } - } - return *this; - } - - /** - * @return IP scope classification (e.g. loopback, link-local, private, global) - */ - IpScope ipScope() const - throw(); - - /** - * Set from a string-format IP and a port - * - * @param ip IP address in V4 or V6 ASCII notation - * @param port Port or 0 for none - */ - void set(const std::string &ip,unsigned int port) - throw(); - - /** - * Set from a raw IP and port number - * - * @param ipBytes Bytes of IP address in network byte order - * @param ipLen Length of IP address: 4 or 16 - * @param port Port number or 0 for none - */ - void set(const void *ipBytes,unsigned int ipLen,unsigned int port) - throw(); - - /** - * Set the port component - * - * @param port Port, 0 to 65535 - */ - inline void setPort(unsigned int port) - { - switch(ss_family) { - case AF_INET: - reinterpret_cast(this)->sin_port = Utils::hton((uint16_t)port); - break; - case AF_INET6: - reinterpret_cast(this)->sin6_port = Utils::hton((uint16_t)port); - break; - } - } - - /** - * @return True if this network/netmask route describes a default route (e.g. 0.0.0.0/0) - */ - inline bool isDefaultRoute() const - { - switch(ss_family) { - case AF_INET: - return ( (reinterpret_cast(this)->sin_addr.s_addr == 0) && (reinterpret_cast(this)->sin_port == 0) ); - case AF_INET6: - const uint8_t *ipb = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - for(int i=0;i<16;++i) { - if (ipb[i]) - return false; - } - return (reinterpret_cast(this)->sin6_port == 0); - } - return false; - } - - /** - * @return ASCII IP/port format representation - */ - std::string toString() const; - - /** - * @return IP portion only, in ASCII string format - */ - std::string toIpString() const; - - /** - * @param ipSlashPort ASCII IP/port format notation - */ - void fromString(const std::string &ipSlashPort); - - /** - * @return Port or 0 if no port component defined - */ - inline unsigned int port() const - throw() - { - switch(ss_family) { - case AF_INET: return Utils::ntoh((uint16_t)(reinterpret_cast(this)->sin_port)); - case AF_INET6: return Utils::ntoh((uint16_t)(reinterpret_cast(this)->sin6_port)); - default: return 0; - } - } - - /** - * Alias for port() - * - * This just aliases port() to make code more readable when netmask bits - * are stuffed there, as they are in Network, EthernetTap, and a few other - * spots. - * - * @return Netmask bits - */ - inline unsigned int netmaskBits() const throw() { return port(); } - - /** - * @return True if netmask bits is valid for the address type - */ - inline bool netmaskBitsValid() const - { - const unsigned int n = port(); - switch(ss_family) { - case AF_INET: return (n <= 32); - case AF_INET6: return (n <= 128); - } - return false; - } - - /** - * Alias for port() - * - * This just aliases port() because for gateways we use this field to - * store the gateway metric. - * - * @return Gateway metric - */ - inline unsigned int metric() const throw() { return port(); } - - /** - * Construct a full netmask as an InetAddress - * - * @return Netmask such as 255.255.255.0 if this address is /24 (port field will be unchanged) - */ - InetAddress netmask() const; - - /** - * Constructs a broadcast address from a network/netmask address - * - * This is only valid for IPv4 and will return a NULL InetAddress for other - * address families. - * - * @return Broadcast address (only IP portion is meaningful) - */ - InetAddress broadcast() const; - - /** - * Return the network -- a.k.a. the IP ANDed with the netmask - * - * @return Network e.g. 10.0.1.0/24 from 10.0.1.200/24 - */ - InetAddress network() const; - - /** - * Test whether this IP/netmask contains this address - * - * @param addr Address to check - * @return True if this IP/netmask (route) contains this address - */ - bool containsAddress(const InetAddress &addr) const; - - /** - * @return True if this is an IPv4 address - */ - inline bool isV4() const throw() { return (ss_family == AF_INET); } - - /** - * @return True if this is an IPv6 address - */ - inline bool isV6() const throw() { return (ss_family == AF_INET6); } - - /** - * @return pointer to raw address bytes or NULL if not available - */ - inline const void *rawIpData() const - { - switch(ss_family) { - case AF_INET: return (const void *)&(reinterpret_cast(this)->sin_addr.s_addr); - case AF_INET6: return (const void *)(reinterpret_cast(this)->sin6_addr.s6_addr); - default: return 0; - } - } - - /** - * @return InetAddress containing only the IP portion of this address and a zero port, or NULL if not IPv4 or IPv6 - */ - inline InetAddress ipOnly() const - { - InetAddress r; - switch(ss_family) { - case AF_INET: - r.ss_family = AF_INET; - reinterpret_cast(&r)->sin_addr.s_addr = reinterpret_cast(this)->sin_addr.s_addr; - break; - case AF_INET6: - r.ss_family = AF_INET6; - memcpy(reinterpret_cast(&r)->sin6_addr.s6_addr,reinterpret_cast(this)->sin6_addr.s6_addr,16); - break; - } - return r; - } - - /** - * Performs an IP-only comparison or, if that is impossible, a memcmp() - * - * @param a InetAddress to compare again - * @return True if only IP portions are equal (false for non-IP or null addresses) - */ - inline bool ipsEqual(const InetAddress &a) const - { - if (ss_family == a.ss_family) { - if (ss_family == AF_INET) - return (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr); - if (ss_family == AF_INET6) - return (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,16) == 0); - return (memcmp(this,&a,sizeof(InetAddress)) == 0); - } - return false; - } - - inline unsigned long hashCode() const - { - if (ss_family == AF_INET) { - return ((unsigned long)reinterpret_cast(this)->sin_addr.s_addr + (unsigned long)reinterpret_cast(this)->sin_port); - } else if (ss_family == AF_INET6) { - unsigned long tmp = reinterpret_cast(this)->sin6_port; - const uint8_t *a = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - for(long i=0;i<16;++i) - reinterpret_cast(&tmp)[i % sizeof(tmp)] ^= a[i]; - return tmp; - } else { - unsigned long tmp = reinterpret_cast(this)->sin6_port; - const uint8_t *a = reinterpret_cast(this); - for(long i=0;i<(long)sizeof(InetAddress);++i) - reinterpret_cast(&tmp)[i % sizeof(tmp)] ^= a[i]; - return tmp; - } - } - - /** - * Set to null/zero - */ - inline void zero() throw() { memset(this,0,sizeof(InetAddress)); } - - /** - * Check whether this is a network/route rather than an IP assignment - * - * A network is an IP/netmask where everything after the netmask is - * zero e.g. 10.0.0.0/8. - * - * @return True if everything after netmask bits is zero - */ - bool isNetwork() const - throw(); - - /** - * @return 14-bit (0-16383) hash of this IP's first 24 or 48 bits (for V4 or V6) for rate limiting code, or 0 if non-IP - */ - inline unsigned long rateGateHash() const - { - unsigned long h = 0; - switch(ss_family) { - case AF_INET: - h = (Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr) & 0xffffff00) >> 8; - h ^= (h >> 14); - break; - case AF_INET6: { - const uint8_t *ip = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - h = ((unsigned long)ip[0]); h <<= 1; - h += ((unsigned long)ip[1]); h <<= 1; - h += ((unsigned long)ip[2]); h <<= 1; - h += ((unsigned long)ip[3]); h <<= 1; - h += ((unsigned long)ip[4]); h <<= 1; - h += ((unsigned long)ip[5]); - } break; - } - return (h & 0x3fff); - } - - /** - * @return True if address family is non-zero - */ - inline operator bool() const throw() { return (ss_family != 0); } - - template - inline void serialize(Buffer &b) const - { - // This is used in the protocol and must be the same as describe in places - // like VERB_HELLO in Packet.hpp. - switch(ss_family) { - case AF_INET: - b.append((uint8_t)0x04); - b.append(&(reinterpret_cast(this)->sin_addr.s_addr),4); - b.append((uint16_t)port()); // just in case sin_port != uint16_t - return; - case AF_INET6: - b.append((uint8_t)0x06); - b.append(reinterpret_cast(this)->sin6_addr.s6_addr,16); - b.append((uint16_t)port()); // just in case sin_port != uint16_t - return; - default: - b.append((uint8_t)0); - return; - } - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - memset(this,0,sizeof(InetAddress)); - unsigned int p = startAt; - switch(b[p++]) { - case 0: - return 1; - case 0x01: - // TODO: Ethernet address (but accept for forward compatibility) - return 7; - case 0x02: - // TODO: Bluetooth address (but accept for forward compatibility) - return 7; - case 0x03: - // TODO: Other address types (but accept for forward compatibility) - // These could be extended/optional things like AF_UNIX, LTE Direct, shared memory, etc. - return (unsigned int)(b.template at(p) + 3); // other addresses begin with 16-bit non-inclusive length - case 0x04: - ss_family = AF_INET; - memcpy(&(reinterpret_cast(this)->sin_addr.s_addr),b.field(p,4),4); p += 4; - reinterpret_cast(this)->sin_port = Utils::hton(b.template at(p)); p += 2; - break; - case 0x06: - ss_family = AF_INET6; - memcpy(reinterpret_cast(this)->sin6_addr.s6_addr,b.field(p,16),16); p += 16; - reinterpret_cast(this)->sin_port = Utils::hton(b.template at(p)); p += 2; - break; - default: - throw std::invalid_argument("invalid serialized InetAddress"); - } - return (p - startAt); - } - - bool operator==(const InetAddress &a) const throw(); - bool operator<(const InetAddress &a) const throw(); - inline bool operator!=(const InetAddress &a) const throw() { return !(*this == a); } - inline bool operator>(const InetAddress &a) const throw() { return (a < *this); } - inline bool operator<=(const InetAddress &a) const throw() { return !(a < *this); } - inline bool operator>=(const InetAddress &a) const throw() { return !(*this < a); } - - /** - * @param mac MAC address seed - * @return IPv6 link-local address - */ - static InetAddress makeIpv6LinkLocal(const MAC &mac); - - /** - * Compute private IPv6 unicast address from network ID and ZeroTier address - * - * This generates a private unicast IPv6 address that is mostly compliant - * with the letter of RFC4193 and certainly compliant in spirit. - * - * RFC4193 specifies a format of: - * - * | 7 bits |1| 40 bits | 16 bits | 64 bits | - * | Prefix |L| Global ID | Subnet ID | Interface ID | - * - * The 'L' bit is set to 1, yielding an address beginning with 0xfd. Then - * the network ID is filled into the global ID, subnet ID, and first byte - * of the "interface ID" field. Since the first 40 bits of the network ID - * is the unique ZeroTier address of its controller, this makes a very - * good random global ID. Since network IDs have 24 more bits, we let it - * overflow into the interface ID. - * - * After that we pad with two bytes: 0x99, 0x93, namely the default ZeroTier - * port in hex. - * - * Finally we fill the remaining 40 bits of the interface ID field with - * the 40-bit unique ZeroTier device ID of the network member. - * - * This yields a valid RFC4193 address with a random global ID, a - * meaningful subnet ID, and a unique interface ID, all mappable back onto - * ZeroTier space. - * - * This in turn could allow us, on networks numbered this way, to emulate - * IPv6 NDP and eliminate all multicast. This could be beneficial for - * small devices and huge networks, e.g. IoT applications. - * - * The returned address is given an odd prefix length of /88, since within - * a given network only the last 40 bits (device ID) are variable. This - * is a bit unusual but as far as we know should not cause any problems with - * any non-braindead IPv6 stack. - * - * @param nwid 64-bit network ID - * @param zeroTierAddress 40-bit device address (in least significant 40 bits, highest 24 bits ignored) - * @return IPv6 private unicast address with /88 netmask - */ - static InetAddress makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress); - - /** - * Compute a private IPv6 "6plane" unicast address from network ID and ZeroTier address - */ - static InetAddress makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress); -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/MAC.hpp b/zto/node/MAC.hpp deleted file mode 100644 index 95623f1..0000000 --- a/zto/node/MAC.hpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_MAC_HPP -#define ZT_MAC_HPP - -#include -#include -#include - -#include "Constants.hpp" -#include "Utils.hpp" -#include "Address.hpp" -#include "Buffer.hpp" - -namespace ZeroTier { - -/** - * 48-byte Ethernet MAC address - */ -class MAC -{ -public: - MAC() throw() : _m(0ULL) {} - MAC(const MAC &m) throw() : _m(m._m) {} - - MAC(const unsigned char a,const unsigned char b,const unsigned char c,const unsigned char d,const unsigned char e,const unsigned char f) throw() : - _m( ((((uint64_t)a) & 0xffULL) << 40) | - ((((uint64_t)b) & 0xffULL) << 32) | - ((((uint64_t)c) & 0xffULL) << 24) | - ((((uint64_t)d) & 0xffULL) << 16) | - ((((uint64_t)e) & 0xffULL) << 8) | - (((uint64_t)f) & 0xffULL) ) {} - - MAC(const char *s) throw() { fromString(s); } - MAC(const std::string &s) throw() { fromString(s.c_str()); } - - MAC(const void *bits,unsigned int len) throw() { setTo(bits,len); } - - MAC(const Address &ztaddr,uint64_t nwid) throw() { fromAddress(ztaddr,nwid); } - - MAC(const uint64_t m) throw() : _m(m & 0xffffffffffffULL) {} - - /** - * @return MAC in 64-bit integer - */ - inline uint64_t toInt() const throw() { return _m; } - - /** - * Set MAC to zero - */ - inline void zero() { _m = 0ULL; } - - /** - * @return True if MAC is non-zero - */ - inline operator bool() const throw() { return (_m != 0ULL); } - - /** - * @param bits Raw MAC in big-endian byte order - * @param len Length, must be >= 6 or result is zero - */ - inline void setTo(const void *bits,unsigned int len) - throw() - { - if (len < 6) { - _m = 0ULL; - return; - } - const unsigned char *b = (const unsigned char *)bits; - _m = ((((uint64_t)*b) & 0xff) << 40); ++b; - _m |= ((((uint64_t)*b) & 0xff) << 32); ++b; - _m |= ((((uint64_t)*b) & 0xff) << 24); ++b; - _m |= ((((uint64_t)*b) & 0xff) << 16); ++b; - _m |= ((((uint64_t)*b) & 0xff) << 8); ++b; - _m |= (((uint64_t)*b) & 0xff); - } - - /** - * @param buf Destination buffer for MAC in big-endian byte order - * @param len Length of buffer, must be >= 6 or nothing is copied - */ - inline void copyTo(void *buf,unsigned int len) const - throw() - { - if (len < 6) - return; - unsigned char *b = (unsigned char *)buf; - *(b++) = (unsigned char)((_m >> 40) & 0xff); - *(b++) = (unsigned char)((_m >> 32) & 0xff); - *(b++) = (unsigned char)((_m >> 24) & 0xff); - *(b++) = (unsigned char)((_m >> 16) & 0xff); - *(b++) = (unsigned char)((_m >> 8) & 0xff); - *b = (unsigned char)(_m & 0xff); - } - - /** - * Append to a buffer in big-endian byte order - * - * @param b Buffer to append to - */ - template - inline void appendTo(Buffer &b) const - throw(std::out_of_range) - { - unsigned char *p = (unsigned char *)b.appendField(6); - *(p++) = (unsigned char)((_m >> 40) & 0xff); - *(p++) = (unsigned char)((_m >> 32) & 0xff); - *(p++) = (unsigned char)((_m >> 24) & 0xff); - *(p++) = (unsigned char)((_m >> 16) & 0xff); - *(p++) = (unsigned char)((_m >> 8) & 0xff); - *p = (unsigned char)(_m & 0xff); - } - - /** - * @return True if this is broadcast (all 0xff) - */ - inline bool isBroadcast() const throw() { return (_m == 0xffffffffffffULL); } - - /** - * @return True if this is a multicast MAC - */ - inline bool isMulticast() const throw() { return ((_m & 0x010000000000ULL) != 0ULL); } - - /** - * @param True if this is a locally-administered MAC - */ - inline bool isLocallyAdministered() const throw() { return ((_m & 0x020000000000ULL) != 0ULL); } - - /** - * @param s Hex MAC, with or without : delimiters - */ - inline void fromString(const char *s) - { - char tmp[8]; - for(int i=0;i<6;++i) - tmp[i] = (char)0; - Utils::unhex(s,tmp,6); - setTo(tmp,6); - } - - /** - * @return MAC address in standard :-delimited hex format - */ - inline std::string toString() const - { - char tmp[24]; - toString(tmp,sizeof(tmp)); - return std::string(tmp); - } - - /** - * @param buf Buffer to contain human-readable MAC - * @param len Length of buffer - */ - inline void toString(char *buf,unsigned int len) const - { - Utils::snprintf(buf,len,"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)(*this)[0],(int)(*this)[1],(int)(*this)[2],(int)(*this)[3],(int)(*this)[4],(int)(*this)[5]); - } - - /** - * Set this MAC to a MAC derived from an address and a network ID - * - * @param ztaddr ZeroTier address - * @param nwid 64-bit network ID - */ - inline void fromAddress(const Address &ztaddr,uint64_t nwid) - throw() - { - uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40; - m |= ztaddr.toInt(); // a is 40 bits - m ^= ((nwid >> 8) & 0xff) << 32; - m ^= ((nwid >> 16) & 0xff) << 24; - m ^= ((nwid >> 24) & 0xff) << 16; - m ^= ((nwid >> 32) & 0xff) << 8; - m ^= (nwid >> 40) & 0xff; - _m = m; - } - - /** - * Get the ZeroTier address for this MAC on this network (assuming no bridging of course, basic unicast) - * - * This just XORs the next-lest-significant 5 bytes of the network ID again to unmask. - * - * @param nwid Network ID - */ - inline Address toAddress(uint64_t nwid) const - throw() - { - uint64_t a = _m & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address - a ^= ((nwid >> 8) & 0xff) << 32; // ... XORed with bits 8-48 of the nwid in little-endian byte order, so unmask it - a ^= ((nwid >> 16) & 0xff) << 24; - a ^= ((nwid >> 24) & 0xff) << 16; - a ^= ((nwid >> 32) & 0xff) << 8; - a ^= (nwid >> 40) & 0xff; - return Address(a); - } - - /** - * @param nwid Network ID - * @return First octet of MAC for this network - */ - static inline unsigned char firstOctetForNetwork(uint64_t nwid) - throw() - { - unsigned char a = ((unsigned char)(nwid & 0xfe) | 0x02); // locally administered, not multicast, from LSB of network ID - return ((a == 0x52) ? 0x32 : a); // blacklist 0x52 since it's used by KVM, libvirt, and other popular virtualization engines... seems de-facto standard on Linux - } - - /** - * @param i Value from 0 to 5 (inclusive) - * @return Byte at said position (address interpreted in big-endian order) - */ - inline unsigned char operator[](unsigned int i) const throw() { return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); } - - /** - * @return 6, which is the number of bytes in a MAC, for container compliance - */ - inline unsigned int size() const throw() { return 6; } - - inline unsigned long hashCode() const throw() { return (unsigned long)_m; } - - inline MAC &operator=(const MAC &m) - throw() - { - _m = m._m; - return *this; - } - inline MAC &operator=(const uint64_t m) - throw() - { - _m = m; - return *this; - } - - inline bool operator==(const MAC &m) const throw() { return (_m == m._m); } - inline bool operator!=(const MAC &m) const throw() { return (_m != m._m); } - inline bool operator<(const MAC &m) const throw() { return (_m < m._m); } - inline bool operator<=(const MAC &m) const throw() { return (_m <= m._m); } - inline bool operator>(const MAC &m) const throw() { return (_m > m._m); } - inline bool operator>=(const MAC &m) const throw() { return (_m >= m._m); } - -private: - uint64_t _m; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Membership.cpp b/zto/node/Membership.cpp deleted file mode 100644 index 22c13c8..0000000 --- a/zto/node/Membership.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "Membership.hpp" -#include "RuntimeEnvironment.hpp" -#include "Peer.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Packet.hpp" -#include "Node.hpp" - -#define ZT_CREDENTIAL_PUSH_EVERY (ZT_NETWORK_AUTOCONF_DELAY / 3) - -namespace ZeroTier { - -Membership::Membership() : - _lastUpdatedMulticast(0), - _lastPushedCom(0), - _comRevocationThreshold(0) -{ - for(unsigned int i=0;i= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) ); - - const Capability *sendCap; - if (localCapabilityIndex >= 0) { - sendCap = &(nconf.capabilities[localCapabilityIndex]); - if ( (_localCaps[localCapabilityIndex].id != sendCap->id()) || ((now - _localCaps[localCapabilityIndex].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) { - _localCaps[localCapabilityIndex].lastPushed = now; - _localCaps[localCapabilityIndex].id = sendCap->id(); - } else sendCap = (const Capability *)0; - } else sendCap = (const Capability *)0; - - const Tag *sendTags[ZT_MAX_NETWORK_TAGS]; - unsigned int sendTagCount = 0; - for(unsigned int t=0;t= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) { - _localTags[t].lastPushed = now; - _localTags[t].id = nconf.tags[t].id(); - sendTags[sendTagCount++] = &(nconf.tags[t]); - } - } - - const CertificateOfOwnership *sendCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; - unsigned int sendCooCount = 0; - for(unsigned int c=0;c= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) { - _localCoos[c].lastPushed = now; - _localCoos[c].id = nconf.certificatesOfOwnership[c].id(); - sendCoos[sendCooCount++] = &(nconf.certificatesOfOwnership[c]); - } - } - - unsigned int tagPtr = 0; - unsigned int cooPtr = 0; - while ((tagPtr < sendTagCount)||(cooPtr < sendCooCount)||(sendCom)||(sendCap)) { - Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - - if (sendCom) { - sendCom = false; - nconf.com.serialize(outp); - _lastPushedCom = now; - } - outp.append((uint8_t)0x00); - - if (sendCap) { - outp.append((uint16_t)1); - sendCap->serialize(outp); - sendCap = (const Capability *)0; - } else outp.append((uint16_t)0); - - const unsigned int tagCountAt = outp.size(); - outp.addSize(2); - unsigned int thisPacketTagCount = 0; - while ((tagPtr < sendTagCount)&&((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { - sendTags[tagPtr++]->serialize(outp); - ++thisPacketTagCount; - } - outp.setAt(tagCountAt,(uint16_t)thisPacketTagCount); - - // No revocations, these propagate differently - outp.append((uint16_t)0); - - const unsigned int cooCountAt = outp.size(); - outp.addSize(2); - unsigned int thisPacketCooCount = 0; - while ((cooPtr < sendCooCount)&&((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { - sendCoos[cooPtr++]->serialize(outp); - ++thisPacketCooCount; - } - outp.setAt(cooCountAt,(uint16_t)thisPacketCooCount); - - outp.compress(); - RR->sw->send(tPtr,outp,true); - } -} - -const Tag *Membership::getTag(const NetworkConfig &nconf,const uint32_t id) const -{ - const _RemoteCredential *const *t = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)id,_RemoteCredentialComp()); - return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,**t))) ? &((*t)->credential) : (const Tag *)0) : (const Tag *)0); -} - -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com) -{ - const uint64_t newts = com.timestamp().first; - if (newts <= _comRevocationThreshold) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (revoked)",com.issuedTo().toString().c_str(),com.networkId()); - return ADD_REJECTED; - } - - const uint64_t oldts = _com.timestamp().first; - if (newts < oldts) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (older than current)",com.issuedTo().toString().c_str(),com.networkId()); - return ADD_REJECTED; - } - if ((newts == oldts)&&(_com == com)) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant)",com.issuedTo().toString().c_str(),com.networkId()); - return ADD_ACCEPTED_REDUNDANT; - } - - switch(com.verify(RR,tPtr)) { - default: - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (invalid signature or object)",com.issuedTo().toString().c_str(),com.networkId()); - return ADD_REJECTED; - case 0: - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new)",com.issuedTo().toString().c_str(),com.networkId()); - _com = com; - return ADD_ACCEPTED_NEW; - case 1: - return ADD_DEFERRED_FOR_WHOIS; - } -} - -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) -{ - _RemoteCredential *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)tag.id(),_RemoteCredentialComp()); - _RemoteCredential *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)tag.id())) ? *htmp : (_RemoteCredential *)0; - if (have) { - if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > tag.timestamp()) ) { - TRACE("addCredential(Tag) for %s on %.16llx REJECTED (revoked or too old)",tag.issuedTo().toString().c_str(),tag.networkId()); - return ADD_REJECTED; - } - if (have->credential == tag) { - TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (redundant)",tag.issuedTo().toString().c_str(),tag.networkId()); - return ADD_ACCEPTED_REDUNDANT; - } - } - - switch(tag.verify(RR,tPtr)) { - default: - TRACE("addCredential(Tag) for %s on %.16llx REJECTED (invalid)",tag.issuedTo().toString().c_str(),tag.networkId()); - return ADD_REJECTED; - case 0: - TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId()); - if (!have) have = _newTag(tag.id()); - have->lastReceived = RR->node->now(); - have->credential = tag; - return ADD_ACCEPTED_NEW; - case 1: - return ADD_DEFERRED_FOR_WHOIS; - } -} - -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) -{ - _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)cap.id(),_RemoteCredentialComp()); - _RemoteCredential *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)cap.id())) ? *htmp : (_RemoteCredential *)0; - if (have) { - if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > cap.timestamp()) ) { - TRACE("addCredential(Capability) for %s on %.16llx REJECTED (revoked or too old)",cap.issuedTo().toString().c_str(),cap.networkId()); - return ADD_REJECTED; - } - if (have->credential == cap) { - TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (redundant)",cap.issuedTo().toString().c_str(),cap.networkId()); - return ADD_ACCEPTED_REDUNDANT; - } - } - - switch(cap.verify(RR,tPtr)) { - default: - TRACE("addCredential(Capability) for %s on %.16llx REJECTED (invalid)",cap.issuedTo().toString().c_str(),cap.networkId()); - return ADD_REJECTED; - case 0: - TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (new)",cap.issuedTo().toString().c_str(),cap.networkId()); - if (!have) have = _newCapability(cap.id()); - have->lastReceived = RR->node->now(); - have->credential = cap; - return ADD_ACCEPTED_NEW; - case 1: - return ADD_DEFERRED_FOR_WHOIS; - } -} - -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev) -{ - switch(rev.verify(RR,tPtr)) { - default: - return ADD_REJECTED; - case 0: { - const uint64_t now = RR->node->now(); - switch(rev.type()) { - default: - return ADD_REJECTED; - case Revocation::CREDENTIAL_TYPE_COM: - return (_revokeCom(rev) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); - case Revocation::CREDENTIAL_TYPE_CAPABILITY: - return (_revokeCap(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); - case Revocation::CREDENTIAL_TYPE_TAG: - return (_revokeTag(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); - case Revocation::CREDENTIAL_TYPE_COO: - return (_revokeCoo(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); - } - } - case 1: - return ADD_DEFERRED_FOR_WHOIS; - } -} - -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) -{ - _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)coo.id(),_RemoteCredentialComp()); - _RemoteCredential *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)coo.id())) ? *htmp : (_RemoteCredential *)0; - if (have) { - if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > coo.timestamp()) ) { - TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (revoked or too old)",coo.issuedTo().toString().c_str(),coo.networkId()); - return ADD_REJECTED; - } - if (have->credential == coo) { - TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx ACCEPTED (redundant)",coo.issuedTo().toString().c_str(),coo.networkId()); - return ADD_ACCEPTED_REDUNDANT; - } - } - - switch(coo.verify(RR,tPtr)) { - default: - TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (invalid)",coo.issuedTo().toString().c_str(),coo.networkId()); - return ADD_REJECTED; - case 0: - TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx ACCEPTED (new)",coo.issuedTo().toString().c_str(),coo.networkId()); - if (!have) have = _newCoo(coo.id()); - have->lastReceived = RR->node->now(); - have->credential = coo; - return ADD_ACCEPTED_NEW; - case 1: - return ADD_DEFERRED_FOR_WHOIS; - } -} - -Membership::_RemoteCredential *Membership::_newTag(const uint64_t id) -{ - _RemoteCredential *t = NULL; - uint64_t minlr = 0xffffffffffffffffULL; - for(unsigned int i=0;iid == ZT_MEMBERSHIP_CRED_ID_UNUSED) { - t = _remoteTags[i]; - break; - } else if (_remoteTags[i]->lastReceived <= minlr) { - t = _remoteTags[i]; - minlr = _remoteTags[i]->lastReceived; - } - } - - if (t) { - t->id = id; - t->lastReceived = 0; - t->revocationThreshold = 0; - t->credential = Tag(); - } - - std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialComp()); - return t; -} - -Membership::_RemoteCredential *Membership::_newCapability(const uint64_t id) -{ - _RemoteCredential *c = NULL; - uint64_t minlr = 0xffffffffffffffffULL; - for(unsigned int i=0;iid == ZT_MEMBERSHIP_CRED_ID_UNUSED) { - c = _remoteCaps[i]; - break; - } else if (_remoteCaps[i]->lastReceived <= minlr) { - c = _remoteCaps[i]; - minlr = _remoteCaps[i]->lastReceived; - } - } - - if (c) { - c->id = id; - c->lastReceived = 0; - c->revocationThreshold = 0; - c->credential = Capability(); - } - - std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialComp()); - return c; -} - -Membership::_RemoteCredential *Membership::_newCoo(const uint64_t id) -{ - _RemoteCredential *c = NULL; - uint64_t minlr = 0xffffffffffffffffULL; - for(unsigned int i=0;iid == ZT_MEMBERSHIP_CRED_ID_UNUSED) { - c = _remoteCoos[i]; - break; - } else if (_remoteCoos[i]->lastReceived <= minlr) { - c = _remoteCoos[i]; - minlr = _remoteCoos[i]->lastReceived; - } - } - - if (c) { - c->id = id; - c->lastReceived = 0; - c->revocationThreshold = 0; - c->credential = CertificateOfOwnership(); - } - - std::sort(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),_RemoteCredentialComp()); - return c; -} - -bool Membership::_revokeCom(const Revocation &rev) -{ - if (rev.threshold() > _comRevocationThreshold) { - _comRevocationThreshold = rev.threshold(); - return true; - } - return false; -} - -bool Membership::_revokeCap(const Revocation &rev,const uint64_t now) -{ - _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)rev.credentialId(),_RemoteCredentialComp()); - _RemoteCredential *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential *)0; - if (!have) have = _newCapability(rev.credentialId()); - if (rev.threshold() > have->revocationThreshold) { - have->lastReceived = now; - have->revocationThreshold = rev.threshold(); - return true; - } - return false; -} - -bool Membership::_revokeTag(const Revocation &rev,const uint64_t now) -{ - _RemoteCredential *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)rev.credentialId(),_RemoteCredentialComp()); - _RemoteCredential *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential *)0; - if (!have) have = _newTag(rev.credentialId()); - if (rev.threshold() > have->revocationThreshold) { - have->lastReceived = now; - have->revocationThreshold = rev.threshold(); - return true; - } - return false; -} - -bool Membership::_revokeCoo(const Revocation &rev,const uint64_t now) -{ - _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)rev.credentialId(),_RemoteCredentialComp()); - _RemoteCredential *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential *)0; - if (!have) have = _newCoo(rev.credentialId()); - if (rev.threshold() > have->revocationThreshold) { - have->lastReceived = now; - have->revocationThreshold = rev.threshold(); - return true; - } - return false; -} - -} // namespace ZeroTier diff --git a/zto/node/Membership.hpp b/zto/node/Membership.hpp deleted file mode 100644 index c28d598..0000000 --- a/zto/node/Membership.hpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_MEMBERSHIP_HPP -#define ZT_MEMBERSHIP_HPP - -#include - -#include "Constants.hpp" -#include "../include/ZeroTierOne.h" -#include "CertificateOfMembership.hpp" -#include "Capability.hpp" -#include "Tag.hpp" -#include "Revocation.hpp" -#include "NetworkConfig.hpp" - -#define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL - -namespace ZeroTier { - -class RuntimeEnvironment; -class Network; - -/** - * A container for certificates of membership and other network credentials - * - * This is essentially a relational join between Peer and Network. - * - * This class is not thread safe. It must be locked externally. - */ -class Membership -{ -private: - template - struct _RemoteCredential - { - _RemoteCredential() : id(ZT_MEMBERSHIP_CRED_ID_UNUSED),lastReceived(0),revocationThreshold(0) {} - uint64_t id; - uint64_t lastReceived; // last time we got this credential - uint64_t revocationThreshold; // credentials before this time are invalid - T credential; - inline bool operator<(const _RemoteCredential &c) const { return (id < c.id); } - }; - - template - struct _RemoteCredentialComp - { - inline bool operator()(const _RemoteCredential *a,const _RemoteCredential *b) const { return (a->id < b->id); } - inline bool operator()(const uint64_t a,const _RemoteCredential *b) const { return (a < b->id); } - inline bool operator()(const _RemoteCredential *a,const uint64_t b) const { return (a->id < b); } - inline bool operator()(const uint64_t a,const uint64_t b) const { return (a < b); } - }; - - // Used to track push state for network config tags[] and capabilities[] entries - struct _LocalCredentialPushState - { - _LocalCredentialPushState() : lastPushed(0),id(0) {} - uint64_t lastPushed; // last time we sent our own copy of this credential - uint64_t id; - }; - -public: - enum AddCredentialResult - { - ADD_REJECTED, - ADD_ACCEPTED_NEW, - ADD_ACCEPTED_REDUNDANT, - ADD_DEFERRED_FOR_WHOIS - }; - - /** - * Iterator to scan forward through capabilities in ascending order of ID - */ - class CapabilityIterator - { - public: - CapabilityIterator(const Membership &m,const NetworkConfig &nconf) : - _m(&m), - _c(&nconf), - _i(&(m._remoteCaps[0])) {} - - inline const Capability *next() - { - for(;;) { - if ((_i != &(_m->_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) { - const Capability *tmp = &((*_i)->credential); - if (_m->_isCredentialTimestampValid(*_c,**_i)) { - ++_i; - return tmp; - } else ++_i; - } else { - return (const Capability *)0; - } - } - } - - private: - const Membership *_m; - const NetworkConfig *_c; - const _RemoteCredential *const *_i; - }; - friend class CapabilityIterator; - - /** - * Iterator to scan forward through tags in ascending order of ID - */ - class TagIterator - { - public: - TagIterator(const Membership &m,const NetworkConfig &nconf) : - _m(&m), - _c(&nconf), - _i(&(m._remoteTags[0])) {} - - inline const Tag *next() - { - for(;;) { - if ((_i != &(_m->_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) { - const Tag *tmp = &((*_i)->credential); - if (_m->_isCredentialTimestampValid(*_c,**_i)) { - ++_i; - return tmp; - } else ++_i; - } else { - return (const Tag *)0; - } - } - } - - private: - const Membership *_m; - const NetworkConfig *_c; - const _RemoteCredential *const *_i; - }; - friend class TagIterator; - - Membership(); - - /** - * Send COM and other credentials to this peer if needed - * - * This checks last pushed times for our COM and for other credentials and - * sends VERB_NETWORK_CREDENTIALS if the recipient might need them. - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - * @param peerAddress Address of member peer (the one that this Membership describes) - * @param nconf My network config - * @param localCapabilityIndex Index of local capability to include (in nconf.capabilities[]) or -1 if none - * @param force If true, send objects regardless of last push time - */ - void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force); - - /** - * Check whether we should push MULTICAST_LIKEs to this peer - * - * @param now Current time - * @return True if we should update multicasts - */ - inline bool shouldLikeMulticasts(const uint64_t now) const { return ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD); } - - /** - * Set time we last updated multicasts for this peer - * - * @param now Current time - */ - inline void likingMulticasts(const uint64_t now) { _lastUpdatedMulticast = now; } - - /** - * Check whether the peer represented by this Membership should be allowed on this network at all - * - * @param nconf Our network config - * @return True if this peer is allowed on this network at all - */ - inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const - { - if (nconf.isPublic()) - return true; - if (_com.timestamp().first <= _comRevocationThreshold) - return false; - return nconf.com.agreesWith(_com); - } - - /** - * Check whether the peer represented by this Membership owns a given resource - * - * @tparam Type of resource: InetAddress or MAC - * @param nconf Our network config - * @param r Resource to check - * @return True if this peer has a certificate of ownership for the given resource - */ - template - inline bool hasCertificateOfOwnershipFor(const NetworkConfig &nconf,const T &r) const - { - for(unsigned int i=0;iid == ZT_MEMBERSHIP_CRED_ID_UNUSED) - break; - if ((_isCredentialTimestampValid(nconf,*_remoteCoos[i]))&&(_remoteCoos[i]->credential.owns(r))) - return true; - } - return false; - } - - /** - * @param nconf Network configuration - * @param id Tag ID - * @return Pointer to tag or NULL if not found - */ - const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const; - - /** - * Validate and add a credential if signature is okay and it's otherwise good - */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com); - - /** - * Validate and add a credential if signature is okay and it's otherwise good - */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag); - - /** - * Validate and add a credential if signature is okay and it's otherwise good - */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap); - - /** - * Validate and add a credential if signature is okay and it's otherwise good - */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev); - - /** - * Validate and add a credential if signature is okay and it's otherwise good - */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo); - -private: - _RemoteCredential *_newTag(const uint64_t id); - _RemoteCredential *_newCapability(const uint64_t id); - _RemoteCredential *_newCoo(const uint64_t id); - bool _revokeCom(const Revocation &rev); - bool _revokeCap(const Revocation &rev,const uint64_t now); - bool _revokeTag(const Revocation &rev,const uint64_t now); - bool _revokeCoo(const Revocation &rev,const uint64_t now); - - template - inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const _RemoteCredential &remoteCredential) const - { - if (!remoteCredential.lastReceived) - return false; - const uint64_t ts = remoteCredential.credential.timestamp(); - return ( (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) && (ts > remoteCredential.revocationThreshold) ); - } - - // Last time we pushed MULTICAST_LIKE(s) - uint64_t _lastUpdatedMulticast; - - // Last time we pushed our COM to this peer - uint64_t _lastPushedCom; - - // Revocation threshold for COM or 0 if none - uint64_t _comRevocationThreshold; - - // Remote member's latest network COM - CertificateOfMembership _com; - - // Sorted (in ascending order of ID) arrays of pointers to remote credentials - _RemoteCredential *_remoteTags[ZT_MAX_NETWORK_TAGS]; - _RemoteCredential *_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]; - _RemoteCredential *_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; - - // This is the RAM allocated for remote credential cache objects - _RemoteCredential _tagMem[ZT_MAX_NETWORK_TAGS]; - _RemoteCredential _capMem[ZT_MAX_NETWORK_CAPABILITIES]; - _RemoteCredential _cooMem[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; - - // Local credential push state tracking - _LocalCredentialPushState _localTags[ZT_MAX_NETWORK_TAGS]; - _LocalCredentialPushState _localCaps[ZT_MAX_NETWORK_CAPABILITIES]; - _LocalCredentialPushState _localCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/MulticastGroup.hpp b/zto/node/MulticastGroup.hpp deleted file mode 100644 index be4e808..0000000 --- a/zto/node/MulticastGroup.hpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_MULTICASTGROUP_HPP -#define ZT_MULTICASTGROUP_HPP - -#include - -#include - -#include "MAC.hpp" -#include "InetAddress.hpp" - -namespace ZeroTier { - -/** - * A multicast group composed of a multicast MAC and a 32-bit ADI field - * - * ADI stands for additional distinguishing information. ADI is primarily for - * adding additional information to broadcast (ff:ff:ff:ff:ff:ff) memberships, - * since straight-up broadcast won't scale. Right now it's zero except for - * IPv4 ARP, where it holds the IPv4 address itself to make ARP into a - * selective multicast query that can scale. - * - * In the future we might add some kind of plugin architecture that can add - * ADI for things like mDNS (multicast DNS) to improve the selectivity of - * those protocols. - * - * MulticastGroup behaves as an immutable value object. - */ -class MulticastGroup -{ -public: - MulticastGroup() - throw() : - _mac(), - _adi(0) - { - } - - MulticastGroup(const MAC &m,uint32_t a) - throw() : - _mac(m), - _adi(a) - { - } - - /** - * Derive the multicast group used for address resolution (ARP/NDP) for an IP - * - * @param ip IP address (port field is ignored) - * @return Multicat group for ARP/NDP - */ - static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip) - throw() - { - if (ip.isV4()) { - // IPv4 wants broadcast MACs, so we shove the V4 address itself into - // the Multicast Group ADI field. Making V4 ARP work is basically why - // ADI was added, as well as handling other things that want mindless - // Ethernet broadcast to all. - return MulticastGroup(MAC(0xffffffffffffULL),Utils::ntoh(*((const uint32_t *)ip.rawIpData()))); - } else if (ip.isV6()) { - // IPv6 is better designed in this respect. We can compute the IPv6 - // multicast address directly from the IP address, and it gives us - // 24 bits of uniqueness. Collisions aren't likely to be common enough - // to care about. - const unsigned char *a = (const unsigned char *)ip.rawIpData(); - return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0); - } - return MulticastGroup(); - } - - /** - * @return Human readable string representing this group (MAC/ADI in hex) - */ - inline std::string toString() const - { - char buf[64]; - Utils::snprintf(buf,sizeof(buf),"%.2x%.2x%.2x%.2x%.2x%.2x/%.8lx",(unsigned int)_mac[0],(unsigned int)_mac[1],(unsigned int)_mac[2],(unsigned int)_mac[3],(unsigned int)_mac[4],(unsigned int)_mac[5],(unsigned long)_adi); - return std::string(buf); - } - - /** - * @return Multicast address - */ - inline const MAC &mac() const throw() { return _mac; } - - /** - * @return Additional distinguishing information - */ - inline uint32_t adi() const throw() { return _adi; } - - inline unsigned long hashCode() const throw() { return (_mac.hashCode() ^ (unsigned long)_adi); } - - inline bool operator==(const MulticastGroup &g) const throw() { return ((_mac == g._mac)&&(_adi == g._adi)); } - inline bool operator!=(const MulticastGroup &g) const throw() { return ((_mac != g._mac)||(_adi != g._adi)); } - inline bool operator<(const MulticastGroup &g) const throw() - { - if (_mac < g._mac) - return true; - else if (_mac == g._mac) - return (_adi < g._adi); - return false; - } - inline bool operator>(const MulticastGroup &g) const throw() { return (g < *this); } - inline bool operator<=(const MulticastGroup &g) const throw() { return !(g < *this); } - inline bool operator>=(const MulticastGroup &g) const throw() { return !(*this < g); } - -private: - MAC _mac; - uint32_t _adi; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Multicaster.cpp b/zto/node/Multicaster.cpp deleted file mode 100644 index 8e534b5..0000000 --- a/zto/node/Multicaster.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "Constants.hpp" -#include "RuntimeEnvironment.hpp" -#include "SharedPtr.hpp" -#include "Multicaster.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Packet.hpp" -#include "Peer.hpp" -#include "C25519.hpp" -#include "CertificateOfMembership.hpp" -#include "Node.hpp" - -namespace ZeroTier { - -Multicaster::Multicaster(const RuntimeEnvironment *renv) : - RR(renv), - _groups(256), - _gatherAuth(256) -{ -} - -Multicaster::~Multicaster() -{ -} - -void Multicaster::addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) -{ - const unsigned char *p = (const unsigned char *)addresses; - const unsigned char *e = p + (5 * count); - Mutex::Lock _l(_groups_m); - MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)]; - while (p != e) { - _add(tPtr,now,nwid,mg,gs,Address(p,5)); - p += 5; - } -} - -void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &member) -{ - Mutex::Lock _l(_groups_m); - MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg)); - if (s) { - for(std::vector::iterator m(s->members.begin());m!=s->members.end();++m) { - if (m->address == member) { - s->members.erase(m); - break; - } - } - } -} - -unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer &appendTo,unsigned int limit) const -{ - unsigned char *p; - unsigned int added = 0,i,k,rptr,totalKnown = 0; - uint64_t a,picked[(ZT_PROTO_MAX_PACKET_LENGTH / 5) + 2]; - - if (!limit) - return 0; - else if (limit > 0xffff) - limit = 0xffff; - - const unsigned int totalAt = appendTo.size(); - appendTo.addSize(4); // sizeof(uint32_t) - const unsigned int addedAt = appendTo.size(); - appendTo.addSize(2); // sizeof(uint16_t) - - { // Return myself if I am a member of this group - SharedPtr network(RR->node->network(nwid)); - if ((network)&&(network->subscribedToMulticastGroup(mg,true))) { - RR->identity.address().appendTo(appendTo); - ++totalKnown; - ++added; - } - } - - Mutex::Lock _l(_groups_m); - - const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg)); - if ((s)&&(!s->members.empty())) { - totalKnown += (unsigned int)s->members.size(); - - // Members are returned in random order so that repeated gather queries - // will return different subsets of a large multicast group. - k = 0; - while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_UDP_DEFAULT_PAYLOAD_MTU)) { - rptr = (unsigned int)RR->node->prng(); - -restart_member_scan: - a = s->members[rptr % (unsigned int)s->members.size()].address.toInt(); - for(i=0;i> 32) & 0xff); - *(p++) = (unsigned char)((a >> 24) & 0xff); - *(p++) = (unsigned char)((a >> 16) & 0xff); - *(p++) = (unsigned char)((a >> 8) & 0xff); - *p = (unsigned char)(a & 0xff); - ++added; - } - } - } - - appendTo.setAt(totalAt,(uint32_t)totalKnown); - appendTo.setAt(addedAt,(uint16_t)added); - - //TRACE("..MC Multicaster::gather() attached %u of %u peers for %.16llx/%s (2)",n,(unsigned int)(gs->second.members.size() - skipped),nwid,mg.toString().c_str()); - - return added; -} - -std::vector
Multicaster::getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const -{ - std::vector
ls; - Mutex::Lock _l(_groups_m); - const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg)); - if (!s) - return ls; - for(std::vector::const_reverse_iterator m(s->members.rbegin());m!=s->members.rend();++m) { - ls.push_back(m->address); - if (ls.size() >= limit) - break; - } - return ls; -} - -void Multicaster::send( - void *tPtr, - unsigned int limit, - uint64_t now, - uint64_t nwid, - bool disableCompression, - const std::vector
&alwaysSendTo, - const MulticastGroup &mg, - const MAC &src, - unsigned int etherType, - const void *data, - unsigned int len) -{ - unsigned long idxbuf[8194]; - unsigned long *indexes = idxbuf; - - try { - Mutex::Lock _l(_groups_m); - MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)]; - - if (!gs.members.empty()) { - // Allocate a memory buffer if group is monstrous - if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long))) - indexes = new unsigned long[gs.members.size()]; - - // Generate a random permutation of member indexes - for(unsigned long i=0;i0;--i) { - unsigned long j = (unsigned long)RR->node->prng() % (i + 1); - unsigned long tmp = indexes[j]; - indexes[j] = indexes[i]; - indexes[i] = tmp; - } - } - - if (gs.members.size() >= limit) { - // Skip queue if we already have enough members to complete the send operation - OutboundMulticast out; - - out.init( - RR, - now, - nwid, - disableCompression, - limit, - 1, // we'll still gather a little from peers to keep multicast list fresh - src, - mg, - etherType, - data, - len); - - unsigned int count = 0; - - for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { - if (*ast != RR->identity.address()) { - out.sendOnly(RR,tPtr,*ast); // optimization: don't use dedup log if it's a one-pass send - if (++count >= limit) - break; - } - } - - unsigned long idx = 0; - while ((count < limit)&&(idx < gs.members.size())) { - Address ma(gs.members[indexes[idx++]].address); - if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) { - out.sendOnly(RR,tPtr,ma); // optimization: don't use dedup log if it's a one-pass send - ++count; - } - } - } else { - unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1; - - if ((gs.members.empty())||((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY)) { - gs.lastExplicitGather = now; - - Address explicitGatherPeers[16]; - unsigned int numExplicitGatherPeers = 0; - SharedPtr bestRoot(RR->topology->getUpstreamPeer()); - if (bestRoot) - explicitGatherPeers[numExplicitGatherPeers++] = bestRoot->address(); - explicitGatherPeers[numExplicitGatherPeers++] = Network::controllerFor(nwid); - SharedPtr network(RR->node->network(nwid)); - if (network) { - std::vector
anchors(network->config().anchors()); - for(std::vector
::const_iterator a(anchors.begin());a!=anchors.end();++a) { - if (*a != RR->identity.address()) { - explicitGatherPeers[numExplicitGatherPeers++] = *a; - if (numExplicitGatherPeers == 16) - break; - } - } - } - - for(unsigned int k=0;kconfig().com) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0; - Packet outp(explicitGatherPeers[k],RR->identity.address(),Packet::VERB_MULTICAST_GATHER); - outp.append(nwid); - outp.append((uint8_t)((com) ? 0x01 : 0x00)); - mg.mac().appendTo(outp); - outp.append((uint32_t)mg.adi()); - outp.append((uint32_t)gatherLimit); - if (com) - com->serialize(outp); - RR->node->expectReplyTo(outp.packetId()); - RR->sw->send(tPtr,outp,true); - } - } - - gs.txQueue.push_back(OutboundMulticast()); - OutboundMulticast &out = gs.txQueue.back(); - - out.init( - RR, - now, - nwid, - disableCompression, - limit, - gatherLimit, - src, - mg, - etherType, - data, - len); - - unsigned int count = 0; - - for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { - if (*ast != RR->identity.address()) { - out.sendAndLog(RR,tPtr,*ast); - if (++count >= limit) - break; - } - } - - unsigned long idx = 0; - while ((count < limit)&&(idx < gs.members.size())) { - Address ma(gs.members[indexes[idx++]].address); - if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) { - out.sendAndLog(RR,tPtr,ma); - ++count; - } - } - } - } catch ( ... ) {} // this is a sanity check to catch any failures and make sure indexes[] still gets deleted - - // Free allocated memory buffer if any - if (indexes != idxbuf) - delete [] indexes; -} - -void Multicaster::clean(uint64_t now) -{ - { - Mutex::Lock _l(_groups_m); - Multicaster::Key *k = (Multicaster::Key *)0; - MulticastGroupStatus *s = (MulticastGroupStatus *)0; - Hashtable::Iterator mm(_groups); - while (mm.next(k,s)) { - for(std::list::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) { - if ((tx->expired(now))||(tx->atLimit())) - s->txQueue.erase(tx++); - else ++tx; - } - - unsigned long count = 0; - { - std::vector::iterator reader(s->members.begin()); - std::vector::iterator writer(reader); - while (reader != s->members.end()) { - if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) { - *writer = *reader; - ++writer; - ++count; - } - ++reader; - } - } - - if (count) { - s->members.resize(count); - } else if (s->txQueue.empty()) { - _groups.erase(*k); - } else { - s->members.clear(); - } - } - } - - { - Mutex::Lock _l(_gatherAuth_m); - _GatherAuthKey *k = (_GatherAuthKey *)0; - uint64_t *ts = NULL; - Hashtable<_GatherAuthKey,uint64_t>::Iterator i(_gatherAuth); - while (i.next(k,ts)) { - if ((now - *ts) >= ZT_MULTICAST_CREDENTIAL_EXPIRATON) - _gatherAuth.erase(*k); - } - } -} - -void Multicaster::addCredential(void *tPtr,const CertificateOfMembership &com,bool alreadyValidated) -{ - if ((alreadyValidated)||(com.verify(RR,tPtr) == 0)) { - Mutex::Lock _l(_gatherAuth_m); - _gatherAuth[_GatherAuthKey(com.networkId(),com.issuedTo())] = RR->node->now(); - } -} - -void Multicaster::_add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) -{ - // assumes _groups_m is locked - - // Do not add self -- even if someone else returns it - if (member == RR->identity.address()) - return; - - for(std::vector::iterator m(gs.members.begin());m!=gs.members.end();++m) { - if (m->address == member) { - m->timestamp = now; - return; - } - } - - gs.members.push_back(MulticastGroupMember(member,now)); - - //TRACE("..MC %s joined multicast group %.16llx/%s via %s",member.toString().c_str(),nwid,mg.toString().c_str(),((learnedFrom) ? learnedFrom.toString().c_str() : "(direct)")); - - for(std::list::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) { - if (tx->atLimit()) - gs.txQueue.erase(tx++); - else { - tx->sendIfNew(RR,tPtr,member); - if (tx->atLimit()) - gs.txQueue.erase(tx++); - else ++tx; - } - } -} - -} // namespace ZeroTier diff --git a/zto/node/Multicaster.hpp b/zto/node/Multicaster.hpp deleted file mode 100644 index f646a5b..0000000 --- a/zto/node/Multicaster.hpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_MULTICASTER_HPP -#define ZT_MULTICASTER_HPP - -#include -#include - -#include -#include -#include - -#include "Constants.hpp" -#include "Hashtable.hpp" -#include "Address.hpp" -#include "MAC.hpp" -#include "MulticastGroup.hpp" -#include "OutboundMulticast.hpp" -#include "Utils.hpp" -#include "Mutex.hpp" -#include "NonCopyable.hpp" - -namespace ZeroTier { - -class RuntimeEnvironment; -class CertificateOfMembership; -class Packet; - -/** - * Database of known multicast peers within a network - */ -class Multicaster : NonCopyable -{ -private: - struct Key - { - Key() : nwid(0),mg() {} - Key(uint64_t n,const MulticastGroup &g) : nwid(n),mg(g) {} - - uint64_t nwid; - MulticastGroup mg; - - inline bool operator==(const Key &k) const throw() { return ((nwid == k.nwid)&&(mg == k.mg)); } - inline unsigned long hashCode() const throw() { return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32))); } - }; - - struct MulticastGroupMember - { - MulticastGroupMember() {} - MulticastGroupMember(const Address &a,uint64_t ts) : address(a),timestamp(ts) {} - - Address address; - uint64_t timestamp; // time of last notification - }; - - struct MulticastGroupStatus - { - MulticastGroupStatus() : lastExplicitGather(0) {} - - uint64_t lastExplicitGather; - std::list txQueue; // pending outbound multicasts - std::vector members; // members of this group - }; - -public: - Multicaster(const RuntimeEnvironment *renv); - ~Multicaster(); - - /** - * Add or update a member in a multicast group - * - * @param now Current time - * @param nwid Network ID - * @param mg Multicast group - * @param member New member address - */ - inline void add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) - { - Mutex::Lock _l(_groups_m); - _add(tPtr,now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member); - } - - /** - * Add multiple addresses from a binary array of 5-byte address fields - * - * It's up to the caller to check bounds on the array before calling this. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - * @param nwid Network ID - * @param mg Multicast group - * @param addresses Raw binary addresses in big-endian format, as a series of 5-byte fields - * @param count Number of addresses - * @param totalKnown Total number of known addresses as reported by peer - */ - void addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); - - /** - * Remove a multicast group member (if present) - * - * @param nwid Network ID - * @param mg Multicast group - * @param member Member to unsubscribe - */ - void remove(uint64_t nwid,const MulticastGroup &mg,const Address &member); - - /** - * Append gather results to a packet by choosing registered multicast recipients at random - * - * This appends the following fields to the packet: - * <[4] 32-bit total number of known members in this multicast group> - * <[2] 16-bit number of members enumerated in this packet> - * <[...] series of 5-byte ZeroTier addresses of enumerated members> - * - * If zero is returned, the first two fields will still have been appended. - * - * @param queryingPeer Peer asking for gather (to skip in results) - * @param nwid Network ID - * @param mg Multicast group - * @param appendTo Packet to append to - * @param limit Maximum number of 5-byte addresses to append - * @return Number of addresses appended - * @throws std::out_of_range Buffer overflow writing to packet - */ - unsigned int gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer &appendTo,unsigned int limit) const; - - /** - * Get subscribers to a multicast group - * - * @param nwid Network ID - * @param mg Multicast group - */ - std::vector
getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const; - - /** - * Send a multicast - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param limit Multicast limit - * @param now Current time - * @param nwid Network ID - * @param disableCompression Disable packet payload compression? - * @param alwaysSendTo Send to these peers first and even if not included in subscriber list - * @param mg Multicast group - * @param src Source Ethernet MAC address or NULL to skip in packet and compute from ZT address (non-bridged mode) - * @param etherType Ethernet frame type - * @param data Packet data - * @param len Length of packet data - */ - void send( - void *tPtr, - unsigned int limit, - uint64_t now, - uint64_t nwid, - bool disableCompression, - const std::vector
&alwaysSendTo, - const MulticastGroup &mg, - const MAC &src, - unsigned int etherType, - const void *data, - unsigned int len); - - /** - * Clean up and resort database - * - * @param RR Runtime environment - * @param now Current time - */ - void clean(uint64_t now); - - /** - * Add an authorization credential - * - * The Multicaster keeps its own track of when valid credentials of network - * membership are presented. This allows it to control MULTICAST_LIKE - * GATHER authorization for networks this node does not belong to. - * - * @param com Certificate of membership - * @param alreadyValidated If true, COM has already been checked and found to be valid and signed - */ - void addCredential(void *tPtr,const CertificateOfMembership &com,bool alreadyValidated); - - /** - * Check authorization for GATHER and LIKE for non-network-members - * - * @param a Address of peer - * @param nwid Network ID - * @param now Current time - * @return True if GATHER and LIKE should be allowed - */ - bool cacheAuthorized(const Address &a,const uint64_t nwid,const uint64_t now) const - { - Mutex::Lock _l(_gatherAuth_m); - const uint64_t *p = _gatherAuth.get(_GatherAuthKey(nwid,a)); - return ((p)&&((now - *p) < ZT_MULTICAST_CREDENTIAL_EXPIRATON)); - } - -private: - void _add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); - - const RuntimeEnvironment *RR; - - Hashtable _groups; - Mutex _groups_m; - - struct _GatherAuthKey - { - _GatherAuthKey() : member(0),networkId(0) {} - _GatherAuthKey(const uint64_t nwid,const Address &a) : member(a.toInt()),networkId(nwid) {} - inline unsigned long hashCode() const { return (unsigned long)(member ^ networkId); } - inline bool operator==(const _GatherAuthKey &k) const { return ((member == k.member)&&(networkId == k.networkId)); } - uint64_t member; - uint64_t networkId; - }; - Hashtable< _GatherAuthKey,uint64_t > _gatherAuth; - Mutex _gatherAuth_m; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Mutex.hpp b/zto/node/Mutex.hpp deleted file mode 100644 index d451ede..0000000 --- a/zto/node/Mutex.hpp +++ /dev/null @@ -1,186 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_MUTEX_HPP -#define ZT_MUTEX_HPP - -#include "Constants.hpp" -#include "NonCopyable.hpp" - -#ifdef __UNIX_LIKE__ - -#include -#include - -namespace ZeroTier { - -class Mutex : NonCopyable -{ -public: - Mutex() - throw() - { - pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); - } - - ~Mutex() - { - pthread_mutex_destroy(&_mh); - } - - inline void lock() - throw() - { - pthread_mutex_lock(&_mh); - } - - inline void unlock() - throw() - { - pthread_mutex_unlock(&_mh); - } - - inline void lock() const - throw() - { - (const_cast (this))->lock(); - } - - inline void unlock() const - throw() - { - (const_cast (this))->unlock(); - } - - /** - * Uses C++ contexts and constructor/destructor to lock/unlock automatically - */ - class Lock : NonCopyable - { - public: - Lock(Mutex &m) - throw() : - _m(&m) - { - m.lock(); - } - - Lock(const Mutex &m) - throw() : - _m(const_cast(&m)) - { - _m->lock(); - } - - ~Lock() - { - _m->unlock(); - } - - private: - Mutex *const _m; - }; - -private: - pthread_mutex_t _mh; -}; - -} // namespace ZeroTier - -#endif // Apple / Linux - -#ifdef __WINDOWS__ - -#include -#include - -namespace ZeroTier { - -class Mutex : NonCopyable -{ -public: - Mutex() - throw() - { - InitializeCriticalSection(&_cs); - } - - ~Mutex() - { - DeleteCriticalSection(&_cs); - } - - inline void lock() - throw() - { - EnterCriticalSection(&_cs); - } - - inline void unlock() - throw() - { - LeaveCriticalSection(&_cs); - } - - inline void lock() const - throw() - { - (const_cast (this))->lock(); - } - - inline void unlock() const - throw() - { - (const_cast (this))->unlock(); - } - - class Lock : NonCopyable - { - public: - Lock(Mutex &m) - throw() : - _m(&m) - { - m.lock(); - } - - Lock(const Mutex &m) - throw() : - _m(const_cast(&m)) - { - _m->lock(); - } - - ~Lock() - { - _m->unlock(); - } - - private: - Mutex *const _m; - }; - -private: - CRITICAL_SECTION _cs; -}; - -} // namespace ZeroTier - -#endif // _WIN32 - -#endif diff --git a/zto/node/Network.cpp b/zto/node/Network.cpp deleted file mode 100644 index 0abfdf8..0000000 --- a/zto/node/Network.cpp +++ /dev/null @@ -1,1615 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include - -#include "Constants.hpp" -#include "../version.h" -#include "Network.hpp" -#include "RuntimeEnvironment.hpp" -#include "MAC.hpp" -#include "Address.hpp" -#include "InetAddress.hpp" -#include "Switch.hpp" -#include "Buffer.hpp" -#include "Packet.hpp" -#include "NetworkController.hpp" -#include "Node.hpp" -#include "Peer.hpp" -#include "Cluster.hpp" - -// Uncomment to make the rules engine dump trace info to stdout -//#define ZT_RULES_ENGINE_DEBUGGING 1 - -namespace ZeroTier { - -namespace { - -#ifdef ZT_RULES_ENGINE_DEBUGGING -#define FILTER_TRACE(f,...) { Utils::snprintf(dpbuf,sizeof(dpbuf),f,##__VA_ARGS__); dlog.push_back(std::string(dpbuf)); } -static const char *_rtn(const ZT_VirtualNetworkRuleType rt) -{ - switch(rt) { - case ZT_NETWORK_RULE_ACTION_DROP: return "ACTION_DROP"; - case ZT_NETWORK_RULE_ACTION_ACCEPT: return "ACTION_ACCEPT"; - case ZT_NETWORK_RULE_ACTION_TEE: return "ACTION_TEE"; - case ZT_NETWORK_RULE_ACTION_WATCH: return "ACTION_WATCH"; - case ZT_NETWORK_RULE_ACTION_REDIRECT: return "ACTION_REDIRECT"; - case ZT_NETWORK_RULE_ACTION_BREAK: return "ACTION_BREAK"; - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: return "MATCH_SOURCE_ZEROTIER_ADDRESS"; - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: return "MATCH_DEST_ZEROTIER_ADDRESS"; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: return "MATCH_VLAN_ID"; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: return "MATCH_VLAN_PCP"; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: return "MATCH_VLAN_DEI"; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: return "MATCH_MAC_SOURCE"; - case ZT_NETWORK_RULE_MATCH_MAC_DEST: return "MATCH_MAC_DEST"; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: return "MATCH_IPV4_SOURCE"; - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: return "MATCH_IPV4_DEST"; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: return "MATCH_IPV6_SOURCE"; - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: return "MATCH_IPV6_DEST"; - case ZT_NETWORK_RULE_MATCH_IP_TOS: return "MATCH_IP_TOS"; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: return "MATCH_IP_PROTOCOL"; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: return "MATCH_ETHERTYPE"; - case ZT_NETWORK_RULE_MATCH_ICMP: return "MATCH_ICMP"; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: return "MATCH_IP_SOURCE_PORT_RANGE"; - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: return "MATCH_IP_DEST_PORT_RANGE"; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: return "MATCH_CHARACTERISTICS"; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: return "MATCH_FRAME_SIZE_RANGE"; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: return "MATCH_TAGS_DIFFERENCE"; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: return "MATCH_TAGS_BITWISE_AND"; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: return "MATCH_TAGS_BITWISE_OR"; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: return "MATCH_TAGS_BITWISE_XOR"; - default: return "???"; - } -} -static const void _dumpFilterTrace(const char *ruleName,uint8_t thisSetMatches,bool inbound,const Address &ztSource,const Address &ztDest,const MAC &macSource,const MAC &macDest,const std::vector &dlog,unsigned int frameLen,unsigned int etherType,const char *msg) -{ - static volatile unsigned long cnt = 0; - printf("%.6lu %c %s %s frameLen=%u etherType=%u" ZT_EOL_S, - cnt++, - ((thisSetMatches) ? 'Y' : '.'), - ruleName, - ((inbound) ? "INBOUND" : "OUTBOUND"), - frameLen, - etherType - ); - for(std::vector::const_iterator m(dlog.begin());m!=dlog.end();++m) - printf(" | %s" ZT_EOL_S,m->c_str()); - printf(" + %c %s->%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x->%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" ZT_EOL_S, - ((thisSetMatches) ? 'Y' : '.'), - ztSource.toString().c_str(), - ztDest.toString().c_str(), - (unsigned int)macSource[0], - (unsigned int)macSource[1], - (unsigned int)macSource[2], - (unsigned int)macSource[3], - (unsigned int)macSource[4], - (unsigned int)macSource[5], - (unsigned int)macDest[0], - (unsigned int)macDest[1], - (unsigned int)macDest[2], - (unsigned int)macDest[3], - (unsigned int)macDest[4], - (unsigned int)macDest[5] - ); - if (msg) - printf(" + (%s)" ZT_EOL_S,msg); - fflush(stdout); -} -#else -#define FILTER_TRACE(f,...) {} -#endif // ZT_RULES_ENGINE_DEBUGGING - -// Returns true if packet appears valid; pos and proto will be set -static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto) -{ - if (frameLen < 40) - return false; - pos = 40; - proto = frameData[6]; - while (pos <= frameLen) { - switch(proto) { - case 0: // hop-by-hop options - case 43: // routing - case 60: // destination options - case 135: // mobility options - if ((pos + 8) > frameLen) - return false; // invalid! - proto = frameData[pos]; - pos += ((unsigned int)frameData[pos + 1] * 8) + 8; - break; - - //case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway - //case 50: - //case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff - default: - return true; - } - } - return false; // overflow == invalid -} - -enum _doZtFilterResult -{ - DOZTFILTER_NO_MATCH, - DOZTFILTER_DROP, - DOZTFILTER_REDIRECT, - DOZTFILTER_ACCEPT, - DOZTFILTER_SUPER_ACCEPT -}; -static _doZtFilterResult _doZtFilter( - const RuntimeEnvironment *RR, - const NetworkConfig &nconf, - const Membership *membership, // can be NULL - const bool inbound, - const Address &ztSource, - Address &ztDest, // MUTABLE -- is changed on REDIRECT actions - const MAC &macSource, - const MAC &macDest, - const uint8_t *const frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId, - const ZT_VirtualNetworkRule *rules, // cannot be NULL - const unsigned int ruleCount, - Address &cc, // MUTABLE -- set to TEE destination if TEE action is taken or left alone otherwise - unsigned int &ccLength, // MUTABLE -- set to length of packet payload to TEE - bool &ccWatch) // MUTABLE -- set to true for WATCH target as opposed to normal TEE -{ -#ifdef ZT_RULES_ENGINE_DEBUGGING - char dpbuf[1024]; // used by FILTER_TRACE macro - std::vector dlog; -#endif // ZT_RULES_ENGINE_DEBUGGING - - // Set to true if we are a TEE/REDIRECT/WATCH target - bool superAccept = false; - - // The default match state for each set of entries starts as 'true' since an - // ACTION with no MATCH entries preceding it is always taken. - uint8_t thisSetMatches = 1; - - for(unsigned int rn=0;rnidentity.address()) { - if (inbound) { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"interpreted as super-ACCEPT on inbound since we are target"); -#endif // ZT_RULES_ENGINE_DEBUGGING - return DOZTFILTER_SUPER_ACCEPT; - } else { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"skipped as no-op on outbound since we are target"); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING - } - } else if (fwdAddr == ztDest) { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"skipped as no-op because destination is already target"); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING - } else { - if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_REDIRECT",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); -#endif // ZT_RULES_ENGINE_DEBUGGING - ztDest = fwdAddr; - return DOZTFILTER_REDIRECT; - } else { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING - cc = fwdAddr; - ccLength = (rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen; - ccWatch = (rt == ZT_NETWORK_RULE_ACTION_WATCH); - } - } - } continue; - - case ZT_NETWORK_RULE_ACTION_BREAK: -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_BREAK",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING - return DOZTFILTER_NO_MATCH; - - // Unrecognized ACTIONs are ignored as no-ops - default: -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING - continue; - } - } else { - // If this is an incoming packet and we are a TEE or REDIRECT target, we should - // super-accept if we accept at all. This will cause us to accept redirected or - // tee'd packets in spite of MAC and ZT addressing checks. - if (inbound) { - switch(rt) { - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_WATCH: - case ZT_NETWORK_RULE_ACTION_REDIRECT: - if (RR->identity.address() == rules[rn].v.fwd.address) - superAccept = true; - break; - default: - break; - } - } - -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING - thisSetMatches = 1; // reset to default true for next batch of entries - continue; - } - } - - // Circuit breaker: no need to evaluate an AND if the set's match state - // is currently false since anything AND false is false. - if ((!thisSetMatches)&&(!(rules[rn].t & 0x40))) - continue; - - // If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result]) - uint8_t thisRuleMatches = 0; - uint64_t ownershipVerificationMask = 1; // this magic value means it hasn't been computed yet -- this is done lazily the first time it's needed - switch(rt) { - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt()); - FILTER_TRACE("%u %s %c %.10llx==%.10llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.zt,ztSource.toInt(),(unsigned int)thisRuleMatches); - break; - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztDest.toInt()); - FILTER_TRACE("%u %s %c %.10llx==%.10llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.zt,ztDest.toInt(),(unsigned int)thisRuleMatches); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - thisRuleMatches = (uint8_t)(rules[rn].v.vlanId == (uint16_t)vlanId); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.vlanId,(unsigned int)vlanId,(unsigned int)thisRuleMatches); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - // NOT SUPPORTED YET - thisRuleMatches = (uint8_t)(rules[rn].v.vlanPcp == 0); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.vlanPcp,0,(unsigned int)thisRuleMatches); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - // NOT SUPPORTED YET - thisRuleMatches = (uint8_t)(rules[rn].v.vlanDei == 0); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.vlanDei,0,(unsigned int)thisRuleMatches); - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macSource); - FILTER_TRACE("%u %s %c %.12llx=%.12llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.mac,macSource.toInt(),(unsigned int)thisRuleMatches); - break; - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macDest); - FILTER_TRACE("%u %s %c %.12llx=%.12llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.mac,macDest.toInt(),(unsigned int)thisRuleMatches); - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 12),4,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).toString().c_str(),InetAddress((const void *)(frameData + 12),4,0).toIpString().c_str(),(unsigned int)thisRuleMatches); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv4] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - break; - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 16),4,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).toString().c_str(),InetAddress((const void *)(frameData + 16),4,0).toIpString().c_str(),(unsigned int)thisRuleMatches); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv4] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 8),16,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).toString().c_str(),InetAddress((const void *)(frameData + 8),16,0).toIpString().c_str(),(unsigned int)thisRuleMatches); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - break; - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 24),16,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).toString().c_str(),InetAddress((const void *)(frameData + 24),16,0).toIpString().c_str(),(unsigned int)thisRuleMatches); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - //thisRuleMatches = (uint8_t)(rules[rn].v.ipTos == ((frameData[1] & 0xfc) >> 2)); - const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask; - thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); - FILTER_TRACE("%u %s %c (IPv4) %u&%u==%u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)tosMasked,(unsigned int)rules[rn].v.ipTos.mask,(unsigned int)rules[rn].v.ipTos.value[0],(unsigned int)rules[rn].v.ipTos.value[1],(unsigned int)thisRuleMatches); - } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { - const uint8_t tosMasked = (((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f)) & rules[rn].v.ipTos.mask; - thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); - FILTER_TRACE("%u %s %c (IPv4) %u&%u==%u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)tosMasked,(unsigned int)rules[rn].v.ipTos.mask,(unsigned int)rules[rn].v.ipTos.value[0],(unsigned int)rules[rn].v.ipTos.value[1],(unsigned int)thisRuleMatches); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == frameData[9]); - FILTER_TRACE("%u %s %c (IPv4) %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.ipProtocol,(unsigned int)frameData[9],(unsigned int)thisRuleMatches); - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0,proto = 0; - if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { - thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto); - FILTER_TRACE("%u %s %c (IPv6) %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.ipProtocol,proto,(unsigned int)thisRuleMatches); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [invalid IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.etherType,etherType,(unsigned int)thisRuleMatches); - break; - case ZT_NETWORK_RULE_MATCH_ICMP: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - if (frameData[9] == 0x01) { // IP protocol == ICMP - const unsigned int ihl = (frameData[0] & 0xf) * 4; - if (frameLen >= (ihl + 2)) { - if (rules[rn].v.icmp.type == frameData[ihl]) { - if ((rules[rn].v.icmp.flags & 0x01) != 0) { - thisRuleMatches = (uint8_t)(frameData[ihl+1] == rules[rn].v.icmp.code); - } else { - thisRuleMatches = 1; - } - } else { - thisRuleMatches = 0; - } - FILTER_TRACE("%u %s %c (IPv4) icmp-type:%d==%d icmp-code:%d==%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(int)frameData[ihl],(int)rules[rn].v.icmp.type,(int)frameData[ihl+1],(((rules[rn].v.icmp.flags & 0x01) != 0) ? (int)rules[rn].v.icmp.code : -1),(unsigned int)thisRuleMatches); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [IPv4 frame invalid] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not ICMP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0,proto = 0; - if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { - if ((proto == 0x3a)&&(frameLen >= (pos+2))) { - if (rules[rn].v.icmp.type == frameData[pos]) { - if ((rules[rn].v.icmp.flags & 0x01) != 0) { - thisRuleMatches = (uint8_t)(frameData[pos+1] == rules[rn].v.icmp.code); - } else { - thisRuleMatches = 1; - } - } else { - thisRuleMatches = 0; - } - FILTER_TRACE("%u %s %c (IPv6) icmp-type:%d==%d icmp-code:%d==%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(int)frameData[pos],(int)rules[rn].v.icmp.type,(int)frameData[pos+1],(((rules[rn].v.icmp.flags & 0x01) != 0) ? (int)rules[rn].v.icmp.code : -1),(unsigned int)thisRuleMatches); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not ICMPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [invalid IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - break; - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - const unsigned int headerLen = 4 * (frameData[0] & 0xf); - int p = -1; - switch(frameData[9]) { // IP protocol number - // All these start with 16-bit source and destination port in that order - case 0x06: // TCP - case 0x11: // UDP - case 0x84: // SCTP - case 0x88: // UDPLite - if (frameLen > (headerLen + 4)) { - unsigned int pos = headerLen + ((rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) ? 2 : 0); - p = (int)frameData[pos++] << 8; - p |= (int)frameData[pos]; - } - break; - } - - thisRuleMatches = (p >= 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0; - FILTER_TRACE("%u %s %c (IPv4) %d in %d-%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),p,(int)rules[rn].v.port[0],(int)rules[rn].v.port[1],(unsigned int)thisRuleMatches); - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0,proto = 0; - if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { - int p = -1; - switch(proto) { // IP protocol number - // All these start with 16-bit source and destination port in that order - case 0x06: // TCP - case 0x11: // UDP - case 0x84: // SCTP - case 0x88: // UDPLite - if (frameLen > (pos + 4)) { - if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) pos += 2; - p = (int)frameData[pos++] << 8; - p |= (int)frameData[pos]; - } - break; - } - thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0; - FILTER_TRACE("%u %s %c (IPv6) %d in %d-%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),p,(int)rules[rn].v.port[0],(int)rules[rn].v.port[1],(unsigned int)thisRuleMatches); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [invalid IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: { - uint64_t cf = (inbound) ? ZT_RULE_PACKET_CHARACTERISTICS_INBOUND : 0ULL; - if (macDest.isMulticast()) cf |= ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST; - if (macDest.isBroadcast()) cf |= ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST; - if (ownershipVerificationMask == 1) { - ownershipVerificationMask = 0; - InetAddress src; - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - src.set((const void *)(frameData + 12),4,0); - } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { - // IPv6 NDP requires special handling, since the src and dest IPs in the packet are empty or link-local. - if ( (frameLen >= (40 + 8 + 16)) && (frameData[6] == 0x3a) && ((frameData[40] == 0x87)||(frameData[40] == 0x88)) ) { - if (frameData[40] == 0x87) { - // Neighbor solicitations contain no reliable source address, so we implement a small - // hack by considering them authenticated. Otherwise you would pretty much have to do - // this manually in the rule set for IPv6 to work at all. - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; - } else { - // Neighbor advertisements on the other hand can absolutely be authenticated. - src.set((const void *)(frameData + 40 + 8),16,0); - } - } else { - // Other IPv6 packets can be handled normally - src.set((const void *)(frameData + 8),16,0); - } - } else if ((etherType == ZT_ETHERTYPE_ARP)&&(frameLen >= 28)) { - src.set((const void *)(frameData + 14),4,0); - } - if (inbound) { - if (membership) { - if ((src)&&(membership->hasCertificateOfOwnershipFor(nconf,src))) - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; - if (membership->hasCertificateOfOwnershipFor(nconf,macSource)) - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED; - } - } else { - for(unsigned int i=0;i= 20)&&(frameData[9] == 0x06)) { - const unsigned int headerLen = 4 * (frameData[0] & 0xf); - cf |= (uint64_t)frameData[headerLen + 13]; - cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0f)) << 8); - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0,proto = 0; - if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { - if ((proto == 0x06)&&(frameLen > (pos + 14))) { - cf |= (uint64_t)frameData[pos + 13]; - cf |= (((uint64_t)(frameData[pos + 12] & 0x0f)) << 8); - } - } - } - thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics) != 0); - FILTER_TRACE("%u %s %c (%.16llx | %.16llx)!=0 -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),cf,rules[rn].v.characteristics,(unsigned int)thisRuleMatches); - } break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1])); - FILTER_TRACE("%u %s %c %u in %u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),frameLen,(unsigned int)rules[rn].v.frameSize[0],(unsigned int)rules[rn].v.frameSize[1],(unsigned int)thisRuleMatches); - break; - case ZT_NETWORK_RULE_MATCH_RANDOM: - thisRuleMatches = (uint8_t)((uint32_t)(RR->node->prng() & 0xffffffffULL) <= rules[rn].v.randomProbability); - FILTER_TRACE("%u %s %c -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)thisRuleMatches); - break; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: - case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: { - const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate()); - if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) { - const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); - if (remoteTag) { - const uint32_t ltv = localTag->value(); - const uint32_t rtv = remoteTag->value(); - if (rt == ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE) { - const uint32_t diff = (ltv > rtv) ? (ltv - rtv) : (rtv - ltv); - thisRuleMatches = (uint8_t)(diff <= rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%u remote:%u difference:%u<=%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,diff,(unsigned int)rules[rn].v.tag.value,thisRuleMatches); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) { - thisRuleMatches = (uint8_t)((ltv & rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x & remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR) { - thisRuleMatches = (uint8_t)((ltv | rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x | remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) { - thisRuleMatches = (uint8_t)((ltv ^ rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x ^ remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) { - thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value)&&(rtv == rules[rn].v.tag.value)); - FILTER_TRACE("%u %s %c TAG %u local:%.8x and remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); - } else { // sanity check, can't really happen - thisRuleMatches = 0; - } - } else { - if ((inbound)&&(!superAccept)) { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c remote tag %u not found -> 0 (inbound side is strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); - } else { - // Outbound side is not strict since if we have to match both tags and - // we are sending a first packet to a recipient, we probably do not know - // about their tags yet. They will filter on inbound and we will filter - // once we get their tag. If we are a tee/redirect target we are also - // not strict since we likely do not have these tags. - thisRuleMatches = 1; - FILTER_TRACE("%u %s %c remote tag %u not found -> 1 (outbound side and TEE/REDIRECT targets are not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); - } - } - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); - } - } break; - case ZT_NETWORK_RULE_MATCH_TAG_SENDER: - case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: { - if (superAccept) { - thisRuleMatches = 1; - FILTER_TRACE("%u %s %c we are a TEE/REDIRECT target -> 1",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); - } else if ( ((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER)&&(inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER)&&(!inbound)) ) { - const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); - if (remoteTag) { - thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u %.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,remoteTag->value(),(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); - } else { - if (rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) { - // If we are checking the receiver and this is an outbound packet, we - // can't be strict since we may not yet know the receiver's tag. - thisRuleMatches = 1; - FILTER_TRACE("%u %s %c (inbound) remote tag %u not found -> 1 (outbound receiver match is not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c (inbound) remote tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); - } - } - } else { // sender and outbound or receiver and inbound - const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate()); - if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) { - thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u %.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,localTag->value(),(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); - } else { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); - } - } - } break; - - // The result of an unsupported MATCH is configurable at the network - // level via a flag. - default: - thisRuleMatches = (uint8_t)((nconf.flags & ZT_NETWORKCONFIG_FLAG_RULES_RESULT_OF_UNSUPPORTED_MATCH) != 0); - break; - } - - if ((rules[rn].t & 0x40)) - thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); - else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); - } - - return DOZTFILTER_NO_MATCH; -} - -} // anonymous namespace - -const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL),0); - -Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr) : - RR(renv), - _uPtr(uptr), - _id(nwid), - _lastAnnouncedMulticastGroupsUpstream(0), - _mac(renv->identity.address(),nwid), - _portInitialized(false), - _lastConfigUpdate(0), - _destroyed(false), - _netconfFailure(NETCONF_FAILURE_NONE), - _portError(0) -{ - for(int i=0;i *dconf = new Dictionary(); - NetworkConfig *nconf = new NetworkConfig(); - try { - std::string conf(RR->node->dataStoreGet(tPtr,confn)); - if (conf.length()) { - dconf->load(conf.c_str()); - if (nconf->fromDictionary(*dconf)) { - this->setConfiguration(tPtr,*nconf,false); - _lastConfigUpdate = 0; // we still want to re-request a new config from the network - gotConf = true; - } - } - } catch ( ... ) {} // ignore invalids, we'll re-request - delete nconf; - delete dconf; - - if (!gotConf) { - // Save a one-byte CR to persist membership while we request a real netconf - RR->node->dataStorePut(tPtr,confn,"\n",1,false); - } - - if (!_portInitialized) { - ZT_VirtualNetworkConfig ctmp; - _externalConfig(&ctmp); - _portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); - _portInitialized = true; - } -} - -Network::~Network() -{ - ZT_VirtualNetworkConfig ctmp; - _externalConfig(&ctmp); - - char n[128]; - if (_destroyed) { - RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); - Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); - RR->node->dataStoreDelete((void *)0,n); - } else { - RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp); - } -} - -bool Network::filterOutgoingPacket( - void *tPtr, - const bool noTee, - const Address &ztSource, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId) -{ - const uint64_t now = RR->node->now(); - Address ztFinalDest(ztDest); - int localCapabilityIndex = -1; - bool accept = false; - - Mutex::Lock _l(_lock); - - Membership *const membership = (ztDest) ? _memberships.get(ztDest) : (Membership *)0; - - Address cc; - unsigned int ccLength = 0; - bool ccWatch = false; - switch(_doZtFilter(RR,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { - - case DOZTFILTER_NO_MATCH: - for(unsigned int c=0;c<_config.capabilityCount;++c) { - ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match - Address cc2; - unsigned int ccLength2 = 0; - bool ccWatch2 = false; - switch (_doZtFilter(RR,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),cc2,ccLength2,ccWatch2)) { - case DOZTFILTER_NO_MATCH: - case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern - break; - - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side - localCapabilityIndex = (int)c; - accept = true; - - if ((!noTee)&&(cc2)) { - Membership &m2 = _membership(cc2); - m2.pushCredentials(RR,tPtr,now,cc2,_config,localCapabilityIndex,false); - - Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch2 ? 0x16 : 0x02)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength2); - outp.compress(); - RR->sw->send(tPtr,outp,true); - } - - break; - } - if (accept) - break; - } - break; - - case DOZTFILTER_DROP: - return false; - - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side - accept = true; - break; - } - - if (accept) { - if (membership) - membership->pushCredentials(RR,tPtr,now,ztDest,_config,localCapabilityIndex,false); - - if ((!noTee)&&(cc)) { - Membership &m2 = _membership(cc); - m2.pushCredentials(RR,tPtr,now,cc,_config,localCapabilityIndex,false); - - Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch ? 0x16 : 0x02)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength); - outp.compress(); - RR->sw->send(tPtr,outp,true); - } - - if ((ztDest != ztFinalDest)&&(ztFinalDest)) { - Membership &m2 = _membership(ztFinalDest); - m2.pushCredentials(RR,tPtr,now,ztFinalDest,_config,localCapabilityIndex,false); - - Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)0x04); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,frameLen); - outp.compress(); - RR->sw->send(tPtr,outp,true); - - return false; // DROP locally, since we redirected - } else { - return true; - } - } else { - return false; - } -} - -int Network::filterIncomingPacket( - void *tPtr, - const SharedPtr &sourcePeer, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId) -{ - Address ztFinalDest(ztDest); - int accept = 0; - - Mutex::Lock _l(_lock); - - Membership &membership = _membership(sourcePeer->address()); - - Address cc; - unsigned int ccLength = 0; - bool ccWatch = false; - switch (_doZtFilter(RR,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { - - case DOZTFILTER_NO_MATCH: { - Membership::CapabilityIterator mci(membership,_config); - const Capability *c; - while ((c = mci.next())) { - ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match - Address cc2; - unsigned int ccLength2 = 0; - bool ccWatch2 = false; - switch(_doZtFilter(RR,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),cc2,ccLength2,ccWatch2)) { - case DOZTFILTER_NO_MATCH: - case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern - break; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - accept = 1; // ACCEPT - break; - case DOZTFILTER_SUPER_ACCEPT: - accept = 2; // super-ACCEPT - break; - } - - if (accept) { - if (cc2) { - _membership(cc2).pushCredentials(RR,tPtr,RR->node->now(),cc2,_config,-1,false); - - Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch2 ? 0x1c : 0x08)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength2); - outp.compress(); - RR->sw->send(tPtr,outp,true); - } - break; - } - } - } break; - - case DOZTFILTER_DROP: - return 0; // DROP - - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - accept = 1; // ACCEPT - break; - case DOZTFILTER_SUPER_ACCEPT: - accept = 2; // super-ACCEPT - break; - } - - if (accept) { - if (cc) { - _membership(cc).pushCredentials(RR,tPtr,RR->node->now(),cc,_config,-1,false); - - Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch ? 0x1c : 0x08)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength); - outp.compress(); - RR->sw->send(tPtr,outp,true); - } - - if ((ztDest != ztFinalDest)&&(ztFinalDest)) { - _membership(ztFinalDest).pushCredentials(RR,tPtr,RR->node->now(),ztFinalDest,_config,-1,false); - - Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)0x0a); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,frameLen); - outp.compress(); - RR->sw->send(tPtr,outp,true); - - return 0; // DROP locally, since we redirected - } - } - - return accept; -} - -bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const -{ - Mutex::Lock _l(_lock); - if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) - return true; - else if (includeBridgedGroups) - return _multicastGroupsBehindMe.contains(mg); - return false; -} - -void Network::multicastSubscribe(void *tPtr,const MulticastGroup &mg) -{ - Mutex::Lock _l(_lock); - if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) { - _myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg); - _sendUpdatesToMembers(tPtr,&mg); - } -} - -void Network::multicastUnsubscribe(const MulticastGroup &mg) -{ - Mutex::Lock _l(_lock); - std::vector::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)); - if ( (i != _myMulticastGroups.end()) && (*i == mg) ) - _myMulticastGroups.erase(i); -} - -uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr) -{ - const unsigned int start = ptr; - - ptr += 8; // skip network ID, which is already obviously known - const unsigned int chunkLen = chunk.at(ptr); ptr += 2; - const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen; - - NetworkConfig *nc = (NetworkConfig *)0; - uint64_t configUpdateId; - { - Mutex::Lock _l(_lock); - - _IncomingConfigChunk *c = (_IncomingConfigChunk *)0; - uint64_t chunkId = 0; - unsigned long totalLength,chunkIndex; - if (ptr < chunk.size()) { - const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0); - configUpdateId = chunk.at(ptr); ptr += 8; - totalLength = chunk.at(ptr); ptr += 4; - chunkIndex = chunk.at(ptr); ptr += 4; - - if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) { // >= since we need room for a null at the end - TRACE("discarded chunk from %s: invalid length or length overflow",source.toString().c_str()); - return 0; - } - - if ((chunk[ptr] != 1)||(chunk.at(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) { - TRACE("discarded chunk from %s: unrecognized signature type",source.toString().c_str()); - return 0; - } - const uint8_t *sig = reinterpret_cast(chunk.field(ptr + 3,ZT_C25519_SIGNATURE_LEN)); - - // We can use the signature, which is unique per chunk, to get a per-chunk ID for local deduplication use - for(unsigned int i=0;i<16;++i) - reinterpret_cast(&chunkId)[i & 7] ^= sig[i]; - - // Find existing or new slot for this update and check if this is a duplicate chunk - for(int i=0;ihaveChunks;++j) { - if (c->haveChunkIds[j] == chunkId) - return 0; - } - - break; - } else if ((!c)||(_incomingConfigChunks[i].ts < c->ts)) { - c = &(_incomingConfigChunks[i]); - } - } - - // If it's not a duplicate, check chunk signature - const Identity controllerId(RR->topology->getIdentity(tPtr,controller())); - if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time? - TRACE("unable to verify chunk from %s: don't have controller identity",source.toString().c_str()); - return 0; - } - if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) { - TRACE("discarded chunk from %s: signature check failed",source.toString().c_str()); - return 0; - } - -#ifdef ZT_ENABLE_CLUSTER - if ((source)&&(RR->cluster)) - RR->cluster->broadcastNetworkConfigChunk(chunk.field(start,chunk.size() - start),chunk.size() - start); -#endif - - // New properly verified chunks can be flooded "virally" through the network - if (fastPropagate) { - Address *a = (Address *)0; - Membership *m = (Membership *)0; - Hashtable::Iterator i(_memberships); - while (i.next(a,m)) { - if ((*a != source)&&(*a != controller())) { - Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CONFIG); - outp.append(reinterpret_cast(chunk.data()) + start,chunk.size() - start); - RR->sw->send(tPtr,outp,true); - } - } - } - } else if ((source == controller())||(!source)) { // since old chunks aren't signed, only accept from controller itself (or via cluster backplane) - // Legacy support for OK(NETWORK_CONFIG_REQUEST) from older controllers - chunkId = packetId; - configUpdateId = chunkId; - totalLength = chunkLen; - chunkIndex = 0; - - if (totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY) - return 0; - - for(int i=0;its)) - c = &(_incomingConfigChunks[i]); - } - -#ifdef ZT_ENABLE_CLUSTER - if ((source)&&(RR->cluster)) - RR->cluster->broadcastNetworkConfigChunk(chunk.field(start,chunk.size() - start),chunk.size() - start); -#endif - } else { - TRACE("discarded single-chunk unsigned legacy config: this is only allowed if the sender is the controller itself"); - return 0; - } - - ++c->ts; // newer is higher, that's all we need - - if (c->updateId != configUpdateId) { - c->updateId = configUpdateId; - c->haveChunks = 0; - c->haveBytes = 0; - } - if (c->haveChunks >= ZT_NETWORK_MAX_UPDATE_CHUNKS) - return false; - c->haveChunkIds[c->haveChunks++] = chunkId; - - memcpy(c->data.unsafeData() + chunkIndex,chunkData,chunkLen); - c->haveBytes += chunkLen; - - if (c->haveBytes == totalLength) { - c->data.unsafeData()[c->haveBytes] = (char)0; // ensure null terminated - - nc = new NetworkConfig(); - try { - if (!nc->fromDictionary(c->data)) { - delete nc; - nc = (NetworkConfig *)0; - } - } catch ( ... ) { - delete nc; - nc = (NetworkConfig *)0; - } - } - } - - if (nc) { - this->setConfiguration(tPtr,*nc,true); - delete nc; - return configUpdateId; - } else { - return 0; - } - - return 0; -} - -int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk) -{ - // _lock is NOT locked when this is called - try { - if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id)) - return 0; - if (_config == nconf) - return 1; // OK config, but duplicate of what we already have - - ZT_VirtualNetworkConfig ctmp; - bool oldPortInitialized; - { - Mutex::Lock _l(_lock); - _config = nconf; - _lastConfigUpdate = RR->node->now(); - _netconfFailure = NETCONF_FAILURE_NONE; - oldPortInitialized = _portInitialized; - _portInitialized = true; - _externalConfig(&ctmp); - } - _portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); - - if (saveToDisk) { - Dictionary *d = new Dictionary(); - try { - char n[64]; - Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); - if (nconf.toDictionary(*d,false)) - RR->node->dataStorePut(tPtr,n,(const void *)d->data(),d->sizeBytes(),true); - } catch ( ... ) {} - delete d; - } - - return 2; // OK and configuration has changed - } catch ( ... ) { - TRACE("ignored invalid configuration for network %.16llx",(unsigned long long)_id); - } - return 0; -} - -void Network::requestConfiguration(void *tPtr) -{ - /* ZeroTier addresses can't begin with 0xff, so this is used to mark controllerless - * network IDs. Controllerless network IDs only support unicast IPv6 using the 6plane - * addressing scheme and have the following format: 0xffSSSSEEEE000000 where SSSS - * is the 16-bit starting IP port range allowed and EEEE is the 16-bit ending IP port - * range allowed. Remaining digits are reserved for future use and must be zero. */ - if ((_id >> 56) == 0xff) { - const uint16_t startPortRange = (uint16_t)((_id >> 40) & 0xffff); - const uint16_t endPortRange = (uint16_t)((_id >> 24) & 0xffff); - if (((_id & 0xffffff) == 0)&&(endPortRange >= startPortRange)) { - NetworkConfig *const nconf = new NetworkConfig(); - - nconf->networkId = _id; - nconf->timestamp = RR->node->now(); - nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; - nconf->revision = 1; - nconf->issuedTo = RR->identity.address(); - nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; - nconf->staticIpCount = 1; - nconf->ruleCount = 14; - nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt()); - - // Drop everything but IPv6 - nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80; // NOT - nconf->rules[0].v.etherType = 0x86dd; // IPv6 - nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; - - // Allow ICMPv6 - nconf->rules[2].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; - nconf->rules[2].v.ipProtocol = 0x3a; // ICMPv6 - nconf->rules[3].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - - // Allow destination ports within range - nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; - nconf->rules[4].v.ipProtocol = 0x11; // UDP - nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40; // OR - nconf->rules[5].v.ipProtocol = 0x06; // TCP - nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE; - nconf->rules[6].v.port[0] = startPortRange; - nconf->rules[6].v.port[1] = endPortRange; - nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - - // Allow non-SYN TCP packets to permit non-connection-initiating traffic - nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80; // NOT - nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; - nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - - // Also allow SYN+ACK which are replies to SYN - nconf->rules[10].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; - nconf->rules[10].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; - nconf->rules[11].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; - nconf->rules[11].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK; - nconf->rules[12].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - - nconf->rules[13].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; - - nconf->type = ZT_NETWORK_TYPE_PUBLIC; - Utils::snprintf(nconf->name,sizeof(nconf->name),"adhoc-%.04x-%.04x",(int)startPortRange,(int)endPortRange); - - this->setConfiguration(tPtr,*nconf,false); - delete nconf; - } else { - this->setNotFound(); - } - return; - } - - const Address ctrl(controller()); - - Dictionary rmd; - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR,(uint64_t)ZT_VENDOR_ZEROTIER); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,(uint64_t)ZT_PROTO_VERSION); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MAJOR); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MINOR); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,(uint64_t)ZEROTIER_ONE_VERSION_REVISION); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES,(uint64_t)ZT_MAX_NETWORK_RULES); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES,(uint64_t)ZT_MAX_NETWORK_CAPABILITIES); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES,(uint64_t)ZT_MAX_CAPABILITY_RULES); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS,(uint64_t)ZT_MAX_NETWORK_TAGS); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION); - - if (ctrl == RR->identity.address()) { - if (RR->localNetworkController) { - RR->localNetworkController->request(_id,InetAddress(),0xffffffffffffffffULL,RR->identity,rmd); - } else { - this->setNotFound(); - } - return; - } - - TRACE("requesting netconf for network %.16llx from controller %s",(unsigned long long)_id,ctrl.toString().c_str()); - - Packet outp(ctrl,RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append((uint64_t)_id); - const unsigned int rmdSize = rmd.sizeBytes(); - outp.append((uint16_t)rmdSize); - outp.append((const void *)rmd.data(),rmdSize); - if (_config) { - outp.append((uint64_t)_config.revision); - outp.append((uint64_t)_config.timestamp); - } else { - outp.append((unsigned char)0,16); - } - outp.compress(); - RR->node->expectReplyTo(outp.packetId()); - RR->sw->send(tPtr,outp,true); -} - -bool Network::gate(void *tPtr,const SharedPtr &peer) -{ - const uint64_t now = RR->node->now(); - Mutex::Lock _l(_lock); - try { - if (_config) { - Membership *m = _memberships.get(peer->address()); - if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config))) ) { - if (!m) - m = &(_membership(peer->address())); - if (m->shouldLikeMulticasts(now)) { - m->pushCredentials(RR,tPtr,now,peer->address(),_config,-1,false); - _announceMulticastGroupsTo(tPtr,peer->address(),_allMulticastGroups()); - m->likingMulticasts(now); - } - return true; - } - } - } catch ( ... ) { - TRACE("gate() check failed for peer %s: unexpected exception",peer->address().toString().c_str()); - } - return false; -} - -void Network::clean() -{ - const uint64_t now = RR->node->now(); - Mutex::Lock _l(_lock); - - if (_destroyed) - return; - - { - Hashtable< MulticastGroup,uint64_t >::Iterator i(_multicastGroupsBehindMe); - MulticastGroup *mg = (MulticastGroup *)0; - uint64_t *ts = (uint64_t *)0; - while (i.next(mg,ts)) { - if ((now - *ts) > (ZT_MULTICAST_LIKE_EXPIRE * 2)) - _multicastGroupsBehindMe.erase(*mg); - } - } - - { - Address *a = (Address *)0; - Membership *m = (Membership *)0; - Hashtable::Iterator i(_memberships); - while (i.next(a,m)) { - if (!RR->topology->getPeerNoCache(*a)) - _memberships.erase(*a); - } - } -} - -void Network::learnBridgeRoute(const MAC &mac,const Address &addr) -{ - Mutex::Lock _l(_lock); - _remoteBridgeRoutes[mac] = addr; - - // Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes - while (_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) { - Hashtable< Address,unsigned long > counts; - Address maxAddr; - unsigned long maxCount = 0; - - MAC *m = (MAC *)0; - Address *a = (Address *)0; - - // Find the address responsible for the most entries - { - Hashtable::Iterator i(_remoteBridgeRoutes); - while (i.next(m,a)) { - const unsigned long c = ++counts[*a]; - if (c > maxCount) { - maxCount = c; - maxAddr = *a; - } - } - } - - // Kill this address from our table, since it's most likely spamming us - { - Hashtable::Iterator i(_remoteBridgeRoutes); - while (i.next(m,a)) { - if (*a == maxAddr) - _remoteBridgeRoutes.erase(*m); - } - } - } -} - -void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now) -{ - Mutex::Lock _l(_lock); - const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); - _multicastGroupsBehindMe.set(mg,now); - if (tmp != _multicastGroupsBehindMe.size()) - _sendUpdatesToMembers(tPtr,&mg); -} - -Membership::AddCredentialResult Network::addCredential(void *tPtr,const CertificateOfMembership &com) -{ - if (com.networkId() != _id) - return Membership::ADD_REJECTED; - const Address a(com.issuedTo()); - Mutex::Lock _l(_lock); - Membership &m = _membership(a); - const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,com); - if ((result == Membership::ADD_ACCEPTED_NEW)||(result == Membership::ADD_ACCEPTED_REDUNDANT)) { - m.pushCredentials(RR,tPtr,RR->node->now(),a,_config,-1,false); - RR->mc->addCredential(tPtr,com,true); - } - return result; -} - -Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev) -{ - if (rev.networkId() != _id) - return Membership::ADD_REJECTED; - - Mutex::Lock _l(_lock); - Membership &m = _membership(rev.target()); - - const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,rev); - - if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) { - Address *a = (Address *)0; - Membership *m = (Membership *)0; - Hashtable::Iterator i(_memberships); - while (i.next(a,m)) { - if ((*a != sentFrom)&&(*a != rev.signer())) { - Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - outp.append((uint8_t)0x00); // no COM - outp.append((uint16_t)0); // no capabilities - outp.append((uint16_t)0); // no tags - outp.append((uint16_t)1); // one revocation! - rev.serialize(outp); - outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(tPtr,outp,true); - } - } - } - - return result; -} - -void Network::destroy() -{ - Mutex::Lock _l(_lock); - _destroyed = true; -} - -ZT_VirtualNetworkStatus Network::_status() const -{ - // assumes _lock is locked - if (_portError) - return ZT_NETWORK_STATUS_PORT_ERROR; - switch(_netconfFailure) { - case NETCONF_FAILURE_ACCESS_DENIED: - return ZT_NETWORK_STATUS_ACCESS_DENIED; - case NETCONF_FAILURE_NOT_FOUND: - return ZT_NETWORK_STATUS_NOT_FOUND; - case NETCONF_FAILURE_NONE: - return ((_config) ? ZT_NETWORK_STATUS_OK : ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION); - default: - return ZT_NETWORK_STATUS_PORT_ERROR; - } -} - -void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const -{ - // assumes _lock is locked - ec->nwid = _id; - ec->mac = _mac.toInt(); - if (_config) - Utils::scopy(ec->name,sizeof(ec->name),_config.name); - else ec->name[0] = (char)0; - ec->status = _status(); - ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE; - ec->mtu = ZT_IF_MTU; - ec->physicalMtu = ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 16); - ec->dhcp = 0; - std::vector
ab(_config.activeBridges()); - ec->bridge = ((_config.allowPassiveBridging())||(std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end())) ? 1 : 0; - ec->broadcastEnabled = (_config) ? (_config.enableBroadcast() ? 1 : 0) : 0; - ec->portError = _portError; - ec->netconfRevision = (_config) ? (unsigned long)_config.revision : 0; - - ec->assignedAddressCount = 0; - for(unsigned int i=0;iassignedAddresses[i]),&(_config.staticIps[i]),sizeof(struct sockaddr_storage)); - ++ec->assignedAddressCount; - } else { - memset(&(ec->assignedAddresses[i]),0,sizeof(struct sockaddr_storage)); - } - } - - ec->routeCount = 0; - for(unsigned int i=0;iroutes[i]),&(_config.routes[i]),sizeof(ZT_VirtualNetworkRoute)); - ++ec->routeCount; - } else { - memset(&(ec->routes[i]),0,sizeof(ZT_VirtualNetworkRoute)); - } - } -} - -void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup) -{ - // Assumes _lock is locked - const uint64_t now = RR->node->now(); - - std::vector groups; - if (newMulticastGroup) - groups.push_back(*newMulticastGroup); - else groups = _allMulticastGroups(); - - if ((newMulticastGroup)||((now - _lastAnnouncedMulticastGroupsUpstream) >= ZT_MULTICAST_ANNOUNCE_PERIOD)) { - if (!newMulticastGroup) - _lastAnnouncedMulticastGroupsUpstream = now; - - // Announce multicast groups to upstream peers (roots, etc.) and also send - // them our COM so that MULTICAST_GATHER can be authenticated properly. - const std::vector
upstreams(RR->topology->upstreamAddresses()); - for(std::vector
::const_iterator a(upstreams.begin());a!=upstreams.end();++a) { - if (_config.com) { - Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - _config.com.serialize(outp); - outp.append((uint8_t)0x00); - outp.append((uint16_t)0); // no capabilities - outp.append((uint16_t)0); // no tags - outp.append((uint16_t)0); // no revocations - outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(tPtr,outp,true); - } - _announceMulticastGroupsTo(tPtr,*a,groups); - } - - // Also announce to controller, and send COM to simplify and generalize behavior even though in theory it does not need it - const Address c(controller()); - if ( (std::find(upstreams.begin(),upstreams.end(),c) == upstreams.end()) && (!_memberships.contains(c)) ) { - if (_config.com) { - Packet outp(c,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - _config.com.serialize(outp); - outp.append((uint8_t)0x00); - outp.append((uint16_t)0); // no capabilities - outp.append((uint16_t)0); // no tags - outp.append((uint16_t)0); // no revocations - outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(tPtr,outp,true); - } - _announceMulticastGroupsTo(tPtr,c,groups); - } - } - - // Make sure that all "network anchors" have Membership records so we will - // push multicasts to them. Note that _membership() also does this but in a - // piecemeal on-demand fashion. - const std::vector
anchors(_config.anchors()); - for(std::vector
::const_iterator a(anchors.begin());a!=anchors.end();++a) - _membership(*a); - - // Send credentials and multicast LIKEs to members, upstreams, and controller - { - Address *a = (Address *)0; - Membership *m = (Membership *)0; - Hashtable::Iterator i(_memberships); - while (i.next(a,m)) { - m->pushCredentials(RR,tPtr,now,*a,_config,-1,false); - if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) { - if (!newMulticastGroup) - m->likingMulticasts(now); - _announceMulticastGroupsTo(tPtr,*a,groups); - } - } - } -} - -void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector &allMulticastGroups) -{ - // Assumes _lock is locked - Packet outp(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); - - for(std::vector::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) { - if ((outp.size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) { - outp.compress(); - RR->sw->send(tPtr,outp,true); - outp.reset(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); - } - - // network ID, MAC, ADI - outp.append((uint64_t)_id); - mg->mac().appendTo(outp); - outp.append((uint32_t)mg->adi()); - } - - if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH) { - outp.compress(); - RR->sw->send(tPtr,outp,true); - } -} - -std::vector Network::_allMulticastGroups() const -{ - // Assumes _lock is locked - std::vector mgs; - mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1); - mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end()); - _multicastGroupsBehindMe.appendKeys(mgs); - if ((_config)&&(_config.enableBroadcast())) - mgs.push_back(Network::BROADCAST); - std::sort(mgs.begin(),mgs.end()); - mgs.erase(std::unique(mgs.begin(),mgs.end()),mgs.end()); - return mgs; -} - -Membership &Network::_membership(const Address &a) -{ - // assumes _lock is locked - return _memberships[a]; -} - -} // namespace ZeroTier diff --git a/zto/node/Network.hpp b/zto/node/Network.hpp deleted file mode 100644 index fccc267..0000000 --- a/zto/node/Network.hpp +++ /dev/null @@ -1,423 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_NETWORK_HPP -#define ZT_NETWORK_HPP - -#include - -#include "../include/ZeroTierOne.h" - -#include -#include -#include -#include -#include - -#include "Constants.hpp" -#include "NonCopyable.hpp" -#include "Hashtable.hpp" -#include "Address.hpp" -#include "Mutex.hpp" -#include "SharedPtr.hpp" -#include "AtomicCounter.hpp" -#include "MulticastGroup.hpp" -#include "MAC.hpp" -#include "Dictionary.hpp" -#include "Multicaster.hpp" -#include "Membership.hpp" -#include "NetworkConfig.hpp" -#include "CertificateOfMembership.hpp" - -#define ZT_NETWORK_MAX_INCOMING_UPDATES 3 -#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1) - -namespace ZeroTier { - -class RuntimeEnvironment; -class Peer; - -/** - * A virtual LAN - */ -class Network : NonCopyable -{ - friend class SharedPtr; - -public: - /** - * Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0 - */ - static const MulticastGroup BROADCAST; - - /** - * Compute primary controller device ID from network ID - */ - static inline Address controllerFor(uint64_t nwid) throw() { return Address(nwid >> 24); } - - /** - * Construct a new network - * - * Note that init() should be called immediately after the network is - * constructed to actually configure the port. - * - * @param renv Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param nwid Network ID - * @param uptr Arbitrary pointer used by externally-facing API (for user use) - */ - Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr); - - ~Network(); - - inline uint64_t id() const { return _id; } - inline Address controller() const { return Address(_id >> 24); } - inline bool multicastEnabled() const { return (_config.multicastLimit > 0); } - inline bool hasConfig() const { return (_config); } - inline uint64_t lastConfigUpdate() const throw() { return _lastConfigUpdate; } - inline ZT_VirtualNetworkStatus status() const { Mutex::Lock _l(_lock); return _status(); } - inline const NetworkConfig &config() const { return _config; } - inline const MAC &mac() const { return _mac; } - - /** - * Apply filters to an outgoing packet - * - * This applies filters from our network config and, if that doesn't match, - * our capabilities in ascending order of capability ID. Additional actions - * such as TEE may be taken, and credentials may be pushed, so this is not - * side-effect-free. It's basically step one in sending something over VL2. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param noTee If true, do not TEE anything anywhere (for two-pass filtering as done with multicast and bridging) - * @param ztSource Source ZeroTier address - * @param ztDest Destination ZeroTier address - * @param macSource Ethernet layer source address - * @param macDest Ethernet layer destination address - * @param frameData Ethernet frame data - * @param frameLen Ethernet frame payload length - * @param etherType 16-bit ethernet type ID - * @param vlanId 16-bit VLAN ID - * @return True if packet should be sent, false if dropped or redirected - */ - bool filterOutgoingPacket( - void *tPtr, - const bool noTee, - const Address &ztSource, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId); - - /** - * Apply filters to an incoming packet - * - * This applies filters from our network config and, if that doesn't match, - * the peer's capabilities in ascending order of capability ID. If there is - * a match certain actions may be taken such as sending a copy of the packet - * to a TEE or REDIRECT target. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param sourcePeer Source Peer - * @param ztDest Destination ZeroTier address - * @param macSource Ethernet layer source address - * @param macDest Ethernet layer destination address - * @param frameData Ethernet frame data - * @param frameLen Ethernet frame payload length - * @param etherType 16-bit ethernet type ID - * @param vlanId 16-bit VLAN ID - * @return 0 == drop, 1 == accept, 2 == accept even if bridged - */ - int filterIncomingPacket( - void *tPtr, - const SharedPtr &sourcePeer, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId); - - /** - * Check whether we are subscribed to a multicast group - * - * @param mg Multicast group - * @param includeBridgedGroups If true, also check groups we've learned via bridging - * @return True if this network endpoint / peer is a member - */ - bool subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const; - - /** - * Subscribe to a multicast group - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param mg New multicast group - */ - void multicastSubscribe(void *tPtr,const MulticastGroup &mg); - - /** - * Unsubscribe from a multicast group - * - * @param mg Multicast group - */ - void multicastUnsubscribe(const MulticastGroup &mg); - - /** - * Handle an inbound network config chunk - * - * This is called from IncomingPacket to handle incoming network config - * chunks via OK(NETWORK_CONFIG_REQUEST) or NETWORK_CONFIG. It verifies - * each chunk and once assembled applies the configuration. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param packetId Packet ID or 0 if none (e.g. via cluster path) - * @param source Address of sender of chunk or NULL if none (e.g. via cluster path) - * @param chunk Buffer containing chunk - * @param ptr Index of chunk and related fields in packet - * @return Update ID if update was fully assembled and accepted or 0 otherwise - */ - uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr); - - /** - * Set network configuration - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param nconf Network configuration - * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. - * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new - */ - int setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk); - - /** - * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this - */ - inline void setAccessDenied() - { - Mutex::Lock _l(_lock); - _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; - } - - /** - * Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this - */ - inline void setNotFound() - { - Mutex::Lock _l(_lock); - _netconfFailure = NETCONF_FAILURE_NOT_FOUND; - } - - /** - * Causes this network to request an updated configuration from its master node now - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - */ - void requestConfiguration(void *tPtr); - - /** - * Determine whether this peer is permitted to communicate on this network - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param peer Peer to check - */ - bool gate(void *tPtr,const SharedPtr &peer); - - /** - * Do periodic cleanup and housekeeping tasks - */ - void clean(); - - /** - * Push state to members such as multicast group memberships and latest COM (if needed) - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - */ - inline void sendUpdatesToMembers(void *tPtr) - { - Mutex::Lock _l(_lock); - _sendUpdatesToMembers(tPtr,(const MulticastGroup *)0); - } - - /** - * Find the node on this network that has this MAC behind it (if any) - * - * @param mac MAC address - * @return ZeroTier address of bridge to this MAC - */ - inline Address findBridgeTo(const MAC &mac) const - { - Mutex::Lock _l(_lock); - const Address *const br = _remoteBridgeRoutes.get(mac); - return ((br) ? *br : Address()); - } - - /** - * Set a bridge route - * - * @param mac MAC address of destination - * @param addr Bridge this MAC is reachable behind - */ - void learnBridgeRoute(const MAC &mac,const Address &addr); - - /** - * Learn a multicast group that is bridged to our tap device - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param mg Multicast group - * @param now Current time - */ - void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now); - - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com); - - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap) - { - if (cap.networkId() != _id) - return Membership::ADD_REJECTED; - Mutex::Lock _l(_lock); - return _membership(cap.issuedTo()).addCredential(RR,tPtr,_config,cap); - } - - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag) - { - if (tag.networkId() != _id) - return Membership::ADD_REJECTED; - Mutex::Lock _l(_lock); - return _membership(tag.issuedTo()).addCredential(RR,tPtr,_config,tag); - } - - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - Membership::AddCredentialResult addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev); - - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo) - { - if (coo.networkId() != _id) - return Membership::ADD_REJECTED; - Mutex::Lock _l(_lock); - return _membership(coo.issuedTo()).addCredential(RR,tPtr,_config,coo); - } - - /** - * Force push credentials (COM, etc.) to a peer now - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param to Destination peer address - * @param now Current time - */ - inline void pushCredentialsNow(void *tPtr,const Address &to,const uint64_t now) - { - Mutex::Lock _l(_lock); - _membership(to).pushCredentials(RR,tPtr,now,to,_config,-1,true); - } - - /** - * Destroy this network - * - * This causes the network to disable itself, destroy its tap device, and on - * delete to delete all trace of itself on disk and remove any persistent tap - * device instances. Call this when a network is being removed from the system. - */ - void destroy(); - - /** - * Get this network's config for export via the ZT core API - * - * @param ec Buffer to fill with externally-visible network configuration - */ - inline void externalConfig(ZT_VirtualNetworkConfig *ec) const - { - Mutex::Lock _l(_lock); - _externalConfig(ec); - } - - /** - * @return Externally usable pointer-to-pointer exported via the core API - */ - inline void **userPtr() throw() { return &_uPtr; } - -private: - ZT_VirtualNetworkStatus _status() const; - void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked - bool _gate(const SharedPtr &peer); - void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup); - void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector &allMulticastGroups); - std::vector _allMulticastGroups() const; - Membership &_membership(const Address &a); - - const RuntimeEnvironment *const RR; - void *_uPtr; - const uint64_t _id; - uint64_t _lastAnnouncedMulticastGroupsUpstream; - MAC _mac; // local MAC address - bool _portInitialized; - - std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap) - Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge) - Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) - - NetworkConfig _config; - uint64_t _lastConfigUpdate; - - struct _IncomingConfigChunk - { - _IncomingConfigChunk() { memset(this,0,sizeof(_IncomingConfigChunk)); } - uint64_t ts; - uint64_t updateId; - uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS]; - unsigned long haveChunks; - unsigned long haveBytes; - Dictionary data; - }; - _IncomingConfigChunk _incomingConfigChunks[ZT_NETWORK_MAX_INCOMING_UPDATES]; - - bool _destroyed; - - enum { - NETCONF_FAILURE_NONE, - NETCONF_FAILURE_ACCESS_DENIED, - NETCONF_FAILURE_NOT_FOUND, - NETCONF_FAILURE_INIT_FAILED - } _netconfFailure; - int _portError; // return value from port config callback - - Hashtable _memberships; - - Mutex _lock; - - AtomicCounter __refCount; -}; - -} // naemspace ZeroTier - -#endif diff --git a/zto/node/NetworkConfig.cpp b/zto/node/NetworkConfig.cpp deleted file mode 100644 index fe7393e..0000000 --- a/zto/node/NetworkConfig.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include - -#include "NetworkConfig.hpp" - -namespace ZeroTier { - -bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const -{ - Buffer *tmp = new Buffer(); - - try { - d.clear(); - - // Try to put the more human-readable fields first - - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) return false; - -#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF - if (includeLegacy) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING_OLD,this->allowPassiveBridging())) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD,this->enableBroadcast())) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,this->isPrivate())) return false; - - std::string v4s; - for(unsigned int i=0;istaticIps[i].ss_family == AF_INET) { - if (v4s.length() > 0) - v4s.push_back(','); - v4s.append(this->staticIps[i].toString()); - } - } - if (v4s.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,v4s.c_str())) return false; - } - std::string v6s; - for(unsigned int i=0;istaticIps[i].ss_family == AF_INET6) { - if (v6s.length() > 0) - v6s.push_back(','); - v6s.append(this->staticIps[i].toString()); - } - } - if (v6s.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,v6s.c_str())) return false; - } - - std::string ets; - unsigned int et = 0; - ZT_VirtualNetworkRuleType lastrt = ZT_NETWORK_RULE_ACTION_ACCEPT; - for(unsigned int i=0;i 0) - ets.push_back(','); - char tmp2[16]; - Utils::snprintf(tmp2,sizeof(tmp2),"%x",et); - ets.append(tmp2); - } - et = 0; - } - lastrt = rt; - } - if (ets.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,ets.c_str())) return false; - } - - if (this->com) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,this->com.toString().c_str())) return false; - } - - std::string ab; - for(unsigned int i=0;ispecialistCount;++i) { - if ((this->specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) { - if (ab.length() > 0) - ab.push_back(','); - ab.append(Address(this->specialists[i]).toString().c_str()); - } - } - if (ab.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,ab.c_str())) return false; - } - } -#endif // ZT_SUPPORT_OLD_STYLE_NETCONF - - // Then add binary blobs - - if (this->com) { - tmp->clear(); - this->com.serialize(*tmp); - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) return false; - } - - tmp->clear(); - for(unsigned int i=0;icapabilityCount;++i) - this->capabilities[i].serialize(*tmp); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) return false; - } - - tmp->clear(); - for(unsigned int i=0;itagCount;++i) - this->tags[i].serialize(*tmp); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) return false; - } - - tmp->clear(); - for(unsigned int i=0;icertificateOfOwnershipCount;++i) - this->certificatesOfOwnership[i].serialize(*tmp); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) return false; - } - - tmp->clear(); - for(unsigned int i=0;ispecialistCount;++i) - tmp->append((uint64_t)this->specialists[i]); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) return false; - } - - tmp->clear(); - for(unsigned int i=0;irouteCount;++i) { - reinterpret_cast(&(this->routes[i].target))->serialize(*tmp); - reinterpret_cast(&(this->routes[i].via))->serialize(*tmp); - tmp->append((uint16_t)this->routes[i].flags); - tmp->append((uint16_t)this->routes[i].metric); - } - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) return false; - } - - tmp->clear(); - for(unsigned int i=0;istaticIpCount;++i) - this->staticIps[i].serialize(*tmp); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) return false; - } - - if (this->ruleCount) { - tmp->clear(); - Capability::serializeRules(*tmp,rules,ruleCount); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) return false; - } - } - - delete tmp; - } catch ( ... ) { - delete tmp; - throw; - } - - return true; -} - -bool NetworkConfig::fromDictionary(const Dictionary &d) -{ - Buffer *tmp = new Buffer(); - - try { - memset(this,0,sizeof(NetworkConfig)); - - // Fields that are always present, new or old - this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,0); - if (!this->networkId) { - delete tmp; - return false; - } - this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0); - this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,0); - this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0); - this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0); - if (!this->issuedTo) { - delete tmp; - return false; - } - this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); - d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); - - if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) { - #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF - char tmp2[1024]; - - // Decode legacy fields if version is old - if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING_OLD)) - this->flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; - if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD)) - this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; - this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; // always enable for old-style netconf - this->type = (d.getB(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,true)) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,tmp2,sizeof(tmp2)) > 0) { - char *saveptr = (char *)0; - for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { - if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) break; - InetAddress ip(f); - if (!ip.isNetwork()) - this->staticIps[this->staticIpCount++] = ip; - } - } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,tmp2,sizeof(tmp2)) > 0) { - char *saveptr = (char *)0; - for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { - if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) break; - InetAddress ip(f); - if (!ip.isNetwork()) - this->staticIps[this->staticIpCount++] = ip; - } - } - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,tmp2,sizeof(tmp2)) > 0) { - this->com.fromString(tmp2); - } - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,tmp2,sizeof(tmp2)) > 0) { - char *saveptr = (char *)0; - for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { - unsigned int et = Utils::hexStrToUInt(f) & 0xffff; - if ((this->ruleCount + 2) > ZT_MAX_NETWORK_RULES) break; - if (et > 0) { - this->rules[this->ruleCount].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE; - this->rules[this->ruleCount].v.etherType = (uint16_t)et; - ++this->ruleCount; - } - this->rules[this->ruleCount++].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - } - } else { - this->rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT; - this->ruleCount = 1; - } - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,tmp2,sizeof(tmp2)) > 0) { - char *saveptr = (char *)0; - for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { - this->addSpecialist(Address(Utils::hexStrToU64(f)),ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE); - } - } - #else - delete tmp; - return false; - #endif // ZT_SUPPORT_OLD_STYLE_NETCONF - } else { - // Otherwise we can use the new fields - this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,0); - this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)ZT_NETWORK_TYPE_PRIVATE); - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) - this->com.deserialize(*tmp,0); - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) { - try { - unsigned int p = 0; - while (p < tmp->size()) { - Capability cap; - p += cap.deserialize(*tmp,p); - this->capabilities[this->capabilityCount++] = cap; - } - } catch ( ... ) {} - std::sort(&(this->capabilities[0]),&(this->capabilities[this->capabilityCount])); - } - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) { - try { - unsigned int p = 0; - while (p < tmp->size()) { - Tag tag; - p += tag.deserialize(*tmp,p); - this->tags[this->tagCount++] = tag; - } - } catch ( ... ) {} - std::sort(&(this->tags[0]),&(this->tags[this->tagCount])); - } - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) { - unsigned int p = 0; - while (p < tmp->size()) { - if (certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) - p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp,p); - else { - CertificateOfOwnership foo; - p += foo.deserialize(*tmp,p); - } - } - } - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) { - unsigned int p = 0; - while ((p + 8) <= tmp->size()) { - if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) - this->specialists[this->specialistCount++] = tmp->at(p); - p += 8; - } - } - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) { - unsigned int p = 0; - while ((p < tmp->size())&&(routeCount < ZT_MAX_NETWORK_ROUTES)) { - p += reinterpret_cast(&(this->routes[this->routeCount].target))->deserialize(*tmp,p); - p += reinterpret_cast(&(this->routes[this->routeCount].via))->deserialize(*tmp,p); - this->routes[this->routeCount].flags = tmp->at(p); p += 2; - this->routes[this->routeCount].metric = tmp->at(p); p += 2; - ++this->routeCount; - } - } - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) { - unsigned int p = 0; - while ((p < tmp->size())&&(staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { - p += this->staticIps[this->staticIpCount++].deserialize(*tmp,p); - } - } - - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) { - this->ruleCount = 0; - unsigned int p = 0; - Capability::deserializeRules(*tmp,p,this->rules,this->ruleCount,ZT_MAX_NETWORK_RULES); - } - } - - //printf("~~~\n%s\n~~~\n",d.data()); - //dump(); - //printf("~~~\n"); - - delete tmp; - return true; - } catch ( ... ) { - delete tmp; - return false; - } -} - -} // namespace ZeroTier diff --git a/zto/node/NetworkConfig.hpp b/zto/node/NetworkConfig.hpp deleted file mode 100644 index 85c2409..0000000 --- a/zto/node/NetworkConfig.hpp +++ /dev/null @@ -1,556 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_NETWORKCONFIG_HPP -#define ZT_NETWORKCONFIG_HPP - -#include -#include -#include - -#include -#include -#include - -#include "../include/ZeroTierOne.h" - -#include "Constants.hpp" -#include "Buffer.hpp" -#include "InetAddress.hpp" -#include "MulticastGroup.hpp" -#include "Address.hpp" -#include "CertificateOfMembership.hpp" -#include "CertificateOfOwnership.hpp" -#include "Capability.hpp" -#include "Tag.hpp" -#include "Dictionary.hpp" -#include "Identity.hpp" -#include "Utils.hpp" - -/** - * Default maximum time delta for COMs, tags, and capabilities - * - * The current value is two hours, providing ample time for a controller to - * experience fail-over, etc. - */ -#define ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA 7200000ULL - -/** - * Default minimum credential TTL and maxDelta for COM timestamps - * - * This is just slightly over three minutes and provides three retries for - * all currently online members to refresh. - */ -#define ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA 185000ULL - -/** - * Flag: allow passive bridging (experimental) - */ -#define ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING 0x0000000000000001ULL - -/** - * Flag: enable broadcast - */ -#define ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST 0x0000000000000002ULL - -/** - * Flag: enable IPv6 NDP emulation for certain V6 address patterns - */ -#define ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION 0x0000000000000004ULL - -/** - * Flag: result of unrecognized MATCH entries in a rules table: match if set, no-match if clear - */ -#define ZT_NETWORKCONFIG_FLAG_RULES_RESULT_OF_UNSUPPORTED_MATCH 0x0000000000000008ULL - -/** - * Flag: disable frame compression - */ -#define ZT_NETWORKCONFIG_FLAG_DISABLE_COMPRESSION 0x0000000000000010ULL - -/** - * Device is an active bridge - */ -#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE 0x0000020000000000ULL - -/** - * Anchors are stable devices on this network that can cache multicast info, etc. - */ -#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR 0x0000040000000000ULL - -/** - * Device can send CIRCUIT_TESTs for this network - */ -#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_CIRCUIT_TESTER 0x0000080000000000ULL - -namespace ZeroTier { - -// Dictionary capacity needed for max size network config -#define ZT_NETWORKCONFIG_DICT_CAPACITY (1024 + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) + (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP)) - -// Dictionary capacity needed for max size network meta-data -#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 1024 - -// Network config version -#define ZT_NETWORKCONFIG_VERSION 7 - -// Fields for meta-data sent with network config requests - -// Network config version -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION "v" -// Protocol version (see Packet.hpp) -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION "pv" -// Software vendor -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR "vend" -// Software major version -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION "majv" -// Software minor version -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION "minv" -// Software revision -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION "revv" -// Rules engine revision -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV "revr" -// Maximum number of rules per network this node can accept -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES "mr" -// Maximum number of capabilities this node can accept -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES "mc" -// Maximum number of rules per capability this node can accept -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES "mcr" -// Maximum number of tags this node can accept -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS "mt" -// Network join authorization token (if any) -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH "a" -// Network configuration meta-data flags -#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS "f" - -// These dictionary keys are short so they don't take up much room. -// By convention we use upper case for binary blobs, but it doesn't really matter. - -// network config version -#define ZT_NETWORKCONFIG_DICT_KEY_VERSION "v" -// network ID -#define ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID "nwid" -// integer(hex) -#define ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP "ts" -// integer(hex) -#define ZT_NETWORKCONFIG_DICT_KEY_REVISION "r" -// address of member -#define ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO "id" -// flags(hex) -#define ZT_NETWORKCONFIG_DICT_KEY_FLAGS "f" -// integer(hex) -#define ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT "ml" -// network type (hex) -#define ZT_NETWORKCONFIG_DICT_KEY_TYPE "t" -// text -#define ZT_NETWORKCONFIG_DICT_KEY_NAME "n" -// credential time max delta in ms -#define ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA "ctmd" -// binary serialized certificate of membership -#define ZT_NETWORKCONFIG_DICT_KEY_COM "C" -// specialists (binary array of uint64_t) -#define ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS "S" -// routes (binary blob) -#define ZT_NETWORKCONFIG_DICT_KEY_ROUTES "RT" -// static IPs (binary blob) -#define ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS "I" -// rules (binary blob) -#define ZT_NETWORKCONFIG_DICT_KEY_RULES "R" -// capabilities (binary blobs) -#define ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES "CAP" -// tags (binary blobs) -#define ZT_NETWORKCONFIG_DICT_KEY_TAGS "TAG" -// tags (binary blobs) -#define ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP "COO" -// curve25519 signature -#define ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE "C25519" - -// Legacy fields -- these are obsoleted but are included when older clients query - -// boolean (now a flag) -#define ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING_OLD "pb" -// boolean (now a flag) -#define ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD "eb" -// IP/bits[,IP/bits,...] -// Note that IPs that end in all zeroes are routes with no assignment in them. -#define ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD "v4s" -// IP/bits[,IP/bits,...] -// Note that IPs that end in all zeroes are routes with no assignment in them. -#define ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD "v6s" -// 0/1 -#define ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD "p" -// integer(hex)[,integer(hex),...] -#define ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD "et" -// string-serialized CertificateOfMembership -#define ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD "com" -// node[,node,...] -#define ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD "ab" -// node;IP/port[,node;IP/port] -#define ZT_NETWORKCONFIG_DICT_KEY_RELAYS_OLD "rl" - -// End legacy fields - -/** - * Network configuration received from network controller nodes - * - * This is a memcpy()'able structure and is safe (in a crash sense) to modify - * without locks. - */ -class NetworkConfig -{ -public: - NetworkConfig() - { - memset(this,0,sizeof(NetworkConfig)); - } - - NetworkConfig(const NetworkConfig &nc) - { - memcpy(this,&nc,sizeof(NetworkConfig)); - } - - inline NetworkConfig &operator=(const NetworkConfig &nc) - { - memcpy(this,&nc,sizeof(NetworkConfig)); - return *this; - } - - /** - * Write this network config to a dictionary for transport - * - * @param d Dictionary - * @param includeLegacy If true, include legacy fields for old node versions - * @return True if dictionary was successfully created, false if e.g. overflow - */ - bool toDictionary(Dictionary &d,bool includeLegacy) const; - - /** - * Read this network config from a dictionary - * - * @param d Dictionary (non-const since it might be modified during parse, should not be used after call) - * @return True if dictionary was valid and network config successfully initialized - */ - bool fromDictionary(const Dictionary &d); - - /** - * @return True if passive bridging is allowed (experimental) - */ - inline bool allowPassiveBridging() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING) != 0); } - - /** - * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network - */ - inline bool enableBroadcast() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); } - - /** - * @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns - */ - inline bool ndpEmulation() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); } - - /** - * @return True if frames should not be compressed - */ - inline bool disableCompression() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_DISABLE_COMPRESSION) != 0); } - - /** - * @return Network type is public (no access control) - */ - inline bool isPublic() const throw() { return (this->type == ZT_NETWORK_TYPE_PUBLIC); } - - /** - * @return Network type is private (certificate access control) - */ - inline bool isPrivate() const throw() { return (this->type == ZT_NETWORK_TYPE_PRIVATE); } - - /** - * @return ZeroTier addresses of devices on this network designated as active bridges - */ - inline std::vector
activeBridges() const - { - std::vector
r; - for(unsigned int i=0;i anchors() const - { - std::vector
r; - for(unsigned int i=0;i> 24) & 0xffffffffffULL)) - return true; - for(unsigned int i=0;i(&(routes[i].target))->toString().c_str()); - printf(" routes[i].via==%s\n",reinterpret_cast(&(routes[i].via))->toIpString().c_str()); - printf(" routes[i].flags==%.4x\n",(unsigned int)routes[i].flags); - printf(" routes[i].metric==%u\n",(unsigned int)routes[i].metric); - } - printf("staticIpCount==%u\n",staticIpCount); - for(unsigned int i=0;i. - */ - -#ifndef ZT_NETWORKCONFIGMASTER_HPP -#define ZT_NETWORKCONFIGMASTER_HPP - -#include - -#include "Constants.hpp" -#include "Dictionary.hpp" -#include "NetworkConfig.hpp" -#include "Revocation.hpp" -#include "Address.hpp" - -namespace ZeroTier { - -class Identity; -struct InetAddress; - -/** - * Interface for network controller implementations - */ -class NetworkController -{ -public: - enum ErrorCode - { - NC_ERROR_NONE = 0, - NC_ERROR_OBJECT_NOT_FOUND = 1, - NC_ERROR_ACCESS_DENIED = 2, - NC_ERROR_INTERNAL_SERVER_ERROR = 3 - }; - - /** - * Interface for sender used to send pushes and replies - */ - class Sender - { - public: - /** - * Send a configuration to a remote peer - * - * @param nwid Network ID - * @param requestPacketId Request packet ID to send OK(NETWORK_CONFIG_REQUEST) or 0 to send NETWORK_CONFIG (push) - * @param destination Destination peer Address - * @param nc Network configuration to send - * @param sendLegacyFormatConfig If true, send an old-format network config - */ - virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig) = 0; - - /** - * Send revocation to a node - * - * @param destination Destination node address - * @param rev Revocation to send - */ - virtual void ncSendRevocation(const Address &destination,const Revocation &rev) = 0; - - /** - * Send a network configuration request error - * - * @param nwid Network ID - * @param requestPacketId Request packet ID or 0 if none - * @param destination Destination peer Address - * @param errorCode Error code - */ - virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode) = 0; - }; - - NetworkController() {} - virtual ~NetworkController() {} - - /** - * Called when this is added to a Node to initialize and supply info - * - * @param signingId Identity for signing of network configurations, certs, etc. - * @param sender Sender implementation for sending replies or config pushes - */ - virtual void init(const Identity &signingId,Sender *sender) = 0; - - /** - * Handle a network configuration request - * - * @param nwid 64-bit network ID - * @param fromAddr Originating wire address or null address if packet is not direct (or from self) - * @param requestPacketId Packet ID of request packet or 0 if not initiated by remote request - * @param identity ZeroTier identity of originating peer - * @param metaData Meta-data bundled with request (if any) - * @return Returns NETCONF_QUERY_OK if result 'nc' is valid, or an error code on error - */ - virtual void request( - uint64_t nwid, - const InetAddress &fromAddr, - uint64_t requestPacketId, - const Identity &identity, - const Dictionary &metaData) = 0; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Node.cpp b/zto/node/Node.cpp deleted file mode 100644 index e7dc637..0000000 --- a/zto/node/Node.cpp +++ /dev/null @@ -1,1136 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -#include "../version.h" - -#include "Constants.hpp" -#include "Node.hpp" -#include "RuntimeEnvironment.hpp" -#include "NetworkController.hpp" -#include "Switch.hpp" -#include "Multicaster.hpp" -#include "Topology.hpp" -#include "Buffer.hpp" -#include "Packet.hpp" -#include "Address.hpp" -#include "Identity.hpp" -#include "SelfAwareness.hpp" -#include "Cluster.hpp" - -const struct sockaddr_storage ZT_SOCKADDR_NULL = {0}; - -namespace ZeroTier { - -/****************************************************************************/ -/* Public Node interface (C++, exposed via CAPI bindings) */ -/****************************************************************************/ - -Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : - _RR(this), - RR(&_RR), - _uPtr(uptr), - _prngStreamPtr(0), - _now(now), - _lastPingCheck(0), - _lastHousekeepingRun(0) -{ - if (callbacks->version != 0) - throw std::runtime_error("callbacks struct version mismatch"); - memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks)); - - _online = false; - - memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr)); - memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo)); - memset(_lastIdentityVerification,0,sizeof(_lastIdentityVerification)); - - // Use Salsa20 alone as a high-quality non-crypto PRNG - char foo[32]; - Utils::getSecureRandom(foo,32); - _prng.init(foo,256,foo); - memset(_prngStream,0,sizeof(_prngStream)); - _prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream)); - - std::string idtmp(dataStoreGet(tptr,"identity.secret")); - if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { - TRACE("identity.secret not found, generating..."); - RR->identity.generate(); - idtmp = RR->identity.toString(true); - if (!dataStorePut(tptr,"identity.secret",idtmp,true)) - throw std::runtime_error("unable to write identity.secret"); - } - RR->publicIdentityStr = RR->identity.toString(false); - RR->secretIdentityStr = RR->identity.toString(true); - idtmp = dataStoreGet(tptr,"identity.public"); - if (idtmp != RR->publicIdentityStr) { - if (!dataStorePut(tptr,"identity.public",RR->publicIdentityStr,false)) - throw std::runtime_error("unable to write identity.public"); - } - - try { - RR->sw = new Switch(RR); - RR->mc = new Multicaster(RR); - RR->topology = new Topology(RR,tptr); - RR->sa = new SelfAwareness(RR); - } catch ( ... ) { - delete RR->sa; - delete RR->topology; - delete RR->mc; - delete RR->sw; - throw; - } - - postEvent(tptr,ZT_EVENT_UP); -} - -Node::~Node() -{ - Mutex::Lock _l(_networks_m); - - _networks.clear(); // ensure that networks are destroyed before shutdow - - delete RR->sa; - delete RR->topology; - delete RR->mc; - delete RR->sw; - -#ifdef ZT_ENABLE_CLUSTER - delete RR->cluster; -#endif -} - -ZT_ResultCode Node::processWirePacket( - void *tptr, - uint64_t now, - const struct sockaddr_storage *localAddress, - const struct sockaddr_storage *remoteAddress, - const void *packetData, - unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline) -{ - _now = now; - RR->sw->onRemotePacket(tptr,*(reinterpret_cast(localAddress)),*(reinterpret_cast(remoteAddress)),packetData,packetLength); - return ZT_RESULT_OK; -} - -ZT_ResultCode Node::processVirtualNetworkFrame( - void *tptr, - uint64_t now, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline) -{ - _now = now; - SharedPtr nw(this->network(nwid)); - if (nw) { - RR->sw->onLocalEthernet(tptr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength); - return ZT_RESULT_OK; - } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; -} - -// Closure used to ping upstream and active/online peers -class _PingPeersThatNeedPing -{ -public: - _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &upstreamsToContact,uint64_t now) : - lastReceiveFromUpstream(0), - RR(renv), - _tPtr(tPtr), - _upstreamsToContact(upstreamsToContact), - _now(now), - _bestCurrentUpstream(RR->topology->getUpstreamPeer()) - { - } - - uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay - - inline void operator()(Topology &t,const SharedPtr &p) - { - const std::vector *const upstreamStableEndpoints = _upstreamsToContact.get(p->address()); - if (upstreamStableEndpoints) { - bool contacted = false; - - // Upstreams must be pinged constantly over both IPv4 and IPv6 to allow - // them to perform three way handshake introductions for both stacks. - - if (!p->doPingAndKeepalive(_tPtr,_now,AF_INET)) { - for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { - const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; - if (addr.ss_family == AF_INET) { - p->sendHELLO(_tPtr,InetAddress(),addr,_now,0); - contacted = true; - break; - } - } - } else contacted = true; - if (!p->doPingAndKeepalive(_tPtr,_now,AF_INET6)) { - for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { - const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; - if (addr.ss_family == AF_INET6) { - p->sendHELLO(_tPtr,InetAddress(),addr,_now,0); - contacted = true; - break; - } - } - } else contacted = true; - - if ((!contacted)&&(_bestCurrentUpstream)) { - const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); - if (up) - p->sendHELLO(_tPtr,up->localAddress(),up->address(),_now,up->nextOutgoingCounter()); - } - - lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); - _upstreamsToContact.erase(p->address()); // erase from upstreams to contact so that we can WHOIS those that remain - } else if (p->isActive(_now)) { - p->doPingAndKeepalive(_tPtr,_now,-1); - } - } - -private: - const RuntimeEnvironment *RR; - void *_tPtr; - Hashtable< Address,std::vector > &_upstreamsToContact; - const uint64_t _now; - const SharedPtr _bestCurrentUpstream; -}; - -ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) -{ - _now = now; - Mutex::Lock bl(_backgroundTasksLock); - - unsigned long timeUntilNextPingCheck = ZT_PING_CHECK_INVERVAL; - const uint64_t timeSinceLastPingCheck = now - _lastPingCheck; - if (timeSinceLastPingCheck >= ZT_PING_CHECK_INVERVAL) { - try { - _lastPingCheck = now; - - // Get networks that need config without leaving mutex locked - std::vector< SharedPtr > needConfig; - { - Mutex::Lock _l(_networks_m); - for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) { - if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) - needConfig.push_back(n->second); - n->second->sendUpdatesToMembers(tptr); - } - } - for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) - (*n)->requestConfiguration(tptr); - - // Do pings and keepalives - Hashtable< Address,std::vector > upstreamsToContact; - RR->topology->getUpstreamsToContact(upstreamsToContact); - _PingPeersThatNeedPing pfunc(RR,tptr,upstreamsToContact,now); - RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); - - // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) - Hashtable< Address,std::vector >::Iterator i(upstreamsToContact); - Address *upstreamAddress = (Address *)0; - std::vector *upstreamStableEndpoints = (std::vector *)0; - while (i.next(upstreamAddress,upstreamStableEndpoints)) - RR->sw->requestWhois(tptr,*upstreamAddress); - - // Update online status, post status change as event - const bool oldOnline = _online; - _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot())); - if (oldOnline != _online) - postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } - } else { - timeUntilNextPingCheck -= (unsigned long)timeSinceLastPingCheck; - } - - if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) { - try { - _lastHousekeepingRun = now; - RR->topology->clean(now); - RR->sa->clean(now); - RR->mc->clean(now); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } - } - - try { -#ifdef ZT_ENABLE_CLUSTER - // If clustering is enabled we have to call cluster->doPeriodicTasks() very often, so we override normal timer deadline behavior - if (RR->cluster) { - RR->sw->doTimerTasks(tptr,now); - RR->cluster->doPeriodicTasks(); - *nextBackgroundTaskDeadline = now + ZT_CLUSTER_PERIODIC_TASK_PERIOD; // this is really short so just tick at this rate - } else { -#endif - *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); -#ifdef ZT_ENABLE_CLUSTER - } -#endif - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } - - return ZT_RESULT_OK; -} - -ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr) -{ - Mutex::Lock _l(_networks_m); - SharedPtr nw = _network(nwid); - if(!nw) - _networks.push_back(std::pair< uint64_t,SharedPtr >(nwid,SharedPtr(new Network(RR,tptr,nwid,uptr)))); - std::sort(_networks.begin(),_networks.end()); // will sort by nwid since it's the first in a pair<> - return ZT_RESULT_OK; -} - -ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr) -{ - std::vector< std::pair< uint64_t,SharedPtr > > newn; - Mutex::Lock _l(_networks_m); - for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) { - if (n->first != nwid) - newn.push_back(*n); - else { - if (uptr) - *uptr = n->second->userPtr(); - n->second->destroy(); - } - } - _networks.swap(newn); - return ZT_RESULT_OK; -} - -ZT_ResultCode Node::multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) -{ - SharedPtr nw(this->network(nwid)); - if (nw) { - nw->multicastSubscribe(tptr,MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff))); - return ZT_RESULT_OK; - } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; -} - -ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) -{ - SharedPtr nw(this->network(nwid)); - if (nw) { - nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff))); - return ZT_RESULT_OK; - } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; -} - -ZT_ResultCode Node::orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed) -{ - RR->topology->addMoon(tptr,moonWorldId,Address(moonSeed)); - return ZT_RESULT_OK; -} - -ZT_ResultCode Node::deorbit(void *tptr,uint64_t moonWorldId) -{ - RR->topology->removeMoon(tptr,moonWorldId); - return ZT_RESULT_OK; -} - -uint64_t Node::address() const -{ - return RR->identity.address().toInt(); -} - -void Node::status(ZT_NodeStatus *status) const -{ - status->address = RR->identity.address().toInt(); - status->publicIdentity = RR->publicIdentityStr.c_str(); - status->secretIdentity = RR->secretIdentityStr.c_str(); - status->online = _online ? 1 : 0; -} - -ZT_PeerList *Node::peers() const -{ - std::vector< std::pair< Address,SharedPtr > > peers(RR->topology->allPeers()); - std::sort(peers.begin(),peers.end()); - - char *buf = (char *)::malloc(sizeof(ZT_PeerList) + (sizeof(ZT_Peer) * peers.size())); - if (!buf) - return (ZT_PeerList *)0; - ZT_PeerList *pl = (ZT_PeerList *)buf; - pl->peers = (ZT_Peer *)(buf + sizeof(ZT_PeerList)); - - pl->peerCount = 0; - for(std::vector< std::pair< Address,SharedPtr > >::iterator pi(peers.begin());pi!=peers.end();++pi) { - ZT_Peer *p = &(pl->peers[pl->peerCount++]); - p->address = pi->second->address().toInt(); - if (pi->second->remoteVersionKnown()) { - p->versionMajor = pi->second->remoteVersionMajor(); - p->versionMinor = pi->second->remoteVersionMinor(); - p->versionRev = pi->second->remoteVersionRevision(); - } else { - p->versionMajor = -1; - p->versionMinor = -1; - p->versionRev = -1; - } - p->latency = pi->second->latency(); - p->role = RR->topology->role(pi->second->identity().address()); - - std::vector< std::pair< SharedPtr,bool > > paths(pi->second->paths(_now)); - SharedPtr bestp(pi->second->getBestPath(_now,false)); - p->pathCount = 0; - for(std::vector< std::pair< SharedPtr,bool > >::iterator path(paths.begin());path!=paths.end();++path) { - memcpy(&(p->paths[p->pathCount].address),&(path->first->address()),sizeof(struct sockaddr_storage)); - p->paths[p->pathCount].lastSend = path->first->lastOut(); - p->paths[p->pathCount].lastReceive = path->first->lastIn(); - p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->first->address()); - p->paths[p->pathCount].linkQuality = (int)path->first->linkQuality(); - p->paths[p->pathCount].expired = path->second; - p->paths[p->pathCount].preferred = (path->first == bestp) ? 1 : 0; - ++p->pathCount; - } - } - - return pl; -} - -ZT_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) const -{ - Mutex::Lock _l(_networks_m); - SharedPtr nw = _network(nwid); - if(nw) { - ZT_VirtualNetworkConfig *nc = (ZT_VirtualNetworkConfig *)::malloc(sizeof(ZT_VirtualNetworkConfig)); - nw->externalConfig(nc); - return nc; - } - return (ZT_VirtualNetworkConfig *)0; -} - -ZT_VirtualNetworkList *Node::networks() const -{ - Mutex::Lock _l(_networks_m); - - char *buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * _networks.size())); - if (!buf) - return (ZT_VirtualNetworkList *)0; - ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf; - nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList)); - - nl->networkCount = 0; - for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) - n->second->externalConfig(&(nl->networks[nl->networkCount++])); - - return nl; -} - -void Node::freeQueryResult(void *qr) -{ - if (qr) - ::free(qr); -} - -int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr) -{ - if (Path::isAddressValidForPath(*(reinterpret_cast(addr)))) { - Mutex::Lock _l(_directPaths_m); - if (std::find(_directPaths.begin(),_directPaths.end(),*(reinterpret_cast(addr))) == _directPaths.end()) { - _directPaths.push_back(*(reinterpret_cast(addr))); - return 1; - } - } - return 0; -} - -void Node::clearLocalInterfaceAddresses() -{ - Mutex::Lock _l(_directPaths_m); - _directPaths.clear(); -} - -int Node::sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) -{ - try { - if (RR->identity.address().toInt() != dest) { - Packet outp(Address(dest),RR->identity.address(),Packet::VERB_USER_MESSAGE); - outp.append(typeId); - outp.append(data,len); - outp.compress(); - RR->sw->send(tptr,outp,true); - return 1; - } - } catch ( ... ) {} - return 0; -} - -void Node::setNetconfMaster(void *networkControllerInstance) -{ - RR->localNetworkController = reinterpret_cast(networkControllerInstance); - RR->localNetworkController->init(RR->identity,this); -} - -ZT_ResultCode Node::circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) -{ - if (test->hopCount > 0) { - try { - Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST); - RR->identity.address().appendTo(outp); - outp.append((uint16_t)((test->reportAtEveryHop != 0) ? 0x03 : 0x02)); - outp.append((uint64_t)test->timestamp); - outp.append((uint64_t)test->testId); - outp.append((uint16_t)0); // originator credential length, updated later - if (test->credentialNetworkId) { - outp.append((uint8_t)0x01); - outp.append((uint64_t)test->credentialNetworkId); - outp.setAt(ZT_PACKET_IDX_PAYLOAD + 23,(uint16_t)9); - } - outp.append((uint16_t)0); - C25519::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + ZT_PACKET_IDX_PAYLOAD,outp.size() - ZT_PACKET_IDX_PAYLOAD)); - outp.append((uint16_t)sig.size()); - outp.append(sig.data,(unsigned int)sig.size()); - outp.append((uint16_t)0); // originator doesn't need an extra credential, since it's the originator - for(unsigned int h=1;hhopCount;++h) { - outp.append((uint8_t)0); - outp.append((uint8_t)(test->hops[h].breadth & 0xff)); - for(unsigned int a=0;ahops[h].breadth;++a) - Address(test->hops[h].addresses[a]).appendTo(outp); - } - - for(unsigned int a=0;ahops[0].breadth;++a) { - outp.newInitializationVector(); - outp.setDestination(Address(test->hops[0].addresses[a])); - RR->sw->send(tptr,outp,true); - } - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet - } - } - - { - test->_internalPtr = reinterpret_cast(reportCallback); - Mutex::Lock _l(_circuitTests_m); - if (std::find(_circuitTests.begin(),_circuitTests.end(),test) == _circuitTests.end()) - _circuitTests.push_back(test); - } - - return ZT_RESULT_OK; -} - -void Node::circuitTestEnd(ZT_CircuitTest *test) -{ - Mutex::Lock _l(_circuitTests_m); - for(;;) { - std::vector< ZT_CircuitTest * >::iterator ct(std::find(_circuitTests.begin(),_circuitTests.end(),test)); - if (ct == _circuitTests.end()) - break; - else _circuitTests.erase(ct); - } -} - -ZT_ResultCode Node::clusterInit( - unsigned int myId, - const struct sockaddr_storage *zeroTierPhysicalEndpoints, - unsigned int numZeroTierPhysicalEndpoints, - int x, - int y, - int z, - void (*sendFunction)(void *,unsigned int,const void *,unsigned int), - void *sendFunctionArg, - int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), - void *addressToLocationFunctionArg) -{ -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - return ZT_RESULT_ERROR_BAD_PARAMETER; - - std::vector eps; - for(unsigned int i=0;icluster = new Cluster(RR,myId,eps,x,y,z,sendFunction,sendFunctionArg,addressToLocationFunction,addressToLocationFunctionArg); - - return ZT_RESULT_OK; -#else - return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION; -#endif -} - -ZT_ResultCode Node::clusterAddMember(unsigned int memberId) -{ -#ifdef ZT_ENABLE_CLUSTER - if (!RR->cluster) - return ZT_RESULT_ERROR_BAD_PARAMETER; - RR->cluster->addMember((uint16_t)memberId); - return ZT_RESULT_OK; -#else - return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION; -#endif -} - -void Node::clusterRemoveMember(unsigned int memberId) -{ -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - RR->cluster->removeMember((uint16_t)memberId); -#endif -} - -void Node::clusterHandleIncomingMessage(const void *msg,unsigned int len) -{ -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - RR->cluster->handleIncomingStateMessage(msg,len); -#endif -} - -void Node::clusterStatus(ZT_ClusterStatus *cs) -{ - if (!cs) - return; -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - RR->cluster->status(*cs); - else -#endif - memset(cs,0,sizeof(ZT_ClusterStatus)); -} - -/****************************************************************************/ -/* Node methods used only within node/ */ -/****************************************************************************/ - -std::string Node::dataStoreGet(void *tPtr,const char *name) -{ - char buf[1024]; - std::string r; - unsigned long olen = 0; - do { - long n = _cb.dataStoreGetFunction(reinterpret_cast(this),_uPtr,tPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); - if (n <= 0) - return std::string(); - r.append(buf,n); - } while (r.length() < olen); - return r; -} - -bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress) -{ - if (!Path::isAddressValidForPath(remoteAddress)) - return false; - - if (RR->topology->isProhibitedEndpoint(ztaddr,remoteAddress)) - return false; - - { - Mutex::Lock _l(_networks_m); - for(std::vector< std::pair< uint64_t, SharedPtr > >::const_iterator i=_networks.begin();i!=_networks.end();++i) { - if (i->second->hasConfig()) { - for(unsigned int k=0;ksecond->config().staticIpCount;++k) { - if (i->second->config().staticIps[k].containsAddress(remoteAddress)) - return false; - } - } - } - } - - return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0) : true); -} - -#ifdef ZT_TRACE -void Node::postTrace(const char *module,unsigned int line,const char *fmt,...) -{ - static Mutex traceLock; - - va_list ap; - char tmp1[1024],tmp2[1024],tmp3[256]; - - Mutex::Lock _l(traceLock); - - time_t now = (time_t)(_now / 1000ULL); -#ifdef __WINDOWS__ - ctime_s(tmp3,sizeof(tmp3),&now); - char *nowstr = tmp3; -#else - char *nowstr = ctime_r(&now,tmp3); -#endif - unsigned long nowstrlen = (unsigned long)strlen(nowstr); - if (nowstr[nowstrlen-1] == '\n') - nowstr[--nowstrlen] = (char)0; - if (nowstr[nowstrlen-1] == '\r') - nowstr[--nowstrlen] = (char)0; - - va_start(ap,fmt); - vsnprintf(tmp2,sizeof(tmp2),fmt,ap); - va_end(ap); - tmp2[sizeof(tmp2)-1] = (char)0; - - Utils::snprintf(tmp1,sizeof(tmp1),"[%s] %s:%u %s",nowstr,module,line,tmp2); - postEvent((void *)0,ZT_EVENT_TRACE,tmp1); -} -#endif // ZT_TRACE - -uint64_t Node::prng() -{ - unsigned int p = (++_prngStreamPtr % ZT_NODE_PRNG_BUF_SIZE); - if (!p) - _prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream)); - return _prngStream[p]; -} - -void Node::postCircuitTestReport(const ZT_CircuitTestReport *report) -{ - std::vector< ZT_CircuitTest * > toNotify; - { - Mutex::Lock _l(_circuitTests_m); - for(std::vector< ZT_CircuitTest * >::iterator i(_circuitTests.begin());i!=_circuitTests.end();++i) { - if ((*i)->testId == report->testId) - toNotify.push_back(*i); - } - } - for(std::vector< ZT_CircuitTest * >::iterator i(toNotify.begin());i!=toNotify.end();++i) - (reinterpret_cast((*i)->_internalPtr))(reinterpret_cast(this),*i,report); -} - -void Node::setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count) -{ - RR->topology->setTrustedPaths(reinterpret_cast(networks),ids,count); -} - -World Node::planet() const -{ - return RR->topology->planet(); -} - -std::vector Node::moons() const -{ - return RR->topology->moons(); -} - -void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig) -{ - if (destination == RR->identity.address()) { - SharedPtr n(network(nwid)); - if (!n) return; - n->setConfiguration((void *)0,nc,true); - } else { - Dictionary *dconf = new Dictionary(); - try { - if (nc.toDictionary(*dconf,sendLegacyFormatConfig)) { - uint64_t configUpdateId = prng(); - if (!configUpdateId) ++configUpdateId; - - const unsigned int totalSize = dconf->sizeBytes(); - unsigned int chunkIndex = 0; - while (chunkIndex < totalSize) { - const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 256))); - Packet outp(destination,RR->identity.address(),(requestPacketId) ? Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG); - if (requestPacketId) { - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - } - - const unsigned int sigStart = outp.size(); - outp.append(nwid); - outp.append((uint16_t)chunkLen); - outp.append((const void *)(dconf->data() + chunkIndex),chunkLen); - - outp.append((uint8_t)0); // no flags - outp.append((uint64_t)configUpdateId); - outp.append((uint32_t)totalSize); - outp.append((uint32_t)chunkIndex); - - C25519::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + sigStart,outp.size() - sigStart)); - outp.append((uint8_t)1); - outp.append((uint16_t)ZT_C25519_SIGNATURE_LEN); - outp.append(sig.data,ZT_C25519_SIGNATURE_LEN); - - outp.compress(); - RR->sw->send((void *)0,outp,true); - chunkIndex += chunkLen; - } - } - delete dconf; - } catch ( ... ) { - delete dconf; - throw; - } - } -} - -void Node::ncSendRevocation(const Address &destination,const Revocation &rev) -{ - if (destination == RR->identity.address()) { - SharedPtr n(network(rev.networkId())); - if (!n) return; - n->addCredential((void *)0,RR->identity.address(),rev); - } else { - Packet outp(destination,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - outp.append((uint8_t)0x00); - outp.append((uint16_t)0); - outp.append((uint16_t)0); - outp.append((uint16_t)1); - rev.serialize(outp); - outp.append((uint16_t)0); - RR->sw->send((void *)0,outp,true); - } -} - -void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode) -{ - if (destination == RR->identity.address()) { - SharedPtr n(network(nwid)); - if (!n) return; - switch(errorCode) { - case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: - case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: - n->setNotFound(); - break; - case NetworkController::NC_ERROR_ACCESS_DENIED: - n->setAccessDenied(); - break; - - default: break; - } - } else if (requestPacketId) { - Packet outp(destination,RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - switch(errorCode) { - //case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: - //case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: - default: - outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); - break; - case NetworkController::NC_ERROR_ACCESS_DENIED: - outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); - break; - } - outp.append(nwid); - RR->sw->send((void *)0,outp,true); - } // else we can't send an ERROR() in response to nothing, so discard -} - -} // namespace ZeroTier - -/****************************************************************************/ -/* CAPI bindings */ -/****************************************************************************/ - -extern "C" { - -enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) -{ - *node = (ZT_Node *)0; - try { - *node = reinterpret_cast(new ZeroTier::Node(uptr,tptr,callbacks,now)); - return ZT_RESULT_OK; - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (std::runtime_error &exc) { - return ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -void ZT_Node_delete(ZT_Node *node) -{ - try { - delete (reinterpret_cast(node)); - } catch ( ... ) {} -} - -enum ZT_ResultCode ZT_Node_processWirePacket( - ZT_Node *node, - void *tptr, - uint64_t now, - const struct sockaddr_storage *localAddress, - const struct sockaddr_storage *remoteAddress, - const void *packetData, - unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline) -{ - try { - return reinterpret_cast(node)->processWirePacket(tptr,now,localAddress,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_OK; // "OK" since invalid packets are simply dropped, but the system is still up - } -} - -enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( - ZT_Node *node, - void *tptr, - uint64_t now, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline) -{ - try { - return reinterpret_cast(node)->processVirtualNetworkFrame(tptr,now,nwid,sourceMac,destMac,etherType,vlanId,frameData,frameLength,nextBackgroundTaskDeadline); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) -{ - try { - return reinterpret_cast(node)->processBackgroundTasks(tptr,now,nextBackgroundTaskDeadline); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr) -{ - try { - return reinterpret_cast(node)->join(nwid,uptr,tptr); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr) -{ - try { - return reinterpret_cast(node)->leave(nwid,uptr,tptr); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) -{ - try { - return reinterpret_cast(node)->multicastSubscribe(tptr,nwid,multicastGroup,multicastAdi); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) -{ - try { - return reinterpret_cast(node)->multicastUnsubscribe(nwid,multicastGroup,multicastAdi); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed) -{ - try { - return reinterpret_cast(node)->orbit(tptr,moonWorldId,moonSeed); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId) -{ - try { - return reinterpret_cast(node)->deorbit(tptr,moonWorldId); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -uint64_t ZT_Node_address(ZT_Node *node) -{ - return reinterpret_cast(node)->address(); -} - -void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status) -{ - try { - reinterpret_cast(node)->status(status); - } catch ( ... ) {} -} - -ZT_PeerList *ZT_Node_peers(ZT_Node *node) -{ - try { - return reinterpret_cast(node)->peers(); - } catch ( ... ) { - return (ZT_PeerList *)0; - } -} - -ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t nwid) -{ - try { - return reinterpret_cast(node)->networkConfig(nwid); - } catch ( ... ) { - return (ZT_VirtualNetworkConfig *)0; - } -} - -ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node) -{ - try { - return reinterpret_cast(node)->networks(); - } catch ( ... ) { - return (ZT_VirtualNetworkList *)0; - } -} - -void ZT_Node_freeQueryResult(ZT_Node *node,void *qr) -{ - try { - reinterpret_cast(node)->freeQueryResult(qr); - } catch ( ... ) {} -} - -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr) -{ - try { - return reinterpret_cast(node)->addLocalInterfaceAddress(addr); - } catch ( ... ) { - return 0; - } -} - -void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node) -{ - try { - reinterpret_cast(node)->clearLocalInterfaceAddresses(); - } catch ( ... ) {} -} - -int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) -{ - try { - return reinterpret_cast(node)->sendUserMessage(tptr,dest,typeId,data,len); - } catch ( ... ) { - return 0; - } -} - -void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) -{ - try { - reinterpret_cast(node)->setNetconfMaster(networkControllerInstance); - } catch ( ... ) {} -} - -enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) -{ - try { - return reinterpret_cast(node)->circuitTestBegin(tptr,test,reportCallback); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test) -{ - try { - reinterpret_cast(node)->circuitTestEnd(test); - } catch ( ... ) {} -} - -enum ZT_ResultCode ZT_Node_clusterInit( - ZT_Node *node, - unsigned int myId, - const struct sockaddr_storage *zeroTierPhysicalEndpoints, - unsigned int numZeroTierPhysicalEndpoints, - int x, - int y, - int z, - void (*sendFunction)(void *,unsigned int,const void *,unsigned int), - void *sendFunctionArg, - int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), - void *addressToLocationFunctionArg) -{ - try { - return reinterpret_cast(node)->clusterInit(myId,zeroTierPhysicalEndpoints,numZeroTierPhysicalEndpoints,x,y,z,sendFunction,sendFunctionArg,addressToLocationFunction,addressToLocationFunctionArg); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -enum ZT_ResultCode ZT_Node_clusterAddMember(ZT_Node *node,unsigned int memberId) -{ - try { - return reinterpret_cast(node)->clusterAddMember(memberId); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -void ZT_Node_clusterRemoveMember(ZT_Node *node,unsigned int memberId) -{ - try { - reinterpret_cast(node)->clusterRemoveMember(memberId); - } catch ( ... ) {} -} - -void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned int len) -{ - try { - reinterpret_cast(node)->clusterHandleIncomingMessage(msg,len); - } catch ( ... ) {} -} - -void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs) -{ - try { - reinterpret_cast(node)->clusterStatus(cs); - } catch ( ... ) {} -} - -void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count) -{ - try { - reinterpret_cast(node)->setTrustedPaths(networks,ids,count); - } catch ( ... ) {} -} - -void ZT_version(int *major,int *minor,int *revision) -{ - if (major) *major = ZEROTIER_ONE_VERSION_MAJOR; - if (minor) *minor = ZEROTIER_ONE_VERSION_MINOR; - if (revision) *revision = ZEROTIER_ONE_VERSION_REVISION; -} - -} // extern "C" diff --git a/zto/node/Node.hpp b/zto/node/Node.hpp deleted file mode 100644 index 03bd7a8..0000000 --- a/zto/node/Node.hpp +++ /dev/null @@ -1,327 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_NODE_HPP -#define ZT_NODE_HPP - -#include -#include -#include - -#include -#include - -#include "Constants.hpp" - -#include "../include/ZeroTierOne.h" - -#include "RuntimeEnvironment.hpp" -#include "InetAddress.hpp" -#include "Mutex.hpp" -#include "MAC.hpp" -#include "Network.hpp" -#include "Path.hpp" -#include "Salsa20.hpp" -#include "NetworkController.hpp" - -#undef TRACE -#ifdef ZT_TRACE -#define TRACE(f,...) RR->node->postTrace(__FILE__,__LINE__,f,##__VA_ARGS__) -#else -#define TRACE(f,...) {} -#endif - -// Bit mask for "expecting reply" hash -#define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255 -#define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31 - -// Size of PRNG stream buffer -#define ZT_NODE_PRNG_BUF_SIZE 64 - -namespace ZeroTier { - -class World; - -/** - * Implementation of Node object as defined in CAPI - * - * The pointer returned by ZT_Node_new() is an instance of this class. - */ -class Node : public NetworkController::Sender -{ -public: - Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); - virtual ~Node(); - - // Get rid of alignment warnings on 32-bit Windows and possibly improve performance -#ifdef __WINDOWS__ - void * operator new(size_t i) { return _mm_malloc(i,16); } - void operator delete(void* p) { _mm_free(p); } -#endif - - // Public API Functions ---------------------------------------------------- - - ZT_ResultCode processWirePacket( - void *tptr, - uint64_t now, - const struct sockaddr_storage *localAddress, - const struct sockaddr_storage *remoteAddress, - const void *packetData, - unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline); - ZT_ResultCode processVirtualNetworkFrame( - void *tptr, - uint64_t now, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline); - ZT_ResultCode processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); - ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr); - ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr); - ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); - ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); - ZT_ResultCode orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed); - ZT_ResultCode deorbit(void *tptr,uint64_t moonWorldId); - uint64_t address() const; - void status(ZT_NodeStatus *status) const; - ZT_PeerList *peers() const; - ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const; - ZT_VirtualNetworkList *networks() const; - void freeQueryResult(void *qr); - int addLocalInterfaceAddress(const struct sockaddr_storage *addr); - void clearLocalInterfaceAddresses(); - int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); - void setNetconfMaster(void *networkControllerInstance); - ZT_ResultCode circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); - void circuitTestEnd(ZT_CircuitTest *test); - ZT_ResultCode clusterInit( - unsigned int myId, - const struct sockaddr_storage *zeroTierPhysicalEndpoints, - unsigned int numZeroTierPhysicalEndpoints, - int x, - int y, - int z, - void (*sendFunction)(void *,unsigned int,const void *,unsigned int), - void *sendFunctionArg, - int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), - void *addressToLocationFunctionArg); - ZT_ResultCode clusterAddMember(unsigned int memberId); - void clusterRemoveMember(unsigned int memberId); - void clusterHandleIncomingMessage(const void *msg,unsigned int len); - void clusterStatus(ZT_ClusterStatus *cs); - - // Internal functions ------------------------------------------------------ - - inline uint64_t now() const throw() { return _now; } - - inline bool putPacket(void *tPtr,const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) - { - return (_cb.wirePacketSendFunction( - reinterpret_cast(this), - _uPtr, - tPtr, - reinterpret_cast(&localAddress), - reinterpret_cast(&addr), - data, - len, - ttl) == 0); - } - - inline void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) - { - _cb.virtualNetworkFrameFunction( - reinterpret_cast(this), - _uPtr, - tPtr, - nwid, - nuptr, - source.toInt(), - dest.toInt(), - etherType, - vlanId, - data, - len); - } - - inline SharedPtr network(uint64_t nwid) const - { - Mutex::Lock _l(_networks_m); - return _network(nwid); - } - - inline bool belongsToNetwork(uint64_t nwid) const - { - Mutex::Lock _l(_networks_m); - for(std::vector< std::pair< uint64_t, SharedPtr > >::const_iterator i=_networks.begin();i!=_networks.end();++i) { - if (i->first == nwid) - return true; - } - return false; - } - - inline std::vector< SharedPtr > allNetworks() const - { - std::vector< SharedPtr > nw; - Mutex::Lock _l(_networks_m); - nw.reserve(_networks.size()); - for(std::vector< std::pair< uint64_t, SharedPtr > >::const_iterator i=_networks.begin();i!=_networks.end();++i) - nw.push_back(i->second); - return nw; - } - - inline std::vector directPaths() const - { - Mutex::Lock _l(_directPaths_m); - return _directPaths; - } - - inline bool dataStorePut(void *tPtr,const char *name,const void *data,unsigned int len,bool secure) { return (_cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,tPtr,name,data,len,(int)secure) == 0); } - inline bool dataStorePut(void *tPtr,const char *name,const std::string &data,bool secure) { return dataStorePut(tPtr,name,(const void *)data.data(),(unsigned int)data.length(),secure); } - inline void dataStoreDelete(void *tPtr,const char *name) { _cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,tPtr,name,(const void *)0,0,0); } - std::string dataStoreGet(void *tPtr,const char *name); - - inline void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast(this),_uPtr,tPtr,ev,md); } - - inline int configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,tPtr,nwid,nuptr,op,nc); } - - inline bool online() const throw() { return _online; } - -#ifdef ZT_TRACE - void postTrace(const char *module,unsigned int line,const char *fmt,...); -#endif - - bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress); - inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } - - uint64_t prng(); - void postCircuitTestReport(const ZT_CircuitTestReport *report); - void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); - - World planet() const; - std::vector moons() const; - - /** - * Register that we are expecting a reply to a packet ID - * - * This only uses the most significant bits of the packet ID, both to save space - * and to avoid using the higher bits that can be modified during armor() to - * mask against the packet send counter used for QoS detection. - * - * @param packetId Packet ID to expect reply to - */ - inline void expectReplyTo(const uint64_t packetId) - { - const unsigned long pid2 = (unsigned long)(packetId >> 32); - const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1); - _expectingRepliesTo[bucket][_expectingRepliesToBucketPtr[bucket]++ & ZT_EXPECTING_REPLIES_BUCKET_MASK2] = (uint32_t)pid2; - } - - /** - * Check whether a given packet ID is something we are expecting a reply to - * - * This only uses the most significant bits of the packet ID, both to save space - * and to avoid using the higher bits that can be modified during armor() to - * mask against the packet send counter used for QoS detection. - * - * @param packetId Packet ID to check - * @return True if we're expecting a reply - */ - inline bool expectingReplyTo(const uint64_t packetId) const - { - const uint32_t pid2 = (uint32_t)(packetId >> 32); - const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1); - for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) { - if (_expectingRepliesTo[bucket][i] == pid2) - return true; - } - return false; - } - - /** - * Check whether we should do potentially expensive identity verification (rate limit) - * - * @param now Current time - * @param from Source address of packet - * @return True if within rate limits - */ - inline bool rateGateIdentityVerification(const uint64_t now,const InetAddress &from) - { - unsigned long iph = from.rateGateHash(); - if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) { - _lastIdentityVerification[iph] = now; - return true; - } - return false; - } - - virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig); - virtual void ncSendRevocation(const Address &destination,const Revocation &rev); - virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode); - -private: - inline SharedPtr _network(uint64_t nwid) const - { - // assumes _networks_m is locked - for(std::vector< std::pair< uint64_t, SharedPtr > >::const_iterator i=_networks.begin();i!=_networks.end();++i) { - if (i->first == nwid) - return i->second; - } - return SharedPtr(); - } - - RuntimeEnvironment _RR; - RuntimeEnvironment *RR; - void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P - ZT_Node_Callbacks _cb; - - // For tracking packet IDs to filter out OK/ERROR replies to packets we did not send - uint8_t _expectingRepliesToBucketPtr[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1]; - uint32_t _expectingRepliesTo[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1][ZT_EXPECTING_REPLIES_BUCKET_MASK2 + 1]; - - // Time of last identity verification indexed by InetAddress.rateGateHash() -- used in IncomingPacket::_doHELLO() via rateGateIdentityVerification() - uint64_t _lastIdentityVerification[16384]; - - std::vector< std::pair< uint64_t, SharedPtr > > _networks; - Mutex _networks_m; - - std::vector< ZT_CircuitTest * > _circuitTests; - Mutex _circuitTests_m; - - std::vector _directPaths; - Mutex _directPaths_m; - - Mutex _backgroundTasksLock; - - unsigned int _prngStreamPtr; - Salsa20 _prng; - uint64_t _prngStream[ZT_NODE_PRNG_BUF_SIZE]; // repeatedly encrypted with _prng to yield a high-quality non-crypto PRNG stream - - uint64_t _now; - uint64_t _lastPingCheck; - uint64_t _lastHousekeepingRun; - bool _online; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/NonCopyable.hpp b/zto/node/NonCopyable.hpp deleted file mode 100644 index 6d4daa8..0000000 --- a/zto/node/NonCopyable.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_NONCOPYABLE_HPP__ -#define ZT_NONCOPYABLE_HPP__ - -namespace ZeroTier { - -/** - * A simple concept that belongs in the C++ language spec - */ -class NonCopyable -{ -protected: - NonCopyable() throw() {} -private: - NonCopyable(const NonCopyable&); - const NonCopyable& operator=(const NonCopyable&); -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/OutboundMulticast.cpp b/zto/node/OutboundMulticast.cpp deleted file mode 100644 index 285bfa5..0000000 --- a/zto/node/OutboundMulticast.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Constants.hpp" -#include "RuntimeEnvironment.hpp" -#include "OutboundMulticast.hpp" -#include "Switch.hpp" -#include "Network.hpp" -#include "Node.hpp" -#include "Peer.hpp" -#include "Topology.hpp" - -namespace ZeroTier { - -void OutboundMulticast::init( - const RuntimeEnvironment *RR, - uint64_t timestamp, - uint64_t nwid, - bool disableCompression, - unsigned int limit, - unsigned int gatherLimit, - const MAC &src, - const MulticastGroup &dest, - unsigned int etherType, - const void *payload, - unsigned int len) -{ - uint8_t flags = 0; - - _timestamp = timestamp; - _nwid = nwid; - if (src) { - _macSrc = src; - flags |= 0x04; - } else { - _macSrc.fromAddress(RR->identity.address(),nwid); - } - _macDest = dest.mac(); - _limit = limit; - _frameLen = (len < ZT_MAX_MTU) ? len : ZT_MAX_MTU; - _etherType = etherType; - - if (gatherLimit) flags |= 0x02; - - /* - TRACE(">>MC %.16llx INIT %.16llx/%s limit %u gatherLimit %u from %s to %s length %u", - (unsigned long long)this, - nwid, - dest.toString().c_str(), - limit, - gatherLimit, - (src) ? src.toString().c_str() : MAC(RR->identity.address(),nwid).toString().c_str(), - dest.toString().c_str(), - len); - */ - - _packet.setSource(RR->identity.address()); - _packet.setVerb(Packet::VERB_MULTICAST_FRAME); - _packet.append((uint64_t)nwid); - _packet.append(flags); - if (gatherLimit) _packet.append((uint32_t)gatherLimit); - if (src) src.appendTo(_packet); - dest.mac().appendTo(_packet); - _packet.append((uint32_t)dest.adi()); - _packet.append((uint16_t)etherType); - _packet.append(payload,_frameLen); - if (!disableCompression) - _packet.compress(); - - memcpy(_frameData,payload,_frameLen); -} - -void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) -{ - const SharedPtr nw(RR->node->network(_nwid)); - const Address toAddr2(toAddr); - if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr2,_macSrc,_macDest,_frameData,_frameLen,_etherType,0))) { - //TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str()); - _packet.newInitializationVector(); - _packet.setDestination(toAddr2); - RR->node->expectReplyTo(_packet.packetId()); - - Packet tmp(_packet); // make a copy of packet so as not to garble the original -- GitHub issue #461 - RR->sw->send(tPtr,tmp,true); - } -} - -} // namespace ZeroTier diff --git a/zto/node/OutboundMulticast.hpp b/zto/node/OutboundMulticast.hpp deleted file mode 100644 index 0ecf113..0000000 --- a/zto/node/OutboundMulticast.hpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_OUTBOUNDMULTICAST_HPP -#define ZT_OUTBOUNDMULTICAST_HPP - -#include - -#include -#include - -#include "Constants.hpp" -#include "MAC.hpp" -#include "MulticastGroup.hpp" -#include "Address.hpp" -#include "Packet.hpp" - -namespace ZeroTier { - -class CertificateOfMembership; -class RuntimeEnvironment; - -/** - * An outbound multicast packet - * - * This object isn't guarded by a mutex; caller must synchronize access. - */ -class OutboundMulticast -{ -public: - /** - * Create an uninitialized outbound multicast - * - * It must be initialized with init(). - */ - OutboundMulticast() {} - - /** - * Initialize outbound multicast - * - * @param RR Runtime environment - * @param timestamp Creation time - * @param nwid Network ID - * @param disableCompression Disable compression of frame payload - * @param limit Multicast limit for desired number of packets to send - * @param gatherLimit Number to lazily/implicitly gather with this frame or 0 for none - * @param src Source MAC address of frame or NULL to imply compute from sender ZT address - * @param dest Destination multicast group (MAC + ADI) - * @param etherType 16-bit Ethernet type ID - * @param payload Data - * @param len Length of data - * @throws std::out_of_range Data too large to fit in a MULTICAST_FRAME - */ - void init( - const RuntimeEnvironment *RR, - uint64_t timestamp, - uint64_t nwid, - bool disableCompression, - unsigned int limit, - unsigned int gatherLimit, - const MAC &src, - const MulticastGroup &dest, - unsigned int etherType, - const void *payload, - unsigned int len); - - /** - * @return Multicast creation time - */ - inline uint64_t timestamp() const throw() { return _timestamp; } - - /** - * @param now Current time - * @return True if this multicast is expired (has exceeded transmit timeout) - */ - inline bool expired(uint64_t now) const throw() { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); } - - /** - * @return True if this outbound multicast has been sent to enough peers - */ - inline bool atLimit() const throw() { return (_alreadySentTo.size() >= _limit); } - - /** - * Just send without checking log - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param toAddr Destination address - */ - void sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr); - - /** - * Just send and log but do not check sent log - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param toAddr Destination address - */ - inline void sendAndLog(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) - { - _alreadySentTo.push_back(toAddr); - sendOnly(RR,tPtr,toAddr); - } - - /** - * Try to send this to a given peer if it hasn't been sent to them already - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param toAddr Destination address - * @return True if address is new and packet was sent to switch, false if duplicate - */ - inline bool sendIfNew(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) - { - if (std::find(_alreadySentTo.begin(),_alreadySentTo.end(),toAddr) == _alreadySentTo.end()) { - sendAndLog(RR,tPtr,toAddr); - return true; - } else { - return false; - } - } - -private: - uint64_t _timestamp; - uint64_t _nwid; - MAC _macSrc; - MAC _macDest; - unsigned int _limit; - unsigned int _frameLen; - unsigned int _etherType; - Packet _packet; - std::vector
_alreadySentTo; - uint8_t _frameData[ZT_MAX_MTU]; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Packet.cpp b/zto/node/Packet.cpp deleted file mode 100644 index 756f314..0000000 --- a/zto/node/Packet.cpp +++ /dev/null @@ -1,1169 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -#include "Packet.hpp" - -#ifdef _MSC_VER -#define FORCE_INLINE static __forceinline -#include -#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ -#else -#define FORCE_INLINE static inline -#endif - -namespace ZeroTier { - -/************************************************************************** */ -/************************************************************************** */ - -/* LZ4 is shipped encapsulated into Packet in an anonymous namespace. - * - * We're doing this as a deliberate workaround for various Linux distribution - * policies that forbid static linking of support libraries. - * - * The reason is that relying on distribution versions of LZ4 has been too - * big a source of bugs and compatibility issues. The LZ4 API is not stable - * enough across versions, and dependency hell ensues. So fark it. */ - -/* Needless to say the code in this anonymous namespace should be considered - * BSD 2-clause licensed. */ - -namespace { - -/* lz4.h ------------------------------------------------------------------ */ - -/* - * LZ4 - Fast LZ compression algorithm - * Header File - * Copyright (C) 2011-2016, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - 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. - - 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. - - You can contact the author at : - - LZ4 homepage : http://www.lz4.org - - LZ4 source repository : https://github.com/lz4/lz4 -*/ - -/** - Introduction - - LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core, - scalable with multi-cores CPU. It features an extremely fast decoder, with speed in - multiple GB/s per core, typically reaching RAM speed limits on multi-core systems. - - The LZ4 compression library provides in-memory compression and decompression functions. - Compression can be done in: - - a single step (described as Simple Functions) - - a single step, reusing a context (described in Advanced Functions) - - unbounded multiple steps (described as Streaming compression) - - lz4.h provides block compression functions. It gives full buffer control to user. - Decompressing an lz4-compressed block also requires metadata (such as compressed size). - Each application is free to encode such metadata in whichever way it wants. - - An additional format, called LZ4 frame specification (doc/lz4_Frame_format.md), - take care of encoding standard metadata alongside LZ4-compressed blocks. - If your application requires interoperability, it's recommended to use it. - A library is provided to take care of it, see lz4frame.h. -*/ - -#define LZ4LIB_API - -/*========== Version =========== */ -#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ -#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ -#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */ - -#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) - -#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE -#define LZ4_QUOTE(str) #str -#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) -#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) - -/*! - * LZ4_MEMORY_USAGE : - * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) - * Increasing memory usage improves compression ratio - * Reduced memory usage can improve speed, due to cache effect - * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache - */ -#define LZ4_MEMORY_USAGE 14 - -#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ -#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) - -/*-********************************************* -* Streaming Compression Functions -***********************************************/ -typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ - -/*! LZ4_resetStream() : - * An LZ4_stream_t structure can be allocated once and re-used multiple times. - * Use this function to init an allocated `LZ4_stream_t` structure and start a new compression. - */ -LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr); - -/*^********************************************** - * !!!!!! STATIC LINKING ONLY !!!!!! - ***********************************************/ -/*-************************************ - * Private definitions - ************************************** - * Do not use these definitions. - * They are exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`. - * Using these definitions will expose code to API and/or ABI break in future versions of the library. - **************************************/ -#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) -#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) -#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ - -typedef struct { - uint32_t hashTable[LZ4_HASH_SIZE_U32]; - uint32_t currentOffset; - uint32_t initCheck; - const uint8_t* dictionary; - uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ - uint32_t dictSize; -} LZ4_stream_t_internal; - -typedef struct { - const uint8_t* externalDict; - size_t extDictSize; - const uint8_t* prefixEnd; - size_t prefixSize; -} LZ4_streamDecode_t_internal; - -/*! - * LZ4_stream_t : - * information structure to track an LZ4 stream. - * init this structure before first use. - * note : only use in association with static linking ! - * this definition is not API/ABI safe, - * and may change in a future version ! - */ -#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) -#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) -union LZ4_stream_u { - unsigned long long table[LZ4_STREAMSIZE_U64]; - LZ4_stream_t_internal internal_donotuse; -} ; /* previously typedef'd to LZ4_stream_t */ - -/*! - * LZ4_streamDecode_t : - * information structure to track an LZ4 stream during decompression. - * init this structure using LZ4_setStreamDecode (or memset()) before first use - * note : only use in association with static linking ! - * this definition is not API/ABI safe, - * and may change in a future version ! - */ -#define LZ4_STREAMDECODESIZE_U64 4 -#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) -union LZ4_streamDecode_u { - unsigned long long table[LZ4_STREAMDECODESIZE_U64]; - LZ4_streamDecode_t_internal internal_donotuse; -} ; /* previously typedef'd to LZ4_streamDecode_t */ - -#ifndef HEAPMODE -# define HEAPMODE 0 -#endif - -//#define ACCELERATION_DEFAULT 1 - -/* LZ4_FORCE_MEMORY_ACCESS - * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. - * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. - * The below switch allow to select different access method for improved performance. - * Method 0 (default) : use `memcpy()`. Safe and portable. - * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). - * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. - * Method 2 : direct access. This method is portable but violate C standard. - * It can generate buggy code on targets which generate assembly depending on alignment. - * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) - * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. - * Prefer these methods in priority order (0 > 1 > 2) - */ -#if 0 -#ifndef LZ4_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define LZ4_FORCE_MEMORY_ACCESS 2 -# elif defined(__INTEL_COMPILER) || \ - (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) -# define LZ4_FORCE_MEMORY_ACCESS 1 -# endif -#endif -#endif - -#ifdef ZT_NO_TYPE_PUNNING -#define LZ4_FORCE_MEMORY_ACCESS 0 -#else -#define LZ4_FORCE_MEMORY_ACCESS 2 -#endif - -/* - * LZ4_FORCE_SW_BITCOUNT - * Define this parameter if your target system or compiler does not support hardware bit count - */ -#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */ -# define LZ4_FORCE_SW_BITCOUNT -#endif - -/*-************************************ -* Compiler Options -**************************************/ -#if 0 -#ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline -# include -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ -#else -# if defined(__GNUC__) || defined(__clang__) -# define FORCE_INLINE static inline __attribute__((always_inline)) -# elif defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# define FORCE_INLINE static inline -# else -# define FORCE_INLINE static -# endif -#endif /* _MSC_VER */ -#endif - -#ifndef FORCE_INLINE -#define FORCE_INLINE static inline -#endif - -#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) -# define expect(expr,value) (__builtin_expect ((expr),(value)) ) -#else -# define expect(expr,value) (expr) -#endif - -#define likely(expr) expect((expr) != 0, 1) -#define unlikely(expr) expect((expr) != 0, 0) - -/*-************************************ -* Memory routines -**************************************/ -//#include /* malloc, calloc, free */ -#define ALLOCATOR(n,s) calloc(n,s) -#define FREEMEM free -//#include /* memset, memcpy */ -#define MEM_INIT memset - -/*-************************************ -* Basic Types -**************************************/ -typedef uint8_t BYTE; -typedef uint16_t U16; -typedef uint32_t U32; -typedef int32_t S32; -typedef uint64_t U64; -typedef uintptr_t uptrval; -typedef uintptr_t reg_t; - -/*-************************************ -* Reading and writing into memory -**************************************/ -static unsigned LZ4_isLittleEndian(void) -{ - const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ - return one.c[0]; -} - -#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) -/* lie to the compiler about data alignment; use with caution */ - -static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; } -static U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; } -static reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; } - -static void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } -static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } - -#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1) - -/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ -/* currently only defined for gcc and icc */ -typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) unalign; - -static U16 LZ4_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } -static U32 LZ4_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } -static reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArch; } - -static void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } -static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; } - -#else /* safe and portable access through memcpy() */ - -static inline U16 LZ4_read16(const void* memPtr) -{ - U16 val; memcpy(&val, memPtr, sizeof(val)); return val; -} - -static inline U32 LZ4_read32(const void* memPtr) -{ - U32 val; memcpy(&val, memPtr, sizeof(val)); return val; -} - -static inline reg_t LZ4_read_ARCH(const void* memPtr) -{ - reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; -} - -static inline void LZ4_write16(void* memPtr, U16 value) -{ - memcpy(memPtr, &value, sizeof(value)); -} - -static inline void LZ4_write32(void* memPtr, U32 value) -{ - memcpy(memPtr, &value, sizeof(value)); -} - -#endif /* LZ4_FORCE_MEMORY_ACCESS */ - -static inline U16 LZ4_readLE16(const void* memPtr) -{ - if (LZ4_isLittleEndian()) { - return LZ4_read16(memPtr); - } else { - const BYTE* p = (const BYTE*)memPtr; - return (U16)((U16)p[0] + (p[1]<<8)); - } -} - -static inline void LZ4_writeLE16(void* memPtr, U16 value) -{ - if (LZ4_isLittleEndian()) { - LZ4_write16(memPtr, value); - } else { - BYTE* p = (BYTE*)memPtr; - p[0] = (BYTE) value; - p[1] = (BYTE)(value>>8); - } -} - -static inline void LZ4_copy8(void* dst, const void* src) -{ - memcpy(dst,src,8); -} - -/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ -static inline void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) -{ - BYTE* d = (BYTE*)dstPtr; - const BYTE* s = (const BYTE*)srcPtr; - BYTE* const e = (BYTE*)dstEnd; - - do { LZ4_copy8(d,s); d+=8; s+=8; } while (d>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll((U64)val) >> 3); -# else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; -# endif - } else /* 32 bits */ { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r; - _BitScanForward( &r, (U32)val ); - return (int)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz((U32)val) >> 3); -# else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; -# endif - } - } else /* Big Endian CPU */ { - if (sizeof(val)==8) { -# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll((U64)val) >> 3); -# else - unsigned r; - if (!(val>>32)) { r=4; } else { r=0; val>>=32; } - if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } - r += (!val); - return r; -# endif - } else /* 32 bits */ { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz((U32)val) >> 3); -# else - unsigned r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; -# endif - } - } -} - -#define STEPSIZE sizeof(reg_t) -static inline unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) -{ - const BYTE* const pStart = pIn; - - while (likely(pIn compression run slower on incompressible data */ - -/*-************************************ -* Local Structures and types -**************************************/ -typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive; -typedef enum { byPtr, byU32, byU16 } tableType_t; - -typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive; -typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; - -typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; -typedef enum { full = 0, partial = 1 } earlyEnd_directive; - -/*-************************************ -* Local Utils -**************************************/ -//int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } -//const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; } -int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } -//int LZ4_sizeofState() { return LZ4_STREAMSIZE; } - -/*-****************************** -* Compression functions -********************************/ -static inline U32 LZ4_hash4(U32 sequence, tableType_t const tableType) -{ - if (tableType == byU16) - return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); - else - return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); -} - -static inline U32 LZ4_hash5(U64 sequence, tableType_t const tableType) -{ - static const U64 prime5bytes = 889523592379ULL; - static const U64 prime8bytes = 11400714785074694791ULL; - const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; - if (LZ4_isLittleEndian()) - return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); - else - return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); -} - -FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) -{ - if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); - return LZ4_hash4(LZ4_read32(p), tableType); -} - -static inline void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) -{ - switch (tableType) - { - case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } - case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } - case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } - } -} - -FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) -{ - U32 const h = LZ4_hashPosition(p, tableType); - LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); -} - -static inline const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) -{ - if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } - if (tableType == byU32) { const U32* const hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } - { const U16* const hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ -} - -FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) -{ - U32 const h = LZ4_hashPosition(p, tableType); - return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); -} - -/** LZ4_compress_generic() : - inlined, to ensure branches are decided at compilation time */ -FORCE_INLINE int LZ4_compress_generic( - LZ4_stream_t_internal* const cctx, - const char* const source, - char* const dest, - const int inputSize, - const int maxOutputSize, - const limitedOutput_directive outputLimited, - const tableType_t tableType, - const dict_directive dict, - const dictIssue_directive dictIssue, - const U32 acceleration) -{ - const BYTE* ip = (const BYTE*) source; - const BYTE* base; - const BYTE* lowLimit; - const BYTE* const lowRefLimit = ip - cctx->dictSize; - const BYTE* const dictionary = cctx->dictionary; - const BYTE* const dictEnd = dictionary + cctx->dictSize; - const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; - const BYTE* anchor = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = iend - LASTLITERALS; - - BYTE* op = (BYTE*) dest; - BYTE* const olimit = op + maxOutputSize; - - U32 forwardH; - - /* Init conditions */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */ - switch(dict) - { - case noDict: - default: - base = (const BYTE*)source; - lowLimit = (const BYTE*)source; - break; - case withPrefix64k: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source - cctx->dictSize; - break; - case usingExtDict: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source; - break; - } - if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ - if (inputSizehashTable, tableType, base); - ip++; forwardH = LZ4_hashPosition(ip, tableType); - - /* Main Loop */ - for ( ; ; ) { - ptrdiff_t refDelta = 0; - const BYTE* match; - BYTE* token; - - /* Find a match */ - { const BYTE* forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = acceleration << LZ4_skipTrigger; - do { - U32 const h = forwardH; - ip = forwardIp; - forwardIp += step; - step = (searchMatchNb++ >> LZ4_skipTrigger); - - if (unlikely(forwardIp > mflimit)) goto _last_literals; - - match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); - if (dict==usingExtDict) { - if (match < (const BYTE*)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE*)source; - } } - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); - - } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) - || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) - || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); - } - - /* Catch up */ - while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } - - /* Encode Literals */ - { unsigned const litLength = (unsigned)(ip - anchor); - token = op++; - if ((outputLimited) && /* Check output buffer overflow */ - (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) - return 0; - if (litLength >= RUN_MASK) { - int len = (int)litLength-RUN_MASK; - *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; - *op++ = (BYTE)len; - } - else *token = (BYTE)(litLength< matchlimit) limit = matchlimit; - matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); - ip += MINMATCH + matchCode; - if (ip==limit) { - unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); - matchCode += more; - ip += more; - } - } else { - matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); - ip += MINMATCH + matchCode; - } - - if ( outputLimited && /* Check output buffer overflow */ - (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) - return 0; - if (matchCode >= ML_MASK) { - *token += ML_MASK; - matchCode -= ML_MASK; - LZ4_write32(op, 0xFFFFFFFF); - while (matchCode >= 4*255) op+=4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4*255; - op += matchCode / 255; - *op++ = (BYTE)(matchCode % 255); - } else - *token += (BYTE)(matchCode); - } - - anchor = ip; - - /* Test end of chunk */ - if (ip > mflimit) break; - - /* Fill table */ - LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); - - /* Test next position */ - match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); - if (dict==usingExtDict) { - if (match < (const BYTE*)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE*)source; - } } - LZ4_putPosition(ip, cctx->hashTable, tableType, base); - if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) - && (match+MAX_DISTANCE>=ip) - && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) - { token=op++; *token=0; goto _next_match; } - - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } - -_last_literals: - /* Encode Last Literals */ - { size_t const lastRun = (size_t)(iend - anchor); - if ( (outputLimited) && /* Check output buffer overflow */ - ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) - return 0; - if (lastRun >= RUN_MASK) { - size_t accumulator = lastRun - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; - *op++ = (BYTE) accumulator; - } else { - *op++ = (BYTE)(lastRun<internal_donotuse; - LZ4_resetStream((LZ4_stream_t*)state); - //if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - - if (maxOutputSize >= LZ4_compressBound(inputSize)) { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } else { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } -} - -static inline int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) -{ -#if (HEAPMODE) - void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ -#else - LZ4_stream_t ctx; - void* const ctxPtr = &ctx; -#endif - - int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); - -#if (HEAPMODE) - FREEMEM(ctxPtr); -#endif - return result; -} - -void LZ4_resetStream (LZ4_stream_t* LZ4_stream) -{ - MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); -} - -/*-***************************** -* Decompression functions -*******************************/ -/*! LZ4_decompress_generic() : - * This generic decompression function cover all use cases. - * It shall be instantiated several times, using different sets of directives - * Note that it is important this generic function is really inlined, - * in order to remove useless branches during compilation optimization. - */ -FORCE_INLINE int LZ4_decompress_generic( - const char* const source, - char* const dest, - int inputSize, - int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ - - int endOnInput, /* endOnOutputSize, endOnInputSize */ - int partialDecoding, /* full, partial */ - int targetOutputSize, /* only used if partialDecoding==partial */ - int dict, /* noDict, withPrefix64k, usingExtDict */ - const BYTE* const lowPrefix, /* == dest when no prefix */ - const BYTE* const dictStart, /* only if dict==usingExtDict */ - const size_t dictSize /* note : = 0 if noDict */ - ) -{ - /* Local Variables */ - const BYTE* ip = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; - - BYTE* op = (BYTE*) dest; - BYTE* const oend = op + outputSize; - BYTE* cpy; - BYTE* oexit = op + targetOutputSize; - const BYTE* const lowLimit = lowPrefix - dictSize; - - const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; - const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; - const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; - - const int safeDecode = (endOnInput==endOnInputSize); - const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); - - - /* Special cases */ - if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ - if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ - if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); - - /* Main Loop : decode sequences */ - while (1) { - size_t length; - const BYTE* match; - size_t offset; - - /* get literal length */ - unsigned const token = *ip++; - if ((length=(token>>ML_BITS)) == RUN_MASK) { - unsigned s; - do { - s = *ip++; - length += s; - } while ( likely(endOnInput ? ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) - || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) - { - if (partialDecoding) { - if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ - if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ - } else { - if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ - if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ - } - memcpy(op, ip, length); - ip += length; - op += length; - break; /* Necessarily EOF, due to parsing restrictions */ - } - LZ4_wildCopy(op, ip, cpy); - ip += length; op = cpy; - - /* get offset */ - offset = LZ4_readLE16(ip); ip+=2; - match = op - offset; - if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */ - LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ - - /* get matchlength */ - length = token & ML_MASK; - if (length == ML_MASK) { - unsigned s; - do { - s = *ip++; - if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; - length += s; - } while (s==255); - if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ - } - length += MINMATCH; - - /* check external dictionary */ - if ((dict==usingExtDict) && (match < lowPrefix)) { - if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ - - if (length <= (size_t)(lowPrefix-match)) { - /* match can be copied as a single segment from external dictionary */ - memmove(op, dictEnd - (lowPrefix-match), length); - op += length; - } else { - /* match encompass external dictionary and current block */ - size_t const copySize = (size_t)(lowPrefix-match); - size_t const restSize = length - copySize; - memcpy(op, dictEnd - copySize, copySize); - op += copySize; - if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ - BYTE* const endOfMatch = op + restSize; - const BYTE* copyFrom = lowPrefix; - while (op < endOfMatch) *op++ = *copyFrom++; - } else { - memcpy(op, lowPrefix, restSize); - op += restSize; - } } - continue; - } - - /* copy match within block */ - cpy = op + length; - if (unlikely(offset<8)) { - const int dec64 = dec64table[offset]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[offset]; - memcpy(op+4, match, 4); - match -= dec64; - } else { LZ4_copy8(op, match); match+=8; } - op += 8; - - if (unlikely(cpy>oend-12)) { - BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); - if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ - if (op < oCopyLimit) { - LZ4_wildCopy(op, match, oCopyLimit); - match += oCopyLimit - op; - op = oCopyLimit; - } - while (op16) LZ4_wildCopy(op+8, match+8, cpy); - } - op=cpy; /* correction */ - } - - /* end of decoding */ - if (endOnInput) - return (int) (((char*)op)-dest); /* Nb of output bytes decoded */ - else - return (int) (((const char*)ip)-source); /* Nb of input bytes read */ - - /* Overflow error detected */ -_output_error: - return (int) (-(((const char*)ip)-source))-1; -} - -static inline int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) -{ - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); -} - -} // anonymous namespace - -/************************************************************************** */ -/************************************************************************** */ - -const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; - -#ifdef ZT_TRACE - -const char *Packet::verbString(Verb v) -{ - switch(v) { - case VERB_NOP: return "NOP"; - case VERB_HELLO: return "HELLO"; - case VERB_ERROR: return "ERROR"; - case VERB_OK: return "OK"; - case VERB_WHOIS: return "WHOIS"; - case VERB_RENDEZVOUS: return "RENDEZVOUS"; - case VERB_FRAME: return "FRAME"; - case VERB_EXT_FRAME: return "EXT_FRAME"; - case VERB_ECHO: return "ECHO"; - case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE"; - case VERB_NETWORK_CREDENTIALS: return "NETWORK_CREDENTIALS"; - case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST"; - case VERB_NETWORK_CONFIG: return "NETWORK_CONFIG"; - case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; - case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; - case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; - case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST"; - case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT"; - case VERB_USER_MESSAGE: return "USER_MESSAGE"; - } - return "(unknown)"; -} - -const char *Packet::errorString(ErrorCode e) -{ - switch(e) { - case ERROR_NONE: return "NONE"; - case ERROR_INVALID_REQUEST: return "INVALID_REQUEST"; - case ERROR_BAD_PROTOCOL_VERSION: return "BAD_PROTOCOL_VERSION"; - case ERROR_OBJ_NOT_FOUND: return "OBJECT_NOT_FOUND"; - case ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION"; - case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION"; - case ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE"; - case ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED"; - case ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST"; - } - return "(unknown)"; -} - -#endif // ZT_TRACE - -void Packet::armor(const void *key,bool encryptPayload,unsigned int counter) -{ - uint8_t mangledKey[32],macKey[32],mac[16]; - uint8_t *const data = reinterpret_cast(unsafeData()); - - // Mask least significant 3 bits of packet ID with counter to embed packet send counter for QoS use - data[7] = (data[7] & 0xf8) | (uint8_t)(counter & 0x07); - - // Set flag now, since it affects key mangle function - setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); - - _salsa20MangleKey((const unsigned char *)key,mangledKey); - Salsa20 s20(mangledKey,256,data + ZT_PACKET_IDX_IV); - - // MAC key is always the first 32 bytes of the Salsa20 key stream - // This is the same construction DJB's NaCl library uses - s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); - - uint8_t *const payload = data + ZT_PACKET_IDX_VERB; - const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - if (encryptPayload) - s20.crypt12(payload,payload,payloadLen); - Poly1305::compute(mac,payload,payloadLen,macKey); - memcpy(data + ZT_PACKET_IDX_MAC,mac,8); -} - -bool Packet::dearmor(const void *key) -{ - uint8_t mangledKey[32],macKey[32],mac[16]; - uint8_t *const data = reinterpret_cast(unsafeData()); - const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - unsigned char *const payload = data + ZT_PACKET_IDX_VERB; - const unsigned int cs = cipher(); - - if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) { - _salsa20MangleKey((const unsigned char *)key,mangledKey); - Salsa20 s20(mangledKey,256,data + ZT_PACKET_IDX_IV); - - s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); - Poly1305::compute(mac,payload,payloadLen,macKey); - if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) - return false; // MAC failed, packet is corrupt, modified, or is not from the sender - - if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) - s20.crypt12(payload,payload,payloadLen); - - return true; - } else { - return false; // unrecognized cipher suite - } -} - -void Packet::cryptField(const void *key,unsigned int start,unsigned int len) -{ - uint8_t *const data = reinterpret_cast(unsafeData()); - uint8_t iv[8]; - for(int i=0;i<8;++i) iv[i] = data[i]; - iv[7] &= 0xf8; // mask off least significant 3 bits of packet ID / IV since this is unset when this function gets called - Salsa20 s20(key,256,iv); - s20.crypt12(data + start,data + start,len); -} - -bool Packet::compress() -{ - char *const data = reinterpret_cast(unsafeData()); - char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2]; - - if ((!compressed())&&(size() > (ZT_PACKET_IDX_PAYLOAD + 64))) { // don't bother compressing tiny packets - int pl = (int)(size() - ZT_PACKET_IDX_PAYLOAD); - int cl = LZ4_compress_fast(data + ZT_PACKET_IDX_PAYLOAD,buf,pl,ZT_PROTO_MAX_PACKET_LENGTH * 2,2); - if ((cl > 0)&&(cl < pl)) { - data[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED; - setSize((unsigned int)cl + ZT_PACKET_IDX_PAYLOAD); - memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,cl); - return true; - } - } - data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); - - return false; -} - -bool Packet::uncompress() -{ - char *const data = reinterpret_cast(unsafeData()); - char buf[ZT_PROTO_MAX_PACKET_LENGTH]; - - if ((compressed())&&(size() >= ZT_PROTO_MIN_PACKET_LENGTH)) { - if (size() > ZT_PACKET_IDX_PAYLOAD) { - unsigned int compLen = size() - ZT_PACKET_IDX_PAYLOAD; - int ucl = LZ4_decompress_safe((const char *)data + ZT_PACKET_IDX_PAYLOAD,buf,compLen,sizeof(buf)); - if ((ucl > 0)&&(ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) { - setSize((unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD); - memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,ucl); - } else { - return false; - } - } - data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); - } - - return true; -} - -} // namespace ZeroTier diff --git a/zto/node/Packet.hpp b/zto/node/Packet.hpp deleted file mode 100644 index 8ad2c0f..0000000 --- a/zto/node/Packet.hpp +++ /dev/null @@ -1,1457 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_N_PACKET_HPP -#define ZT_N_PACKET_HPP - -#include -#include -#include - -#include -#include - -#include "Constants.hpp" - -#include "Address.hpp" -#include "Poly1305.hpp" -#include "Salsa20.hpp" -#include "Utils.hpp" -#include "Buffer.hpp" - -//#ifdef ZT_USE_SYSTEM_LZ4 -//#include -//#else -//#include "../ext/lz4/lz4.h" -//#endif - -/** - * Protocol version -- incremented only for major changes - * - * 1 - 0.2.0 ... 0.2.5 - * 2 - 0.3.0 ... 0.4.5 - * + Added signature and originating peer to multicast frame - * + Double size of multicast frame bloom filter - * 3 - 0.5.0 ... 0.6.0 - * + Yet another multicast redesign - * + New crypto completely changes key agreement cipher - * 4 - 0.6.0 ... 1.0.6 - * + BREAKING CHANGE: New identity format based on hashcash design - * 5 - 1.1.0 ... 1.1.5 - * + Supports circuit test, proof of work, and echo - * + Supports in-band world (root server definition) updates - * + Clustering! (Though this will work with protocol v4 clients.) - * + Otherwise backward compatible with protocol v4 - * 6 - 1.1.5 ... 1.1.10 - * + Network configuration format revisions including binary values - * 7 - 1.1.10 ... 1.1.17 - * + Introduce trusted paths for local SDN use - * 8 - 1.1.17 ... 1.2.0 - * + Multipart network configurations for large network configs - * + Tags and Capabilities - * + Inline push of CertificateOfMembership deprecated - * + Certificates of representation for federation and mesh - * 9 - 1.2.0 ... CURRENT - * + In-band encoding of packet counter for link quality measurement - */ -#define ZT_PROTO_VERSION 9 - -/** - * Minimum supported protocol version - */ -#define ZT_PROTO_VERSION_MIN 4 - -/** - * Maximum hop count allowed by packet structure (3 bits, 0-7) - * - * This is a protocol constant. It's the maximum allowed by the length - * of the hop counter -- three bits. See node/Constants.hpp for the - * pragmatic forwarding limit, which is typically lower. - */ -#define ZT_PROTO_MAX_HOPS 7 - -/** - * Cipher suite: Curve25519/Poly1305/Salsa20/12/NOCRYPT - * - * This specifies Poly1305 MAC using a 32-bit key derived from the first - * 32 bytes of a Salsa20/12 keystream as in the Salsa20/12 cipher suite, - * but the payload is not encrypted. This is currently only used to send - * HELLO since that's the public key specification packet and must be - * sent in the clear. Key agreement is performed using Curve25519 elliptic - * curve Diffie-Hellman. - */ -#define ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE 0 - -/** - * Cipher suite: Curve25519/Poly1305/Salsa20/12 - * - * This specifies Poly1305 using the first 32 bytes of a Salsa20/12 key - * stream as its one-time-use key followed by payload encryption with - * the remaining Salsa20/12 key stream. Key agreement is performed using - * Curve25519 elliptic curve Diffie-Hellman. - */ -#define ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 1 - -/** - * Cipher suite: NONE - * - * This differs from POLY1305/NONE in that *no* crypto is done, not even - * authentication. This is for trusted local LAN interconnects for internal - * SDN use within a data center. - * - * For this mode the MAC field becomes a trusted path ID and must match the - * configured ID of a trusted path or the packet is discarded. - */ -#define ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH 2 - -/** - * DEPRECATED payload encrypted flag, may be re-used in the future. - * - * This has been replaced by the three-bit cipher suite selection field. - */ -#define ZT_PROTO_FLAG_ENCRYPTED 0x80 - -/** - * Header flag indicating that a packet is fragmented - * - * If this flag is set, the receiver knows to expect more than one fragment. - * See Packet::Fragment for details. - */ -#define ZT_PROTO_FLAG_FRAGMENTED 0x40 - -/** - * Verb flag indicating payload is compressed with LZ4 - */ -#define ZT_PROTO_VERB_FLAG_COMPRESSED 0x80 - -/** - * Rounds used for Salsa20 encryption in ZT - * - * Discussion: - * - * DJB (Salsa20's designer) designed Salsa20 with a significant margin of 20 - * rounds, but has said repeatedly that 12 is likely sufficient. So far (as of - * July 2015) there are no published attacks against 12 rounds, let alone 20. - * - * In cryptography, a "break" means something different from what it means in - * common discussion. If a cipher is 256 bits strong and someone finds a way - * to reduce key search to 254 bits, this constitues a "break" in the academic - * literature. 254 bits is still far beyond what can be leveraged to accomplish - * a "break" as most people would understand it -- the actual decryption and - * reading of traffic. - * - * Nevertheless, "attacks only get better" as cryptographers like to say. As - * a result, they recommend not using anything that's shown any weakness even - * if that weakness is so far only meaningful to academics. It may be a sign - * of a deeper problem. - * - * So why choose a lower round count? - * - * Turns out the speed difference is nontrivial. On a Macbook Pro (Core i3) 20 - * rounds of SSE-optimized Salsa20 achieves ~508mb/sec/core, while 12 rounds - * hits ~832mb/sec/core. ZeroTier is designed for multiple objectives: - * security, simplicity, and performance. In this case a deference was made - * for performance. - * - * Meta discussion: - * - * The cipher is not the thing you should be paranoid about. - * - * I'll qualify that. If the cipher is known to be weak, like RC4, or has a - * key size that is too small, like DES, then yes you should worry about - * the cipher. - * - * But if the cipher is strong and your adversary is anyone other than the - * intelligence apparatus of a major superpower, you are fine in that - * department. - * - * Go ahead. Search for the last ten vulnerabilities discovered in SSL. Not - * a single one involved the breaking of a cipher. Now broaden your search. - * Look for issues with SSH, IPSec, etc. The only cipher-related issues you - * will find might involve the use of RC4 or MD5, algorithms with known - * issues or small key/digest sizes. But even weak ciphers are difficult to - * exploit in the real world -- you usually need a lot of data and a lot of - * compute time. No, virtually EVERY security vulnerability you will find - * involves a problem with the IMPLEMENTATION not with the cipher. - * - * A flaw in ZeroTier's protocol or code is incredibly, unbelievably - * more likely than a flaw in Salsa20 or any other cipher or cryptographic - * primitive it uses. We're talking odds of dying in a car wreck vs. odds of - * being personally impacted on the head by a meteorite. Nobody without a - * billion dollar budget is going to break into your network by actually - * cracking Salsa20/12 (or even /8) in the field. - * - * So stop worrying about the cipher unless you are, say, the Kremlin and your - * adversary is the NSA and the GCHQ. In that case... well that's above my - * pay grade. I'll just say defense in depth. - */ -#define ZT_PROTO_SALSA20_ROUNDS 12 - -/** - * PUSH_DIRECT_PATHS flag: forget path - */ -#define ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH 0x01 - -/** - * PUSH_DIRECT_PATHS flag: cluster redirect - */ -#define ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT 0x02 - -// Field indexes in packet header -#define ZT_PACKET_IDX_IV 0 -#define ZT_PACKET_IDX_DEST 8 -#define ZT_PACKET_IDX_SOURCE 13 -#define ZT_PACKET_IDX_FLAGS 18 -#define ZT_PACKET_IDX_MAC 19 -#define ZT_PACKET_IDX_VERB 27 -#define ZT_PACKET_IDX_PAYLOAD 28 - -/** - * Packet buffer size (can be changed) - * - * The current value is big enough for ZT_MAX_PACKET_FRAGMENTS, the pragmatic - * packet fragment limit, times the default UDP MTU. Most packets won't be - * this big. - */ -#define ZT_PROTO_MAX_PACKET_LENGTH (ZT_MAX_PACKET_FRAGMENTS * ZT_UDP_DEFAULT_PAYLOAD_MTU) - -/** - * Minimum viable packet length (a.k.a. header length) - */ -#define ZT_PROTO_MIN_PACKET_LENGTH ZT_PACKET_IDX_PAYLOAD - -// Indexes of fields in fragment header -#define ZT_PACKET_FRAGMENT_IDX_PACKET_ID 0 -#define ZT_PACKET_FRAGMENT_IDX_DEST 8 -#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR 13 -#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO 14 -#define ZT_PACKET_FRAGMENT_IDX_HOPS 15 -#define ZT_PACKET_FRAGMENT_IDX_PAYLOAD 16 - -/** - * Magic number found at ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR - */ -#define ZT_PACKET_FRAGMENT_INDICATOR ZT_ADDRESS_RESERVED_PREFIX - -/** - * Minimum viable fragment length - */ -#define ZT_PROTO_MIN_FRAGMENT_LENGTH ZT_PACKET_FRAGMENT_IDX_PAYLOAD - -// Field incides for parsing verbs ------------------------------------------- - -// Some verbs have variable-length fields. Those aren't fully defined here -// yet-- instead they are parsed using relative indexes in IncomingPacket. -// See their respective handler functions. - -#define ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION + 1) -#define ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION + 1) -#define ZT_PROTO_VERB_HELLO_IDX_REVISION (ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION + 1) -#define ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP (ZT_PROTO_VERB_HELLO_IDX_REVISION + 2) -#define ZT_PROTO_VERB_HELLO_IDX_IDENTITY (ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP + 8) - -#define ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID (ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB + 1) -#define ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE (ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID + 8) -#define ZT_PROTO_VERB_ERROR_IDX_PAYLOAD (ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE + 1) - -#define ZT_PROTO_VERB_OK_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID (ZT_PROTO_VERB_OK_IDX_IN_RE_VERB + 1) -#define ZT_PROTO_VERB_OK_IDX_PAYLOAD (ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID + 8) - -#define ZT_PROTO_VERB_WHOIS_IDX_ZTADDRESS (ZT_PACKET_IDX_PAYLOAD) - -#define ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT (ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS + 5) -#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN (ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT + 2) -#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN + 1) - -#define ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2) - -#define ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID 8 -#define ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS (ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID + ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID) -#define ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS 1 -#define ZT_PROTO_VERB_EXT_FRAME_IDX_COM (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS) -#define ZT_PROTO_VERB_EXT_FRAME_IDX_TO (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS) -#define ZT_PROTO_VERB_EXT_FRAME_LEN_TO 6 -#define ZT_PROTO_VERB_EXT_FRAME_IDX_FROM (ZT_PROTO_VERB_EXT_FRAME_IDX_TO + ZT_PROTO_VERB_EXT_FRAME_LEN_TO) -#define ZT_PROTO_VERB_EXT_FRAME_LEN_FROM 6 -#define ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_EXT_FRAME_IDX_FROM + ZT_PROTO_VERB_EXT_FRAME_LEN_FROM) -#define ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE 2 -#define ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE + ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE) - -#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN + 2) - -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC + 6) -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI + 4) -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT + 4) - -// Note: COM, GATHER_LIMIT, and SOURCE_MAC are optional, and so are specified without size -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC + 6) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI + 4) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE + 2) - -#define ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP (ZT_PROTO_VERB_OK_IDX_PAYLOAD) -#define ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP + 8) -#define ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION + 1) -#define ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION + 1) -#define ZT_PROTO_VERB_HELLO__OK__IDX_REVISION (ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION + 1) - -#define ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY (ZT_PROTO_VERB_OK_IDX_PAYLOAD) - -#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD) -#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN + 2) - -#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD) -#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC + 6) -#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI + 4) - -#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD) -#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC + 6) -#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI + 4) -#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS + 1) - -// --------------------------------------------------------------------------- - -namespace ZeroTier { - -/** - * ZeroTier packet - * - * Packet format: - * <[8] 64-bit packet ID / crypto IV / packet counter> - * <[5] destination ZT address> - * <[5] source ZT address> - * <[1] flags/cipher/hops> - * <[8] 64-bit MAC (or trusted path ID in trusted path mode)> - * [... -- begin encryption envelope -- ...] - * <[1] encrypted flags (MS 3 bits) and verb (LS 5 bits)> - * [... verb-specific payload ...] - * - * Packets smaller than 28 bytes are invalid and silently discarded. - * - * The 64-bit packet ID is a strongly random value used as a crypto IV. - * Its least significant 3 bits are also used as a monotonically increasing - * (and looping) counter for sending packets to a particular recipient. This - * can be used for link quality monitoring and reporting and has no crypto - * impact as it does not increase the likelihood of an IV collision. (The - * crypto we use is not sensitive to the nature of the IV, only that it does - * not repeat.) - * - * The flags/cipher/hops bit field is: FFCCCHHH where C is a 3-bit cipher - * selection allowing up to 7 cipher suites, F is outside-envelope flags, - * and H is hop count. - * - * The three-bit hop count is the only part of a packet that is mutable in - * transit without invalidating the MAC. All other bits in the packet are - * immutable. This is because intermediate nodes can increment the hop - * count up to 7 (protocol max). - * - * For unencrypted packets, MAC is computed on plaintext. Only HELLO is ever - * sent in the clear, as it's the "here is my public key" message. - */ -class Packet : public Buffer -{ -public: - /** - * A packet fragment - * - * Fragments are sent if a packet is larger than UDP MTU. The first fragment - * is sent with its normal header with the fragmented flag set. Remaining - * fragments are sent this way. - * - * The fragmented bit indicates that there is at least one fragment. Fragments - * themselves contain the total, so the receiver must "learn" this from the - * first fragment it receives. - * - * Fragments are sent with the following format: - * <[8] packet ID of packet whose fragment this belongs to> - * <[5] destination ZT address> - * <[1] 0xff, a reserved address, signals that this isn't a normal packet> - * <[1] total fragments (most significant 4 bits), fragment no (LS 4 bits)> - * <[1] ZT hop count (top 5 bits unused and must be zero)> - * <[...] fragment data> - * - * The protocol supports a maximum of 16 fragments. If a fragment is received - * before its main packet header, it should be cached for a brief period of - * time to see if its parent arrives. Loss of any fragment constitutes packet - * loss; there is no retransmission mechanism. The receiver must wait for full - * receipt to authenticate and decrypt; there is no per-fragment MAC. (But if - * fragments are corrupt, the MAC will fail for the whole assembled packet.) - */ - class Fragment : public Buffer - { - public: - Fragment() : - Buffer() - { - } - - template - Fragment(const Buffer &b) - throw(std::out_of_range) : - Buffer(b) - { - } - - Fragment(const void *data,unsigned int len) : - Buffer(data,len) - { - } - - /** - * Initialize from a packet - * - * @param p Original assembled packet - * @param fragStart Start of fragment (raw index in packet data) - * @param fragLen Length of fragment in bytes - * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) - * @param fragTotal Total number of fragments (including 0) - * @throws std::out_of_range Packet size would exceed buffer - */ - Fragment(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) - throw(std::out_of_range) - { - init(p,fragStart,fragLen,fragNo,fragTotal); - } - - /** - * Initialize from a packet - * - * @param p Original assembled packet - * @param fragStart Start of fragment (raw index in packet data) - * @param fragLen Length of fragment in bytes - * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) - * @param fragTotal Total number of fragments (including 0) - * @throws std::out_of_range Packet size would exceed buffer - */ - inline void init(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) - throw(std::out_of_range) - { - if ((fragStart + fragLen) > p.size()) - throw std::out_of_range("Packet::Fragment: tried to construct fragment of packet past its length"); - setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH); - - // NOTE: this copies both the IV/packet ID and the destination address. - memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID,13),p.field(ZT_PACKET_IDX_IV,13),13); - - (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR; - (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf)); - (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0; - - memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,fragLen),p.field(fragStart,fragLen),fragLen); - } - - /** - * Get this fragment's destination - * - * @return Destination ZT address - */ - inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - - /** - * @return True if fragment is of a valid length - */ - inline bool lengthValid() const { return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); } - - /** - * @return ID of packet this is a fragment of - */ - inline uint64_t packetId() const { return at(ZT_PACKET_FRAGMENT_IDX_PACKET_ID); } - - /** - * @return Total number of fragments in packet - */ - inline unsigned int totalFragments() const { return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf); } - - /** - * @return Fragment number of this fragment - */ - inline unsigned int fragmentNumber() const { return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf); } - - /** - * @return Fragment ZT hop count - */ - inline unsigned int hops() const { return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]); } - - /** - * Increment this packet's hop count - */ - inline void incrementHops() - { - (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = (((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]) + 1) & ZT_PROTO_MAX_HOPS; - } - - /** - * @return Length of payload in bytes - */ - inline unsigned int payloadLength() const { return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); } - - /** - * @return Raw packet payload - */ - inline const unsigned char *payload() const - { - return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD); - } - }; - - /** - * ZeroTier protocol verbs - */ - enum Verb /* Max value: 32 (5 bits) */ - { - /** - * No operation (ignored, no reply) - */ - VERB_NOP = 0x00, - - /** - * Announcement of a node's existence and vitals: - * <[1] protocol version> - * <[1] software major version> - * <[1] software minor version> - * <[2] software revision> - * <[8] timestamp for determining latency> - * <[...] binary serialized identity (see Identity)> - * <[...] physical destination address of packet> - * <[8] 64-bit world ID of current planet> - * <[8] 64-bit timestamp of current planet> - * [... remainder if packet is encrypted using cryptField() ...] - * <[2] 16-bit number of moons> - * [<[1] 8-bit type ID of moon>] - * [<[8] 64-bit world ID of moon>] - * [<[8] 64-bit timestamp of moon>] - * [... additional moon type/ID/timestamp tuples ...] - * <[2] 16-bit length of certificate of representation> - * [... certificate of representation ...] - * - * HELLO is sent in the clear as it is how peers share their identity - * public keys. A few additional fields are sent in the clear too, but - * these are things that are public info or are easy to determine. As - * of 1.2.0 we have added a few more fields, but since these could have - * the potential to be sensitive we introduced the encryption of the - * remainder of the packet. See cryptField(). Packet MAC is still - * performed of course, so authentication occurs as normal. - * - * Destination address is the actual wire address to which the packet - * was sent. See InetAddress::serialize() for format. - * - * OK payload: - * <[8] HELLO timestamp field echo> - * <[1] protocol version> - * <[1] software major version> - * <[1] software minor version> - * <[2] software revision> - * <[...] physical destination address of packet> - * <[2] 16-bit length of world update(s) or 0 if none> - * [[...] updates to planets and/or moons] - * <[2] 16-bit length of certificate of representation> - * [... certificate of representation ...] - * - * With the exception of the timestamp, the other fields pertain to the - * respondent who is sending OK and are not echoes. - * - * Note that OK is fully encrypted so no selective cryptField() of - * potentially sensitive fields is needed. - * - * ERROR has no payload. - */ - VERB_HELLO = 0x01, - - /** - * Error response: - * <[1] in-re verb> - * <[8] in-re packet ID> - * <[1] error code> - * <[...] error-dependent payload> - */ - VERB_ERROR = 0x02, - - /** - * Success response: - * <[1] in-re verb> - * <[8] in-re packet ID> - * <[...] request-specific payload> - */ - VERB_OK = 0x03, - - /** - * Query an identity by address: - * <[5] address to look up> - * [<[...] additional addresses to look up> - * - * OK response payload: - * <[...] binary serialized identity> - * [<[...] additional binary serialized identities>] - * - * If querying a cluster, duplicate OK responses may occasionally occur. - * These must be tolerated, which is easy since they'll have info you - * already have. - * - * If the address is not found, no response is generated. The semantics - * of WHOIS is similar to ARP and NDP in that persistent retrying can - * be performed. - */ - VERB_WHOIS = 0x04, - - /** - * Relay-mediated NAT traversal or firewall punching initiation: - * <[1] flags (unused, currently 0)> - * <[5] ZeroTier address of peer that might be found at this address> - * <[2] 16-bit protocol address port> - * <[1] protocol address length (4 for IPv4, 16 for IPv6)> - * <[...] protocol address (network byte order)> - * - * An upstream node can send this to inform both sides of a relay of - * information they might use to establish a direct connection. - * - * Upon receipt a peer sends HELLO to establish a direct link. - * - * No OK or ERROR is generated. - */ - VERB_RENDEZVOUS = 0x05, - - /** - * ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME): - * <[8] 64-bit network ID> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * MAC addresses are derived from the packet's source and destination - * ZeroTier addresses. This is a shortened EXT_FRAME that elides full - * Ethernet framing and other optional flags and features when they - * are not necessary. - * - * ERROR may be generated if a membership certificate is needed for a - * closed network. Payload will be network ID. - */ - VERB_FRAME = 0x06, - - /** - * Full Ethernet frame with MAC addressing and optional fields: - * <[8] 64-bit network ID> - * <[1] flags> - * <[6] destination MAC or all zero for destination node> - * <[6] source MAC or all zero for node of origin> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * Flags: - * 0x01 - Certificate of network membership attached (DEPRECATED) - * 0x02 - Most significant bit of subtype (see below) - * 0x04 - Middle bit of subtype (see below) - * 0x08 - Least significant bit of subtype (see below) - * 0x10 - ACK requested in the form of OK(EXT_FRAME) - * - * Subtypes (0..7): - * 0x0 - Normal frame (bridging can be determined by checking MAC) - * 0x1 - TEEd outbound frame - * 0x2 - REDIRECTed outbound frame - * 0x3 - WATCHed outbound frame (TEE with ACK, ACK bit also set) - * 0x4 - TEEd inbound frame - * 0x5 - REDIRECTed inbound frame - * 0x6 - WATCHed inbound frame - * 0x7 - (reserved for future use) - * - * An extended frame carries full MAC addressing, making it a - * superset of VERB_FRAME. It is used for bridged traffic, - * redirected or observed traffic via rules, and can in theory - * be used for multicast though MULTICAST_FRAME exists for that - * purpose and has additional options and capabilities. - * - * OK payload (if ACK flag is set): - * <[8] 64-bit network ID> - */ - VERB_EXT_FRAME = 0x07, - - /** - * ECHO request (a.k.a. ping): - * <[...] arbitrary payload> - * - * This generates OK with a copy of the transmitted payload. No ERROR - * is generated. Response to ECHO requests is optional and ECHO may be - * ignored if a node detects a possible flood. - */ - VERB_ECHO = 0x08, - - /** - * Announce interest in multicast group(s): - * <[8] 64-bit network ID> - * <[6] multicast Ethernet address> - * <[4] multicast additional distinguishing information (ADI)> - * [... additional tuples of network/address/adi ...] - * - * LIKEs may be sent to any peer, though a good implementation should - * restrict them to peers on the same network they're for and to network - * controllers and root servers. In the current network, root servers - * will provide the service of final multicast cache. - * - * VERB_NETWORK_CREDENTIALS should be pushed along with this, especially - * if using upstream (e.g. root) nodes as multicast databases. This allows - * GATHERs to be authenticated. - * - * OK/ERROR are not generated. - */ - VERB_MULTICAST_LIKE = 0x09, - - /** - * Network credentials push: - * [<[...] one or more certificates of membership>] - * <[1] 0x00, null byte marking end of COM array> - * <[2] 16-bit number of capabilities> - * <[...] one or more serialized Capability> - * <[2] 16-bit number of tags> - * <[...] one or more serialized Tags> - * <[2] 16-bit number of revocations> - * <[...] one or more serialized Revocations> - * <[2] 16-bit number of certificates of ownership> - * <[...] one or more serialized CertificateOfOwnership> - * - * This can be sent by anyone at any time to push network credentials. - * These will of course only be accepted if they are properly signed. - * Credentials can be for any number of networks. - * - * The use of a zero byte to terminate the COM section is for legacy - * backward compatiblity. Newer fields are prefixed with a length. - * - * OK/ERROR are not generated. - */ - VERB_NETWORK_CREDENTIALS = 0x0a, - - /** - * Network configuration request: - * <[8] 64-bit network ID> - * <[2] 16-bit length of request meta-data dictionary> - * <[...] string-serialized request meta-data> - * <[8] 64-bit revision of netconf we currently have> - * <[8] 64-bit timestamp of netconf we currently have> - * - * This message requests network configuration from a node capable of - * providing it. - * - * Respones to this are always whole configs intended for the recipient. - * For patches and other updates a NETWORK_CONFIG is sent instead. - * - * It would be valid and correct as of 1.2.0 to use NETWORK_CONFIG always, - * but OK(NTEWORK_CONFIG_REQUEST) should be sent for compatibility. - * - * OK response payload: - * <[8] 64-bit network ID> - * <[2] 16-bit length of network configuration dictionary chunk> - * <[...] network configuration dictionary (may be incomplete)> - * [ ... end of legacy single chunk response ... ] - * <[1] 8-bit flags> - * <[8] 64-bit config update ID (should never be 0)> - * <[4] 32-bit total length of assembled dictionary> - * <[4] 32-bit index of chunk> - * [ ... end signed portion ... ] - * <[1] 8-bit chunk signature type> - * <[2] 16-bit length of chunk signature> - * <[...] chunk signature> - * - * The chunk signature signs the entire payload of the OK response. - * Currently only one signature type is supported: ed25519 (1). - * - * Each config chunk is signed to prevent memory exhaustion or - * traffic crowding DOS attacks against config fragment assembly. - * - * If the packet is from the network controller it is permitted to end - * before the config update ID or other chunking related or signature - * fields. This is to support older controllers that don't include - * these fields and may be removed in the future. - * - * ERROR response payload: - * <[8] 64-bit network ID> - */ - VERB_NETWORK_CONFIG_REQUEST = 0x0b, - - /** - * Network configuration data push: - * <[8] 64-bit network ID> - * <[2] 16-bit length of network configuration dictionary chunk> - * <[...] network configuration dictionary (may be incomplete)> - * <[1] 8-bit flags> - * <[8] 64-bit config update ID (should never be 0)> - * <[4] 32-bit total length of assembled dictionary> - * <[4] 32-bit index of chunk> - * [ ... end signed portion ... ] - * <[1] 8-bit chunk signature type> - * <[2] 16-bit length of chunk signature> - * <[...] chunk signature> - * - * This is a direct push variant for network config updates. It otherwise - * carries the same payload as OK(NETWORK_CONFIG_REQUEST) and has the same - * semantics. - * - * The legacy mode missing the additional chunking fields is not supported - * here. - * - * Flags: - * 0x01 - Use fast propagation - * - * An OK should be sent if the config is successfully received and - * accepted. - * - * OK payload: - * <[8] 64-bit network ID> - * <[8] 64-bit config update ID> - */ - VERB_NETWORK_CONFIG = 0x0c, - - /** - * Request endpoints for multicast distribution: - * <[8] 64-bit network ID> - * <[1] flags> - * <[6] MAC address of multicast group being queried> - * <[4] 32-bit ADI for multicast group being queried> - * <[4] 32-bit requested max number of multicast peers> - * [<[...] network certificate of membership>] - * - * Flags: - * 0x01 - COM is attached - * - * This message asks a peer for additional known endpoints that have - * LIKEd a given multicast group. It's sent when the sender wishes - * to send multicast but does not have the desired number of recipient - * peers. - * - * More than one OK response can occur if the response is broken up across - * multiple packets or if querying a clustered node. - * - * The COM should be included so that upstream nodes that are not - * members of our network can validate our request. - * - * OK response payload: - * <[8] 64-bit network ID> - * <[6] MAC address of multicast group being queried> - * <[4] 32-bit ADI for multicast group being queried> - * [begin gather results -- these same fields can be in OK(MULTICAST_FRAME)] - * <[4] 32-bit total number of known members in this multicast group> - * <[2] 16-bit number of members enumerated in this packet> - * <[...] series of 5-byte ZeroTier addresses of enumerated members> - * - * ERROR is not generated; queries that return no response are dropped. - */ - VERB_MULTICAST_GATHER = 0x0d, - - /** - * Multicast frame: - * <[8] 64-bit network ID> - * <[1] flags> - * [<[4] 32-bit implicit gather limit>] - * [<[6] source MAC>] - * <[6] destination MAC (multicast address)> - * <[4] 32-bit multicast ADI (multicast address extension)> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * Flags: - * 0x01 - Network certificate of membership attached (DEPRECATED) - * 0x02 - Implicit gather limit field is present - * 0x04 - Source MAC is specified -- otherwise it's computed from sender - * - * OK and ERROR responses are optional. OK may be generated if there are - * implicit gather results or if the recipient wants to send its own - * updated certificate of network membership to the sender. ERROR may be - * generated if a certificate is needed or if multicasts to this group - * are no longer wanted (multicast unsubscribe). - * - * OK response payload: - * <[8] 64-bit network ID> - * <[6] MAC address of multicast group> - * <[4] 32-bit ADI for multicast group> - * <[1] flags> - * [<[...] network certficate of membership (DEPRECATED)>] - * [<[...] implicit gather results if flag 0x01 is set>] - * - * OK flags (same bits as request flags): - * 0x01 - OK includes certificate of network membership (DEPRECATED) - * 0x02 - OK includes implicit gather results - * - * ERROR response payload: - * <[8] 64-bit network ID> - * <[6] multicast group MAC> - * <[4] 32-bit multicast group ADI> - */ - VERB_MULTICAST_FRAME = 0x0e, - - /** - * Push of potential endpoints for direct communication: - * <[2] 16-bit number of paths> - * <[...] paths> - * - * Path record format: - * <[1] 8-bit path flags> - * <[2] length of extended path characteristics or 0 for none> - * <[...] extended path characteristics> - * <[1] address type> - * <[1] address length in bytes> - * <[...] address> - * - * Path record flags: - * 0x01 - Forget this path if currently known (not implemented yet) - * 0x02 - Cluster redirect -- use this in preference to others - * - * The receiver may, upon receiving a push, attempt to establish a - * direct link to one or more of the indicated addresses. It is the - * responsibility of the sender to limit which peers it pushes direct - * paths to to those with whom it has a trust relationship. The receiver - * must obey any restrictions provided such as exclusivity or blacklists. - * OK responses to this message are optional. - * - * Note that a direct path push does not imply that learned paths can't - * be used unless they are blacklisted explicitly or unless flag 0x01 - * is set. - * - * Only a subset of this functionality is currently implemented: basic - * path pushing and learning. Blacklisting and trust are not fully - * implemented yet (encryption is still always used). - * - * OK and ERROR are not generated. - */ - VERB_PUSH_DIRECT_PATHS = 0x10, - - /** - * Source-routed circuit test message: - * <[5] address of originator of circuit test> - * <[2] 16-bit flags> - * <[8] 64-bit timestamp> - * <[8] 64-bit test ID (arbitrary, set by tester)> - * <[2] 16-bit originator credential length (includes type)> - * [[1] originator credential type (for authorizing test)] - * [[...] originator credential] - * <[2] 16-bit length of additional fields> - * [[...] additional fields] - * [ ... end of signed portion of request ... ] - * <[2] 16-bit length of signature of request> - * <[...] signature of request by originator> - * <[2] 16-bit length of additional fields> - * [[...] additional fields] - * <[...] next hop(s) in path> - * - * Flags: - * 0x01 - Report back to originator at all hops - * 0x02 - Report back to originator at last hop - * - * Originator credential types: - * 0x01 - 64-bit network ID for which originator is controller - * - * Path record format: - * <[1] 8-bit flags (unused, must be zero)> - * <[1] 8-bit breadth (number of next hops)> - * <[...] one or more ZeroTier addresses of next hops> - * - * The circuit test allows a device to send a message that will traverse - * the network along a specified path, with each hop optionally reporting - * back to the tester via VERB_CIRCUIT_TEST_REPORT. - * - * Each circuit test packet includes a digital signature by the originator - * of the request, as well as a credential by which that originator claims - * authorization to perform the test. Currently this signature is ed25519, - * but in the future flags might be used to indicate an alternative - * algorithm. For example, the originator might be a network controller. - * In this case the test might be authorized if the recipient is a member - * of a network controlled by it, and if the previous hop(s) are also - * members. Each hop may include its certificate of network membership. - * - * Circuit test paths consist of a series of records. When a node receives - * an authorized circuit test, it: - * - * (1) Reports back to circuit tester as flags indicate - * (2) Reads and removes the next hop from the packet's path - * (3) Sends the packet along to next hop(s), if any. - * - * It is perfectly legal for a path to contain the same hop more than - * once. In fact, this can be a very useful test to determine if a hop - * can be reached bidirectionally and if so what that connectivity looks - * like. - * - * The breadth field in source-routed path records allows a hop to forward - * to more than one recipient, allowing the tester to specify different - * forms of graph traversal in a test. - * - * There is no hard limit to the number of hops in a test, but it is - * practically limited by the maximum size of a (possibly fragmented) - * ZeroTier packet. - * - * Support for circuit tests is optional. If they are not supported, the - * node should respond with an UNSUPPORTED_OPERATION error. If a circuit - * test request is not authorized, it may be ignored or reported as - * an INVALID_REQUEST. No OK messages are generated, but TEST_REPORT - * messages may be sent (see below). - * - * ERROR packet format: - * <[8] 64-bit timestamp (echoed from original> - * <[8] 64-bit test ID (echoed from original)> - */ - VERB_CIRCUIT_TEST = 0x11, - - /** - * Circuit test hop report: - * <[8] 64-bit timestamp (echoed from original test)> - * <[8] 64-bit test ID (echoed from original test)> - * <[8] 64-bit reserved field (set to 0, currently unused)> - * <[1] 8-bit vendor ID (set to 0, currently unused)> - * <[1] 8-bit reporter protocol version> - * <[1] 8-bit reporter software major version> - * <[1] 8-bit reporter software minor version> - * <[2] 16-bit reporter software revision> - * <[2] 16-bit reporter OS/platform or 0 if not specified> - * <[2] 16-bit reporter architecture or 0 if not specified> - * <[2] 16-bit error code (set to 0, currently unused)> - * <[8] 64-bit report flags> - * <[8] 64-bit packet ID of received CIRCUIT_TEST packet> - * <[5] upstream ZeroTier address from which CIRCUIT_TEST was received> - * <[1] 8-bit packet hop count of received CIRCUIT_TEST> - * <[...] local wire address on which packet was received> - * <[...] remote wire address from which packet was received> - * <[2] 16-bit path link quality of path over which packet was received> - * <[1] 8-bit number of next hops (breadth)> - * <[...] next hop information> - * - * Next hop information record format: - * <[5] ZeroTier address of next hop> - * <[...] current best direct path address, if any, 0 if none> - * - * Report flags: - * 0x1 - Upstream peer in circuit test path allowed in path (e.g. network COM valid) - * - * Circuit test reports can be sent by hops in a circuit test to report - * back results. They should include information about the sender as well - * as about the paths to which next hops are being sent. - * - * If a test report is received and no circuit test was sent, it should be - * ignored. This message generates no OK or ERROR response. - */ - VERB_CIRCUIT_TEST_REPORT = 0x12, - - /** - * A message with arbitrary user-definable content: - * <[8] 64-bit arbitrary message type ID> - * [<[...] message payload>] - * - * This can be used to send arbitrary messages over VL1. It generates no - * OK or ERROR and has no special semantics outside of whatever the user - * (via the ZeroTier core API) chooses to give it. - * - * Message type IDs less than or equal to 65535 are reserved for use by - * ZeroTier, Inc. itself. We recommend making up random ones for your own - * implementations. - */ - VERB_USER_MESSAGE = 0x14 - }; - - /** - * Error codes for VERB_ERROR - */ - enum ErrorCode - { - /* No error, not actually used in transit */ - ERROR_NONE = 0x00, - - /* Invalid request */ - ERROR_INVALID_REQUEST = 0x01, - - /* Bad/unsupported protocol version */ - ERROR_BAD_PROTOCOL_VERSION = 0x02, - - /* Unknown object queried */ - ERROR_OBJ_NOT_FOUND = 0x03, - - /* HELLO pushed an identity whose address is already claimed */ - ERROR_IDENTITY_COLLISION = 0x04, - - /* Verb or use case not supported/enabled by this node */ - ERROR_UNSUPPORTED_OPERATION = 0x05, - - /* Network membership certificate update needed */ - ERROR_NEED_MEMBERSHIP_CERTIFICATE = 0x06, - - /* Tried to join network, but you're not a member */ - ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */ - - /* Multicasts to this group are not wanted */ - ERROR_UNWANTED_MULTICAST = 0x08 - }; - -#ifdef ZT_TRACE - static const char *verbString(Verb v); - static const char *errorString(ErrorCode e); -#endif - - template - Packet(const Buffer &b) : - Buffer(b) - { - } - - Packet(const void *data,unsigned int len) : - Buffer(data,len) - { - } - - /** - * Construct a new empty packet with a unique random packet ID - * - * Flags and hops will be zero. Other fields and data region are undefined. - * Use the header access methods (setDestination() and friends) to fill out - * the header. Payload should be appended; initial size is header size. - */ - Packet() : - Buffer(ZT_PROTO_MIN_PACKET_LENGTH) - { - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops - } - - /** - * Make a copy of a packet with a new initialization vector and destination address - * - * This can be used to take one draft prototype packet and quickly make copies to - * encrypt for different destinations. - * - * @param prototype Prototype packet - * @param dest Destination ZeroTier address for new packet - */ - Packet(const Packet &prototype,const Address &dest) : - Buffer(prototype) - { - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - setDestination(dest); - } - - /** - * Construct a new empty packet with a unique random packet ID - * - * @param dest Destination ZT address - * @param source Source ZT address - * @param v Verb - */ - Packet(const Address &dest,const Address &source,const Verb v) : - Buffer(ZT_PROTO_MIN_PACKET_LENGTH) - { - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - setDestination(dest); - setSource(source); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops - setVerb(v); - } - - /** - * Reset this packet structure for reuse in place - * - * @param dest Destination ZT address - * @param source Source ZT address - * @param v Verb - */ - inline void reset(const Address &dest,const Address &source,const Verb v) - { - setSize(ZT_PROTO_MIN_PACKET_LENGTH); - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - setDestination(dest); - setSource(source); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops - setVerb(v); - } - - /** - * Generate a new IV / packet ID in place - * - * This can be used to re-use a packet buffer multiple times to send - * technically different but otherwise identical copies of the same - * packet. - */ - inline void newInitializationVector() { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); } - - /** - * Set this packet's destination - * - * @param dest ZeroTier address of destination - */ - inline void setDestination(const Address &dest) { dest.copyTo(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - - /** - * Set this packet's source - * - * @param source ZeroTier address of source - */ - inline void setSource(const Address &source) { source.copyTo(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - - /** - * Get this packet's destination - * - * @return Destination ZT address - */ - inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - - /** - * Get this packet's source - * - * @return Source ZT address - */ - inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - - /** - * @return True if packet is of valid length - */ - inline bool lengthValid() const { return (size() >= ZT_PROTO_MIN_PACKET_LENGTH); } - - /** - * @return True if packet is fragmented (expect fragments) - */ - inline bool fragmented() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0); } - - /** - * Set this packet's fragmented flag - * - * @param f Fragmented flag value - */ - inline void setFragmented(bool f) - { - if (f) - (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED; - else (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED); - } - - /** - * @return True if compressed (result only valid if unencrypted) - */ - inline bool compressed() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0); } - - /** - * @return ZeroTier forwarding hops (0 to 7) - */ - inline unsigned int hops() const { return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07); } - - /** - * Increment this packet's hop count - */ - inline void incrementHops() - { - unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; - b = (b & 0xf8) | ((b + 1) & 0x07); - } - - /** - * @return Cipher suite selector: 0 - 7 (see #defines) - */ - inline unsigned int cipher() const - { - return (((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x38) >> 3); - } - - /** - * Set this packet's cipher suite - */ - inline void setCipher(unsigned int c) - { - unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; - b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH - // Set DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers - if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) - b |= ZT_PROTO_FLAG_ENCRYPTED; - else b &= (~ZT_PROTO_FLAG_ENCRYPTED); - } - - /** - * Get the trusted path ID for this packet (only meaningful if cipher is trusted path) - * - * @return Trusted path ID (from MAC field) - */ - inline uint64_t trustedPathId() const { return at(ZT_PACKET_IDX_MAC); } - - /** - * Set this packet's trusted path ID and set the cipher spec to trusted path - * - * @param tpid Trusted path ID - */ - inline void setTrusted(const uint64_t tpid) - { - setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH); - setAt(ZT_PACKET_IDX_MAC,tpid); - } - - /** - * Get this packet's unique ID (the IV field interpreted as uint64_t) - * - * Note that the least significant 3 bits of this ID will change when armor() - * is called to armor the packet for transport. This is because armor() will - * mask the last 3 bits against the send counter for QoS monitoring use prior - * to actually using the IV to encrypt and MAC the packet. Be aware of this - * when grabbing the packetId of a new packet prior to armor/send. - * - * @return Packet ID - */ - inline uint64_t packetId() const { return at(ZT_PACKET_IDX_IV); } - - /** - * @return Value of link quality counter extracted from this packet's ID, range 0 to 7 (3 bits) - */ - inline unsigned int linkQualityCounter() const { return (unsigned int)(reinterpret_cast(data())[7] & 0x07); } - - /** - * Set packet verb - * - * This also has the side-effect of clearing any verb flags, such as - * compressed, and so must only be done during packet composition. - * - * @param v New packet verb - */ - inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; } - - /** - * @return Packet verb (not including flag bits) - */ - inline Verb verb() const { return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f); } - - /** - * @return Length of packet payload - */ - inline unsigned int payloadLength() const { return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH)); } - - /** - * @return Raw packet payload - */ - inline const unsigned char *payload() const { return field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); } - - /** - * Armor packet for transport - * - * @param key 32-byte key - * @param encryptPayload If true, encrypt packet payload, else just MAC - * @param counter Packet send counter for destination peer -- only least significant 3 bits are used - */ - void armor(const void *key,bool encryptPayload,unsigned int counter); - - /** - * Verify and (if encrypted) decrypt packet - * - * This does not handle trusted path mode packets and will return false - * for these. These are handled in IncomingPacket if the sending physical - * address and MAC field match a trusted path. - * - * @param key 32-byte key - * @return False if packet is invalid or failed MAC authenticity check - */ - bool dearmor(const void *key); - - /** - * Encrypt/decrypt a separately armored portion of a packet - * - * This currently uses Salsa20/12, but any message that uses this should - * incorporate a cipher selector to permit this to be changed later. To - * ensure that key stream is not reused, the key is slightly altered for - * this use case and the same initial 32 keystream bytes that are taken - * for MAC in ordinary armor() are also skipped here. - * - * This is currently only used to mask portions of HELLO as an extra - * security precation since most of that message is sent in the clear. - * - * This must NEVER be used more than once in the same packet, as doing - * so will result in re-use of the same key stream. - * - * @param key 32-byte key - * @param start Start of encrypted portion - * @param len Length of encrypted portion - */ - void cryptField(const void *key,unsigned int start,unsigned int len); - - /** - * Attempt to compress payload if not already (must be unencrypted) - * - * This requires that the payload at least contain the verb byte already - * set. The compressed flag in the verb is set if compression successfully - * results in a size reduction. If no size reduction occurs, compression - * is not done and the flag is left cleared. - * - * @return True if compression occurred - */ - bool compress(); - - /** - * Attempt to decompress payload if it is compressed (must be unencrypted) - * - * If payload is compressed, it is decompressed and the compressed verb - * flag is cleared. Otherwise nothing is done and true is returned. - * - * @return True if data is now decompressed and valid, false on error - */ - bool uncompress(); - -private: - static const unsigned char ZERO_KEY[32]; - - /** - * Deterministically mangle a 256-bit crypto key based on packet - * - * This uses extra data from the packet to mangle the secret, giving us an - * effective IV that is somewhat more than 64 bits. This is "free" for - * Salsa20 since it has negligible key setup time so using a different - * key each time is fine. - * - * @param in Input key (32 bytes) - * @param out Output buffer (32 bytes) - */ - inline void _salsa20MangleKey(const unsigned char *in,unsigned char *out) const - { - const unsigned char *d = (const unsigned char *)data(); - - // IV and source/destination addresses. Using the addresses divides the - // key space into two halves-- A->B and B->A (since order will change). - for(unsigned int i=0;i<18;++i) // 8 + (ZT_ADDRESS_LENGTH * 2) == 18 - out[i] = in[i] ^ d[i]; - - // Flags, but with hop count masked off. Hop count is altered by forwarding - // nodes. It's one of the only parts of a packet modifiable by people - // without the key. - out[18] = in[18] ^ (d[ZT_PACKET_IDX_FLAGS] & 0xf8); - - // Raw packet size in bytes -- thus each packet size defines a new - // key space. - out[19] = in[19] ^ (unsigned char)(size() & 0xff); - out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian - - // Rest of raw key is used unchanged - for(unsigned int i=21;i<32;++i) - out[i] = in[i]; - } -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Path.cpp b/zto/node/Path.cpp deleted file mode 100644 index 7366b56..0000000 --- a/zto/node/Path.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Path.hpp" -#include "RuntimeEnvironment.hpp" -#include "Node.hpp" - -namespace ZeroTier { - -bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now) -{ - if (RR->node->putPacket(tPtr,_localAddress,address(),data,len)) { - _lastOut = now; - return true; - } - return false; -} - -} // namespace ZeroTier diff --git a/zto/node/Path.hpp b/zto/node/Path.hpp deleted file mode 100644 index aef628d..0000000 --- a/zto/node/Path.hpp +++ /dev/null @@ -1,319 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_PATH_HPP -#define ZT_PATH_HPP - -#include -#include -#include - -#include -#include - -#include "Constants.hpp" -#include "InetAddress.hpp" -#include "SharedPtr.hpp" -#include "AtomicCounter.hpp" -#include "NonCopyable.hpp" -#include "Utils.hpp" - -/** - * Maximum return value of preferenceRank() - */ -#define ZT_PATH_MAX_PREFERENCE_RANK ((ZT_INETADDRESS_MAX_SCOPE << 1) | 1) - -namespace ZeroTier { - -class RuntimeEnvironment; - -/** - * A path across the physical network - */ -class Path : NonCopyable -{ - friend class SharedPtr; - -public: - /** - * Efficient unique key for paths in a Hashtable - */ - class HashKey - { - public: - HashKey() {} - - HashKey(const InetAddress &l,const InetAddress &r) - { - // This is an ad-hoc bit packing algorithm to yield unique keys for - // remote addresses and their local-side counterparts if defined. - // Portability across runtimes is not needed. - if (r.ss_family == AF_INET) { - _k[0] = (uint64_t)reinterpret_cast(&r)->sin_addr.s_addr; - _k[1] = (uint64_t)reinterpret_cast(&r)->sin_port; - if (l.ss_family == AF_INET) { - _k[2] = (uint64_t)reinterpret_cast(&l)->sin_addr.s_addr; - _k[3] = (uint64_t)reinterpret_cast(&r)->sin_port; - } else { - _k[2] = 0; - _k[3] = 0; - } - } else if (r.ss_family == AF_INET6) { - const uint8_t *a = reinterpret_cast(reinterpret_cast(&r)->sin6_addr.s6_addr); - uint8_t *b = reinterpret_cast(_k); - for(unsigned int i=0;i<16;++i) b[i] = a[i]; - _k[2] = ~((uint64_t)reinterpret_cast(&r)->sin6_port); - if (l.ss_family == AF_INET6) { - _k[2] ^= ((uint64_t)reinterpret_cast(&r)->sin6_port) << 32; - a = reinterpret_cast(reinterpret_cast(&l)->sin6_addr.s6_addr); - b += 24; - for(unsigned int i=0;i<8;++i) b[i] = a[i]; - a += 8; - for(unsigned int i=0;i<8;++i) b[i] ^= a[i]; - } - } else { - _k[0] = 0; - _k[1] = 0; - _k[2] = 0; - _k[3] = 0; - } - } - - inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2] + _k[3]); } - - inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) && (_k[3] == k._k[3]) ); } - inline bool operator!=(const HashKey &k) const { return (!(*this == k)); } - - private: - uint64_t _k[4]; - }; - - Path() : - _lastOut(0), - _lastIn(0), - _lastTrustEstablishedPacketReceived(0), - _incomingLinkQualityFastLog(0xffffffffffffffffULL), - _incomingLinkQualitySlowLogPtr(0), - _incomingLinkQualitySlowLogCounter(-64), // discard first fast log - _incomingLinkQualityPreviousPacketCounter(0), - _outgoingPacketCounter(0), - _addr(), - _localAddress(), - _ipScope(InetAddress::IP_SCOPE_NONE) - { - for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) - _incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX; - } - - Path(const InetAddress &localAddress,const InetAddress &addr) : - _lastOut(0), - _lastIn(0), - _lastTrustEstablishedPacketReceived(0), - _incomingLinkQualityFastLog(0xffffffffffffffffULL), - _incomingLinkQualitySlowLogPtr(0), - _incomingLinkQualitySlowLogCounter(-64), // discard first fast log - _incomingLinkQualityPreviousPacketCounter(0), - _outgoingPacketCounter(0), - _addr(addr), - _localAddress(localAddress), - _ipScope(addr.ipScope()) - { - for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) - _incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX; - } - - /** - * Called when a packet is received from this remote path, regardless of content - * - * @param t Time of receive - */ - inline void received(const uint64_t t) { _lastIn = t; } - - /** - * Update link quality using a counter from an incoming packet (or packet head in fragmented case) - * - * @param counter Packet link quality counter (range 0 to 7, must not have other bits set) - */ - inline void updateLinkQuality(const unsigned int counter) - { - const unsigned int prev = _incomingLinkQualityPreviousPacketCounter; - _incomingLinkQualityPreviousPacketCounter = counter; - const uint64_t fl = (_incomingLinkQualityFastLog = ((_incomingLinkQualityFastLog << 1) | (uint64_t)(prev == ((counter - 1) & 0x7)))); - if (++_incomingLinkQualitySlowLogCounter >= 64) { - _incomingLinkQualitySlowLogCounter = 0; - _incomingLinkQualitySlowLog[_incomingLinkQualitySlowLogPtr++ % sizeof(_incomingLinkQualitySlowLog)] = (uint8_t)Utils::countBits(fl); - } - } - - /** - * @return Link quality from 0 (min) to 255 (max) - */ - inline unsigned int linkQuality() const - { - unsigned long slsize = _incomingLinkQualitySlowLogPtr; - if (slsize > (unsigned long)sizeof(_incomingLinkQualitySlowLog)) - slsize = (unsigned long)sizeof(_incomingLinkQualitySlowLog); - else if (!slsize) - return 255; // ZT_PATH_LINK_QUALITY_MAX - unsigned long lq = 0; - for(unsigned long i=0;i= 255) ? 255 : lq); - } - - /** - * Set time last trusted packet was received (done in Peer::received()) - */ - inline void trustedPacketReceived(const uint64_t t) { _lastTrustEstablishedPacketReceived = t; } - - /** - * Send a packet via this path (last out time is also updated) - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param data Packet data - * @param len Packet length - * @param now Current time - * @return True if transport reported success - */ - bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now); - - /** - * Manually update last sent time - * - * @param t Time of send - */ - inline void sent(const uint64_t t) { _lastOut = t; } - - /** - * @return Address of local side of this path or NULL if unspecified - */ - inline const InetAddress &localAddress() const { return _localAddress; } - - /** - * @return Physical address - */ - inline const InetAddress &address() const { return _addr; } - - /** - * @return IP scope -- faster shortcut for address().ipScope() - */ - inline InetAddress::IpScope ipScope() const { return _ipScope; } - - /** - * @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms - */ - inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } - - /** - * @return Preference rank, higher == better - */ - inline unsigned int preferenceRank() const - { - // This causes us to rank paths in order of IP scope rank (see InetAdddress.hpp) but - // within each IP scope class to prefer IPv6 over IPv4. - return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) ); - } - - /** - * Check whether this address is valid for a ZeroTier path - * - * This checks the address type and scope against address types and scopes - * that we currently support for ZeroTier communication. - * - * @param a Address to check - * @return True if address is good for ZeroTier path use - */ - static inline bool isAddressValidForPath(const InetAddress &a) - { - if ((a.ss_family == AF_INET)||(a.ss_family == AF_INET6)) { - switch(a.ipScope()) { - /* Note: we don't do link-local at the moment. Unfortunately these - * cause several issues. The first is that they usually require a - * device qualifier, which we don't handle yet and can't portably - * push in PUSH_DIRECT_PATHS. The second is that some OSes assign - * these very ephemerally or otherwise strangely. So we'll use - * private, pseudo-private, shared (e.g. carrier grade NAT), or - * global IP addresses. */ - case InetAddress::IP_SCOPE_PRIVATE: - case InetAddress::IP_SCOPE_PSEUDOPRIVATE: - case InetAddress::IP_SCOPE_SHARED: - case InetAddress::IP_SCOPE_GLOBAL: - if (a.ss_family == AF_INET6) { - // TEMPORARY HACK: for now, we are going to blacklist he.net IPv6 - // tunnels due to very spotty performance and low MTU issues over - // these IPv6 tunnel links. - const uint8_t *ipd = reinterpret_cast(reinterpret_cast(&a)->sin6_addr.s6_addr); - if ((ipd[0] == 0x20)&&(ipd[1] == 0x01)&&(ipd[2] == 0x04)&&(ipd[3] == 0x70)) - return false; - } - return true; - default: - return false; - } - } - return false; - } - - /** - * @return True if path appears alive - */ - inline bool alive(const uint64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); } - - /** - * @return True if this path needs a heartbeat - */ - inline bool needsHeartbeat(const uint64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); } - - /** - * @return Last time we sent something - */ - inline uint64_t lastOut() const { return _lastOut; } - - /** - * @return Last time we received anything - */ - inline uint64_t lastIn() const { return _lastIn; } - - /** - * Return and increment outgoing packet counter (used with Packet::armor()) - * - * @return Next value that should be used for outgoing packet counter (only least significant 3 bits are used) - */ - inline unsigned int nextOutgoingCounter() { return _outgoingPacketCounter++; } - -private: - volatile uint64_t _lastOut; - volatile uint64_t _lastIn; - volatile uint64_t _lastTrustEstablishedPacketReceived; - volatile uint64_t _incomingLinkQualityFastLog; - volatile unsigned long _incomingLinkQualitySlowLogPtr; - volatile signed int _incomingLinkQualitySlowLogCounter; - volatile unsigned int _incomingLinkQualityPreviousPacketCounter; - volatile unsigned int _outgoingPacketCounter; - InetAddress _addr; - InetAddress _localAddress; - InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often - volatile uint8_t _incomingLinkQualitySlowLog[32]; - AtomicCounter __refCount; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Peer.cpp b/zto/node/Peer.cpp deleted file mode 100644 index 0795a6e..0000000 --- a/zto/node/Peer.cpp +++ /dev/null @@ -1,498 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "../version.h" - -#include "Constants.hpp" -#include "Peer.hpp" -#include "Node.hpp" -#include "Switch.hpp" -#include "Network.hpp" -#include "SelfAwareness.hpp" -#include "Cluster.hpp" -#include "Packet.hpp" - -#ifndef AF_MAX -#if AF_INET > AF_INET6 -#define AF_MAX AF_INET -#else -#define AF_MAX AF_INET6 -#endif -#endif - -namespace ZeroTier { - -Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : - RR(renv), - _lastReceive(0), - _lastNontrivialReceive(0), - _lastTriedMemorizedPath(0), - _lastDirectPathPushSent(0), - _lastDirectPathPushReceive(0), - _lastCredentialRequestSent(0), - _lastWhoisRequestReceived(0), - _lastEchoRequestReceived(0), - _lastComRequestReceived(0), - _lastComRequestSent(0), - _lastCredentialsReceived(0), - _lastTrustEstablishedPacketReceived(0), - _remoteClusterOptimal4(0), - _vProto(0), - _vMajor(0), - _vMinor(0), - _vRevision(0), - _id(peerIdentity), - _numPaths(0), - _latency(0), - _directPathPushCutoffCount(0), - _credentialsCutoffCount(0) -{ - memset(_remoteClusterOptimal6,0,sizeof(_remoteClusterOptimal6)); - if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) - throw std::runtime_error("new peer identity key agreement failed"); -} - -void Peer::received( - void *tPtr, - const SharedPtr &path, - const unsigned int hops, - const uint64_t packetId, - const Packet::Verb verb, - const uint64_t inRePacketId, - const Packet::Verb inReVerb, - const bool trustEstablished) -{ - const uint64_t now = RR->node->now(); - -#ifdef ZT_ENABLE_CLUSTER - bool suboptimalPath = false; - if ((RR->cluster)&&(hops == 0)) { - // Note: findBetterEndpoint() is first since we still want to check - // for a better endpoint even if we don't actually send a redirect. - InetAddress redirectTo; - if ( (verb != Packet::VERB_OK) && (verb != Packet::VERB_ERROR) && (verb != Packet::VERB_RENDEZVOUS) && (verb != Packet::VERB_PUSH_DIRECT_PATHS) && (RR->cluster->findBetterEndpoint(redirectTo,_id.address(),path->address(),false)) ) { - if (_vProto >= 5) { - // For newer peers we can send a more idiomatic verb: PUSH_DIRECT_PATHS. - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); - outp.append((uint16_t)1); // count == 1 - outp.append((uint8_t)ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT); // flags: cluster redirect - outp.append((uint16_t)0); // no extensions - if (redirectTo.ss_family == AF_INET) { - outp.append((uint8_t)4); - outp.append((uint8_t)6); - outp.append(redirectTo.rawIpData(),4); - } else { - outp.append((uint8_t)6); - outp.append((uint8_t)18); - outp.append(redirectTo.rawIpData(),16); - } - outp.append((uint16_t)redirectTo.port()); - outp.armor(_key,true,path->nextOutgoingCounter()); - path->send(RR,tPtr,outp.data(),outp.size(),now); - } else { - // For older peers we use RENDEZVOUS to coax them into contacting us elsewhere. - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); // no flags - RR->identity.address().appendTo(outp); - outp.append((uint16_t)redirectTo.port()); - if (redirectTo.ss_family == AF_INET) { - outp.append((uint8_t)4); - outp.append(redirectTo.rawIpData(),4); - } else { - outp.append((uint8_t)16); - outp.append(redirectTo.rawIpData(),16); - } - outp.armor(_key,true,path->nextOutgoingCounter()); - path->send(RR,tPtr,outp.data(),outp.size(),now); - } - suboptimalPath = true; - } - } -#endif - - _lastReceive = now; - switch (verb) { - case Packet::VERB_FRAME: - case Packet::VERB_EXT_FRAME: - case Packet::VERB_NETWORK_CONFIG_REQUEST: - case Packet::VERB_NETWORK_CONFIG: - case Packet::VERB_MULTICAST_FRAME: - _lastNontrivialReceive = now; - break; - default: break; - } - - if (trustEstablished) { - _lastTrustEstablishedPacketReceived = now; - path->trustedPacketReceived(now); - } - - if (_vProto >= 9) - path->updateLinkQuality((unsigned int)(packetId & 7)); - - if (hops == 0) { - bool pathIsConfirmed = false; - { - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address() == path->address()) { - _paths[p].lastReceive = now; - _paths[p].path = path; // local address may have changed! -#ifdef ZT_ENABLE_CLUSTER - _paths[p].localClusterSuboptimal = suboptimalPath; -#endif - pathIsConfirmed = true; - break; - } - } - } - - if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { - if (verb == Packet::VERB_OK) { - Mutex::Lock _l(_paths_m); - - // Since this is a new path, figure out where to put it (possibly replacing an old/dead one) - unsigned int slot; - if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) { - slot = _numPaths++; - } else { - // First try to replace the worst within the same address family, if possible - int worstSlot = -1; - uint64_t worstScore = 0xffffffffffffffffULL; - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address().ss_family == path->address().ss_family) { - const uint64_t s = _pathScore(p,now); - if (s < worstScore) { - worstScore = s; - worstSlot = (int)p; - } - } - } - if (worstSlot >= 0) { - slot = (unsigned int)worstSlot; - } else { - // If we can't find one with the same family, replace the worst of any family - slot = ZT_MAX_PEER_NETWORK_PATHS - 1; - for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p,now); - if (s < worstScore) { - worstScore = s; - slot = p; - } - } - } - } - - _paths[slot].lastReceive = now; - _paths[slot].path = path; -#ifdef ZT_ENABLE_CLUSTER - _paths[slot].localClusterSuboptimal = suboptimalPath; - if (RR->cluster) - RR->cluster->broadcastHavePeer(_id); -#endif - } else { - TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); - path->sent(now); - } - } - } else if (this->trustEstablished(now)) { - // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) -#ifdef ZT_ENABLE_CLUSTER - // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection - const bool haveCluster = (RR->cluster); -#else - const bool haveCluster = false; -#endif - if ( ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) && (!haveCluster) ) { - _lastDirectPathPushSent = now; - - std::vector pathsToPush; - - std::vector dps(RR->node->directPaths()); - for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) - pathsToPush.push_back(*i); - - std::vector sym(RR->sa->getSymmetricNatPredictions()); - for(unsigned long i=0,added=0;inode->prng() % sym.size()]); - if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { - pathsToPush.push_back(tmp); - if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) - break; - } - } - - if (pathsToPush.size() > 0) { -#ifdef ZT_TRACE - std::string ps; - for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { - if (ps.length() > 0) - ps.push_back(','); - ps.append(p->toString()); - } - TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); -#endif - - std::vector::const_iterator p(pathsToPush.begin()); - while (p != pathsToPush.end()) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); - outp.addSize(2); // leave room for count - - unsigned int count = 0; - while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) { - uint8_t addressType = 4; - switch(p->ss_family) { - case AF_INET: - break; - case AF_INET6: - addressType = 6; - break; - default: // we currently only push IP addresses - ++p; - continue; - } - - outp.append((uint8_t)0); // no flags - outp.append((uint16_t)0); // no extensions - outp.append(addressType); - outp.append((uint8_t)((addressType == 4) ? 6 : 18)); - outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); - outp.append((uint16_t)p->port()); - - ++count; - ++p; - } - - if (count) { - outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - outp.armor(_key,true,path->nextOutgoingCounter()); - path->send(RR,tPtr,outp.data(),outp.size(),now); - } - } - } - } - } -} - -bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if ( (_paths[p].path->address() == addr) && ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) - return true; - } - return false; -} - -bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) -{ - Mutex::Lock _l(_paths_m); - - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)||(forceEvenIfDead)) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; - } - } - } - - if (bestp >= 0) { - return _paths[bestp].path->send(RR,tPtr,data,len,now); - } else { - return false; - } -} - -SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) -{ - Mutex::Lock _l(_paths_m); - - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; - } - } - } - - if (bestp >= 0) { - return _paths[bestp].path; - } else { - return SharedPtr(); - } -} - -void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) -{ - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); - - outp.append((unsigned char)ZT_PROTO_VERSION); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); - outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - outp.append(now); - RR->identity.serialize(outp,false); - atAddress.serialize(outp); - - outp.append((uint64_t)RR->topology->planetWorldId()); - outp.append((uint64_t)RR->topology->planetWorldTimestamp()); - - const unsigned int startCryptedPortionAt = outp.size(); - - std::vector moons(RR->topology->moons()); - std::vector moonsWanted(RR->topology->moonsWanted()); - outp.append((uint16_t)(moons.size() + moonsWanted.size())); - for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { - outp.append((uint8_t)m->type()); - outp.append((uint64_t)m->id()); - outp.append((uint64_t)m->timestamp()); - } - for(std::vector::const_iterator m(moonsWanted.begin());m!=moonsWanted.end();++m) { - outp.append((uint8_t)World::TYPE_MOON); - outp.append(*m); - outp.append((uint64_t)0); - } - - const unsigned int corSizeAt = outp.size(); - outp.addSize(2); - RR->topology->appendCertificateOfRepresentation(outp); - outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); - - outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt); - - RR->node->expectReplyTo(outp.packetId()); - - if (atAddress) { - outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC - RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size()); - } else { - RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC - } -} - -void Peer::attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) -{ - if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); - RR->node->expectReplyTo(outp.packetId()); - outp.armor(_key,true,counter); - RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size()); - } else { - sendHELLO(tPtr,localAddr,atAddress,now,counter); - } -} - -void Peer::tryMemorizedPath(void *tPtr,uint64_t now) -{ - if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) { - _lastTriedMemorizedPath = now; - InetAddress mp; - if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) - attemptToContactAt(tPtr,InetAddress(),mp,now,true,0); - } -} - -bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) -{ - Mutex::Lock _l(_paths_m); - - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; - } - } - } - - if (bestp >= 0) { - if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter()); - _paths[bestp].path->sent(now); - } - return true; - } else { - return false; - } -} - -bool Peer::hasActiveDirectPath(uint64_t now) const -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if (((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION)&&(_paths[p].path->alive(now))) - return true; - } - return false; -} - -void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - attemptToContactAt(tPtr,_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter()); - _paths[p].path->sent(now); - _paths[p].lastReceive = 0; // path will not be used unless it speaks again - } - } -} - -void Peer::getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const -{ - Mutex::Lock _l(_paths_m); - - int bestp4 = -1,bestp6 = -1; - uint64_t best4 = 0ULL,best6 = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) { - if (_paths[p].path->address().ss_family == AF_INET) { - const uint64_t s = _pathScore(p,now); - if (s >= best4) { - best4 = s; - bestp4 = (int)p; - } - } else if (_paths[p].path->address().ss_family == AF_INET6) { - const uint64_t s = _pathScore(p,now); - if (s >= best6) { - best6 = s; - bestp6 = (int)p; - } - } - } - } - - if (bestp4 >= 0) - v4 = _paths[bestp4].path->address(); - if (bestp6 >= 0) - v6 = _paths[bestp6].path->address(); -} - -} // namespace ZeroTier diff --git a/zto/node/Peer.hpp b/zto/node/Peer.hpp deleted file mode 100644 index 4183641..0000000 --- a/zto/node/Peer.hpp +++ /dev/null @@ -1,509 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_PEER_HPP -#define ZT_PEER_HPP - -#include - -#include "Constants.hpp" - -#include -#include -#include -#include - -#include "../include/ZeroTierOne.h" - -#include "RuntimeEnvironment.hpp" -#include "Path.hpp" -#include "Address.hpp" -#include "Utils.hpp" -#include "Identity.hpp" -#include "InetAddress.hpp" -#include "Packet.hpp" -#include "SharedPtr.hpp" -#include "AtomicCounter.hpp" -#include "Hashtable.hpp" -#include "Mutex.hpp" -#include "NonCopyable.hpp" - -namespace ZeroTier { - -/** - * Peer on P2P Network (virtual layer 1) - */ -class Peer : NonCopyable -{ - friend class SharedPtr; - -private: - Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized - -public: - ~Peer() { Utils::burn(_key,sizeof(_key)); } - - /** - * Construct a new peer - * - * @param renv Runtime environment - * @param myIdentity Identity of THIS node (for key agreement) - * @param peerIdentity Identity of peer - * @throws std::runtime_error Key agreement with peer's identity failed - */ - Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity); - - /** - * @return This peer's ZT address (short for identity().address()) - */ - inline const Address &address() const throw() { return _id.address(); } - - /** - * @return This peer's identity - */ - inline const Identity &identity() const throw() { return _id; } - - /** - * Log receipt of an authenticated packet - * - * This is called by the decode pipe when a packet is proven to be authentic - * and appears to be valid. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param path Path over which packet was received - * @param hops ZeroTier (not IP) hops - * @param packetId Packet ID - * @param verb Packet verb - * @param inRePacketId Packet ID in reply to (default: none) - * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) - * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established - */ - void received( - void *tPtr, - const SharedPtr &path, - const unsigned int hops, - const uint64_t packetId, - const Packet::Verb verb, - const uint64_t inRePacketId, - const Packet::Verb inReVerb, - const bool trustEstablished); - - /** - * @param now Current time - * @param addr Remote address - * @return True if we have an active path to this destination - */ - bool hasActivePathTo(uint64_t now,const InetAddress &addr) const; - - /** - * Set which known path for an address family is optimal - * - * @param addr Address to make exclusive - */ - inline void setClusterOptimal(const InetAddress &addr) - { - if (addr.ss_family == AF_INET) { - _remoteClusterOptimal4 = (uint32_t)reinterpret_cast(&addr)->sin_addr.s_addr; - } else if (addr.ss_family == AF_INET6) { - memcpy(_remoteClusterOptimal6,reinterpret_cast(&addr)->sin6_addr.s6_addr,16); - } - } - - /** - * Send via best direct path - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param data Packet data - * @param len Packet length - * @param now Current time - * @param forceEvenIfDead If true, send even if the path is not 'alive' - * @return True if we actually sent something - */ - bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); - - /** - * Get the best current direct path - * - * @param now Current time - * @param includeExpired If true, include even expired paths - * @return Best current path or NULL if none - */ - SharedPtr getBestPath(uint64_t now,bool includeExpired); - - /** - * Send a HELLO to this peer at a specified physical address - * - * No statistics or sent times are updated here. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localAddr Local address - * @param atAddress Destination address - * @param now Current time - * @param counter Outgoing packet counter - */ - void sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter); - - /** - * Send ECHO (or HELLO for older peers) to this peer at the given address - * - * No statistics or sent times are updated here. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localAddr Local address - * @param atAddress Destination address - * @param now Current time - * @param sendFullHello If true, always send a full HELLO instead of just an ECHO - * @param counter Outgoing packet counter - */ - void attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); - - /** - * Try a memorized or statically defined path if any are known - * - * Under the hood this is done periodically based on ZT_TRY_MEMORIZED_PATH_INTERVAL. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - */ - void tryMemorizedPath(void *tPtr,uint64_t now); - - /** - * Send pings or keepalives depending on configured timeouts - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - * @param inetAddressFamily Keep this address family alive, or -1 for any - * @return True if we have at least one direct path of the given family (or any if family is -1) - */ - bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); - - /** - * @param now Current time - * @return True if this peer has at least one active and alive direct path - */ - bool hasActiveDirectPath(uint64_t now) const; - - /** - * Reset paths within a given IP scope and address family - * - * Resetting a path involves sending an ECHO to it and then deactivating - * it until or unless it responds. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param scope IP scope - * @param inetAddressFamily Family e.g. AF_INET - * @param now Current time - */ - void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); - - /** - * Get most recently active path addresses for IPv4 and/or IPv6 - * - * Note that v4 and v6 are not modified if they are not found, so - * initialize these to a NULL address to be able to check. - * - * @param now Current time - * @param v4 Result parameter to receive active IPv4 address, if any - * @param v6 Result parameter to receive active IPv6 address, if any - */ - void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; - - /** - * @param now Current time - * @return All known direct paths to this peer and whether they are expired (true == expired) - */ - inline std::vector< std::pair< SharedPtr,bool > > paths(const uint64_t now) const - { - std::vector< std::pair< SharedPtr,bool > > pp; - Mutex::Lock _l(_paths_m); - for(unsigned int p=0,np=_numPaths;p,bool >(_paths[p].path,(now - _paths[p].lastReceive) > ZT_PEER_PATH_EXPIRATION)); - return pp; - } - - /** - * @return Time of last receive of anything, whether direct or relayed - */ - inline uint64_t lastReceive() const { return _lastReceive; } - - /** - * @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT - */ - inline bool isAlive(const uint64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } - - /** - * @return True if this peer has sent us real network traffic recently - */ - inline uint64_t isActive(uint64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } - - /** - * @return Latency in milliseconds or 0 if unknown - */ - inline unsigned int latency() const { return _latency; } - - /** - * This computes a quality score for relays and root servers - * - * If we haven't heard anything from these in ZT_PEER_ACTIVITY_TIMEOUT, they - * receive the worst possible quality (max unsigned int). Otherwise the - * quality is a product of latency and the number of potential missed - * pings. This causes roots and relays to switch over a bit faster if they - * fail. - * - * @return Relay quality score computed from latency and other factors, lower is better - */ - inline unsigned int relayQuality(const uint64_t now) const - { - const uint64_t tsr = now - _lastReceive; - if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT) - return (~(unsigned int)0); - unsigned int l = _latency; - if (!l) - l = 0xffff; - return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1)); - } - - /** - * Update latency with a new direct measurment - * - * @param l Direct latency measurment in ms - */ - inline void addDirectLatencyMeasurment(unsigned int l) - { - unsigned int ol = _latency; - if ((ol > 0)&&(ol < 10000)) - _latency = (ol + std::min(l,(unsigned int)65535)) / 2; - else _latency = std::min(l,(unsigned int)65535); - } - -#ifdef ZT_ENABLE_CLUSTER - /** - * @param now Current time - * @return True if this peer has at least one active direct path that is not cluster-suboptimal - */ - inline bool hasLocalClusterOptimalPath(uint64_t now) const - { - for(unsigned int p=0,np=_numPaths;palive(now)) && (!_paths[p].localClusterSuboptimal) ) - return true; - } - return false; - } -#endif - - /** - * @return 256-bit secret symmetric encryption key - */ - inline const unsigned char *key() const { return _key; } - - /** - * Set the currently known remote version of this peer's client - * - * @param vproto Protocol version - * @param vmaj Major version - * @param vmin Minor version - * @param vrev Revision - */ - inline void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev) - { - _vProto = (uint16_t)vproto; - _vMajor = (uint16_t)vmaj; - _vMinor = (uint16_t)vmin; - _vRevision = (uint16_t)vrev; - } - - inline unsigned int remoteVersionProtocol() const { return _vProto; } - inline unsigned int remoteVersionMajor() const { return _vMajor; } - inline unsigned int remoteVersionMinor() const { return _vMinor; } - inline unsigned int remoteVersionRevision() const { return _vRevision; } - - inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } - - /** - * @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms - */ - inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } - - /** - * Rate limit gate for VERB_PUSH_DIRECT_PATHS - */ - inline bool rateGatePushDirectPaths(const uint64_t now) - { - if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) - ++_directPathPushCutoffCount; - else _directPathPushCutoffCount = 0; - _lastDirectPathPushReceive = now; - return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT); - } - - /** - * Rate limit gate for VERB_NETWORK_CREDENTIALS - */ - inline bool rateGateCredentialsReceived(const uint64_t now) - { - if ((now - _lastCredentialsReceived) <= ZT_PEER_CREDENTIALS_CUTOFF_TIME) - ++_credentialsCutoffCount; - else _credentialsCutoffCount = 0; - _lastCredentialsReceived = now; - return (_directPathPushCutoffCount < ZT_PEER_CREDEITIALS_CUTOFF_LIMIT); - } - - /** - * Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE - */ - inline bool rateGateRequestCredentials(const uint64_t now) - { - if ((now - _lastCredentialRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { - _lastCredentialRequestSent = now; - return true; - } - return false; - } - - /** - * Rate limit gate for inbound WHOIS requests - */ - inline bool rateGateInboundWhoisRequest(const uint64_t now) - { - if ((now - _lastWhoisRequestReceived) >= ZT_PEER_WHOIS_RATE_LIMIT) { - _lastWhoisRequestReceived = now; - return true; - } - return false; - } - - /** - * Rate limit gate for inbound ECHO requests - */ - inline bool rateGateEchoRequest(const uint64_t now) - { - if ((now - _lastEchoRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { - _lastEchoRequestReceived = now; - return true; - } - return false; - } - - /** - * Rate gate incoming requests for network COM - */ - inline bool rateGateIncomingComRequest(const uint64_t now) - { - if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { - _lastComRequestReceived = now; - return true; - } - return false; - } - - /** - * Rate gate outgoing requests for network COM - */ - inline bool rateGateOutgoingComRequest(const uint64_t now) - { - if ((now - _lastComRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { - _lastComRequestSent = now; - return true; - } - return false; - } - -private: - inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const - { - uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); - - if (_paths[p].path->address().ss_family == AF_INET) { - s += (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4)); - } else if (_paths[p].path->address().ss_family == AF_INET6) { - uint64_t clusterWeight = ZT_PEER_PING_PERIOD; - const uint8_t *a = reinterpret_cast(reinterpret_cast(&(_paths[p].path->address()))->sin6_addr.s6_addr); - for(long i=0;i<16;++i) { - if (a[i] != _remoteClusterOptimal6[i]) { - clusterWeight = 0; - break; - } - } - s += clusterWeight; - } - - s += (ZT_PEER_PING_PERIOD / 2) * (uint64_t)_paths[p].path->alive(now); - -#ifdef ZT_ENABLE_CLUSTER - s -= ZT_PEER_PING_PERIOD * (uint64_t)_paths[p].localClusterSuboptimal; -#endif - - return s; - } - - uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; - - const RuntimeEnvironment *RR; - - uint64_t _lastReceive; // direct or indirect - uint64_t _lastNontrivialReceive; // frames, things like netconf, etc. - uint64_t _lastTriedMemorizedPath; - uint64_t _lastDirectPathPushSent; - uint64_t _lastDirectPathPushReceive; - uint64_t _lastCredentialRequestSent; - uint64_t _lastWhoisRequestReceived; - uint64_t _lastEchoRequestReceived; - uint64_t _lastComRequestReceived; - uint64_t _lastComRequestSent; - uint64_t _lastCredentialsReceived; - uint64_t _lastTrustEstablishedPacketReceived; - - uint8_t _remoteClusterOptimal6[16]; - uint32_t _remoteClusterOptimal4; - - uint16_t _vProto; - uint16_t _vMajor; - uint16_t _vMinor; - uint16_t _vRevision; - - Identity _id; - - struct { - uint64_t lastReceive; - SharedPtr path; -#ifdef ZT_ENABLE_CLUSTER - bool localClusterSuboptimal; -#endif - } _paths[ZT_MAX_PEER_NETWORK_PATHS]; - Mutex _paths_m; - - unsigned int _numPaths; - unsigned int _latency; - unsigned int _directPathPushCutoffCount; - unsigned int _credentialsCutoffCount; - - AtomicCounter __refCount; -}; - -} // namespace ZeroTier - -// Add a swap() for shared ptr's to peers to speed up peer sorts -namespace std { - template<> - inline void swap(ZeroTier::SharedPtr &a,ZeroTier::SharedPtr &b) - { - a.swap(b); - } -} - -#endif diff --git a/zto/node/Poly1305.cpp b/zto/node/Poly1305.cpp deleted file mode 100644 index b78071f..0000000 --- a/zto/node/Poly1305.cpp +++ /dev/null @@ -1,628 +0,0 @@ -/* -20080912 -D. J. Bernstein -Public domain. -*/ - -#include "Constants.hpp" -#include "Poly1305.hpp" - -#include -#include -#include -#include - -#ifdef __WINDOWS__ -#pragma warning(disable: 4146) -#endif - -namespace ZeroTier { - -#if 0 - -// "Naive" implementation, which is slower... might still want this on some older -// or weird platforms if the later versions have issues. - -static inline void add(unsigned int h[17],const unsigned int c[17]) -{ - unsigned int j; - unsigned int u; - u = 0; - for (j = 0;j < 17;++j) { u += h[j] + c[j]; h[j] = u & 255; u >>= 8; } -} - -static inline void squeeze(unsigned int h[17]) -{ - unsigned int j; - unsigned int u; - u = 0; - for (j = 0;j < 16;++j) { u += h[j]; h[j] = u & 255; u >>= 8; } - u += h[16]; h[16] = u & 3; - u = 5 * (u >> 2); - for (j = 0;j < 16;++j) { u += h[j]; h[j] = u & 255; u >>= 8; } - u += h[16]; h[16] = u; -} - -static const unsigned int minusp[17] = { - 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252 -} ; - -static inline void freeze(unsigned int h[17]) -{ - unsigned int horig[17]; - unsigned int j; - unsigned int negative; - for (j = 0;j < 17;++j) horig[j] = h[j]; - add(h,minusp); - negative = -(h[16] >> 7); - for (j = 0;j < 17;++j) h[j] ^= negative & (horig[j] ^ h[j]); -} - -static inline void mulmod(unsigned int h[17],const unsigned int r[17]) -{ - unsigned int hr[17]; - unsigned int i; - unsigned int j; - unsigned int u; - - for (i = 0;i < 17;++i) { - u = 0; - for (j = 0;j <= i;++j) u += h[j] * r[i - j]; - for (j = i + 1;j < 17;++j) u += 320 * h[j] * r[i + 17 - j]; - hr[i] = u; - } - for (i = 0;i < 17;++i) h[i] = hr[i]; - squeeze(h); -} - -static inline int crypto_onetimeauth(unsigned char *out,const unsigned char *in,unsigned long long inlen,const unsigned char *k) -{ - unsigned int j; - unsigned int r[17]; - unsigned int h[17]; - unsigned int c[17]; - - r[0] = k[0]; - r[1] = k[1]; - r[2] = k[2]; - r[3] = k[3] & 15; - r[4] = k[4] & 252; - r[5] = k[5]; - r[6] = k[6]; - r[7] = k[7] & 15; - r[8] = k[8] & 252; - r[9] = k[9]; - r[10] = k[10]; - r[11] = k[11] & 15; - r[12] = k[12] & 252; - r[13] = k[13]; - r[14] = k[14]; - r[15] = k[15] & 15; - r[16] = 0; - - for (j = 0;j < 17;++j) h[j] = 0; - - while (inlen > 0) { - for (j = 0;j < 17;++j) c[j] = 0; - for (j = 0;(j < 16) && (j < inlen);++j) c[j] = in[j]; - c[j] = 1; - in += j; inlen -= j; - add(h,c); - mulmod(h,r); - } - - freeze(h); - - for (j = 0;j < 16;++j) c[j] = k[j + 16]; - c[16] = 0; - add(h,c); - for (j = 0;j < 16;++j) out[j] = h[j]; - return 0; -} - -void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key) - throw() -{ - crypto_onetimeauth((unsigned char *)auth,(const unsigned char *)data,len,(const unsigned char *)key); -} - -#endif - -namespace { - -typedef struct poly1305_context { - size_t aligner; - unsigned char opaque[136]; -} poly1305_context; - -#if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__)) - -////////////////////////////////////////////////////////////////////////////// -// 128-bit implementation for MSC and GCC from Poly1305-donna - -#if defined(_MSC_VER) - #include - - typedef struct uint128_t { - unsigned long long lo; - unsigned long long hi; - } uint128_t; - - #define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi) - #define ADD(out, in) { unsigned long long t = out.lo; out.lo += in.lo; out.hi += (out.lo < t) + in.hi; } - #define ADDLO(out, in) { unsigned long long t = out.lo; out.lo += in; out.hi += (out.lo < t); } - #define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift))) - #define LO(in) (in.lo) - -// #define POLY1305_NOINLINE __declspec(noinline) -#elif defined(__GNUC__) - #if defined(__SIZEOF_INT128__) - typedef unsigned __int128 uint128_t; - #else - typedef unsigned uint128_t __attribute__((mode(TI))); - #endif - - #define MUL(out, x, y) out = ((uint128_t)x * y) - #define ADD(out, in) out += in - #define ADDLO(out, in) out += in - #define SHR(in, shift) (unsigned long long)(in >> (shift)) - #define LO(in) (unsigned long long)(in) - -// #define POLY1305_NOINLINE __attribute__((noinline)) -#endif - -#define poly1305_block_size 16 - -/* 17 + sizeof(size_t) + 8*sizeof(unsigned long long) */ -typedef struct poly1305_state_internal_t { - unsigned long long r[3]; - unsigned long long h[3]; - unsigned long long pad[2]; - size_t leftover; - unsigned char buffer[poly1305_block_size]; - unsigned char final; -} poly1305_state_internal_t; - -/* interpret eight 8 bit unsigned integers as a 64 bit unsigned integer in little endian */ -static inline unsigned long long -U8TO64(const unsigned char *p) { - return - (((unsigned long long)(p[0] & 0xff) ) | - ((unsigned long long)(p[1] & 0xff) << 8) | - ((unsigned long long)(p[2] & 0xff) << 16) | - ((unsigned long long)(p[3] & 0xff) << 24) | - ((unsigned long long)(p[4] & 0xff) << 32) | - ((unsigned long long)(p[5] & 0xff) << 40) | - ((unsigned long long)(p[6] & 0xff) << 48) | - ((unsigned long long)(p[7] & 0xff) << 56)); -} - -/* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little endian */ -static inline void -U64TO8(unsigned char *p, unsigned long long v) { - p[0] = (v ) & 0xff; - p[1] = (v >> 8) & 0xff; - p[2] = (v >> 16) & 0xff; - p[3] = (v >> 24) & 0xff; - p[4] = (v >> 32) & 0xff; - p[5] = (v >> 40) & 0xff; - p[6] = (v >> 48) & 0xff; - p[7] = (v >> 56) & 0xff; -} - -static inline void -poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long long t0,t1; - - /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ - t0 = U8TO64(&key[0]); - t1 = U8TO64(&key[8]); - - st->r[0] = ( t0 ) & 0xffc0fffffff; - st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; - st->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f; - - /* h = 0 */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - - /* save pad for later */ - st->pad[0] = U8TO64(&key[16]); - st->pad[1] = U8TO64(&key[24]); - - st->leftover = 0; - st->final = 0; -} - -static inline void -poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { - const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */ - unsigned long long r0,r1,r2; - unsigned long long s1,s2; - unsigned long long h0,h1,h2; - unsigned long long c; - uint128_t d0,d1,d2,d; - - r0 = st->r[0]; - r1 = st->r[1]; - r2 = st->r[2]; - - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - - s1 = r1 * (5 << 2); - s2 = r2 * (5 << 2); - - while (bytes >= poly1305_block_size) { - unsigned long long t0,t1; - - /* h += m[i] */ - t0 = U8TO64(&m[0]); - t1 = U8TO64(&m[8]); - - h0 += (( t0 ) & 0xfffffffffff); - h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); - h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit; - - /* h *= r */ - MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d); - MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d); - MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d); - - /* (partial) h %= p */ - c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff; - ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff; - ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff; - h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff; - h1 += c; - - m += poly1305_block_size; - bytes -= poly1305_block_size; - } - - st->h[0] = h0; - st->h[1] = h1; - st->h[2] = h2; -} - -static inline void -poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long long h0,h1,h2,c; - unsigned long long g0,g1,g2; - unsigned long long t0,t1; - - /* process the remaining block */ - if (st->leftover) { - size_t i = st->leftover; - st->buffer[i] = 1; - for (i = i + 1; i < poly1305_block_size; i++) - st->buffer[i] = 0; - st->final = 1; - poly1305_blocks(st, st->buffer, poly1305_block_size); - } - - /* fully carry h */ - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - - c = (h1 >> 44); h1 &= 0xfffffffffff; - h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; - h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; - h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff; - h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; - h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; - h1 += c; - - /* compute h + -p */ - g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff; - g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff; - g2 = h2 + c - ((unsigned long long)1 << 42); - - /* select h if h < p, or h + -p if h >= p */ - c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1; - g0 &= c; - g1 &= c; - g2 &= c; - c = ~c; - h0 = (h0 & c) | g0; - h1 = (h1 & c) | g1; - h2 = (h2 & c) | g2; - - /* h = (h + pad) */ - t0 = st->pad[0]; - t1 = st->pad[1]; - - h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff; - h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff; - h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff; - - /* mac = h % (2^128) */ - h0 = ((h0 ) | (h1 << 44)); - h1 = ((h1 >> 20) | (h2 << 24)); - - U64TO8(&mac[0], h0); - U64TO8(&mac[8], h1); - - /* zero out the state */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->r[0] = 0; - st->r[1] = 0; - st->r[2] = 0; - st->pad[0] = 0; - st->pad[1] = 0; -} - -////////////////////////////////////////////////////////////////////////////// - -#else - -////////////////////////////////////////////////////////////////////////////// -// More portable 64-bit implementation - -#define poly1305_block_size 16 - -/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */ -typedef struct poly1305_state_internal_t { - unsigned long r[5]; - unsigned long h[5]; - unsigned long pad[4]; - size_t leftover; - unsigned char buffer[poly1305_block_size]; - unsigned char final; -} poly1305_state_internal_t; - -/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ -static unsigned long -U8TO32(const unsigned char *p) { - return - (((unsigned long)(p[0] & 0xff) ) | - ((unsigned long)(p[1] & 0xff) << 8) | - ((unsigned long)(p[2] & 0xff) << 16) | - ((unsigned long)(p[3] & 0xff) << 24)); -} - -/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */ -static void -U32TO8(unsigned char *p, unsigned long v) { - p[0] = (v ) & 0xff; - p[1] = (v >> 8) & 0xff; - p[2] = (v >> 16) & 0xff; - p[3] = (v >> 24) & 0xff; -} - -static inline void -poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - - /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ - st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; - st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; - st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; - st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; - st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; - - /* h = 0 */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->h[3] = 0; - st->h[4] = 0; - - /* save pad for later */ - st->pad[0] = U8TO32(&key[16]); - st->pad[1] = U8TO32(&key[20]); - st->pad[2] = U8TO32(&key[24]); - st->pad[3] = U8TO32(&key[28]); - - st->leftover = 0; - st->final = 0; -} - -static inline void -poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { - const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */ - unsigned long r0,r1,r2,r3,r4; - unsigned long s1,s2,s3,s4; - unsigned long h0,h1,h2,h3,h4; - unsigned long long d0,d1,d2,d3,d4; - unsigned long c; - - r0 = st->r[0]; - r1 = st->r[1]; - r2 = st->r[2]; - r3 = st->r[3]; - r4 = st->r[4]; - - s1 = r1 * 5; - s2 = r2 * 5; - s3 = r3 * 5; - s4 = r4 * 5; - - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - h3 = st->h[3]; - h4 = st->h[4]; - - while (bytes >= poly1305_block_size) { - /* h += m[i] */ - h0 += (U8TO32(m+ 0) ) & 0x3ffffff; - h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; - h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; - h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; - h4 += (U8TO32(m+12) >> 8) | hibit; - - /* h *= r */ - d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); - d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); - d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); - d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); - d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); - - /* (partial) h %= p */ - c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; - d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; - d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; - d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; - d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; - h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; - h1 += c; - - m += poly1305_block_size; - bytes -= poly1305_block_size; - } - - st->h[0] = h0; - st->h[1] = h1; - st->h[2] = h2; - st->h[3] = h3; - st->h[4] = h4; -} - -static inline void -poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long h0,h1,h2,h3,h4,c; - unsigned long g0,g1,g2,g3,g4; - unsigned long long f; - unsigned long mask; - - /* process the remaining block */ - if (st->leftover) { - size_t i = st->leftover; - st->buffer[i++] = 1; - for (; i < poly1305_block_size; i++) - st->buffer[i] = 0; - st->final = 1; - poly1305_blocks(st, st->buffer, poly1305_block_size); - } - - /* fully carry h */ - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - h3 = st->h[3]; - h4 = st->h[4]; - - c = h1 >> 26; h1 = h1 & 0x3ffffff; - h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; - h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; - h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; - h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; - h1 += c; - - /* compute h + -p */ - g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; - g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; - g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; - g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; - g4 = h4 + c - (1 << 26); - - /* select h if h < p, or h + -p if h >= p */ - mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; - g0 &= mask; - g1 &= mask; - g2 &= mask; - g3 &= mask; - g4 &= mask; - mask = ~mask; - h0 = (h0 & mask) | g0; - h1 = (h1 & mask) | g1; - h2 = (h2 & mask) | g2; - h3 = (h3 & mask) | g3; - h4 = (h4 & mask) | g4; - - /* h = h % (2^128) */ - h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; - h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; - h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; - h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; - - /* mac = (h + pad) % (2^128) */ - f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; - f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; - f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; - f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; - - U32TO8(mac + 0, h0); - U32TO8(mac + 4, h1); - U32TO8(mac + 8, h2); - U32TO8(mac + 12, h3); - - /* zero out the state */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->h[3] = 0; - st->h[4] = 0; - st->r[0] = 0; - st->r[1] = 0; - st->r[2] = 0; - st->r[3] = 0; - st->r[4] = 0; - st->pad[0] = 0; - st->pad[1] = 0; - st->pad[2] = 0; - st->pad[3] = 0; -} - -////////////////////////////////////////////////////////////////////////////// - -#endif // MSC/GCC or not - -static inline void -poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - size_t i; - - /* handle leftover */ - if (st->leftover) { - size_t want = (poly1305_block_size - st->leftover); - if (want > bytes) - want = bytes; - for (i = 0; i < want; i++) - st->buffer[st->leftover + i] = m[i]; - bytes -= want; - m += want; - st->leftover += want; - if (st->leftover < poly1305_block_size) - return; - poly1305_blocks(st, st->buffer, poly1305_block_size); - st->leftover = 0; - } - - /* process full blocks */ - if (bytes >= poly1305_block_size) { - size_t want = (bytes & ~(poly1305_block_size - 1)); - poly1305_blocks(st, m, want); - m += want; - bytes -= want; - } - - /* store leftover */ - if (bytes) { - for (i = 0; i < bytes; i++) - st->buffer[st->leftover + i] = m[i]; - st->leftover += bytes; - } -} - -} // anonymous namespace - -void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key) - throw() -{ - poly1305_context ctx; - poly1305_init(&ctx,reinterpret_cast(key)); - poly1305_update(&ctx,reinterpret_cast(data),(size_t)len); - poly1305_finish(&ctx,reinterpret_cast(auth)); -} - -} // namespace ZeroTier diff --git a/zto/node/Poly1305.hpp b/zto/node/Poly1305.hpp deleted file mode 100644 index 62d5754..0000000 --- a/zto/node/Poly1305.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_POLY1305_HPP -#define ZT_POLY1305_HPP - -namespace ZeroTier { - -#define ZT_POLY1305_KEY_LEN 32 -#define ZT_POLY1305_MAC_LEN 16 - -/** - * Poly1305 one-time authentication code - * - * This takes a one-time-use 32-byte key and generates a 16-byte message - * authentication code. The key must never be re-used for a different - * message. - * - * In Packet this is done by using the first 32 bytes of the stream cipher - * keystream as a one-time-use key. These 32 bytes are then discarded and - * the packet is encrypted with the next N bytes. - */ -class Poly1305 -{ -public: - /** - * Compute a one-time authentication code - * - * @param auth Buffer to receive code -- MUST be 16 bytes in length - * @param data Data to authenticate - * @param len Length of data to authenticate in bytes - * @param key 32-byte one-time use key to authenticate data (must not be reused) - */ - static void compute(void *auth,const void *data,unsigned int len,const void *key) - throw(); -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/README.md b/zto/node/README.md deleted file mode 100644 index 1728400..0000000 --- a/zto/node/README.md +++ /dev/null @@ -1,14 +0,0 @@ -ZeroTier Network Hypervisor Core -====== - -This directory contains the *real* ZeroTier: a completely OS-independent global virtual Ethernet switch engine. This is where the magic happens. - -Give it wire packets and it gives you Ethernet packets, and vice versa. The core contains absolutely no actual I/O, port configuration, or other OS-specific code (except Utils::getSecureRandom()). It provides a simple C API via [/include/ZeroTierOne.h](../include/ZeroTierOne.h). It's designed to be small and maximally portable for future use on small embedded and special purpose systems. - -Code in here follows these guidelines: - - - Keep it minimal, especially in terms of code footprint and memory use. - - There should be no OS-dependent code here unless absolutely necessary (e.g. getSecureRandom). - - If it's not part of the core virtual Ethernet switch it does not belong here. - - No C++11 or C++14 since older and embedded compilers don't support it yet and this should be maximally portable. - - Minimize the use of complex C++ features since at some point we might end up "minus-minus'ing" this code if doing so proves necessary to port to tiny embedded systems. diff --git a/zto/node/Revocation.cpp b/zto/node/Revocation.cpp deleted file mode 100644 index bab5653..0000000 --- a/zto/node/Revocation.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Revocation.hpp" -#include "RuntimeEnvironment.hpp" -#include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Network.hpp" - -namespace ZeroTier { - -int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const -{ - if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) - return -1; - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); - return 1; - } - try { - Buffer tmp; - this->serialize(tmp,true); - return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); - } catch ( ... ) { - return -1; - } -} - -} // namespace ZeroTier diff --git a/zto/node/Revocation.hpp b/zto/node/Revocation.hpp deleted file mode 100644 index 8b9ce6d..0000000 --- a/zto/node/Revocation.hpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_REVOCATION_HPP -#define ZT_REVOCATION_HPP - -#include -#include -#include -#include - -#include "Constants.hpp" -#include "../include/ZeroTierOne.h" -#include "Address.hpp" -#include "C25519.hpp" -#include "Utils.hpp" -#include "Buffer.hpp" -#include "Identity.hpp" - -/** - * Flag: fast propagation via rumor mill algorithm - */ -#define ZT_REVOCATION_FLAG_FAST_PROPAGATE 0x1ULL - -namespace ZeroTier { - -class RuntimeEnvironment; - -/** - * Revocation certificate to instantaneously revoke a COM, capability, or tag - */ -class Revocation -{ -public: - /** - * Credential type being revoked - */ - enum CredentialType - { - CREDENTIAL_TYPE_NULL = 0, - CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership - CREDENTIAL_TYPE_CAPABILITY = 2, - CREDENTIAL_TYPE_TAG = 3, - CREDENTIAL_TYPE_COO = 4 // CertificateOfOwnership - }; - - Revocation() - { - memset(this,0,sizeof(Revocation)); - } - - /** - * @param i ID (arbitrary for revocations, currently random) - * @param nwid Network ID - * @param cid Credential ID being revoked (0 for all or for COMs, which lack IDs) - * @param thr Revocation time threshold before which credentials will be revoked - * @param fl Flags - * @param tgt Target node whose credential(s) are being revoked - * @param ct Credential type being revoked - */ - Revocation(const uint64_t i,const uint64_t nwid,const uint64_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const CredentialType ct) : - _id(i), - _networkId(nwid), - _credentialId(cid), - _threshold(thr), - _flags(fl), - _target(tgt), - _signedBy(), - _type(ct) {} - - inline uint64_t id() const { return _id; } - inline uint64_t networkId() const { return _networkId; } - inline uint64_t credentialId() const { return _credentialId; } - inline uint64_t threshold() const { return _threshold; } - inline const Address &target() const { return _target; } - inline const Address &signer() const { return _signedBy; } - inline CredentialType type() const { return _type; } - - inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); } - - /** - * @param signer Signing identity, must have private key - * @return True if signature was successful - */ - inline bool sign(const Identity &signer) - { - if (signer.hasPrivate()) { - Buffer tmp; - _signedBy = signer.address(); - this->serialize(tmp,true); - _signature = signer.sign(tmp.data(),tmp.size()); - return true; - } - return false; - } - - /** - * Verify this revocation's signature - * - * @param RR Runtime environment to provide for peer lookup, etc. - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; - - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - b.append(_id); - b.append(_networkId); - b.append(_credentialId); - b.append(_threshold); - b.append(_flags); - _target.appendTo(b); - _signedBy.appendTo(b); - b.append((uint8_t)_type); - - if (!forSign) { - b.append((uint8_t)1); // 1 == Ed25519 signature - b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); - } - - // This is the size of any additional fields, currently 0. - b.append((uint16_t)0); - - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - memset(this,0,sizeof(Revocation)); - - unsigned int p = startAt; - - _id = b.template at(p); p += 8; - _networkId = b.template at(p); p += 8; - _credentialId = b.template at(p); p += 8; - _threshold = b.template at(p); p += 8; - _flags = b.template at(p); p += 8; - _target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; - _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; - _type = (CredentialType)b[p++]; - - if (b[p++] == 1) { - if (b.template at(p) == ZT_C25519_SIGNATURE_LEN) { - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); - p += ZT_C25519_SIGNATURE_LEN; - } else throw std::runtime_error("invalid signature"); - } else { - p += 2 + b.template at(p); - } - - p += 2 + b.template at(p); - if (p > b.size()) - throw std::runtime_error("extended field overflow"); - - return (p - startAt); - } - -private: - uint64_t _id; - uint64_t _networkId; - uint64_t _credentialId; - uint64_t _threshold; - uint64_t _flags; - Address _target; - Address _signedBy; - CredentialType _type; - C25519::Signature _signature; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/RuntimeEnvironment.hpp b/zto/node/RuntimeEnvironment.hpp deleted file mode 100644 index 7ba1c98..0000000 --- a/zto/node/RuntimeEnvironment.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_RUNTIMEENVIRONMENT_HPP -#define ZT_RUNTIMEENVIRONMENT_HPP - -#include - -#include "Constants.hpp" -#include "Identity.hpp" -#include "Mutex.hpp" - -namespace ZeroTier { - -class NodeConfig; -class Switch; -class Topology; -class Node; -class Multicaster; -class NetworkController; -class SelfAwareness; -class Cluster; - -/** - * Holds global state for an instance of ZeroTier::Node - */ -class RuntimeEnvironment -{ -public: - RuntimeEnvironment(Node *n) : - node(n) - ,identity() - ,localNetworkController((NetworkController *)0) - ,sw((Switch *)0) - ,mc((Multicaster *)0) - ,topology((Topology *)0) - ,sa((SelfAwareness *)0) -#ifdef ZT_ENABLE_CLUSTER - ,cluster((Cluster *)0) -#endif - { - } - - // Node instance that owns this RuntimeEnvironment - Node *const node; - - // This node's identity - Identity identity; - std::string publicIdentityStr; - std::string secretIdentityStr; - - // This is set externally to an instance of this base class - NetworkController *localNetworkController; - - /* - * Order matters a bit here. These are constructed in this order - * and then deleted in the opposite order on Node exit. The order ensures - * that things that are needed are there before they're needed. - * - * These are constant and never null after startup unless indicated. - */ - - Switch *sw; - Multicaster *mc; - Topology *topology; - SelfAwareness *sa; -#ifdef ZT_ENABLE_CLUSTER - Cluster *cluster; -#endif -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/SHA512.cpp b/zto/node/SHA512.cpp deleted file mode 100644 index 76737d3..0000000 --- a/zto/node/SHA512.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#include "SHA512.hpp" -#include "Utils.hpp" - -namespace ZeroTier { - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -// Code taken from NaCl by D. J. Bernstein and others -// Public domain - -/* -20080913 -D. J. Bernstein -Public domain. -*/ - -#define uint64 uint64_t - -#ifdef ZT_NO_TYPE_PUNNING - -static uint64 load_bigendian(const unsigned char *x) -{ - return - (uint64) (x[7]) \ - | (((uint64) (x[6])) << 8) \ - | (((uint64) (x[5])) << 16) \ - | (((uint64) (x[4])) << 24) \ - | (((uint64) (x[3])) << 32) \ - | (((uint64) (x[2])) << 40) \ - | (((uint64) (x[1])) << 48) \ - | (((uint64) (x[0])) << 56) - ; -} - -static void store_bigendian(unsigned char *x,uint64 u) -{ - x[7] = u; u >>= 8; - x[6] = u; u >>= 8; - x[5] = u; u >>= 8; - x[4] = u; u >>= 8; - x[3] = u; u >>= 8; - x[2] = u; u >>= 8; - x[1] = u; u >>= 8; - x[0] = u; -} - -#else // !ZT_NO_TYPE_PUNNING - -#define load_bigendian(x) Utils::ntoh(*((const uint64_t *)(x))) -#define store_bigendian(x,u) (*((uint64_t *)(x)) = Utils::hton((u))) - -#endif // ZT_NO_TYPE_PUNNING - -#define SHR(x,c) ((x) >> (c)) -#define ROTR(x,c) (((x) >> (c)) | ((x) << (64 - (c)))) - -#define Ch(x,y,z) ((x & y) ^ (~x & z)) -#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z)) -#define Sigma0(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) -#define Sigma1(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) -#define sigma0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x,7)) -#define sigma1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x,6)) - -#define M(w0,w14,w9,w1) w0 = sigma1(w14) + w9 + sigma0(w1) + w0; - -#define EXPAND \ - M(w0 ,w14,w9 ,w1 ) \ - M(w1 ,w15,w10,w2 ) \ - M(w2 ,w0 ,w11,w3 ) \ - M(w3 ,w1 ,w12,w4 ) \ - M(w4 ,w2 ,w13,w5 ) \ - M(w5 ,w3 ,w14,w6 ) \ - M(w6 ,w4 ,w15,w7 ) \ - M(w7 ,w5 ,w0 ,w8 ) \ - M(w8 ,w6 ,w1 ,w9 ) \ - M(w9 ,w7 ,w2 ,w10) \ - M(w10,w8 ,w3 ,w11) \ - M(w11,w9 ,w4 ,w12) \ - M(w12,w10,w5 ,w13) \ - M(w13,w11,w6 ,w14) \ - M(w14,w12,w7 ,w15) \ - M(w15,w13,w8 ,w0 ) - -#define F(w,k) \ - T1 = h + Sigma1(e) + Ch(e,f,g) + k + w; \ - T2 = Sigma0(a) + Maj(a,b,c); \ - h = g; \ - g = f; \ - f = e; \ - e = d + T1; \ - d = c; \ - c = b; \ - b = a; \ - a = T1 + T2; - -static inline int crypto_hashblocks(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen) -{ - uint64 state[8]; - uint64 a; - uint64 b; - uint64 c; - uint64 d; - uint64 e; - uint64 f; - uint64 g; - uint64 h; - uint64 T1; - uint64 T2; - - a = load_bigendian(statebytes + 0); state[0] = a; - b = load_bigendian(statebytes + 8); state[1] = b; - c = load_bigendian(statebytes + 16); state[2] = c; - d = load_bigendian(statebytes + 24); state[3] = d; - e = load_bigendian(statebytes + 32); state[4] = e; - f = load_bigendian(statebytes + 40); state[5] = f; - g = load_bigendian(statebytes + 48); state[6] = g; - h = load_bigendian(statebytes + 56); state[7] = h; - - while (inlen >= 128) { - uint64 w0 = load_bigendian(in + 0); - uint64 w1 = load_bigendian(in + 8); - uint64 w2 = load_bigendian(in + 16); - uint64 w3 = load_bigendian(in + 24); - uint64 w4 = load_bigendian(in + 32); - uint64 w5 = load_bigendian(in + 40); - uint64 w6 = load_bigendian(in + 48); - uint64 w7 = load_bigendian(in + 56); - uint64 w8 = load_bigendian(in + 64); - uint64 w9 = load_bigendian(in + 72); - uint64 w10 = load_bigendian(in + 80); - uint64 w11 = load_bigendian(in + 88); - uint64 w12 = load_bigendian(in + 96); - uint64 w13 = load_bigendian(in + 104); - uint64 w14 = load_bigendian(in + 112); - uint64 w15 = load_bigendian(in + 120); - - F(w0 ,0x428a2f98d728ae22ULL) - F(w1 ,0x7137449123ef65cdULL) - F(w2 ,0xb5c0fbcfec4d3b2fULL) - F(w3 ,0xe9b5dba58189dbbcULL) - F(w4 ,0x3956c25bf348b538ULL) - F(w5 ,0x59f111f1b605d019ULL) - F(w6 ,0x923f82a4af194f9bULL) - F(w7 ,0xab1c5ed5da6d8118ULL) - F(w8 ,0xd807aa98a3030242ULL) - F(w9 ,0x12835b0145706fbeULL) - F(w10,0x243185be4ee4b28cULL) - F(w11,0x550c7dc3d5ffb4e2ULL) - F(w12,0x72be5d74f27b896fULL) - F(w13,0x80deb1fe3b1696b1ULL) - F(w14,0x9bdc06a725c71235ULL) - F(w15,0xc19bf174cf692694ULL) - - EXPAND - - F(w0 ,0xe49b69c19ef14ad2ULL) - F(w1 ,0xefbe4786384f25e3ULL) - F(w2 ,0x0fc19dc68b8cd5b5ULL) - F(w3 ,0x240ca1cc77ac9c65ULL) - F(w4 ,0x2de92c6f592b0275ULL) - F(w5 ,0x4a7484aa6ea6e483ULL) - F(w6 ,0x5cb0a9dcbd41fbd4ULL) - F(w7 ,0x76f988da831153b5ULL) - F(w8 ,0x983e5152ee66dfabULL) - F(w9 ,0xa831c66d2db43210ULL) - F(w10,0xb00327c898fb213fULL) - F(w11,0xbf597fc7beef0ee4ULL) - F(w12,0xc6e00bf33da88fc2ULL) - F(w13,0xd5a79147930aa725ULL) - F(w14,0x06ca6351e003826fULL) - F(w15,0x142929670a0e6e70ULL) - - EXPAND - - F(w0 ,0x27b70a8546d22ffcULL) - F(w1 ,0x2e1b21385c26c926ULL) - F(w2 ,0x4d2c6dfc5ac42aedULL) - F(w3 ,0x53380d139d95b3dfULL) - F(w4 ,0x650a73548baf63deULL) - F(w5 ,0x766a0abb3c77b2a8ULL) - F(w6 ,0x81c2c92e47edaee6ULL) - F(w7 ,0x92722c851482353bULL) - F(w8 ,0xa2bfe8a14cf10364ULL) - F(w9 ,0xa81a664bbc423001ULL) - F(w10,0xc24b8b70d0f89791ULL) - F(w11,0xc76c51a30654be30ULL) - F(w12,0xd192e819d6ef5218ULL) - F(w13,0xd69906245565a910ULL) - F(w14,0xf40e35855771202aULL) - F(w15,0x106aa07032bbd1b8ULL) - - EXPAND - - F(w0 ,0x19a4c116b8d2d0c8ULL) - F(w1 ,0x1e376c085141ab53ULL) - F(w2 ,0x2748774cdf8eeb99ULL) - F(w3 ,0x34b0bcb5e19b48a8ULL) - F(w4 ,0x391c0cb3c5c95a63ULL) - F(w5 ,0x4ed8aa4ae3418acbULL) - F(w6 ,0x5b9cca4f7763e373ULL) - F(w7 ,0x682e6ff3d6b2b8a3ULL) - F(w8 ,0x748f82ee5defb2fcULL) - F(w9 ,0x78a5636f43172f60ULL) - F(w10,0x84c87814a1f0ab72ULL) - F(w11,0x8cc702081a6439ecULL) - F(w12,0x90befffa23631e28ULL) - F(w13,0xa4506cebde82bde9ULL) - F(w14,0xbef9a3f7b2c67915ULL) - F(w15,0xc67178f2e372532bULL) - - EXPAND - - F(w0 ,0xca273eceea26619cULL) - F(w1 ,0xd186b8c721c0c207ULL) - F(w2 ,0xeada7dd6cde0eb1eULL) - F(w3 ,0xf57d4f7fee6ed178ULL) - F(w4 ,0x06f067aa72176fbaULL) - F(w5 ,0x0a637dc5a2c898a6ULL) - F(w6 ,0x113f9804bef90daeULL) - F(w7 ,0x1b710b35131c471bULL) - F(w8 ,0x28db77f523047d84ULL) - F(w9 ,0x32caab7b40c72493ULL) - F(w10,0x3c9ebe0a15c9bebcULL) - F(w11,0x431d67c49c100d4cULL) - F(w12,0x4cc5d4becb3e42b6ULL) - F(w13,0x597f299cfc657e2aULL) - F(w14,0x5fcb6fab3ad6faecULL) - F(w15,0x6c44198c4a475817ULL) - - a += state[0]; - b += state[1]; - c += state[2]; - d += state[3]; - e += state[4]; - f += state[5]; - g += state[6]; - h += state[7]; - - state[0] = a; - state[1] = b; - state[2] = c; - state[3] = d; - state[4] = e; - state[5] = f; - state[6] = g; - state[7] = h; - - in += 128; - inlen -= 128; - } - - store_bigendian(statebytes + 0,state[0]); - store_bigendian(statebytes + 8,state[1]); - store_bigendian(statebytes + 16,state[2]); - store_bigendian(statebytes + 24,state[3]); - store_bigendian(statebytes + 32,state[4]); - store_bigendian(statebytes + 40,state[5]); - store_bigendian(statebytes + 48,state[6]); - store_bigendian(statebytes + 56,state[7]); - - return 0; -} - -#define blocks crypto_hashblocks - -static const unsigned char iv[64] = { - 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, - 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, - 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, - 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, - 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, - 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, - 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, - 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 -}; - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -void SHA512::hash(void *digest,const void *data,unsigned int len) -{ - unsigned char h[64]; - unsigned char padded[256]; - int i; - uint64_t bytes = len; - - const unsigned char *in = (const unsigned char *)data; - unsigned int inlen = len; - - for (i = 0;i < 64;++i) h[i] = iv[i]; - - blocks(h,in,inlen); - in += inlen; - inlen &= 127; - in -= inlen; - - for (i = 0;i < (int)inlen;++i) padded[i] = in[i]; - padded[inlen] = 0x80; - - if (inlen < 112) { - for (i = inlen + 1;i < 119;++i) padded[i] = 0; - padded[119] = (unsigned char)((bytes >> 61) & 0xff); - padded[120] = (unsigned char)((bytes >> 53) & 0xff); - padded[121] = (unsigned char)((bytes >> 45) & 0xff); - padded[122] = (unsigned char)((bytes >> 37) & 0xff); - padded[123] = (unsigned char)((bytes >> 29) & 0xff); - padded[124] = (unsigned char)((bytes >> 21) & 0xff); - padded[125] = (unsigned char)((bytes >> 13) & 0xff); - padded[126] = (unsigned char)((bytes >> 5) & 0xff); - padded[127] = (unsigned char)((bytes << 3) & 0xff); - blocks(h,padded,128); - } else { - for (i = inlen + 1;i < 247;++i) padded[i] = 0; - padded[247] = (unsigned char)((bytes >> 61) & 0xff); - padded[248] = (unsigned char)((bytes >> 53) & 0xff); - padded[249] = (unsigned char)((bytes >> 45) & 0xff); - padded[250] = (unsigned char)((bytes >> 37) & 0xff); - padded[251] = (unsigned char)((bytes >> 29) & 0xff); - padded[252] = (unsigned char)((bytes >> 21) & 0xff); - padded[253] = (unsigned char)((bytes >> 13) & 0xff); - padded[254] = (unsigned char)((bytes >> 5) & 0xff); - padded[255] = (unsigned char)((bytes << 3) & 0xff); - blocks(h,padded,256); - } - - for (i = 0;i < 64;++i) ((unsigned char *)digest)[i] = h[i]; -} - -} // namespace ZeroTier diff --git a/zto/node/SHA512.hpp b/zto/node/SHA512.hpp deleted file mode 100644 index 639a7df..0000000 --- a/zto/node/SHA512.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_SHA512_HPP -#define ZT_SHA512_HPP - -#define ZT_SHA512_DIGEST_LEN 64 - -namespace ZeroTier { - -/** - * SHA-512 digest algorithm - */ -class SHA512 -{ -public: - static void hash(void *digest,const void *data,unsigned int len); -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Salsa20.cpp b/zto/node/Salsa20.cpp deleted file mode 100644 index 1a4641f..0000000 --- a/zto/node/Salsa20.cpp +++ /dev/null @@ -1,1358 +0,0 @@ -/* - * Based on public domain code available at: http://cr.yp.to/snuffle.html - * - * Modifications and C-native SSE macro based SSE implementation by - * Adam Ierymenko . - * - * Since the original was public domain, this is too. - */ - -#include "Constants.hpp" -#include "Salsa20.hpp" - -#define ROTATE(v,c) (((v) << (c)) | ((v) >> (32 - (c)))) -#define XOR(v,w) ((v) ^ (w)) -#define PLUS(v,w) ((uint32_t)((v) + (w))) - -// Set up laod/store macros with appropriate endianness (we don't use these in SSE mode) -#ifndef ZT_SALSA20_SSE - -#if __BYTE_ORDER == __LITTLE_ENDIAN - -#ifdef ZT_NO_TYPE_PUNNING -// Slower version that does not use type punning -#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) ) -static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); } -#else -// Fast version that just does 32-bit load/store -#define U8TO32_LITTLE(p) (*((const uint32_t *)((const void *)(p)))) -#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = (v) -#endif // ZT_NO_TYPE_PUNNING - -#else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?) - -#ifdef __GNUC__ - -// Use GNUC builtin bswap macros on big-endian machines if available -#define U8TO32_LITTLE(p) __builtin_bswap32(*((const uint32_t *)((const void *)(p)))) -#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = __builtin_bswap32((v)) - -#else // no __GNUC__ - -// Otherwise do it the slow, manual way on BE machines -#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) ) -static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); } - -#endif // __GNUC__ or not - -#endif // __BYTE_ORDER little or big? - -#endif // !ZT_SALSA20_SSE - -// Statically compute and define SSE constants -#ifdef ZT_SALSA20_SSE -class _s20sseconsts -{ -public: - _s20sseconsts() - { - maskLo32 = _mm_shuffle_epi32(_mm_cvtsi32_si128(-1), _MM_SHUFFLE(1, 0, 1, 0)); - maskHi32 = _mm_slli_epi64(maskLo32, 32); - } - __m128i maskLo32,maskHi32; -}; -static const _s20sseconsts _S20SSECONSTANTS; -#endif - -namespace ZeroTier { - -void Salsa20::init(const void *key,unsigned int kbits,const void *iv) - throw() -{ -#ifdef ZT_SALSA20_SSE - const uint32_t *k = (const uint32_t *)key; - - _state.i[0] = 0x61707865; - _state.i[3] = 0x6b206574; - _state.i[13] = k[0]; - _state.i[10] = k[1]; - _state.i[7] = k[2]; - _state.i[4] = k[3]; - if (kbits == 256) { - k += 4; - _state.i[1] = 0x3320646e; - _state.i[2] = 0x79622d32; - } else { - _state.i[1] = 0x3120646e; - _state.i[2] = 0x79622d36; - } - _state.i[15] = k[0]; - _state.i[12] = k[1]; - _state.i[9] = k[2]; - _state.i[6] = k[3]; - _state.i[14] = ((const uint32_t *)iv)[0]; - _state.i[11] = ((const uint32_t *)iv)[1]; - _state.i[5] = 0; - _state.i[8] = 0; -#else - const char *constants; - const uint8_t *k = (const uint8_t *)key; - - _state.i[1] = U8TO32_LITTLE(k + 0); - _state.i[2] = U8TO32_LITTLE(k + 4); - _state.i[3] = U8TO32_LITTLE(k + 8); - _state.i[4] = U8TO32_LITTLE(k + 12); - if (kbits == 256) { /* recommended */ - k += 16; - constants = "expand 32-byte k"; - } else { /* kbits == 128 */ - constants = "expand 16-byte k"; - } - _state.i[5] = U8TO32_LITTLE(constants + 4); - _state.i[6] = U8TO32_LITTLE(((const uint8_t *)iv) + 0); - _state.i[7] = U8TO32_LITTLE(((const uint8_t *)iv) + 4); - _state.i[8] = 0; - _state.i[9] = 0; - _state.i[10] = U8TO32_LITTLE(constants + 8); - _state.i[11] = U8TO32_LITTLE(k + 0); - _state.i[12] = U8TO32_LITTLE(k + 4); - _state.i[13] = U8TO32_LITTLE(k + 8); - _state.i[14] = U8TO32_LITTLE(k + 12); - _state.i[15] = U8TO32_LITTLE(constants + 12); - _state.i[0] = U8TO32_LITTLE(constants + 0); -#endif -} - -void Salsa20::crypt12(const void *in,void *out,unsigned int bytes) - throw() -{ - uint8_t tmp[64]; - const uint8_t *m = (const uint8_t *)in; - uint8_t *c = (uint8_t *)out; - uint8_t *ctarget = c; - unsigned int i; - -#ifndef ZT_SALSA20_SSE - uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; -#endif - - if (!bytes) - return; - -#ifndef ZT_SALSA20_SSE - j0 = _state.i[0]; - j1 = _state.i[1]; - j2 = _state.i[2]; - j3 = _state.i[3]; - j4 = _state.i[4]; - j5 = _state.i[5]; - j6 = _state.i[6]; - j7 = _state.i[7]; - j8 = _state.i[8]; - j9 = _state.i[9]; - j10 = _state.i[10]; - j11 = _state.i[11]; - j12 = _state.i[12]; - j13 = _state.i[13]; - j14 = _state.i[14]; - j15 = _state.i[15]; -#endif - - for (;;) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) - tmp[i] = m[i]; - m = tmp; - ctarget = c; - c = tmp; - } - -#ifdef ZT_SALSA20_SSE - __m128i X0 = _mm_loadu_si128((const __m128i *)&(_state.v[0])); - __m128i X1 = _mm_loadu_si128((const __m128i *)&(_state.v[1])); - __m128i X2 = _mm_loadu_si128((const __m128i *)&(_state.v[2])); - __m128i X3 = _mm_loadu_si128((const __m128i *)&(_state.v[3])); - __m128i T; - __m128i X0s = X0; - __m128i X1s = X1; - __m128i X2s = X2; - __m128i X3s = X3; - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - X0 = _mm_add_epi32(X0s,X0); - X1 = _mm_add_epi32(X1s,X1); - X2 = _mm_add_epi32(X2s,X2); - X3 = _mm_add_epi32(X3s,X3); - - __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3)); - __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3)); - __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32)); - __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32)); - _mm_storeu_ps(reinterpret_cast(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m)))))); - _mm_storeu_ps(reinterpret_cast(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 4))))); - _mm_storeu_ps(reinterpret_cast(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 8))))); - _mm_storeu_ps(reinterpret_cast(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 12))))); - - if (!(++_state.i[8])) { - ++_state.i[5]; // state reordered for SSE - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } -#else - x0 = j0; - x1 = j1; - x2 = j2; - x3 = j3; - x4 = j4; - x5 = j5; - x6 = j6; - x7 = j7; - x8 = j8; - x9 = j9; - x10 = j10; - x11 = j11; - x12 = j12; - x13 = j13; - x14 = j14; - x15 = j15; - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - x0 = PLUS(x0,j0); - x1 = PLUS(x1,j1); - x2 = PLUS(x2,j2); - x3 = PLUS(x3,j3); - x4 = PLUS(x4,j4); - x5 = PLUS(x5,j5); - x6 = PLUS(x6,j6); - x7 = PLUS(x7,j7); - x8 = PLUS(x8,j8); - x9 = PLUS(x9,j9); - x10 = PLUS(x10,j10); - x11 = PLUS(x11,j11); - x12 = PLUS(x12,j12); - x13 = PLUS(x13,j13); - x14 = PLUS(x14,j14); - x15 = PLUS(x15,j15); - - U32TO8_LITTLE(c + 0,XOR(x0,U8TO32_LITTLE(m + 0))); - U32TO8_LITTLE(c + 4,XOR(x1,U8TO32_LITTLE(m + 4))); - U32TO8_LITTLE(c + 8,XOR(x2,U8TO32_LITTLE(m + 8))); - U32TO8_LITTLE(c + 12,XOR(x3,U8TO32_LITTLE(m + 12))); - U32TO8_LITTLE(c + 16,XOR(x4,U8TO32_LITTLE(m + 16))); - U32TO8_LITTLE(c + 20,XOR(x5,U8TO32_LITTLE(m + 20))); - U32TO8_LITTLE(c + 24,XOR(x6,U8TO32_LITTLE(m + 24))); - U32TO8_LITTLE(c + 28,XOR(x7,U8TO32_LITTLE(m + 28))); - U32TO8_LITTLE(c + 32,XOR(x8,U8TO32_LITTLE(m + 32))); - U32TO8_LITTLE(c + 36,XOR(x9,U8TO32_LITTLE(m + 36))); - U32TO8_LITTLE(c + 40,XOR(x10,U8TO32_LITTLE(m + 40))); - U32TO8_LITTLE(c + 44,XOR(x11,U8TO32_LITTLE(m + 44))); - U32TO8_LITTLE(c + 48,XOR(x12,U8TO32_LITTLE(m + 48))); - U32TO8_LITTLE(c + 52,XOR(x13,U8TO32_LITTLE(m + 52))); - U32TO8_LITTLE(c + 56,XOR(x14,U8TO32_LITTLE(m + 56))); - U32TO8_LITTLE(c + 60,XOR(x15,U8TO32_LITTLE(m + 60))); - - if (!(++j8)) { - ++j9; - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } -#endif - - if (bytes <= 64) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) - ctarget[i] = c[i]; - } - -#ifndef ZT_SALSA20_SSE - _state.i[8] = j8; - _state.i[9] = j9; -#endif - - return; - } - - bytes -= 64; - c += 64; - m += 64; - } -} - -void Salsa20::crypt20(const void *in,void *out,unsigned int bytes) - throw() -{ - uint8_t tmp[64]; - const uint8_t *m = (const uint8_t *)in; - uint8_t *c = (uint8_t *)out; - uint8_t *ctarget = c; - unsigned int i; - -#ifndef ZT_SALSA20_SSE - uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; -#endif - - if (!bytes) - return; - -#ifndef ZT_SALSA20_SSE - j0 = _state.i[0]; - j1 = _state.i[1]; - j2 = _state.i[2]; - j3 = _state.i[3]; - j4 = _state.i[4]; - j5 = _state.i[5]; - j6 = _state.i[6]; - j7 = _state.i[7]; - j8 = _state.i[8]; - j9 = _state.i[9]; - j10 = _state.i[10]; - j11 = _state.i[11]; - j12 = _state.i[12]; - j13 = _state.i[13]; - j14 = _state.i[14]; - j15 = _state.i[15]; -#endif - - for (;;) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) - tmp[i] = m[i]; - m = tmp; - ctarget = c; - c = tmp; - } - -#ifdef ZT_SALSA20_SSE - __m128i X0 = _mm_loadu_si128((const __m128i *)&(_state.v[0])); - __m128i X1 = _mm_loadu_si128((const __m128i *)&(_state.v[1])); - __m128i X2 = _mm_loadu_si128((const __m128i *)&(_state.v[2])); - __m128i X3 = _mm_loadu_si128((const __m128i *)&(_state.v[3])); - __m128i T; - __m128i X0s = X0; - __m128i X1s = X1; - __m128i X2s = X2; - __m128i X3s = X3; - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - X0 = _mm_add_epi32(X0s,X0); - X1 = _mm_add_epi32(X1s,X1); - X2 = _mm_add_epi32(X2s,X2); - X3 = _mm_add_epi32(X3s,X3); - - __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3)); - __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3)); - __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32)); - __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32)); - _mm_storeu_ps(reinterpret_cast(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m)))))); - _mm_storeu_ps(reinterpret_cast(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 4))))); - _mm_storeu_ps(reinterpret_cast(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 8))))); - _mm_storeu_ps(reinterpret_cast(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 12))))); - - if (!(++_state.i[8])) { - ++_state.i[5]; // state reordered for SSE - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } -#else - x0 = j0; - x1 = j1; - x2 = j2; - x3 = j3; - x4 = j4; - x5 = j5; - x6 = j6; - x7 = j7; - x8 = j8; - x9 = j9; - x10 = j10; - x11 = j11; - x12 = j12; - x13 = j13; - x14 = j14; - x15 = j15; - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - x0 = PLUS(x0,j0); - x1 = PLUS(x1,j1); - x2 = PLUS(x2,j2); - x3 = PLUS(x3,j3); - x4 = PLUS(x4,j4); - x5 = PLUS(x5,j5); - x6 = PLUS(x6,j6); - x7 = PLUS(x7,j7); - x8 = PLUS(x8,j8); - x9 = PLUS(x9,j9); - x10 = PLUS(x10,j10); - x11 = PLUS(x11,j11); - x12 = PLUS(x12,j12); - x13 = PLUS(x13,j13); - x14 = PLUS(x14,j14); - x15 = PLUS(x15,j15); - - U32TO8_LITTLE(c + 0,XOR(x0,U8TO32_LITTLE(m + 0))); - U32TO8_LITTLE(c + 4,XOR(x1,U8TO32_LITTLE(m + 4))); - U32TO8_LITTLE(c + 8,XOR(x2,U8TO32_LITTLE(m + 8))); - U32TO8_LITTLE(c + 12,XOR(x3,U8TO32_LITTLE(m + 12))); - U32TO8_LITTLE(c + 16,XOR(x4,U8TO32_LITTLE(m + 16))); - U32TO8_LITTLE(c + 20,XOR(x5,U8TO32_LITTLE(m + 20))); - U32TO8_LITTLE(c + 24,XOR(x6,U8TO32_LITTLE(m + 24))); - U32TO8_LITTLE(c + 28,XOR(x7,U8TO32_LITTLE(m + 28))); - U32TO8_LITTLE(c + 32,XOR(x8,U8TO32_LITTLE(m + 32))); - U32TO8_LITTLE(c + 36,XOR(x9,U8TO32_LITTLE(m + 36))); - U32TO8_LITTLE(c + 40,XOR(x10,U8TO32_LITTLE(m + 40))); - U32TO8_LITTLE(c + 44,XOR(x11,U8TO32_LITTLE(m + 44))); - U32TO8_LITTLE(c + 48,XOR(x12,U8TO32_LITTLE(m + 48))); - U32TO8_LITTLE(c + 52,XOR(x13,U8TO32_LITTLE(m + 52))); - U32TO8_LITTLE(c + 56,XOR(x14,U8TO32_LITTLE(m + 56))); - U32TO8_LITTLE(c + 60,XOR(x15,U8TO32_LITTLE(m + 60))); - - if (!(++j8)) { - ++j9; - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } -#endif - - if (bytes <= 64) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) - ctarget[i] = c[i]; - } - -#ifndef ZT_SALSA20_SSE - _state.i[8] = j8; - _state.i[9] = j9; -#endif - - return; - } - - bytes -= 64; - c += 64; - m += 64; - } -} - -} // namespace ZeroTier diff --git a/zto/node/Salsa20.hpp b/zto/node/Salsa20.hpp deleted file mode 100644 index 6405d45..0000000 --- a/zto/node/Salsa20.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Based on public domain code available at: http://cr.yp.to/snuffle.html - * - * This therefore is public domain. - */ - -#ifndef ZT_SALSA20_HPP -#define ZT_SALSA20_HPP - -#include -#include -#include - -#include "Constants.hpp" -#include "Utils.hpp" - -#if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || defined(__WINDOWS__)) -#define ZT_SALSA20_SSE 1 -#endif - -#ifdef ZT_SALSA20_SSE -#include -#endif // ZT_SALSA20_SSE - -namespace ZeroTier { - -/** - * Salsa20 stream cipher - */ -class Salsa20 -{ -public: - Salsa20() throw() {} - - ~Salsa20() { Utils::burn(&_state,sizeof(_state)); } - - /** - * @param key Key bits - * @param kbits Number of key bits: 128 or 256 (recommended) - * @param iv 64-bit initialization vector - */ - Salsa20(const void *key,unsigned int kbits,const void *iv) - throw() - { - init(key,kbits,iv); - } - - /** - * Initialize cipher - * - * @param key Key bits - * @param kbits Number of key bits: 128 or 256 (recommended) - * @param iv 64-bit initialization vector - */ - void init(const void *key,unsigned int kbits,const void *iv) - throw(); - - /** - * Encrypt/decrypt data using Salsa20/12 - * - * @param in Input data - * @param out Output buffer - * @param bytes Length of data - */ - void crypt12(const void *in,void *out,unsigned int bytes) - throw(); - - /** - * Encrypt/decrypt data using Salsa20/20 - * - * @param in Input data - * @param out Output buffer - * @param bytes Length of data - */ - void crypt20(const void *in,void *out,unsigned int bytes) - throw(); - -private: - union { -#ifdef ZT_SALSA20_SSE - __m128i v[4]; -#endif // ZT_SALSA20_SSE - uint32_t i[16]; - } _state; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/SelfAwareness.cpp b/zto/node/SelfAwareness.cpp deleted file mode 100644 index cba84cd..0000000 --- a/zto/node/SelfAwareness.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#include -#include - -#include "Constants.hpp" -#include "SelfAwareness.hpp" -#include "RuntimeEnvironment.hpp" -#include "Node.hpp" -#include "Topology.hpp" -#include "Packet.hpp" -#include "Peer.hpp" -#include "Switch.hpp" - -// Entry timeout -- make it fairly long since this is just to prevent stale buildup -#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000 - -namespace ZeroTier { - -class _ResetWithinScope -{ -public: - _ResetWithinScope(void *tPtr,uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) : - _now(now), - _tPtr(tPtr), - _family(inetAddressFamily), - _scope(scope) {} - - inline void operator()(Topology &t,const SharedPtr &p) { p->resetWithinScope(_tPtr,_scope,_family,_now); } - -private: - uint64_t _now; - void *_tPtr; - int _family; - InetAddress::IpScope _scope; -}; - -SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : - RR(renv), - _phy(128) -{ -} - -void SelfAwareness::iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) -{ - const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); - - if ((scope != reporterPhysicalAddress.ipScope())||(scope == InetAddress::IP_SCOPE_NONE)||(scope == InetAddress::IP_SCOPE_LOOPBACK)||(scope == InetAddress::IP_SCOPE_MULTICAST)) - return; - - Mutex::Lock _l(_phy_m); - PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalAddress,reporterPhysicalAddress,scope)]; - - if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { - // Changes to external surface reported by trusted peers causes path reset in this scope - TRACE("physical address %s for scope %u as seen from %s(%s) differs from %s, resetting paths in scope",myPhysicalAddress.toString().c_str(),(unsigned int)scope,reporter.toString().c_str(),reporterPhysicalAddress.toString().c_str(),entry.mySurface.toString().c_str()); - - entry.mySurface = myPhysicalAddress; - entry.ts = now; - entry.trusted = trusted; - - // Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing' - // due to multiple reports of endpoint change. - // Don't use 'entry' after this since hash table gets modified. - { - Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); - PhySurfaceKey *k = (PhySurfaceKey *)0; - PhySurfaceEntry *e = (PhySurfaceEntry *)0; - while (i.next(k,e)) { - if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope)) - _phy.erase(*k); - } - } - - // Reset all paths within this scope and address family - _ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); - RR->topology->eachPeer<_ResetWithinScope &>(rset); - } else { - // Otherwise just update DB to use to determine external surface info - entry.mySurface = myPhysicalAddress; - entry.ts = now; - entry.trusted = trusted; - } -} - -void SelfAwareness::clean(uint64_t now) -{ - Mutex::Lock _l(_phy_m); - Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); - PhySurfaceKey *k = (PhySurfaceKey *)0; - PhySurfaceEntry *e = (PhySurfaceEntry *)0; - while (i.next(k,e)) { - if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) - _phy.erase(*k); - } -} - -std::vector SelfAwareness::getSymmetricNatPredictions() -{ - /* This is based on ideas and strategies found here: - * https://tools.ietf.org/html/draft-takeda-symmetric-nat-traversal-00 - * - * For each IP address reported by a trusted (upstream) peer, we find - * the external port most recently reported by ANY peer for that IP. - * - * We only do any of this for global IPv4 addresses since private IPs - * and IPv6 are not going to have symmetric NAT. - * - * SECURITY NOTE: - * - * We never use IPs reported by non-trusted peers, since this could lead - * to a minor vulnerability whereby a peer could poison our cache with - * bad external surface reports via OK(HELLO) and then possibly coax us - * into suggesting their IP to other peers via PUSH_DIRECT_PATHS. This - * in turn could allow them to MITM flows. - * - * Since flows are encrypted and authenticated they could not actually - * read or modify traffic, but they could gather meta-data for forensics - * purpsoes or use this as a DOS attack vector. */ - - std::map< uint32_t,std::pair > maxPortByIp; - InetAddress theOneTrueSurface; - bool symmetric = false; - { - Mutex::Lock _l(_phy_m); - - { // First get IPs from only trusted peers, and perform basic NAT type characterization - Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); - PhySurfaceKey *k = (PhySurfaceKey *)0; - PhySurfaceEntry *e = (PhySurfaceEntry *)0; - while (i.next(k,e)) { - if ((e->trusted)&&(e->mySurface.ss_family == AF_INET)&&(e->mySurface.ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { - if (!theOneTrueSurface) - theOneTrueSurface = e->mySurface; - else if (theOneTrueSurface != e->mySurface) - symmetric = true; - maxPortByIp[reinterpret_cast(&(e->mySurface))->sin_addr.s_addr] = std::pair(e->ts,e->mySurface.port()); - } - } - } - - { // Then find max port per IP from a trusted peer - Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); - PhySurfaceKey *k = (PhySurfaceKey *)0; - PhySurfaceEntry *e = (PhySurfaceEntry *)0; - while (i.next(k,e)) { - if ((e->mySurface.ss_family == AF_INET)&&(e->mySurface.ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { - std::map< uint32_t,std::pair >::iterator mp(maxPortByIp.find(reinterpret_cast(&(e->mySurface))->sin_addr.s_addr)); - if ((mp != maxPortByIp.end())&&(mp->second.first < e->ts)) { - mp->second.first = e->ts; - mp->second.second = e->mySurface.port(); - } - } - } - } - } - - if (symmetric) { - std::vector r; - for(unsigned int k=1;k<=3;++k) { - for(std::map< uint32_t,std::pair >::iterator i(maxPortByIp.begin());i!=maxPortByIp.end();++i) { - unsigned int p = i->second.second + k; - if (p > 65535) p -= 64511; - InetAddress pred(&(i->first),4,p); - if (std::find(r.begin(),r.end(),pred) == r.end()) - r.push_back(pred); - } - } - return r; - } - - return std::vector(); -} - -} // namespace ZeroTier diff --git a/zto/node/SelfAwareness.hpp b/zto/node/SelfAwareness.hpp deleted file mode 100644 index c1db0c8..0000000 --- a/zto/node/SelfAwareness.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_SELFAWARENESS_HPP -#define ZT_SELFAWARENESS_HPP - -#include "Constants.hpp" -#include "InetAddress.hpp" -#include "Hashtable.hpp" -#include "Address.hpp" -#include "Mutex.hpp" - -namespace ZeroTier { - -class RuntimeEnvironment; - -/** - * Tracks changes to this peer's real world addresses - */ -class SelfAwareness -{ -public: - SelfAwareness(const RuntimeEnvironment *renv); - - /** - * Called when a trusted remote peer informs us of our external network address - * - * @param reporter ZeroTier address of reporting peer - * @param receivedOnLocalAddress Local address on which report was received - * @param reporterPhysicalAddress Physical address that reporting peer seems to have - * @param myPhysicalAddress Physical address that peer says we have - * @param trusted True if this peer is trusted as an authority to inform us of external address changes - * @param now Current time - */ - void iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); - - /** - * Clean up database periodically - * - * @param now Current time - */ - void clean(uint64_t now); - - /** - * If we appear to be behind a symmetric NAT, get predictions for possible external endpoints - * - * @return Symmetric NAT predictions or empty vector if none - */ - std::vector getSymmetricNatPredictions(); - -private: - struct PhySurfaceKey - { - Address reporter; - InetAddress receivedOnLocalAddress; - InetAddress reporterPhysicalAddress; - InetAddress::IpScope scope; - - PhySurfaceKey() : reporter(),scope(InetAddress::IP_SCOPE_NONE) {} - PhySurfaceKey(const Address &r,const InetAddress &rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalAddress(rol),reporterPhysicalAddress(ra),scope(s) {} - - inline unsigned long hashCode() const throw() { return ((unsigned long)reporter.toInt() + (unsigned long)scope); } - inline bool operator==(const PhySurfaceKey &k) const throw() { return ((reporter == k.reporter)&&(receivedOnLocalAddress == k.receivedOnLocalAddress)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); } - }; - struct PhySurfaceEntry - { - InetAddress mySurface; - uint64_t ts; - bool trusted; - - PhySurfaceEntry() : mySurface(),ts(0),trusted(false) {} - PhySurfaceEntry(const InetAddress &a,const uint64_t t) : mySurface(a),ts(t),trusted(false) {} - }; - - const RuntimeEnvironment *RR; - - Hashtable< PhySurfaceKey,PhySurfaceEntry > _phy; - Mutex _phy_m; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/SharedPtr.hpp b/zto/node/SharedPtr.hpp deleted file mode 100644 index 1dd3b43..0000000 --- a/zto/node/SharedPtr.hpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_SHAREDPTR_HPP -#define ZT_SHAREDPTR_HPP - -#include "Mutex.hpp" -#include "AtomicCounter.hpp" - -namespace ZeroTier { - -/** - * Simple reference counted pointer - * - * This is an introspective shared pointer. Classes that need to be reference - * counted must list this as a 'friend' and must have a private instance of - * AtomicCounter called __refCount. They should also have private destructors, - * since only this class should delete them. - * - * Because this is introspective, it is safe to apply to a naked pointer - * multiple times provided there is always at least one holding SharedPtr. - * - * Once C++11 is ubiquitous, this and a few other things like Thread might get - * torn out for their standard equivalents. - */ -template -class SharedPtr -{ -public: - SharedPtr() - throw() : - _ptr((T *)0) - { - } - - SharedPtr(T *obj) - throw() : - _ptr(obj) - { - ++obj->__refCount; - } - - SharedPtr(const SharedPtr &sp) - throw() : - _ptr(sp._getAndInc()) - { - } - - ~SharedPtr() - { - if (_ptr) { - if (--_ptr->__refCount <= 0) - delete _ptr; - } - } - - inline SharedPtr &operator=(const SharedPtr &sp) - { - if (_ptr != sp._ptr) { - T *p = sp._getAndInc(); - if (_ptr) { - if (--_ptr->__refCount <= 0) - delete _ptr; - } - _ptr = p; - } - return *this; - } - - /** - * Set to a naked pointer and increment its reference count - * - * This assumes this SharedPtr is NULL and that ptr is not a 'zombie.' No - * checks are performed. - * - * @param ptr Naked pointer to assign - */ - inline void setToUnsafe(T *ptr) - { - ++ptr->__refCount; - _ptr = ptr; - } - - /** - * Swap with another pointer 'for free' without ref count overhead - * - * @param with Pointer to swap with - */ - inline void swap(SharedPtr &with) - throw() - { - T *tmp = _ptr; - _ptr = with._ptr; - with._ptr = tmp; - } - - inline operator bool() const throw() { return (_ptr != (T *)0); } - inline T &operator*() const throw() { return *_ptr; } - inline T *operator->() const throw() { return _ptr; } - - /** - * @return Raw pointer to held object - */ - inline T *ptr() const throw() { return _ptr; } - - /** - * Set this pointer to NULL - */ - inline void zero() - { - if (_ptr) { - if (--_ptr->__refCount <= 0) - delete _ptr; - _ptr = (T *)0; - } - } - - /** - * Set this pointer to NULL if this is the only pointer holding the object - * - * @return True if object was deleted and SharedPtr is now NULL (or was already NULL) - */ - inline bool reclaimIfWeak() - { - if (_ptr) { - if (++_ptr->__refCount <= 2) { - if (--_ptr->__refCount <= 1) { - delete _ptr; - _ptr = (T *)0; - return true; - } else { - return false; - } - } else { - return false; - } - } else { - return true; - } - } - - inline bool operator==(const SharedPtr &sp) const throw() { return (_ptr == sp._ptr); } - inline bool operator!=(const SharedPtr &sp) const throw() { return (_ptr != sp._ptr); } - inline bool operator>(const SharedPtr &sp) const throw() { return (_ptr > sp._ptr); } - inline bool operator<(const SharedPtr &sp) const throw() { return (_ptr < sp._ptr); } - inline bool operator>=(const SharedPtr &sp) const throw() { return (_ptr >= sp._ptr); } - inline bool operator<=(const SharedPtr &sp) const throw() { return (_ptr <= sp._ptr); } - -private: - inline T *_getAndInc() const - throw() - { - if (_ptr) - ++_ptr->__refCount; - return _ptr; - } - - T *_ptr; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Switch.cpp b/zto/node/Switch.cpp deleted file mode 100644 index 56299a9..0000000 --- a/zto/node/Switch.cpp +++ /dev/null @@ -1,881 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -#include -#include -#include - -#include "../version.h" -#include "../include/ZeroTierOne.h" - -#include "Constants.hpp" -#include "RuntimeEnvironment.hpp" -#include "Switch.hpp" -#include "Node.hpp" -#include "InetAddress.hpp" -#include "Topology.hpp" -#include "Peer.hpp" -#include "SelfAwareness.hpp" -#include "Packet.hpp" -#include "Cluster.hpp" - -namespace ZeroTier { - -#ifdef ZT_TRACE -static const char *etherTypeName(const unsigned int etherType) -{ - switch(etherType) { - case ZT_ETHERTYPE_IPV4: return "IPV4"; - case ZT_ETHERTYPE_ARP: return "ARP"; - case ZT_ETHERTYPE_RARP: return "RARP"; - case ZT_ETHERTYPE_ATALK: return "ATALK"; - case ZT_ETHERTYPE_AARP: return "AARP"; - case ZT_ETHERTYPE_IPX_A: return "IPX_A"; - case ZT_ETHERTYPE_IPX_B: return "IPX_B"; - case ZT_ETHERTYPE_IPV6: return "IPV6"; - } - return "UNKNOWN"; -} -#endif // ZT_TRACE - -Switch::Switch(const RuntimeEnvironment *renv) : - RR(renv), - _lastBeaconResponse(0), - _outstandingWhoisRequests(32), - _lastUniteAttempt(8) // only really used on root servers and upstreams, and it'll grow there just fine -{ -} - -void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len) -{ - try { - const uint64_t now = RR->node->now(); - - SharedPtr path(RR->topology->getPath(localAddr,fromAddr)); - path->received(now); - - if (len == 13) { - /* LEGACY: before VERB_PUSH_DIRECT_PATHS, peers used broadcast - * announcements on the LAN to solve the 'same network problem.' We - * no longer send these, but we'll listen for them for a while to - * locate peers with versions <1.0.4. */ - - const Address beaconAddr(reinterpret_cast(data) + 8,5); - if (beaconAddr == RR->identity.address()) - return; - if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localAddr,fromAddr)) - return; - const SharedPtr peer(RR->topology->getPeer(tPtr,beaconAddr)); - if (peer) { // we'll only respond to beacons from known peers - if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses - _lastBeaconResponse = now; - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); - outp.armor(peer->key(),true,path->nextOutgoingCounter()); - path->send(RR,tPtr,outp.data(),outp.size(),now); - } - } - - } else if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) { // SECURITY: min length check is important since we do some C-style stuff below! - if (reinterpret_cast(data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) { - // Handle fragment ---------------------------------------------------- - - Packet::Fragment fragment(data,len); - const Address destination(fragment.destination()); - - if (destination != RR->identity.address()) { -#ifdef ZT_ENABLE_CLUSTER - const bool isClusterFrontplane = ((RR->cluster)&&(RR->cluster->isClusterPeerFrontplane(fromAddr))); -#else - const bool isClusterFrontplane = false; -#endif - - if ( (!RR->topology->amRoot()) && (!path->trustEstablished(now)) && (!isClusterFrontplane) ) - return; - - if (fragment.hops() < ZT_RELAY_MAX_HOPS) { - fragment.incrementHops(); - - // Note: we don't bother initiating NAT-t for fragments, since heads will set that off. - // It wouldn't hurt anything, just redundant and unnecessary. - SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); - if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) { -#ifdef ZT_ENABLE_CLUSTER - if ((RR->cluster)&&(!isClusterFrontplane)) { - RR->cluster->relayViaCluster(Address(),destination,fragment.data(),fragment.size(),false); - return; - } -#endif - - // Don't know peer or no direct path -- so relay via someone upstream - relayTo = RR->topology->getUpstreamPeer(); - if (relayTo) - relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true); - } - } else { - TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str()); - } - } else { - // Fragment looks like ours - const uint64_t fragmentPacketId = fragment.packetId(); - const unsigned int fragmentNumber = fragment.fragmentNumber(); - const unsigned int totalFragments = fragment.totalFragments(); - - if ((totalFragments <= ZT_MAX_PACKET_FRAGMENTS)&&(fragmentNumber < ZT_MAX_PACKET_FRAGMENTS)&&(fragmentNumber > 0)&&(totalFragments > 1)) { - // Fragment appears basically sane. Its fragment number must be - // 1 or more, since a Packet with fragmented bit set is fragment 0. - // Total fragments must be more than 1, otherwise why are we - // seeing a Packet::Fragment? - - Mutex::Lock _l(_rxQueue_m); - RXQueueEntry *const rq = _findRXQueueEntry(now,fragmentPacketId); - - if ((!rq->timestamp)||(rq->packetId != fragmentPacketId)) { - // No packet found, so we received a fragment without its head. - //TRACE("fragment (%u/%u) of %.16llx from %s",fragmentNumber + 1,totalFragments,fragmentPacketId,fromAddr.toString().c_str()); - - rq->timestamp = now; - rq->packetId = fragmentPacketId; - rq->frags[fragmentNumber - 1] = fragment; - rq->totalFragments = totalFragments; // total fragment count is known - rq->haveFragments = 1 << fragmentNumber; // we have only this fragment - rq->complete = false; - } else if (!(rq->haveFragments & (1 << fragmentNumber))) { - // We have other fragments and maybe the head, so add this one and check - //TRACE("fragment (%u/%u) of %.16llx from %s",fragmentNumber + 1,totalFragments,fragmentPacketId,fromAddr.toString().c_str()); - - rq->frags[fragmentNumber - 1] = fragment; - rq->totalFragments = totalFragments; - - if (Utils::countBits(rq->haveFragments |= (1 << fragmentNumber)) == totalFragments) { - // We have all fragments -- assemble and process full Packet - //TRACE("packet %.16llx is complete, assembling and processing...",fragmentPacketId); - - for(unsigned int f=1;ffrag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); - - if (rq->frag0.tryDecode(RR,tPtr)) { - rq->timestamp = 0; // packet decoded, free entry - } else { - rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something - } - } - } // else this is a duplicate fragment, ignore - } - } - - // -------------------------------------------------------------------- - } else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) { // min length check is important! - // Handle packet head ------------------------------------------------- - - const Address destination(reinterpret_cast(data) + 8,ZT_ADDRESS_LENGTH); - const Address source(reinterpret_cast(data) + 13,ZT_ADDRESS_LENGTH); - - //TRACE("<< %.16llx %s -> %s (size: %u)",(unsigned long long)packet->packetId(),source.toString().c_str(),destination.toString().c_str(),packet->size()); - -#ifdef ZT_ENABLE_CLUSTER - if ( (source == RR->identity.address()) && ((!RR->cluster)||(!RR->cluster->isClusterPeerFrontplane(fromAddr))) ) - return; -#else - if (source == RR->identity.address()) - return; -#endif - - if (destination != RR->identity.address()) { - if ( (!RR->topology->amRoot()) && (!path->trustEstablished(now)) && (source != RR->identity.address()) ) - return; - - Packet packet(data,len); - - if (packet.hops() < ZT_RELAY_MAX_HOPS) { -#ifdef ZT_ENABLE_CLUSTER - if (source != RR->identity.address()) // don't increment hops for cluster frontplane relays - packet.incrementHops(); -#else - packet.incrementHops(); -#endif - - SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); - if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) { - if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) { // don't send RENDEZVOUS for cluster frontplane relays - const InetAddress *hintToSource = (InetAddress *)0; - const InetAddress *hintToDest = (InetAddress *)0; - - InetAddress destV4,destV6; - InetAddress sourceV4,sourceV6; - relayTo->getRendezvousAddresses(now,destV4,destV6); - - const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); - if (sourcePeer) { - sourcePeer->getRendezvousAddresses(now,sourceV4,sourceV6); - if ((destV6)&&(sourceV6)) { - hintToSource = &destV6; - hintToDest = &sourceV6; - } else if ((destV4)&&(sourceV4)) { - hintToSource = &destV4; - hintToDest = &sourceV4; - } - - if ((hintToSource)&&(hintToDest)) { - unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for obscure NAT-t reasons - const unsigned int completed = alt + 2; - while (alt != completed) { - if ((alt & 1) == 0) { - Packet outp(source,RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - destination.appendTo(outp); - outp.append((uint16_t)hintToSource->port()); - if (hintToSource->ss_family == AF_INET6) { - outp.append((uint8_t)16); - outp.append(hintToSource->rawIpData(),16); - } else { - outp.append((uint8_t)4); - outp.append(hintToSource->rawIpData(),4); - } - send(tPtr,outp,true); - } else { - Packet outp(destination,RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - source.appendTo(outp); - outp.append((uint16_t)hintToDest->port()); - if (hintToDest->ss_family == AF_INET6) { - outp.append((uint8_t)16); - outp.append(hintToDest->rawIpData(),16); - } else { - outp.append((uint8_t)4); - outp.append(hintToDest->rawIpData(),4); - } - send(tPtr,outp,true); - } - ++alt; - } - } - } - } - } else { -#ifdef ZT_ENABLE_CLUSTER - if ((RR->cluster)&&(source != RR->identity.address())) { - RR->cluster->relayViaCluster(source,destination,packet.data(),packet.size(),_shouldUnite(now,source,destination)); - return; - } -#endif - relayTo = RR->topology->getUpstreamPeer(&source,1,true); - if (relayTo) - relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); - } - } else { - TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet.source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str()); - } - } else if ((reinterpret_cast(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { - // Packet is the head of a fragmented packet series - - const uint64_t packetId = ( - (((uint64_t)reinterpret_cast(data)[0]) << 56) | - (((uint64_t)reinterpret_cast(data)[1]) << 48) | - (((uint64_t)reinterpret_cast(data)[2]) << 40) | - (((uint64_t)reinterpret_cast(data)[3]) << 32) | - (((uint64_t)reinterpret_cast(data)[4]) << 24) | - (((uint64_t)reinterpret_cast(data)[5]) << 16) | - (((uint64_t)reinterpret_cast(data)[6]) << 8) | - ((uint64_t)reinterpret_cast(data)[7]) - ); - - Mutex::Lock _l(_rxQueue_m); - RXQueueEntry *const rq = _findRXQueueEntry(now,packetId); - - if ((!rq->timestamp)||(rq->packetId != packetId)) { - // If we have no other fragments yet, create an entry and save the head - //TRACE("fragment (0/?) of %.16llx from %s",pid,fromAddr.toString().c_str()); - - rq->timestamp = now; - rq->packetId = packetId; - rq->frag0.init(data,len,path,now); - rq->totalFragments = 0; - rq->haveFragments = 1; - rq->complete = false; - } else if (!(rq->haveFragments & 1)) { - // If we have other fragments but no head, see if we are complete with the head - - if ((rq->totalFragments > 1)&&(Utils::countBits(rq->haveFragments |= 1) == rq->totalFragments)) { - // We have all fragments -- assemble and process full Packet - //TRACE("packet %.16llx is complete, assembling and processing...",pid); - - rq->frag0.init(data,len,path,now); - for(unsigned int f=1;ftotalFragments;++f) - rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); - - if (rq->frag0.tryDecode(RR,tPtr)) { - rq->timestamp = 0; // packet decoded, free entry - } else { - rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something - } - } else { - // Still waiting on more fragments, but keep the head - rq->frag0.init(data,len,path,now); - } - } // else this is a duplicate head, ignore - } else { - // Packet is unfragmented, so just process it - IncomingPacket packet(data,len,path,now); - if (!packet.tryDecode(RR,tPtr)) { - Mutex::Lock _l(_rxQueue_m); - RXQueueEntry *rq = &(_rxQueue[ZT_RX_QUEUE_SIZE - 1]); - unsigned long i = ZT_RX_QUEUE_SIZE - 1; - while ((i)&&(rq->timestamp)) { - RXQueueEntry *tmp = &(_rxQueue[--i]); - if (tmp->timestamp < rq->timestamp) - rq = tmp; - } - rq->timestamp = now; - rq->packetId = packet.packetId(); - rq->frag0 = packet; - rq->totalFragments = 1; - rq->haveFragments = 1; - rq->complete = true; - } - } - - // -------------------------------------------------------------------- - } - } - } catch (std::exception &ex) { - TRACE("dropped packet from %s: unexpected exception: %s",fromAddr.toString().c_str(),ex.what()); - } catch ( ... ) { - TRACE("dropped packet from %s: unexpected exception: (unknown)",fromAddr.toString().c_str()); - } -} - -void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) -{ - if (!network->hasConfig()) - return; - - // Check if this packet is from someone other than the tap -- i.e. bridged in - bool fromBridged; - if ((fromBridged = (from != network->mac()))) { - if (!network->config().permitsBridging(RR->identity.address())) { - TRACE("%.16llx: %s -> %s %s not forwarded, bridging disabled or this peer not a bridge",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); - return; - } - } - - if (to.isMulticast()) { - MulticastGroup multicastGroup(to,0); - - if (to.isBroadcast()) { - if ( (etherType == ZT_ETHERTYPE_ARP) && (len >= 28) && ((((const uint8_t *)data)[2] == 0x08)&&(((const uint8_t *)data)[3] == 0x00)&&(((const uint8_t *)data)[4] == 6)&&(((const uint8_t *)data)[5] == 4)&&(((const uint8_t *)data)[7] == 0x01)) ) { - /* IPv4 ARP is one of the few special cases that we impose upon what is - * otherwise a straightforward Ethernet switch emulation. Vanilla ARP - * is dumb old broadcast and simply doesn't scale. ZeroTier multicast - * groups have an additional field called ADI (additional distinguishing - * information) which was added specifically for ARP though it could - * be used for other things too. We then take ARP broadcasts and turn - * them into multicasts by stuffing the IP address being queried into - * the 32-bit ADI field. In practice this uses our multicast pub/sub - * system to implement a kind of extended/distributed ARP table. */ - multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); - } else if (!network->config().enableBroadcast()) { - // Don't transmit broadcasts if this network doesn't want them - TRACE("%.16llx: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled",network->id()); - return; - } - } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) { - // IPv6 NDP emulation for certain very special patterns of private IPv6 addresses -- if enabled - if ((network->config().ndpEmulation())&&(reinterpret_cast(data)[6] == 0x3a)&&(reinterpret_cast(data)[40] == 0x87)) { // ICMPv6 neighbor solicitation - Address v6EmbeddedAddress; - const uint8_t *const pkt6 = reinterpret_cast(data) + 40 + 8; - const uint8_t *my6 = (const uint8_t *)0; - - // ZT-RFC4193 address: fdNN:NNNN:NNNN:NNNN:NN99:93DD:DDDD:DDDD / 88 (one /128 per actual host) - - // ZT-6PLANE address: fcXX:XXXX:XXDD:DDDD:DDDD:####:####:#### / 40 (one /80 per actual host) - // (XX - lower 32 bits of network ID XORed with higher 32 bits) - - // For these to work, we must have a ZT-managed address assigned in one of the - // above formats, and the query must match its prefix. - for(unsigned int sipk=0;sipkconfig().staticIpCount;++sipk) { - const InetAddress *const sip = &(network->config().staticIps[sipk]); - if (sip->ss_family == AF_INET6) { - my6 = reinterpret_cast(reinterpret_cast(&(*sip))->sin6_addr.s6_addr); - const unsigned int sipNetmaskBits = Utils::ntoh((uint16_t)reinterpret_cast(&(*sip))->sin6_port); - if ((sipNetmaskBits == 88)&&(my6[0] == 0xfd)&&(my6[9] == 0x99)&&(my6[10] == 0x93)) { // ZT-RFC4193 /88 ??? - unsigned int ptr = 0; - while (ptr != 11) { - if (pkt6[ptr] != my6[ptr]) - break; - ++ptr; - } - if (ptr == 11) { // prefix match! - v6EmbeddedAddress.setTo(pkt6 + ptr,5); - break; - } - } else if (sipNetmaskBits == 40) { // ZT-6PLANE /40 ??? - const uint32_t nwid32 = (uint32_t)((network->id() ^ (network->id() >> 32)) & 0xffffffff); - if ( (my6[0] == 0xfc) && (my6[1] == (uint8_t)((nwid32 >> 24) & 0xff)) && (my6[2] == (uint8_t)((nwid32 >> 16) & 0xff)) && (my6[3] == (uint8_t)((nwid32 >> 8) & 0xff)) && (my6[4] == (uint8_t)(nwid32 & 0xff))) { - unsigned int ptr = 0; - while (ptr != 5) { - if (pkt6[ptr] != my6[ptr]) - break; - ++ptr; - } - if (ptr == 5) { // prefix match! - v6EmbeddedAddress.setTo(pkt6 + ptr,5); - break; - } - } - } - } - } - - if ((v6EmbeddedAddress)&&(v6EmbeddedAddress != RR->identity.address())) { - const MAC peerMac(v6EmbeddedAddress,network->id()); - TRACE("IPv6 NDP emulation: %.16llx: forging response for %s/%s",network->id(),v6EmbeddedAddress.toString().c_str(),peerMac.toString().c_str()); - - uint8_t adv[72]; - adv[0] = 0x60; adv[1] = 0x00; adv[2] = 0x00; adv[3] = 0x00; - adv[4] = 0x00; adv[5] = 0x20; - adv[6] = 0x3a; adv[7] = 0xff; - for(int i=0;i<16;++i) adv[8 + i] = pkt6[i]; - for(int i=0;i<16;++i) adv[24 + i] = my6[i]; - adv[40] = 0x88; adv[41] = 0x00; - adv[42] = 0x00; adv[43] = 0x00; // future home of checksum - adv[44] = 0x60; adv[45] = 0x00; adv[46] = 0x00; adv[47] = 0x00; - for(int i=0;i<16;++i) adv[48 + i] = pkt6[i]; - adv[64] = 0x02; adv[65] = 0x01; - adv[66] = peerMac[0]; adv[67] = peerMac[1]; adv[68] = peerMac[2]; adv[69] = peerMac[3]; adv[70] = peerMac[4]; adv[71] = peerMac[5]; - - uint16_t pseudo_[36]; - uint8_t *const pseudo = reinterpret_cast(pseudo_); - for(int i=0;i<32;++i) pseudo[i] = adv[8 + i]; - pseudo[32] = 0x00; pseudo[33] = 0x00; pseudo[34] = 0x00; pseudo[35] = 0x20; - pseudo[36] = 0x00; pseudo[37] = 0x00; pseudo[38] = 0x00; pseudo[39] = 0x3a; - for(int i=0;i<32;++i) pseudo[40 + i] = adv[40 + i]; - uint32_t checksum = 0; - for(int i=0;i<36;++i) checksum += Utils::hton(pseudo_[i]); - while ((checksum >> 16)) checksum = (checksum & 0xffff) + (checksum >> 16); - checksum = ~checksum; - adv[42] = (checksum >> 8) & 0xff; - adv[43] = checksum & 0xff; - - RR->node->putFrame(tPtr,network->id(),network->userPtr(),peerMac,from,ZT_ETHERTYPE_IPV6,0,adv,72); - return; // NDP emulation done. We have forged a "fake" reply, so no need to send actual NDP query. - } // else no NDP emulation - } // else no NDP emulation - } - - // Check this after NDP emulation, since that has to be allowed in exactly this case - if (network->config().multicastLimit == 0) { - TRACE("%.16llx: dropped multicast: not allowed on network",network->id()); - return; - } - - /* Learn multicast groups for bridged-in hosts. - * Note that some OSes, most notably Linux, do this for you by learning - * multicast addresses on bridge interfaces and subscribing each slave. - * But in that case this does no harm, as the sets are just merged. */ - if (fromBridged) - network->learnBridgedMulticastGroup(tPtr,multicastGroup,RR->node->now()); - - //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),multicastGroup.toString().c_str(),etherTypeName(etherType),len); - - // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. - if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); - return; - } - - RR->mc->send( - tPtr, - network->config().multicastLimit, - RR->node->now(), - network->id(), - network->config().disableCompression(), - network->config().activeBridges(), - multicastGroup, - (fromBridged) ? from : MAC(), - etherType, - data, - len); - } else if (to == network->mac()) { - // Destination is this node, so just reinject it - RR->node->putFrame(tPtr,network->id(),network->userPtr(),from,to,etherType,vlanId,data,len); - } else if (to[0] == MAC::firstOctetForNetwork(network->id())) { - // Destination is another ZeroTier peer on the same network - - Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this - SharedPtr toPeer(RR->topology->getPeer(tPtr,toZT)); - - if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); - return; - } - - if (fromBridged) { - Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(network->id()); - outp.append((unsigned char)0x00); - to.appendTo(outp); - from.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(data,len); - if (!network->config().disableCompression()) - outp.compress(); - send(tPtr,outp,true); - } else { - Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); - outp.append(network->id()); - outp.append((uint16_t)etherType); - outp.append(data,len); - if (!network->config().disableCompression()) - outp.compress(); - send(tPtr,outp,true); - } - - //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom); - } else { - // Destination is bridged behind a remote peer - - // We filter with a NULL destination ZeroTier address first. Filtrations - // for each ZT destination are also done below. This is the same rationale - // and design as for multicast. - if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); - return; - } - - Address bridges[ZT_MAX_BRIDGE_SPAM]; - unsigned int numBridges = 0; - - /* Create an array of up to ZT_MAX_BRIDGE_SPAM recipients for this bridged frame. */ - bridges[0] = network->findBridgeTo(to); - std::vector
activeBridges(network->config().activeBridges()); - if ((bridges[0])&&(bridges[0] != RR->identity.address())&&(network->config().permitsBridging(bridges[0]))) { - /* We have a known bridge route for this MAC, send it there. */ - ++numBridges; - } else if (!activeBridges.empty()) { - /* If there is no known route, spam to up to ZT_MAX_BRIDGE_SPAM active - * bridges. If someone responds, we'll learn the route. */ - std::vector
::const_iterator ab(activeBridges.begin()); - if (activeBridges.size() <= ZT_MAX_BRIDGE_SPAM) { - // If there are <= ZT_MAX_BRIDGE_SPAM active bridges, spam them all - while (ab != activeBridges.end()) { - bridges[numBridges++] = *ab; - ++ab; - } - } else { - // Otherwise pick a random set of them - while (numBridges < ZT_MAX_BRIDGE_SPAM) { - if (ab == activeBridges.end()) - ab = activeBridges.begin(); - if (((unsigned long)RR->node->prng() % (unsigned long)activeBridges.size()) == 0) { - bridges[numBridges++] = *ab; - ++ab; - } else ++ab; - } - } - } - - for(unsigned int b=0;bfilterOutgoingPacket(tPtr,true,RR->identity.address(),bridges[b],from,to,(const uint8_t *)data,len,etherType,vlanId)) { - Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(network->id()); - outp.append((uint8_t)0x00); - to.appendTo(outp); - from.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(data,len); - if (!network->config().disableCompression()) - outp.compress(); - send(tPtr,outp,true); - } else { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); - } - } - } -} - -void Switch::send(void *tPtr,Packet &packet,bool encrypt) -{ - if (packet.destination() == RR->identity.address()) { - TRACE("BUG: caught attempt to send() to self, ignored"); - return; - } - - if (!_trySend(tPtr,packet,encrypt)) { - Mutex::Lock _l(_txQueue_m); - _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt)); - } -} - -void Switch::requestWhois(void *tPtr,const Address &addr) -{ -#ifdef ZT_TRACE - if (addr == RR->identity.address()) { - fprintf(stderr,"FATAL BUG: Switch::requestWhois() caught attempt to WHOIS self" ZT_EOL_S); - abort(); - } -#endif - - bool inserted = false; - { - Mutex::Lock _l(_outstandingWhoisRequests_m); - WhoisRequest &r = _outstandingWhoisRequests[addr]; - if (r.lastSent) { - r.retries = 0; // reset retry count if entry already existed, but keep waiting and retry again after normal timeout - } else { - r.lastSent = RR->node->now(); - inserted = true; - } - } - if (inserted) - _sendWhoisRequest(tPtr,addr,(const Address *)0,0); -} - -void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) -{ - { // cancel pending WHOIS since we now know this peer - Mutex::Lock _l(_outstandingWhoisRequests_m); - _outstandingWhoisRequests.erase(peer->address()); - } - - { // finish processing any packets waiting on peer's public key / identity - Mutex::Lock _l(_rxQueue_m); - unsigned long i = ZT_RX_QUEUE_SIZE; - while (i) { - RXQueueEntry *rq = &(_rxQueue[--i]); - if ((rq->timestamp)&&(rq->complete)) { - if (rq->frag0.tryDecode(RR,tPtr)) - rq->timestamp = 0; - } - } - } - - { // finish sending any packets waiting on peer's public key / identity - Mutex::Lock _l(_txQueue_m); - for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { - if (txi->dest == peer->address()) { - if (_trySend(tPtr,txi->packet,txi->encrypt)) - _txQueue.erase(txi++); - else ++txi; - } else ++txi; - } - } -} - -unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) -{ - unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum - - { // Retry outstanding WHOIS requests - Mutex::Lock _l(_outstandingWhoisRequests_m); - Hashtable< Address,WhoisRequest >::Iterator i(_outstandingWhoisRequests); - Address *a = (Address *)0; - WhoisRequest *r = (WhoisRequest *)0; - while (i.next(a,r)) { - const unsigned long since = (unsigned long)(now - r->lastSent); - if (since >= ZT_WHOIS_RETRY_DELAY) { - if (r->retries >= ZT_MAX_WHOIS_RETRIES) { - TRACE("WHOIS %s timed out",a->toString().c_str()); - _outstandingWhoisRequests.erase(*a); - } else { - r->lastSent = now; - r->peersConsulted[r->retries] = _sendWhoisRequest(tPtr,*a,r->peersConsulted,(r->retries > 1) ? r->retries : 0); - TRACE("WHOIS %s (retry %u)",a->toString().c_str(),r->retries); - ++r->retries; - nextDelay = std::min(nextDelay,(unsigned long)ZT_WHOIS_RETRY_DELAY); - } - } else { - nextDelay = std::min(nextDelay,ZT_WHOIS_RETRY_DELAY - since); - } - } - } - - { // Time out TX queue packets that never got WHOIS lookups or other info. - Mutex::Lock _l(_txQueue_m); - for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { - if (_trySend(tPtr,txi->packet,txi->encrypt)) - _txQueue.erase(txi++); - else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { - TRACE("TX %s -> %s timed out",txi->packet.source().toString().c_str(),txi->packet.destination().toString().c_str()); - _txQueue.erase(txi++); - } else ++txi; - } - } - - { // Remove really old last unite attempt entries to keep table size controlled - Mutex::Lock _l(_lastUniteAttempt_m); - Hashtable< _LastUniteKey,uint64_t >::Iterator i(_lastUniteAttempt); - _LastUniteKey *k = (_LastUniteKey *)0; - uint64_t *v = (uint64_t *)0; - while (i.next(k,v)) { - if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 8)) - _lastUniteAttempt.erase(*k); - } - } - - return nextDelay; -} - -bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address &destination) -{ - Mutex::Lock _l(_lastUniteAttempt_m); - uint64_t &ts = _lastUniteAttempt[_LastUniteKey(source,destination)]; - if ((now - ts) >= ZT_MIN_UNITE_INTERVAL) { - ts = now; - return true; - } - return false; -} - -Address Switch::_sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) -{ - SharedPtr upstream(RR->topology->getUpstreamPeer(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); - if (upstream) { - Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); - addr.appendTo(outp); - RR->node->expectReplyTo(outp.packetId()); - send(tPtr,outp,true); - } - return Address(); -} - -bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) -{ - SharedPtr viaPath; - const uint64_t now = RR->node->now(); - const Address destination(packet.destination()); - -#ifdef ZT_ENABLE_CLUSTER - uint64_t clusterMostRecentTs = 0; - int clusterMostRecentMemberId = -1; - uint8_t clusterPeerSecret[ZT_PEER_SECRET_KEY_LENGTH]; - if (RR->cluster) - clusterMostRecentMemberId = RR->cluster->checkSendViaCluster(destination,clusterMostRecentTs,clusterPeerSecret); -#endif - - const SharedPtr peer(RR->topology->getPeer(tPtr,destination)); - if (peer) { - /* First get the best path, and if it's dead (and this is not a root) - * we attempt to re-activate that path but this packet will flow - * upstream. If the path comes back alive, it will be used in the future. - * For roots we don't do the alive check since roots are not required - * to send heartbeats "down" and because we have to at least try to - * go somewhere. */ - - viaPath = peer->getBestPath(now,false); - if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { -#ifdef ZT_ENABLE_CLUSTER - if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) { -#endif - if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(tPtr,viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); - viaPath->sent(now); - } -#ifdef ZT_ENABLE_CLUSTER - } -#endif - viaPath.zero(); - } - -#ifdef ZT_ENABLE_CLUSTER - if (clusterMostRecentMemberId >= 0) { - if ((viaPath)&&(viaPath->lastIn() < clusterMostRecentTs)) - viaPath.zero(); - } else if (!viaPath) { -#else - if (!viaPath) { -#endif - peer->tryMemorizedPath(tPtr,now); // periodically attempt memorized or statically defined paths, if any are known - const SharedPtr relay(RR->topology->getUpstreamPeer()); - if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) { - if (!(viaPath = peer->getBestPath(now,true))) - return false; - } -#ifdef ZT_ENABLE_CLUSTER - } -#else - } -#endif - } else { -#ifdef ZT_ENABLE_CLUSTER - if (clusterMostRecentMemberId < 0) { -#else - requestWhois(tPtr,destination); - return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly -#endif -#ifdef ZT_ENABLE_CLUSTER - } -#endif - } - - unsigned int chunkSize = std::min(packet.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); - packet.setFragmented(chunkSize < packet.size()); - -#ifdef ZT_ENABLE_CLUSTER - const uint64_t trustedPathId = (viaPath) ? RR->topology->getOutboundPathTrust(viaPath->address()) : 0; - if (trustedPathId) { - packet.setTrusted(trustedPathId); - } else { - packet.armor((clusterMostRecentMemberId >= 0) ? clusterPeerSecret : peer->key(),encrypt,(viaPath) ? viaPath->nextOutgoingCounter() : 0); - } -#else - const uint64_t trustedPathId = RR->topology->getOutboundPathTrust(viaPath->address()); - if (trustedPathId) { - packet.setTrusted(trustedPathId); - } else { - packet.armor(peer->key(),encrypt,viaPath->nextOutgoingCounter()); - } -#endif - -#ifdef ZT_ENABLE_CLUSTER - if ( ((viaPath)&&(viaPath->send(RR,tPtr,packet.data(),chunkSize,now))) || ((clusterMostRecentMemberId >= 0)&&(RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,packet.data(),chunkSize))) ) { -#else - if (viaPath->send(RR,tPtr,packet.data(),chunkSize,now)) { -#endif - if (chunkSize < packet.size()) { - // Too big for one packet, fragment the rest - unsigned int fragStart = chunkSize; - unsigned int remaining = packet.size() - chunkSize; - unsigned int fragsRemaining = (remaining / (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)); - if ((fragsRemaining * (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining) - ++fragsRemaining; - const unsigned int totalFragments = fragsRemaining + 1; - - for(unsigned int fno=1;fnosend(RR,tPtr,frag.data(),frag.size(),now); - else if (clusterMostRecentMemberId >= 0) - RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,frag.data(),frag.size()); -#else - viaPath->send(RR,tPtr,frag.data(),frag.size(),now); -#endif - fragStart += chunkSize; - remaining -= chunkSize; - } - } - } - - return true; -} - -} // namespace ZeroTier diff --git a/zto/node/Switch.hpp b/zto/node/Switch.hpp deleted file mode 100644 index ff35093..0000000 --- a/zto/node/Switch.hpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_N_SWITCH_HPP -#define ZT_N_SWITCH_HPP - -#include -#include -#include -#include - -#include "Constants.hpp" -#include "Mutex.hpp" -#include "MAC.hpp" -#include "NonCopyable.hpp" -#include "Packet.hpp" -#include "Utils.hpp" -#include "InetAddress.hpp" -#include "Topology.hpp" -#include "Array.hpp" -#include "Network.hpp" -#include "SharedPtr.hpp" -#include "IncomingPacket.hpp" -#include "Hashtable.hpp" - -namespace ZeroTier { - -class RuntimeEnvironment; -class Peer; - -/** - * Core of the distributed Ethernet switch and protocol implementation - * - * This class is perhaps a bit misnamed, but it's basically where everything - * meets. Transport-layer ZT packets come in here, as do virtual network - * packets from tap devices, and this sends them where they need to go and - * wraps/unwraps accordingly. It also handles queues and timeouts and such. - */ -class Switch : NonCopyable -{ -public: - Switch(const RuntimeEnvironment *renv); - - /** - * Called when a packet is received from the real network - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localAddr Local interface address - * @param fromAddr Internet IP address of origin - * @param data Packet data - * @param len Packet length - */ - void onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len); - - /** - * Called when a packet comes from a local Ethernet tap - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param network Which network's TAP did this packet come from? - * @param from Originating MAC address - * @param to Destination MAC address - * @param etherType Ethernet packet type - * @param vlanId VLAN ID or 0 if none - * @param data Ethernet payload - * @param len Frame length - */ - void onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); - - /** - * Send a packet to a ZeroTier address (destination in packet) - * - * The packet must be fully composed with source and destination but not - * yet encrypted. If the destination peer is known the packet - * is sent immediately. Otherwise it is queued and a WHOIS is dispatched. - * - * The packet may be compressed. Compression isn't done here. - * - * Needless to say, the packet's source must be this node. Otherwise it - * won't be encrypted right. (This is not used for relaying.) - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param packet Packet to send (buffer may be modified) - * @param encrypt Encrypt packet payload? (always true except for HELLO) - */ - void send(void *tPtr,Packet &packet,bool encrypt); - - /** - * Request WHOIS on a given address - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param addr Address to look up - */ - void requestWhois(void *tPtr,const Address &addr); - - /** - * Run any processes that are waiting for this peer's identity - * - * Called when we learn of a peer's identity from HELLO, OK(WHOIS), etc. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param peer New peer - */ - void doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer); - - /** - * Perform retries and other periodic timer tasks - * - * This can return a very long delay if there are no pending timer - * tasks. The caller should cap this comparatively vs. other values. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - * @return Number of milliseconds until doTimerTasks() should be run again - */ - unsigned long doTimerTasks(void *tPtr,uint64_t now); - -private: - bool _shouldUnite(const uint64_t now,const Address &source,const Address &destination); - Address _sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); - bool _trySend(void *tPtr,Packet &packet,bool encrypt); // packet is modified if return is true - - const RuntimeEnvironment *const RR; - uint64_t _lastBeaconResponse; - - // Outstanding WHOIS requests and how many retries they've undergone - struct WhoisRequest - { - WhoisRequest() : lastSent(0),retries(0) {} - uint64_t lastSent; - Address peersConsulted[ZT_MAX_WHOIS_RETRIES]; // by retry - unsigned int retries; // 0..ZT_MAX_WHOIS_RETRIES - }; - Hashtable< Address,WhoisRequest > _outstandingWhoisRequests; - Mutex _outstandingWhoisRequests_m; - - // Packets waiting for WHOIS replies or other decode info or missing fragments - struct RXQueueEntry - { - RXQueueEntry() : timestamp(0) {} - uint64_t timestamp; // 0 if entry is not in use - uint64_t packetId; - IncomingPacket frag0; // head of packet - Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any) - unsigned int totalFragments; // 0 if only frag0 received, waiting for frags - uint32_t haveFragments; // bit mask, LSB to MSB - bool complete; // if true, packet is complete - }; - RXQueueEntry _rxQueue[ZT_RX_QUEUE_SIZE]; - Mutex _rxQueue_m; - - /* Returns the matching or oldest entry. Caller must check timestamp and - * packet ID to determine which. */ - inline RXQueueEntry *_findRXQueueEntry(uint64_t now,uint64_t packetId) - { - RXQueueEntry *rq; - RXQueueEntry *oldest = &(_rxQueue[ZT_RX_QUEUE_SIZE - 1]); - unsigned long i = ZT_RX_QUEUE_SIZE; - while (i) { - rq = &(_rxQueue[--i]); - if ((rq->packetId == packetId)&&(rq->timestamp)) - return rq; - if ((now - rq->timestamp) >= ZT_RX_QUEUE_EXPIRE) - rq->timestamp = 0; - if (rq->timestamp < oldest->timestamp) - oldest = rq; - } - return oldest; - } - - // ZeroTier-layer TX queue entry - struct TXQueueEntry - { - TXQueueEntry() {} - TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc) : - dest(d), - creationTime(ct), - packet(p), - encrypt(enc) {} - - Address dest; - uint64_t creationTime; - Packet packet; // unencrypted/unMAC'd packet -- this is done at send time - bool encrypt; - }; - std::list< TXQueueEntry > _txQueue; - Mutex _txQueue_m; - - // Tracks sending of VERB_RENDEZVOUS to relaying peers - struct _LastUniteKey - { - _LastUniteKey() : x(0),y(0) {} - _LastUniteKey(const Address &a1,const Address &a2) - { - if (a1 > a2) { - x = a2.toInt(); - y = a1.toInt(); - } else { - x = a1.toInt(); - y = a2.toInt(); - } - } - inline unsigned long hashCode() const throw() { return ((unsigned long)x ^ (unsigned long)y); } - inline bool operator==(const _LastUniteKey &k) const throw() { return ((x == k.x)&&(y == k.y)); } - uint64_t x,y; - }; - Hashtable< _LastUniteKey,uint64_t > _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior - Mutex _lastUniteAttempt_m; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Tag.cpp b/zto/node/Tag.cpp deleted file mode 100644 index 3f924da..0000000 --- a/zto/node/Tag.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Tag.hpp" -#include "RuntimeEnvironment.hpp" -#include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Network.hpp" - -namespace ZeroTier { - -int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const -{ - if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) - return -1; - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); - return 1; - } - try { - Buffer<(sizeof(Tag) * 2)> tmp; - this->serialize(tmp,true); - return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); - } catch ( ... ) { - return -1; - } -} - -} // namespace ZeroTier diff --git a/zto/node/Tag.hpp b/zto/node/Tag.hpp deleted file mode 100644 index 3808590..0000000 --- a/zto/node/Tag.hpp +++ /dev/null @@ -1,201 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_TAG_HPP -#define ZT_TAG_HPP - -#include -#include -#include -#include - -#include "Constants.hpp" -#include "C25519.hpp" -#include "Address.hpp" -#include "Identity.hpp" -#include "Buffer.hpp" - -namespace ZeroTier { - -class RuntimeEnvironment; - -/** - * A tag that can be associated with members and matched in rules - * - * Capabilities group rules, while tags group members subject to those - * rules. Tag values can be matched in rules, and tags relevant to a - * capability are presented along with it. - * - * E.g. a capability might be "can speak Samba/CIFS within your - * department." This cap might have a rule to allow TCP/137 but - * only if a given tag ID's value matches between two peers. The - * capability is what members can do, while the tag is who they are. - * Different departments might have tags with the same ID but different - * values. - * - * Unlike capabilities tags are signed only by the issuer and are never - * transferrable. - */ -class Tag -{ -public: - Tag() - { - memset(this,0,sizeof(Tag)); - } - - /** - * @param nwid Network ID - * @param ts Timestamp - * @param issuedTo Address to which this tag was issued - * @param id Tag ID - * @param value Tag value - */ - Tag(const uint64_t nwid,const uint64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) : - _networkId(nwid), - _ts(ts), - _id(id), - _value(value), - _issuedTo(issuedTo), - _signedBy() - { - } - - inline uint64_t networkId() const { return _networkId; } - inline uint64_t timestamp() const { return _ts; } - inline uint32_t id() const { return _id; } - inline const uint32_t &value() const { return _value; } - inline const Address &issuedTo() const { return _issuedTo; } - inline const Address &signedBy() const { return _signedBy; } - - /** - * Sign this tag - * - * @param signer Signing identity, must have private key - * @return True if signature was successful - */ - inline bool sign(const Identity &signer) - { - if (signer.hasPrivate()) { - Buffer tmp; - _signedBy = signer.address(); - this->serialize(tmp,true); - _signature = signer.sign(tmp.data(),tmp.size()); - return true; - } - return false; - } - - /** - * Check this tag's signature - * - * @param RR Runtime environment to allow identity lookup for signedBy - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; - - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - // These are the same between Tag and Capability - b.append(_networkId); - b.append(_ts); - b.append(_id); - - b.append(_value); - - _issuedTo.appendTo(b); - _signedBy.appendTo(b); - if (!forSign) { - b.append((uint8_t)1); // 1 == Ed25519 - b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); - } - - b.append((uint16_t)0); // length of additional fields, currently 0 - - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; - - memset(this,0,sizeof(Tag)); - - _networkId = b.template at(p); p += 8; - _ts = b.template at(p); p += 8; - _id = b.template at(p); p += 4; - - _value = b.template at(p); p += 4; - - _issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; - _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; - if (b[p++] == 1) { - if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) - throw std::runtime_error("invalid signature length"); - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; - } else { - p += 2 + b.template at(p); - } - - p += 2 + b.template at(p); - if (p > b.size()) - throw std::runtime_error("extended field overflow"); - - return (p - startAt); - } - - // Provides natural sort order by ID - inline bool operator<(const Tag &t) const { return (_id < t._id); } - - inline bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); } - inline bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); } - - // For searching sorted arrays or lists of Tags by ID - struct IdComparePredicate - { - inline bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); } - inline bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); } - inline bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); } - inline bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); } - inline bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); } - inline bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); } - inline bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); } - inline bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); } - inline bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); } - }; - -private: - uint64_t _networkId; - uint64_t _ts; - uint32_t _id; - uint32_t _value; - Address _issuedTo; - Address _signedBy; - C25519::Signature _signature; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Topology.cpp b/zto/node/Topology.cpp deleted file mode 100644 index a1d3733..0000000 --- a/zto/node/Topology.cpp +++ /dev/null @@ -1,475 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Constants.hpp" -#include "Topology.hpp" -#include "RuntimeEnvironment.hpp" -#include "Node.hpp" -#include "Network.hpp" -#include "NetworkConfig.hpp" -#include "Buffer.hpp" -#include "Switch.hpp" - -namespace ZeroTier { - -/* - * 2016-01-13 ZeroTier planet definition for the third planet of Sol: - * - * There are two roots, each of which is a cluster spread across multiple - * continents and providers. They are named Alice and Bob after the - * canonical example names used in cryptography. - * - * Alice: - * - * root-alice-ams-01: Amsterdam, Netherlands - * root-alice-joh-01: Johannesburg, South Africa - * root-alice-nyc-01: New York, New York, USA - * root-alice-sao-01: Sao Paolo, Brazil - * root-alice-sfo-01: San Francisco, California, USA - * root-alice-sgp-01: Singapore - * - * Bob: - * - * root-bob-dfw-01: Dallas, Texas, USA - * root-bob-fra-01: Frankfurt, Germany - * root-bob-par-01: Paris, France - * root-bob-syd-01: Sydney, Australia - * root-bob-tok-01: Tokyo, Japan - * root-bob-tor-01: Toronto, Canada - */ -#define ZT_DEFAULT_WORLD_LENGTH 634 -static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x52,0x3c,0x32,0x50,0x1a,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x4a,0xf7,0x86,0xa8,0x40,0xd6,0x52,0xea,0xae,0x9e,0x7a,0xbf,0x4c,0x97,0x66,0xab,0x2d,0x6f,0xaf,0xc9,0x2b,0x3a,0xff,0xed,0xd6,0x30,0x3e,0xc4,0x6a,0x65,0xf2,0xbd,0x83,0x52,0xf5,0x40,0xe9,0xcc,0x0d,0x6e,0x89,0x3f,0x9a,0xa0,0xb8,0xdf,0x42,0xd2,0x2f,0x84,0xe6,0x03,0x26,0x0f,0xa8,0xe3,0xcc,0x05,0x05,0x03,0xef,0x12,0x80,0x0d,0xce,0x3e,0xb6,0x58,0x3b,0x1f,0xa8,0xad,0xc7,0x25,0xf9,0x43,0x71,0xa7,0x5c,0x9a,0xc7,0xe1,0xa3,0xb8,0x88,0xd0,0x71,0x6c,0x94,0x99,0x73,0x41,0x0b,0x1b,0x48,0x84,0x02,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09,0x06,0x26,0x07,0xf0,0xd0,0x1d,0x01,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09}; - -Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : - RR(renv), - _trustedPathCount(0), - _amRoot(false) -{ - try { - World cachedPlanet; - std::string buf(RR->node->dataStoreGet(tPtr,"planet")); - if (buf.length() > 0) { - Buffer dswtmp(buf.data(),(unsigned int)buf.length()); - cachedPlanet.deserialize(dswtmp,0); - } - addWorld(tPtr,cachedPlanet,false); - } catch ( ... ) {} - - World defaultPlanet; - { - Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); - defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top - } - addWorld(tPtr,defaultPlanet,false); -} - -SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) -{ -#ifdef ZT_TRACE - if ((!peer)||(peer->address() == RR->identity.address())) { - if (!peer) - fprintf(stderr,"FATAL BUG: addPeer() caught attempt to add NULL peer" ZT_EOL_S); - else fprintf(stderr,"FATAL BUG: addPeer() caught attempt to add peer for self" ZT_EOL_S); - abort(); - } -#endif - - SharedPtr np; - { - Mutex::Lock _l(_peers_m); - SharedPtr &hp = _peers[peer->address()]; - if (!hp) - hp = peer; - np = hp; - } - - saveIdentity(tPtr,np->identity()); - - return np; -} - -SharedPtr Topology::getPeer(void *tPtr,const Address &zta) -{ - if (zta == RR->identity.address()) { - TRACE("BUG: ignored attempt to getPeer() for self, returned NULL"); - return SharedPtr(); - } - - { - Mutex::Lock _l(_peers_m); - const SharedPtr *const ap = _peers.get(zta); - if (ap) - return *ap; - } - - try { - Identity id(_getIdentity(tPtr,zta)); - if (id) { - SharedPtr np(new Peer(RR,RR->identity,id)); - { - Mutex::Lock _l(_peers_m); - SharedPtr &ap = _peers[zta]; - if (!ap) - ap.swap(np); - return ap; - } - } - } catch ( ... ) {} // invalid identity on disk? - - return SharedPtr(); -} - -Identity Topology::getIdentity(void *tPtr,const Address &zta) -{ - if (zta == RR->identity.address()) { - return RR->identity; - } else { - Mutex::Lock _l(_peers_m); - const SharedPtr *const ap = _peers.get(zta); - if (ap) - return (*ap)->identity(); - } - return _getIdentity(tPtr,zta); -} - -void Topology::saveIdentity(void *tPtr,const Identity &id) -{ - if (id) { - char p[128]; - Utils::snprintf(p,sizeof(p),"iddb.d/%.10llx",(unsigned long long)id.address().toInt()); - RR->node->dataStorePut(tPtr,p,id.toString(false),false); - } -} - -SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid) -{ - const uint64_t now = RR->node->now(); - unsigned int bestQualityOverall = ~((unsigned int)0); - unsigned int bestQualityNotAvoid = ~((unsigned int)0); - const SharedPtr *bestOverall = (const SharedPtr *)0; - const SharedPtr *bestNotAvoid = (const SharedPtr *)0; - - Mutex::Lock _l1(_peers_m); - Mutex::Lock _l2(_upstreams_m); - - for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { - const SharedPtr *p = _peers.get(*a); - if (p) { - bool avoiding = false; - for(unsigned int i=0;iaddress()) { - avoiding = true; - break; - } - } - const unsigned int q = (*p)->relayQuality(now); - if (q <= bestQualityOverall) { - bestQualityOverall = q; - bestOverall = &(*p); - } - if ((!avoiding)&&(q <= bestQualityNotAvoid)) { - bestQualityNotAvoid = q; - bestNotAvoid = &(*p); - } - } - } - - if (bestNotAvoid) { - return *bestNotAvoid; - } else if ((!strictAvoid)&&(bestOverall)) { - return *bestOverall; - } - - return SharedPtr(); -} - -bool Topology::isUpstream(const Identity &id) const -{ - Mutex::Lock _l(_upstreams_m); - return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end()); -} - -bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const -{ - Mutex::Lock _l(_upstreams_m); - if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),addr) != _upstreamAddresses.end()) - return true; - for(std::vector< std::pair< uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) { - if (s->second == addr) - return true; - } - return false; -} - -ZT_PeerRole Topology::role(const Address &ztaddr) const -{ - Mutex::Lock _l(_upstreams_m); - if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { - for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { - if (i->identity.address() == ztaddr) - return ZT_PEER_ROLE_PLANET; - } - return ZT_PEER_ROLE_MOON; - } - return ZT_PEER_ROLE_LEAF; -} - -bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const -{ - Mutex::Lock _l(_upstreams_m); - - // For roots the only permitted addresses are those defined. This adds just a little - // bit of extra security against spoofing, replaying, etc. - if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { - for(std::vector::const_iterator r(_planet.roots().begin());r!=_planet.roots().end();++r) { - if (r->identity.address() == ztaddr) { - if (r->stableEndpoints.size() == 0) - return false; // no stable endpoints specified, so allow dynamic paths - for(std::vector::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { - if (ipaddr.ipsEqual(*e)) - return false; - } - } - } - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::const_iterator r(m->roots().begin());r!=m->roots().end();++r) { - if (r->identity.address() == ztaddr) { - if (r->stableEndpoints.size() == 0) - return false; // no stable endpoints specified, so allow dynamic paths - for(std::vector::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { - if (ipaddr.ipsEqual(*e)) - return false; - } - } - } - } - return true; - } - - return false; -} - -bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew) -{ - if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) - return false; - - Mutex::Lock _l1(_upstreams_m); - Mutex::Lock _l2(_peers_m); - - World *existing = (World *)0; - switch(newWorld.type()) { - case World::TYPE_PLANET: - existing = &_planet; - break; - case World::TYPE_MOON: - for(std::vector< World >::iterator m(_moons.begin());m!=_moons.end();++m) { - if (m->id() == newWorld.id()) { - existing = &(*m); - break; - } - } - break; - default: - return false; - } - - if (existing) { - if (existing->shouldBeReplacedBy(newWorld)) - *existing = newWorld; - else return false; - } else if (newWorld.type() == World::TYPE_MOON) { - if (alwaysAcceptNew) { - _moons.push_back(newWorld); - existing = &(_moons.back()); - } else { - for(std::vector< std::pair >::iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { - if (m->first == newWorld.id()) { - for(std::vector::const_iterator r(newWorld.roots().begin());r!=newWorld.roots().end();++r) { - if (r->identity.address() == m->second) { - _moonSeeds.erase(m); - _moons.push_back(newWorld); - existing = &(_moons.back()); - break; - } - } - if (existing) - break; - } - } - } - if (!existing) - return false; - } else { - return false; - } - - char savePath[64]; - if (existing->type() == World::TYPE_MOON) { - Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",existing->id()); - } else { - Utils::scopy(savePath,sizeof(savePath),"planet"); - } - try { - Buffer dswtmp; - existing->serialize(dswtmp,false); - RR->node->dataStorePut(tPtr,savePath,dswtmp.data(),dswtmp.size(),false); - } catch ( ... ) { - RR->node->dataStoreDelete(tPtr,savePath); - } - - _memoizeUpstreams(tPtr); - - return true; -} - -void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed) -{ - char savePath[64]; - Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); - - try { - std::string moonBin(RR->node->dataStoreGet(tPtr,savePath)); - if (moonBin.length() > 1) { - Buffer wtmp(moonBin.data(),(unsigned int)moonBin.length()); - World w; - w.deserialize(wtmp); - if ((w.type() == World::TYPE_MOON)&&(w.id() == id)) { - addWorld(tPtr,w,true); - return; - } - } - } catch ( ... ) {} - - if (seed) { - Mutex::Lock _l(_upstreams_m); - if (std::find(_moonSeeds.begin(),_moonSeeds.end(),std::pair(id,seed)) == _moonSeeds.end()) - _moonSeeds.push_back(std::pair(id,seed)); - } -} - -void Topology::removeMoon(void *tPtr,const uint64_t id) -{ - Mutex::Lock _l1(_upstreams_m); - Mutex::Lock _l2(_peers_m); - - std::vector nm; - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - if (m->id() != id) { - nm.push_back(*m); - } else { - char savePath[64]; - Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); - RR->node->dataStoreDelete(tPtr,savePath); - } - } - _moons.swap(nm); - - std::vector< std::pair > cm; - for(std::vector< std::pair >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { - if (m->first != id) - cm.push_back(*m); - } - _moonSeeds.swap(cm); - - _memoizeUpstreams(tPtr); -} - -void Topology::clean(uint64_t now) -{ - { - Mutex::Lock _l1(_peers_m); - Mutex::Lock _l2(_upstreams_m); - Hashtable< Address,SharedPtr >::Iterator i(_peers); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - while (i.next(a,p)) { - if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) - _peers.erase(*a); - } - } - { - Mutex::Lock _l(_paths_m); - Hashtable< Path::HashKey,SharedPtr >::Iterator i(_paths); - Path::HashKey *k = (Path::HashKey *)0; - SharedPtr *p = (SharedPtr *)0; - while (i.next(k,p)) { - if (p->reclaimIfWeak()) - _paths.erase(*k); - } - } -} - -Identity Topology::_getIdentity(void *tPtr,const Address &zta) -{ - char p[128]; - Utils::snprintf(p,sizeof(p),"iddb.d/%.10llx",(unsigned long long)zta.toInt()); - std::string ids(RR->node->dataStoreGet(tPtr,p)); - if (ids.length() > 0) { - try { - return Identity(ids); - } catch ( ... ) {} // ignore invalid IDs - } - return Identity(); -} - -void Topology::_memoizeUpstreams(void *tPtr) -{ - // assumes _upstreams_m and _peers_m are locked - _upstreamAddresses.clear(); - _amRoot = false; - - for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { - if (i->identity == RR->identity) { - _amRoot = true; - } else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) { - _upstreamAddresses.push_back(i->identity.address()); - SharedPtr &hp = _peers[i->identity.address()]; - if (!hp) { - hp = new Peer(RR,RR->identity,i->identity); - saveIdentity(tPtr,i->identity); - } - } - } - - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { - if (i->identity == RR->identity) { - _amRoot = true; - } else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) { - _upstreamAddresses.push_back(i->identity.address()); - SharedPtr &hp = _peers[i->identity.address()]; - if (!hp) { - hp = new Peer(RR,RR->identity,i->identity); - saveIdentity(tPtr,i->identity); - } - } - } - } - - std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end()); - - _cor.clear(); - for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { - if (!_cor.addRepresentative(*a)) - break; - } - _cor.sign(RR->identity,RR->node->now()); -} - -} // namespace ZeroTier diff --git a/zto/node/Topology.hpp b/zto/node/Topology.hpp deleted file mode 100644 index 4870ab5..0000000 --- a/zto/node/Topology.hpp +++ /dev/null @@ -1,456 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_TOPOLOGY_HPP -#define ZT_TOPOLOGY_HPP - -#include -#include - -#include -#include -#include -#include - -#include "Constants.hpp" -#include "../include/ZeroTierOne.h" - -#include "Address.hpp" -#include "Identity.hpp" -#include "Peer.hpp" -#include "Path.hpp" -#include "Mutex.hpp" -#include "InetAddress.hpp" -#include "Hashtable.hpp" -#include "World.hpp" -#include "CertificateOfRepresentation.hpp" - -namespace ZeroTier { - -class RuntimeEnvironment; - -/** - * Database of network topology - */ -class Topology -{ -public: - Topology(const RuntimeEnvironment *renv,void *tPtr); - - /** - * Add a peer to database - * - * This will not replace existing peers. In that case the existing peer - * record is returned. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param peer Peer to add - * @return New or existing peer (should replace 'peer') - */ - SharedPtr addPeer(void *tPtr,const SharedPtr &peer); - - /** - * Get a peer from its address - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param zta ZeroTier address of peer - * @return Peer or NULL if not found - */ - SharedPtr getPeer(void *tPtr,const Address &zta); - - /** - * Get a peer only if it is presently in memory (no disk cache) - * - * This also does not update the lastUsed() time for peers, which means - * that it won't prevent them from falling out of RAM. This is currently - * used in the Cluster code to update peer info without forcing all peers - * across the entire cluster to remain in memory cache. - * - * @param zta ZeroTier address - */ - inline SharedPtr getPeerNoCache(const Address &zta) - { - Mutex::Lock _l(_peers_m); - const SharedPtr *const ap = _peers.get(zta); - if (ap) - return *ap; - return SharedPtr(); - } - - /** - * Get a Path object for a given local and remote physical address, creating if needed - * - * @param l Local address or NULL for 'any' or 'wildcard' - * @param r Remote address - * @return Pointer to canonicalized Path object - */ - inline SharedPtr getPath(const InetAddress &l,const InetAddress &r) - { - Mutex::Lock _l(_paths_m); - SharedPtr &p = _paths[Path::HashKey(l,r)]; - if (!p) - p.setToUnsafe(new Path(l,r)); - return p; - } - - /** - * Get the identity of a peer - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param zta ZeroTier address of peer - * @return Identity or NULL Identity if not found - */ - Identity getIdentity(void *tPtr,const Address &zta); - - /** - * Cache an identity - * - * This is done automatically on addPeer(), and so is only useful for - * cluster identity replication. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param id Identity to cache - */ - void saveIdentity(void *tPtr,const Identity &id); - - /** - * Get the current best upstream peer - * - * @return Root server with lowest latency or NULL if none - */ - inline SharedPtr getUpstreamPeer() { return getUpstreamPeer((const Address *)0,0,false); } - - /** - * Get the current best upstream peer, avoiding those in the supplied avoid list - * - * @param avoid Nodes to avoid - * @param avoidCount Number of nodes to avoid - * @param strictAvoid If false, consider avoided root servers anyway if no non-avoid root servers are available - * @return Root server or NULL if none available - */ - SharedPtr getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid); - - /** - * @param id Identity to check - * @return True if this is a root server or a network preferred relay from one of our networks - */ - bool isUpstream(const Identity &id) const; - - /** - * @param addr Address to check - * @return True if we should accept a world update from this address - */ - bool shouldAcceptWorldUpdateFrom(const Address &addr) const; - - /** - * @param ztaddr ZeroTier address - * @return Peer role for this device - */ - ZT_PeerRole role(const Address &ztaddr) const; - - /** - * Check for prohibited endpoints - * - * Right now this returns true if the designated ZT address is a root and if - * the IP (IP only, not port) does not equal any of the IPs defined in the - * current World. This is an extra little security feature in case root keys - * get appropriated or something. - * - * Otherwise it returns false. - * - * @param ztaddr ZeroTier address - * @param ipaddr IP address - * @return True if this ZT/IP pair should not be allowed to be used - */ - bool isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const; - - /** - * Gets upstreams to contact and their stable endpoints (if known) - * - * @param eps Hash table to fill with addresses and their stable endpoints - */ - inline void getUpstreamsToContact(Hashtable< Address,std::vector > &eps) const - { - Mutex::Lock _l(_upstreams_m); - for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { - if (i->identity != RR->identity) { - std::vector &ips = eps[i->identity.address()]; - for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { - if (std::find(ips.begin(),ips.end(),*j) == ips.end()) - ips.push_back(*j); - } - } - } - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { - if (i->identity != RR->identity) { - std::vector &ips = eps[i->identity.address()]; - for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { - if (std::find(ips.begin(),ips.end(),*j) == ips.end()) - ips.push_back(*j); - } - } - } - } - for(std::vector< std::pair >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) - eps[m->second]; - } - - /** - * @return Vector of active upstream addresses (including roots) - */ - inline std::vector
upstreamAddresses() const - { - Mutex::Lock _l(_upstreams_m); - return _upstreamAddresses; - } - - /** - * @return Current moons - */ - inline std::vector moons() const - { - Mutex::Lock _l(_upstreams_m); - return _moons; - } - - /** - * @return Moon IDs we are waiting for from seeds - */ - inline std::vector moonsWanted() const - { - Mutex::Lock _l(_upstreams_m); - std::vector mw; - for(std::vector< std::pair >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) { - if (std::find(mw.begin(),mw.end(),s->first) == mw.end()) - mw.push_back(s->first); - } - return mw; - } - - /** - * @return Current planet - */ - inline World planet() const - { - Mutex::Lock _l(_upstreams_m); - return _planet; - } - - /** - * @return Current planet's world ID - */ - inline uint64_t planetWorldId() const - { - return _planet.id(); // safe to read without lock, and used from within eachPeer() so don't lock - } - - /** - * @return Current planet's world timestamp - */ - inline uint64_t planetWorldTimestamp() const - { - return _planet.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock - } - - /** - * Validate new world and update if newer and signature is okay - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param newWorld A new or updated planet or moon to learn - * @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one - * @return True if it was valid and newer than current (or totally new for moons) - */ - bool addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew); - - /** - * Add a moon - * - * This loads it from moons.d if present, and if not adds it to - * a list of moons that we want to contact. - * - * @param id Moon ID - * @param seed If non-NULL, an address of any member of the moon to contact - */ - void addMoon(void *tPtr,const uint64_t id,const Address &seed); - - /** - * Remove a moon - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param id Moon's world ID - */ - void removeMoon(void *tPtr,const uint64_t id); - - /** - * Clean and flush database - */ - void clean(uint64_t now); - - /** - * @param now Current time - * @return Number of peers with active direct paths - */ - inline unsigned long countActive(uint64_t now) const - { - unsigned long cnt = 0; - Mutex::Lock _l(_peers_m); - Hashtable< Address,SharedPtr >::Iterator i(const_cast(this)->_peers); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - while (i.next(a,p)) { - cnt += (unsigned long)((*p)->hasActiveDirectPath(now)); - } - return cnt; - } - - /** - * Apply a function or function object to all peers - * - * @param f Function to apply - * @tparam F Function or function object type - */ - template - inline void eachPeer(F f) - { - Mutex::Lock _l(_peers_m); - Hashtable< Address,SharedPtr >::Iterator i(_peers); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - while (i.next(a,p)) { -#ifdef ZT_TRACE - if (!(*p)) { - fprintf(stderr,"FATAL BUG: eachPeer() caught NULL peer for %s -- peer pointers in Topology should NEVER be NULL" ZT_EOL_S,a->toString().c_str()); - abort(); - } -#endif - f(*this,*((const SharedPtr *)p)); - } - } - - /** - * @return All currently active peers by address (unsorted) - */ - inline std::vector< std::pair< Address,SharedPtr > > allPeers() const - { - Mutex::Lock _l(_peers_m); - return _peers.entries(); - } - - /** - * @return True if I am a root server in a planet or moon - */ - inline bool amRoot() const { return _amRoot; } - - /** - * Get the outbound trusted path ID for a physical address, or 0 if none - * - * @param physicalAddress Physical address to which we are sending the packet - * @return Trusted path ID or 0 if none (0 is not a valid trusted path ID) - */ - inline uint64_t getOutboundPathTrust(const InetAddress &physicalAddress) - { - for(unsigned int i=0;i<_trustedPathCount;++i) { - if (_trustedPathNetworks[i].containsAddress(physicalAddress)) - return _trustedPathIds[i]; - } - return 0; - } - - /** - * Check whether in incoming trusted path marked packet is valid - * - * @param physicalAddress Originating physical address - * @param trustedPathId Trusted path ID from packet (from MAC field) - */ - inline bool shouldInboundPathBeTrusted(const InetAddress &physicalAddress,const uint64_t trustedPathId) - { - for(unsigned int i=0;i<_trustedPathCount;++i) { - if ((_trustedPathIds[i] == trustedPathId)&&(_trustedPathNetworks[i].containsAddress(physicalAddress))) - return true; - } - return false; - } - - /** - * Set trusted paths in this topology - * - * @param networks Array of networks (prefix/netmask bits) - * @param ids Array of trusted path IDs - * @param count Number of trusted paths (if larger than ZT_MAX_TRUSTED_PATHS overflow is ignored) - */ - inline void setTrustedPaths(const InetAddress *networks,const uint64_t *ids,unsigned int count) - { - if (count > ZT_MAX_TRUSTED_PATHS) - count = ZT_MAX_TRUSTED_PATHS; - Mutex::Lock _l(_trustedPaths_m); - for(unsigned int i=0;i - void appendCertificateOfRepresentation(Buffer &buf) - { - Mutex::Lock _l(_upstreams_m); - _cor.serialize(buf); - } - -private: - Identity _getIdentity(void *tPtr,const Address &zta); - void _memoizeUpstreams(void *tPtr); - - const RuntimeEnvironment *const RR; - - uint64_t _trustedPathIds[ZT_MAX_TRUSTED_PATHS]; - InetAddress _trustedPathNetworks[ZT_MAX_TRUSTED_PATHS]; - unsigned int _trustedPathCount; - Mutex _trustedPaths_m; - - Hashtable< Address,SharedPtr > _peers; - Mutex _peers_m; - - Hashtable< Path::HashKey,SharedPtr > _paths; - Mutex _paths_m; - - World _planet; - std::vector _moons; - std::vector< std::pair > _moonSeeds; - std::vector
_upstreamAddresses; - CertificateOfRepresentation _cor; - bool _amRoot; - Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc. -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/Utils.cpp b/zto/node/Utils.cpp deleted file mode 100644 index fb448dd..0000000 --- a/zto/node/Utils.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "Constants.hpp" - -#ifdef __UNIX_LIKE__ -#include -#include -#include -#include -#include -#include -#include -#endif - -#ifdef __WINDOWS__ -#include -#endif - -#include "Utils.hpp" -#include "Mutex.hpp" -#include "Salsa20.hpp" - -namespace ZeroTier { - -const char Utils::HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; - -// Crazy hack to force memory to be securely zeroed in spite of the best efforts of optimizing compilers. -static void _Utils_doBurn(volatile uint8_t *ptr,unsigned int len) -{ - volatile uint8_t *const end = ptr + len; - while (ptr != end) *(ptr++) = (uint8_t)0; -} -static void (*volatile _Utils_doBurn_ptr)(volatile uint8_t *,unsigned int) = _Utils_doBurn; -void Utils::burn(void *ptr,unsigned int len) { (_Utils_doBurn_ptr)((volatile uint8_t *)ptr,len); } - -std::string Utils::hex(const void *data,unsigned int len) -{ - std::string r; - r.reserve(len * 2); - for(unsigned int i=0;i> 4]); - r.push_back(HEXCHARS[((const unsigned char *)data)[i] & 0x0f]); - } - return r; -} - -std::string Utils::unhex(const char *hex,unsigned int maxlen) -{ - int n = 1; - unsigned char c,b = 0; - const char *eof = hex + maxlen; - std::string r; - - if (!maxlen) - return r; - - while ((c = (unsigned char)*(hex++))) { - if ((c >= 48)&&(c <= 57)) { // 0..9 - if ((n ^= 1)) - r.push_back((char)(b | (c - 48))); - else b = (c - 48) << 4; - } else if ((c >= 65)&&(c <= 70)) { // A..F - if ((n ^= 1)) - r.push_back((char)(b | (c - (65 - 10)))); - else b = (c - (65 - 10)) << 4; - } else if ((c >= 97)&&(c <= 102)) { // a..f - if ((n ^= 1)) - r.push_back((char)(b | (c - (97 - 10)))); - else b = (c - (97 - 10)) << 4; - } - if (hex == eof) - break; - } - - return r; -} - -unsigned int Utils::unhex(const char *hex,unsigned int maxlen,void *buf,unsigned int len) -{ - int n = 1; - unsigned char c,b = 0; - unsigned int l = 0; - const char *eof = hex + maxlen; - - if (!maxlen) - return 0; - - while ((c = (unsigned char)*(hex++))) { - if ((c >= 48)&&(c <= 57)) { // 0..9 - if ((n ^= 1)) { - if (l >= len) break; - ((unsigned char *)buf)[l++] = (b | (c - 48)); - } else b = (c - 48) << 4; - } else if ((c >= 65)&&(c <= 70)) { // A..F - if ((n ^= 1)) { - if (l >= len) break; - ((unsigned char *)buf)[l++] = (b | (c - (65 - 10))); - } else b = (c - (65 - 10)) << 4; - } else if ((c >= 97)&&(c <= 102)) { // a..f - if ((n ^= 1)) { - if (l >= len) break; - ((unsigned char *)buf)[l++] = (b | (c - (97 - 10))); - } else b = (c - (97 - 10)) << 4; - } - if (hex == eof) - break; - } - - return l; -} - -void Utils::getSecureRandom(void *buf,unsigned int bytes) -{ - static Mutex globalLock; - static Salsa20 s20; - static bool s20Initialized = false; - static uint8_t randomBuf[65536]; - static unsigned int randomPtr = sizeof(randomBuf); - - Mutex::Lock _l(globalLock); - - /* Just for posterity we Salsa20 encrypt the result of whatever system - * CSPRNG we use. There have been several bugs at the OS or OS distribution - * level in the past that resulted in systematically weak or predictable - * keys due to random seeding problems. This mitigates that by grabbing - * a bit of extra entropy and further randomizing the result, and comes - * at almost no cost and with no real downside if the random source is - * good. */ - if (!s20Initialized) { - s20Initialized = true; - uint64_t s20Key[4]; - s20Key[0] = (uint64_t)time(0); // system clock - s20Key[1] = (uint64_t)buf; // address of buf - s20Key[2] = (uint64_t)s20Key; // address of s20Key[] - s20Key[3] = (uint64_t)&s20; // address of s20 - s20.init(s20Key,256,s20Key); - } - -#ifdef __WINDOWS__ - - static HCRYPTPROV cryptProvider = NULL; - - for(unsigned int i=0;i= sizeof(randomBuf)) { - if (cryptProvider == NULL) { - if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { - fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n"); - exit(1); - } - } - if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomBuf),(BYTE *)randomBuf)) { - fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n"); - exit(1); - } - randomPtr = 0; - s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf)); - } - ((uint8_t *)buf)[i] = randomBuf[randomPtr++]; - } - -#else // not __WINDOWS__ - - static int devURandomFd = -1; - - if (devURandomFd < 0) { - devURandomFd = ::open("/dev/urandom",O_RDONLY); - if (devURandomFd < 0) { - fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n"); - exit(1); - return; - } - } - - for(unsigned int i=0;i= sizeof(randomBuf)) { - for(;;) { - if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) { - ::close(devURandomFd); - devURandomFd = ::open("/dev/urandom",O_RDONLY); - if (devURandomFd < 0) { - fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n"); - exit(1); - return; - } - } else break; - } - randomPtr = 0; - s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf)); - } - ((uint8_t *)buf)[i] = randomBuf[randomPtr++]; - } - -#endif // __WINDOWS__ or not -} - -bool Utils::scopy(char *dest,unsigned int len,const char *src) -{ - if (!len) - return false; // sanity check - if (!src) { - *dest = (char)0; - return true; - } - char *end = dest + len; - while ((*dest++ = *src++)) { - if (dest == end) { - *(--dest) = (char)0; - return false; - } - } - return true; -} - -unsigned int Utils::snprintf(char *buf,unsigned int len,const char *fmt,...) - throw(std::length_error) -{ - va_list ap; - - va_start(ap,fmt); - int n = (int)vsnprintf(buf,len,fmt,ap); - va_end(ap); - - if ((n >= (int)len)||(n < 0)) { - if (len) - buf[len - 1] = (char)0; - throw std::length_error("buf[] overflow in Utils::snprintf"); - } - - return (unsigned int)n; -} - -} // namespace ZeroTier diff --git a/zto/node/Utils.hpp b/zto/node/Utils.hpp deleted file mode 100644 index ceb29d7..0000000 --- a/zto/node/Utils.hpp +++ /dev/null @@ -1,386 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_UTILS_HPP -#define ZT_UTILS_HPP - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "Constants.hpp" - -namespace ZeroTier { - -/** - * Miscellaneous utility functions and global constants - */ -class Utils -{ -public: - /** - * Perform a time-invariant binary comparison - * - * @param a First binary string - * @param b Second binary string - * @param len Length of strings - * @return True if strings are equal - */ - static inline bool secureEq(const void *a,const void *b,unsigned int len) - { - uint8_t diff = 0; - for(unsigned int i=0;i(a))[i] ^ (reinterpret_cast(b))[i] ); - return (diff == 0); - } - - /** - * Securely zero memory, avoiding compiler optimizations and such - */ - static void burn(void *ptr,unsigned int len); - - /** - * Convert binary data to hexadecimal - * - * @param data Data to convert to hex - * @param len Length of data - * @return Hexadecimal string - */ - static std::string hex(const void *data,unsigned int len); - static inline std::string hex(const std::string &data) { return hex(data.data(),(unsigned int)data.length()); } - - /** - * Convert hexadecimal to binary data - * - * This ignores all non-hex characters, just stepping over them and - * continuing. Upper and lower case are supported for letters a-f. - * - * @param hex Hexadecimal ASCII code (non-hex chars are ignored, stops at zero or maxlen) - * @param maxlen Maximum length of hex string buffer - * @return Binary data - */ - static std::string unhex(const char *hex,unsigned int maxlen); - static inline std::string unhex(const std::string &hex) { return unhex(hex.c_str(),(unsigned int)hex.length()); } - - /** - * Convert hexadecimal to binary data - * - * This ignores all non-hex characters, just stepping over them and - * continuing. Upper and lower case are supported for letters a-f. - * - * @param hex Hexadecimal ASCII - * @param maxlen Maximum length of hex string buffer - * @param buf Buffer to fill - * @param len Length of buffer - * @return Number of characters actually written - */ - static unsigned int unhex(const char *hex,unsigned int maxlen,void *buf,unsigned int len); - static inline unsigned int unhex(const std::string &hex,void *buf,unsigned int len) { return unhex(hex.c_str(),(unsigned int)hex.length(),buf,len); } - - /** - * Generate secure random bytes - * - * This will try to use whatever OS sources of entropy are available. It's - * guarded by an internal mutex so it's thread-safe. - * - * @param buf Buffer to fill - * @param bytes Number of random bytes to generate - */ - static void getSecureRandom(void *buf,unsigned int bytes); - - /** - * Tokenize a string (alias for strtok_r or strtok_s depending on platform) - * - * @param str String to split - * @param delim Delimiters - * @param saveptr Pointer to a char * for temporary reentrant storage - */ - static inline char *stok(char *str,const char *delim,char **saveptr) - throw() - { -#ifdef __WINDOWS__ - return strtok_s(str,delim,saveptr); -#else - return strtok_r(str,delim,saveptr); -#endif - } - - // String to number converters -- defined here to permit portability - // ifdefs for platforms that lack some of the strtoXX functions. - static inline unsigned int strToUInt(const char *s) - throw() - { - return (unsigned int)strtoul(s,(char **)0,10); - } - static inline int strToInt(const char *s) - throw() - { - return (int)strtol(s,(char **)0,10); - } - static inline unsigned long strToULong(const char *s) - throw() - { - return strtoul(s,(char **)0,10); - } - static inline long strToLong(const char *s) - throw() - { - return strtol(s,(char **)0,10); - } - static inline unsigned long long strToU64(const char *s) - throw() - { -#ifdef __WINDOWS__ - return (unsigned long long)_strtoui64(s,(char **)0,10); -#else - return strtoull(s,(char **)0,10); -#endif - } - static inline long long strTo64(const char *s) - throw() - { -#ifdef __WINDOWS__ - return (long long)_strtoi64(s,(char **)0,10); -#else - return strtoll(s,(char **)0,10); -#endif - } - static inline unsigned int hexStrToUInt(const char *s) - throw() - { - return (unsigned int)strtoul(s,(char **)0,16); - } - static inline int hexStrToInt(const char *s) - throw() - { - return (int)strtol(s,(char **)0,16); - } - static inline unsigned long hexStrToULong(const char *s) - throw() - { - return strtoul(s,(char **)0,16); - } - static inline long hexStrToLong(const char *s) - throw() - { - return strtol(s,(char **)0,16); - } - static inline unsigned long long hexStrToU64(const char *s) - throw() - { -#ifdef __WINDOWS__ - return (unsigned long long)_strtoui64(s,(char **)0,16); -#else - return strtoull(s,(char **)0,16); -#endif - } - static inline long long hexStrTo64(const char *s) - throw() - { -#ifdef __WINDOWS__ - return (long long)_strtoi64(s,(char **)0,16); -#else - return strtoll(s,(char **)0,16); -#endif - } - static inline double strToDouble(const char *s) - throw() - { - return strtod(s,(char **)0); - } - - /** - * Perform a safe C string copy, ALWAYS null-terminating the result - * - * This will never ever EVER result in dest[] not being null-terminated - * regardless of any input parameter (other than len==0 which is invalid). - * - * @param dest Destination buffer (must not be NULL) - * @param len Length of dest[] (if zero, false is returned and nothing happens) - * @param src Source string (if NULL, dest will receive a zero-length string and true is returned) - * @return True on success, false on overflow (buffer will still be 0-terminated) - */ - static bool scopy(char *dest,unsigned int len,const char *src); - - /** - * Variant of snprintf that is portable and throws an exception - * - * This just wraps the local implementation whatever it's called, while - * performing a few other checks and adding exceptions for overflow. - * - * @param buf Buffer to write to - * @param len Length of buffer in bytes - * @param fmt Format string - * @param ... Format arguments - * @throws std::length_error buf[] too short (buf[] will still be left null-terminated) - */ - static unsigned int snprintf(char *buf,unsigned int len,const char *fmt,...) - throw(std::length_error); - - /** - * Count the number of bits set in an integer - * - * @param v 32-bit integer - * @return Number of bits set in this integer (0-32) - */ - static inline uint32_t countBits(uint32_t v) - { - v = v - ((v >> 1) & (uint32_t)0x55555555); - v = (v & (uint32_t)0x33333333) + ((v >> 2) & (uint32_t)0x33333333); - return ((((v + (v >> 4)) & (uint32_t)0xF0F0F0F) * (uint32_t)0x1010101) >> 24); - } - - /** - * Count the number of bits set in an integer - * - * @param v 64-bit integer - * @return Number of bits set in this integer (0-64) - */ - static inline uint64_t countBits(uint64_t v) - { - v = v - ((v >> 1) & (uint64_t)~(uint64_t)0/3); - v = (v & (uint64_t)~(uint64_t)0/15*3) + ((v >> 2) & (uint64_t)~(uint64_t)0/15*3); - v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0/255*15; - return (uint64_t)(v * ((uint64_t)~(uint64_t)0/255)) >> 56; - } - - /** - * Check if a memory buffer is all-zero - * - * @param p Memory to scan - * @param len Length of memory - * @return True if memory is all zero - */ - static inline bool isZero(const void *p,unsigned int len) - { - for(unsigned int i=0;i> 8) | - ((n & 0x0000FF0000000000ULL) >> 24) | - ((n & 0x00FF000000000000ULL) >> 40) | - ((n & 0xFF00000000000000ULL) >> 56) - ); -#endif -#else - return n; -#endif - } - static inline int64_t hton(int64_t n) throw() { return (int64_t)hton((uint64_t)n); } - - static inline uint8_t ntoh(uint8_t n) throw() { return n; } - static inline int8_t ntoh(int8_t n) throw() { return n; } - static inline uint16_t ntoh(uint16_t n) throw() { return ntohs(n); } - static inline int16_t ntoh(int16_t n) throw() { return (int16_t)ntohs((uint16_t)n); } - static inline uint32_t ntoh(uint32_t n) throw() { return ntohl(n); } - static inline int32_t ntoh(int32_t n) throw() { return (int32_t)ntohl((uint32_t)n); } - static inline uint64_t ntoh(uint64_t n) - throw() - { -#if __BYTE_ORDER == __LITTLE_ENDIAN -#if defined(__GNUC__) && !defined(__OpenBSD__) - return __builtin_bswap64(n); -#else - return ( - ((n & 0x00000000000000FFULL) << 56) | - ((n & 0x000000000000FF00ULL) << 40) | - ((n & 0x0000000000FF0000ULL) << 24) | - ((n & 0x00000000FF000000ULL) << 8) | - ((n & 0x000000FF00000000ULL) >> 8) | - ((n & 0x0000FF0000000000ULL) >> 24) | - ((n & 0x00FF000000000000ULL) >> 40) | - ((n & 0xFF00000000000000ULL) >> 56) - ); -#endif -#else - return n; -#endif - } - static inline int64_t ntoh(int64_t n) throw() { return (int64_t)ntoh((uint64_t)n); } - - /** - * Compare Peer version tuples - * - * @return -1, 0, or 1 based on whether first tuple is less than, equal to, or greater than second - */ - static inline int compareVersion(unsigned int maj1,unsigned int min1,unsigned int rev1,unsigned int b1,unsigned int maj2,unsigned int min2,unsigned int rev2,unsigned int b2) - { - if (maj1 > maj2) - return 1; - else if (maj1 < maj2) - return -1; - else { - if (min1 > min2) - return 1; - else if (min1 < min2) - return -1; - else { - if (rev1 > rev2) - return 1; - else if (rev1 < rev2) - return -1; - else { - if (b1 > b2) - return 1; - else if (b1 < b2) - return -1; - else return 0; - } - } - } - } - - /** - * Hexadecimal characters 0-f - */ - static const char HEXCHARS[16]; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/node/World.hpp b/zto/node/World.hpp deleted file mode 100644 index 6e835be..0000000 --- a/zto/node/World.hpp +++ /dev/null @@ -1,278 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_WORLD_HPP -#define ZT_WORLD_HPP - -#include -#include - -#include "Constants.hpp" -#include "InetAddress.hpp" -#include "Identity.hpp" -#include "Buffer.hpp" -#include "C25519.hpp" - -/** - * Maximum number of roots (sanity limit, okay to increase) - * - * A given root can (through multi-homing) be distributed across any number of - * physical endpoints, but having more than one is good to permit total failure - * of one root or its withdrawal due to compromise without taking the whole net - * down. - */ -#define ZT_WORLD_MAX_ROOTS 4 - -/** - * Maximum number of stable endpoints per root (sanity limit, okay to increase) - */ -#define ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT 32 - -/** - * The (more than) maximum length of a serialized World - */ -#define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 128) - -/** - * World ID for Earth - * - * This is the ID for the ZeroTier World used on planet Earth. It is unrelated - * to the public network 8056c2e21c000001 of the same name. It was chosen - * from Earth's approximate distance from the sun in kilometers. - */ -#define ZT_WORLD_ID_EARTH 149604618 - -/** - * World ID for Mars -- for future use by SpaceX or others - */ -#define ZT_WORLD_ID_MARS 227883110 - -namespace ZeroTier { - -/** - * A world definition (formerly known as a root topology) - * - * Think of a World as a single data center. Within this data center a set - * of distributed fault tolerant root servers provide stable anchor points - * for a peer to peer network that provides VLAN service. Updates to a world - * definition can be published by signing them with the previous revision's - * signing key, and should be very infrequent. - * - * The maximum data center size is approximately 2.5 cubic light seconds, - * since many protocols have issues with >5s RTT latencies. - * - * ZeroTier operates a World for Earth capable of encompassing the planet, its - * orbits, the Moon (about 1.3 light seconds), and nearby Lagrange points. A - * world ID for Mars and nearby space is defined but not yet used, and a test - * world ID is provided for testing purposes. - */ -class World -{ -public: - /** - * World type -- do not change IDs - */ - enum Type - { - TYPE_NULL = 0, - TYPE_PLANET = 1, // Planets, of which there is currently one (Earth) - TYPE_MOON = 127 // Moons, which are user-created and many - }; - - /** - * Upstream server definition in world/moon - */ - struct Root - { - Identity identity; - std::vector stableEndpoints; - - inline bool operator==(const Root &r) const throw() { return ((identity == r.identity)&&(stableEndpoints == r.stableEndpoints)); } - inline bool operator!=(const Root &r) const throw() { return (!(*this == r)); } - inline bool operator<(const Root &r) const throw() { return (identity < r.identity); } // for sorting - }; - - /** - * Construct an empty / null World - */ - World() : - _id(0), - _ts(0), - _type(TYPE_NULL) {} - - /** - * @return Root servers for this world and their stable endpoints - */ - inline const std::vector &roots() const { return _roots; } - - /** - * @return World type: planet or moon - */ - inline Type type() const { return _type; } - - /** - * @return World unique identifier - */ - inline uint64_t id() const { return _id; } - - /** - * @return World definition timestamp - */ - inline uint64_t timestamp() const { return _ts; } - - /** - * @return C25519 signature - */ - inline const C25519::Signature &signature() const { return _signature; } - - /** - * @return Public key that must sign next update - */ - inline const C25519::Public &updatesMustBeSignedBy() const { return _updatesMustBeSignedBy; } - - /** - * Check whether a world update should replace this one - * - * @param update Candidate update - * @return True if update is newer than current, matches its ID and type, and is properly signed (or if current is NULL) - */ - inline bool shouldBeReplacedBy(const World &update) - { - if ((_id == 0)||(_type == TYPE_NULL)) - return true; - if ((_id == update._id)&&(_ts < update._ts)&&(_type == update._type)) { - Buffer tmp; - update.serialize(tmp,true); - return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature); - } - return false; - } - - /** - * @return True if this World is non-empty - */ - inline operator bool() const { return (_type != TYPE_NULL); } - - template - inline void serialize(Buffer &b,bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - b.append((uint8_t)_type); - b.append((uint64_t)_id); - b.append((uint64_t)_ts); - b.append(_updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN); - if (!forSign) - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); - b.append((uint8_t)_roots.size()); - for(std::vector::const_iterator r(_roots.begin());r!=_roots.end();++r) { - r->identity.serialize(b); - b.append((uint8_t)r->stableEndpoints.size()); - for(std::vector::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep) - ep->serialize(b); - } - if (_type == TYPE_MOON) - b.append((uint16_t)0); // no attached dictionary (for future use) - - if (forSign) b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; - - _roots.clear(); - - switch((Type)b[p++]) { - case TYPE_NULL: _type = TYPE_NULL; break; // shouldn't ever really happen in serialized data but it's not invalid - case TYPE_PLANET: _type = TYPE_PLANET; break; - case TYPE_MOON: _type = TYPE_MOON; break; - default: - throw std::invalid_argument("invalid world type"); - } - - _id = b.template at(p); p += 8; - _ts = b.template at(p); p += 8; - memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); p += ZT_C25519_PUBLIC_KEY_LEN; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; - const unsigned int numRoots = (unsigned int)b[p++]; - if (numRoots > ZT_WORLD_MAX_ROOTS) - throw std::invalid_argument("too many roots in World"); - for(unsigned int k=0;k ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) - throw std::invalid_argument("too many stable endpoints in World/Root"); - for(unsigned int kk=0;kk(p) + 2; - - return (p - startAt); - } - - inline bool operator==(const World &w) const { return ((_id == w._id)&&(_ts == w._ts)&&(_updatesMustBeSignedBy == w._updatesMustBeSignedBy)&&(_signature == w._signature)&&(_roots == w._roots)&&(_type == w._type)); } - inline bool operator!=(const World &w) const { return (!(*this == w)); } - - inline bool operator<(const World &w) const { return (((int)_type < (int)w._type) ? true : ((_type == w._type) ? (_id < w._id) : false)); } - - /** - * Create a World object signed with a key pair - * - * @param t World type - * @param id World ID - * @param ts World timestamp / revision - * @param sk Key that must be used to sign the next future update to this world - * @param roots Roots and their stable endpoints - * @param signWith Key to sign this World with (can have the same public as the next-update signing key, but doesn't have to) - * @return Signed World object - */ - static inline World make(World::Type t,uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector &roots,const C25519::Pair &signWith) - { - World w; - w._id = id; - w._ts = ts; - w._type = t; - w._updatesMustBeSignedBy = sk; - w._roots = roots; - - Buffer tmp; - w.serialize(tmp,true); - w._signature = C25519::sign(signWith,tmp.data(),tmp.size()); - - return w; - } - -protected: - uint64_t _id; - uint64_t _ts; - Type _type; - C25519::Public _updatesMustBeSignedBy; - C25519::Signature _signature; - std::vector _roots; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/objects.mk b/zto/objects.mk deleted file mode 100644 index 74efc33..0000000 --- a/zto/objects.mk +++ /dev/null @@ -1,34 +0,0 @@ -OBJS=\ - controller/EmbeddedNetworkController.o \ - controller/JSONDB.o \ - node/C25519.o \ - node/Capability.o \ - node/CertificateOfMembership.o \ - node/CertificateOfOwnership.o \ - node/Cluster.o \ - node/Identity.o \ - node/IncomingPacket.o \ - node/InetAddress.o \ - node/Membership.o \ - node/Multicaster.o \ - node/Network.o \ - node/NetworkConfig.o \ - node/Node.o \ - node/OutboundMulticast.o \ - node/Packet.o \ - node/Path.o \ - node/Peer.o \ - node/Poly1305.o \ - node/Revocation.o \ - node/Salsa20.o \ - node/SelfAwareness.o \ - node/SHA512.o \ - node/Switch.o \ - node/Tag.o \ - node/Topology.o \ - node/Utils.o \ - osdep/ManagedRoute.o \ - osdep/Http.o \ - osdep/OSUtils.o \ - service/ClusterGeoIpService.o \ - service/SoftwareUpdater.o diff --git a/zto/one.cpp b/zto/one.cpp deleted file mode 100644 index edefe82..0000000 --- a/zto/one.cpp +++ /dev/null @@ -1,1506 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "node/Constants.hpp" - -#ifdef __WINDOWS__ -#include -#include -#include -#include -#include -#include -#include -#include "osdep/WindowsEthernetTap.hpp" -#include "windows/ZeroTierOne/ServiceInstaller.h" -#include "windows/ZeroTierOne/ServiceBase.h" -#include "windows/ZeroTierOne/ZeroTierOneService.h" -#else -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __LINUX__ -#include -#include -#include -#include -#include -#endif -#endif - -#include -#include -#include -#include - -#include "version.h" -#include "include/ZeroTierOne.h" - -#include "node/Identity.hpp" -#include "node/CertificateOfMembership.hpp" -#include "node/Utils.hpp" -#include "node/NetworkController.hpp" -#include "node/Buffer.hpp" -#include "node/World.hpp" - -#include "osdep/OSUtils.hpp" -#include "osdep/Http.hpp" -#include "osdep/Thread.hpp" - -#include "service/OneService.hpp" - -#include "ext/json/json.hpp" - -#define ZT_PID_PATH "zerotier-one.pid" - -using namespace ZeroTier; - -static OneService *volatile zt1Service = (OneService *)0; - -#define PROGRAM_NAME "ZeroTier One" -#define COPYRIGHT_NOTICE "Copyright (c) 2011-2017 ZeroTier, Inc." -#define LICENSE_GRANT \ - "This is free software: you may copy, modify, and/or distribute this" ZT_EOL_S \ - "work under the terms of the GNU General Public License, version 3 or" ZT_EOL_S \ - "later as published by the Free Software Foundation." ZT_EOL_S \ - "No warranty expressed or implied." ZT_EOL_S - -/****************************************************************************/ -/* zerotier-cli personality */ -/****************************************************************************/ - -// This is getting deprecated soon in favor of the stuff in cli/ - -static void cliPrintHelp(const char *pn,FILE *out) -{ - fprintf(out, - "%s version %d.%d.%d build %d (platform %d arch %d)" ZT_EOL_S, - PROGRAM_NAME, - ZEROTIER_ONE_VERSION_MAJOR, ZEROTIER_ONE_VERSION_MINOR, ZEROTIER_ONE_VERSION_REVISION, ZEROTIER_ONE_VERSION_BUILD, - ZT_BUILD_PLATFORM, ZT_BUILD_ARCHITECTURE); - fprintf(out, - COPYRIGHT_NOTICE ZT_EOL_S - LICENSE_GRANT ZT_EOL_S); - fprintf(out,"Usage: %s [-switches] []" ZT_EOL_S"" ZT_EOL_S,pn); - fprintf(out,"Available switches:" ZT_EOL_S); - fprintf(out," -h - Display this help" ZT_EOL_S); - fprintf(out," -v - Show version" ZT_EOL_S); - fprintf(out," -j - Display full raw JSON output" ZT_EOL_S); - fprintf(out," -D - ZeroTier home path for parameter auto-detect" ZT_EOL_S); - fprintf(out," -p - HTTP port (default: auto)" ZT_EOL_S); - fprintf(out," -T - Authentication token (default: auto)" ZT_EOL_S); - fprintf(out,ZT_EOL_S"Available commands:" ZT_EOL_S); - fprintf(out," info - Display status info" ZT_EOL_S); - fprintf(out," listpeers - List all peers" ZT_EOL_S); - fprintf(out," listnetworks - List all networks" ZT_EOL_S); - fprintf(out," join - Join a network" ZT_EOL_S); - fprintf(out," leave - Leave a network" ZT_EOL_S); - fprintf(out," set - Set a network setting" ZT_EOL_S); - fprintf(out," listmoons - List moons (federated root sets)" ZT_EOL_S); - fprintf(out," orbit - Join a moon via any member root" ZT_EOL_S); - fprintf(out," deorbit - Leave a moon" ZT_EOL_S); -} - -static std::string cliFixJsonCRs(const std::string &s) -{ - std::string r; - for(std::string::const_iterator c(s.begin());c!=s.end();++c) { - if (*c == '\n') - r.append(ZT_EOL_S); - else r.push_back(*c); - } - return r; -} - -#ifdef __WINDOWS__ -static int cli(int argc, _TCHAR* argv[]) -#else -static int cli(int argc,char **argv) -#endif -{ - unsigned int port = 0; - std::string homeDir,command,arg1,arg2,authToken; - std::string ip("127.0.0.1"); - bool json = false; - for(int i=1;i 0xffff)||(port == 0)) { - cliPrintHelp(argv[0],stdout); - return 1; - } - break; - - case 'D': - if (argv[i][2]) { - homeDir = argv[i] + 2; - } else { - cliPrintHelp(argv[0],stdout); - return 1; - } - break; - - case 'H': - if (argv[i][2]) { - ip = argv[i] + 2; - } else { - cliPrintHelp(argv[0],stdout); - return 1; - } - break; - - case 'T': - if (argv[i][2]) { - authToken = argv[i] + 2; - } else { - cliPrintHelp(argv[0],stdout); - return 1; - } - break; - - case 'v': - if (argv[i][2]) { - cliPrintHelp(argv[0],stdout); - return 1; - } - printf("%d.%d.%d" ZT_EOL_S,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION); - return 0; - - case 'h': - case '?': - default: - cliPrintHelp(argv[0],stdout); - return 0; - } - } else { - if (arg1.length()) - arg2 = argv[i]; - else if (command.length()) - arg1 = argv[i]; - else command = argv[i]; - } - } - if (!homeDir.length()) - homeDir = OneService::platformDefaultHomePath(); - - if ((!port)||(!authToken.length())) { - if (!homeDir.length()) { - fprintf(stderr,"%s: missing port or authentication token and no home directory specified to auto-detect" ZT_EOL_S,argv[0]); - return 2; - } - - if (!port) { - std::string portStr; - OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),portStr); - port = Utils::strToUInt(portStr.c_str()); - if ((port == 0)||(port > 0xffff)) { - fprintf(stderr,"%s: missing port and zerotier-one.port not found in %s" ZT_EOL_S,argv[0],homeDir.c_str()); - return 2; - } - } - - if (!authToken.length()) { - OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),authToken); -#ifdef __UNIX_LIKE__ - if (!authToken.length()) { - const char *hd = getenv("HOME"); - if (hd) { - char p[4096]; -#ifdef __APPLE__ - Utils::snprintf(p,sizeof(p),"%s/Library/Application Support/ZeroTier/One/authtoken.secret",hd); -#else - Utils::snprintf(p,sizeof(p),"%s/.zeroTierOneAuthToken",hd); -#endif - OSUtils::readFile(p,authToken); - } - } -#endif - if (!authToken.length()) { - fprintf(stderr,"%s: missing authentication token and authtoken.secret not found (or readable) in %s" ZT_EOL_S,argv[0],homeDir.c_str()); - return 2; - } - } - } - - InetAddress addr; - { - char addrtmp[256]; - Utils::snprintf(addrtmp,sizeof(addrtmp),"%s/%u",ip.c_str(),port); - addr = InetAddress(addrtmp); - } - - std::map requestHeaders; - std::map responseHeaders; - std::string responseBody; - - requestHeaders["X-ZT1-Auth"] = authToken; - - if ((command.length() > 0)&&(command[0] == '/')) { - unsigned int scode = Http::GET( - 1024 * 1024 * 16, - 60000, - (const struct sockaddr *)&addr, - command.c_str(), - requestHeaders, - responseHeaders, - responseBody); - if (scode == 200) { - printf("%s",cliFixJsonCRs(responseBody).c_str()); - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } else if ((command == "info")||(command == "status")) { - const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/status",requestHeaders,responseHeaders,responseBody); - - nlohmann::json j; - try { - j = OSUtils::jsonParse(responseBody); - } catch (std::exception &exc) { - printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what()); - return 1; - } catch ( ... ) { - printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str()); - return 1; - } - - if (scode == 200) { - if (json) { - printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); - } else { - if (j.is_object()) { - printf("200 info %s %s %s" ZT_EOL_S, - OSUtils::jsonString(j["address"],"-").c_str(), - OSUtils::jsonString(j["version"],"-").c_str(), - ((j["tcpFallbackActive"]) ? "TUNNELED" : ((j["online"]) ? "ONLINE" : "OFFLINE"))); - } - } - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } else if (command == "listpeers") { - const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/peer",requestHeaders,responseHeaders,responseBody); - - nlohmann::json j; - try { - j = OSUtils::jsonParse(responseBody); - } catch (std::exception &exc) { - printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what()); - return 1; - } catch ( ... ) { - printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str()); - return 1; - } - - if (scode == 200) { - if (json) { - printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); - } else { - printf("200 listpeers " ZT_EOL_S); - if (j.is_array()) { - for(unsigned long k=0;k= 0) { - Utils::snprintf(ver,sizeof(ver),"%lld.%lld.%lld",vmaj,vmin,vrev); - } else { - ver[0] = '-'; - ver[1] = (char)0; - } - printf("200 listpeers %s %s %d %s %s" ZT_EOL_S, - OSUtils::jsonString(p["address"],"-").c_str(), - bestPath.c_str(), - (int)OSUtils::jsonInt(p["latency"],0), - ver, - OSUtils::jsonString(p["role"],"-").c_str()); - } - } - } - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } else if (command == "listnetworks") { - const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/network",requestHeaders,responseHeaders,responseBody); - - nlohmann::json j; - try { - j = OSUtils::jsonParse(responseBody); - } catch (std::exception &exc) { - printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what()); - return 1; - } catch ( ... ) { - printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str()); - return 1; - } - - if (scode == 200) { - if (json) { - printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); - } else { - printf("200 listnetworks " ZT_EOL_S); - if (j.is_array()) { - for(unsigned long i=0;i 0) aa.push_back(','); - aa.append(addr.get()); - } - } - } - if (aa.length() == 0) aa = "-"; - printf("200 listnetworks %s %s %s %s %s %s %s" ZT_EOL_S, - OSUtils::jsonString(n["nwid"],"-").c_str(), - OSUtils::jsonString(n["name"],"-").c_str(), - OSUtils::jsonString(n["mac"],"-").c_str(), - OSUtils::jsonString(n["status"],"-").c_str(), - OSUtils::jsonString(n["type"],"-").c_str(), - OSUtils::jsonString(n["portDeviceName"],"-").c_str(), - aa.c_str()); - } - } - } - } - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } else if (command == "join") { - if (arg1.length() != 16) { - cliPrintHelp(argv[0],stderr); - return 2; - } - requestHeaders["Content-Type"] = "application/json"; - requestHeaders["Content-Length"] = "2"; - unsigned int scode = Http::POST( - 1024 * 1024 * 16, - 60000, - (const struct sockaddr *)&addr, - (std::string("/network/") + arg1).c_str(), - requestHeaders, - "{}", - 2, - responseHeaders, - responseBody); - if (scode == 200) { - if (json) { - printf("%s",cliFixJsonCRs(responseBody).c_str()); - } else { - printf("200 join OK" ZT_EOL_S); - } - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } else if (command == "leave") { - if (arg1.length() != 16) { - cliPrintHelp(argv[0],stderr); - return 2; - } - unsigned int scode = Http::DEL( - 1024 * 1024 * 16, - 60000, - (const struct sockaddr *)&addr, - (std::string("/network/") + arg1).c_str(), - requestHeaders, - responseHeaders, - responseBody); - if (scode == 200) { - if (json) { - printf("%s",cliFixJsonCRs(responseBody).c_str()); - } else { - printf("200 leave OK" ZT_EOL_S); - } - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } else if (command == "listmoons") { - const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/moon",requestHeaders,responseHeaders,responseBody); - - nlohmann::json j; - try { - j = OSUtils::jsonParse(responseBody); - } catch (std::exception &exc) { - printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what()); - return 1; - } catch ( ... ) { - printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str()); - return 1; - } - - if (scode == 200) { - printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } else if (command == "orbit") { - const uint64_t worldId = Utils::hexStrToU64(arg1.c_str()); - const uint64_t seed = Utils::hexStrToU64(arg2.c_str()); - if ((worldId)&&(seed)) { - char jsons[1024]; - Utils::snprintf(jsons,sizeof(jsons),"{\"seed\":\"%s\"}",arg2.c_str()); - char cl[128]; - Utils::snprintf(cl,sizeof(cl),"%u",(unsigned int)strlen(jsons)); - requestHeaders["Content-Type"] = "application/json"; - requestHeaders["Content-Length"] = cl; - unsigned int scode = Http::POST( - 1024 * 1024 * 16, - 60000, - (const struct sockaddr *)&addr, - (std::string("/moon/") + arg1).c_str(), - requestHeaders, - jsons, - (unsigned long)strlen(jsons), - responseHeaders, - responseBody); - if (scode == 200) { - printf("200 orbit OK" ZT_EOL_S); - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } - } else if (command == "deorbit") { - unsigned int scode = Http::DEL( - 1024 * 1024 * 16, - 60000, - (const struct sockaddr *)&addr, - (std::string("/moon/") + arg1).c_str(), - requestHeaders, - responseHeaders, - responseBody); - if (scode == 200) { - if (json) { - printf("%s",cliFixJsonCRs(responseBody).c_str()); - } else { - printf("200 deorbit OK" ZT_EOL_S); - } - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } else if (command == "set") { - if (arg1.length() != 16) { - cliPrintHelp(argv[0],stderr); - return 2; - } - std::size_t eqidx = arg2.find('='); - if (eqidx != std::string::npos) { - if ((arg2.substr(0,eqidx) == "allowManaged")||(arg2.substr(0,eqidx) == "allowGlobal")||(arg2.substr(0,eqidx) == "allowDefault")) { - char jsons[1024]; - Utils::snprintf(jsons,sizeof(jsons),"{\"%s\":%s}", - arg2.substr(0,eqidx).c_str(), - (((arg2.substr(eqidx,2) == "=t")||(arg2.substr(eqidx,2) == "=1")) ? "true" : "false")); - char cl[128]; - Utils::snprintf(cl,sizeof(cl),"%u",(unsigned int)strlen(jsons)); - requestHeaders["Content-Type"] = "application/json"; - requestHeaders["Content-Length"] = cl; - unsigned int scode = Http::POST( - 1024 * 1024 * 16, - 60000, - (const struct sockaddr *)&addr, - (std::string("/network/") + arg1).c_str(), - requestHeaders, - jsons, - (unsigned long)strlen(jsons), - responseHeaders, - responseBody); - if (scode == 200) { - printf("%s",cliFixJsonCRs(responseBody).c_str()); - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } - } else { - cliPrintHelp(argv[0],stderr); - return 2; - } - } else { - cliPrintHelp(argv[0],stderr); - return 0; - } - - return 0; -} - -/****************************************************************************/ -/* zerotier-idtool personality */ -/****************************************************************************/ - -static void idtoolPrintHelp(FILE *out,const char *pn) -{ - fprintf(out, - "%s version %d.%d.%d" ZT_EOL_S, - PROGRAM_NAME, - ZEROTIER_ONE_VERSION_MAJOR, ZEROTIER_ONE_VERSION_MINOR, ZEROTIER_ONE_VERSION_REVISION); - fprintf(out, - COPYRIGHT_NOTICE ZT_EOL_S - LICENSE_GRANT ZT_EOL_S); - fprintf(out,"Usage: %s []" ZT_EOL_S"" ZT_EOL_S"Commands:" ZT_EOL_S,pn); - fprintf(out," generate [] [] []" ZT_EOL_S); - fprintf(out," validate " ZT_EOL_S); - fprintf(out," getpublic " ZT_EOL_S); - fprintf(out," sign " ZT_EOL_S); - fprintf(out," verify " ZT_EOL_S); - fprintf(out," initmoon " ZT_EOL_S); - fprintf(out," genmoon " ZT_EOL_S); -} - -static Identity getIdFromArg(char *arg) -{ - Identity id; - if ((strlen(arg) > 32)&&(arg[10] == ':')) { // identity is a literal on the command line - if (id.fromString(arg)) - return id; - } else { // identity is to be read from a file - std::string idser; - if (OSUtils::readFile(arg,idser)) { - if (id.fromString(idser)) - return id; - } - } - return Identity(); -} - -#ifdef __WINDOWS__ -static int idtool(int argc, _TCHAR* argv[]) -#else -static int idtool(int argc,char **argv) -#endif -{ - if (argc < 2) { - idtoolPrintHelp(stdout,argv[0]); - return 1; - } - - if (!strcmp(argv[1],"generate")) { - uint64_t vanity = 0; - int vanityBits = 0; - if (argc >= 5) { - vanity = Utils::hexStrToU64(argv[4]) & 0xffffffffffULL; - vanityBits = 4 * (int)strlen(argv[4]); - if (vanityBits > 40) - vanityBits = 40; - } - - Identity id; - for(;;) { - id.generate(); - if ((id.address().toInt() >> (40 - vanityBits)) == vanity) { - if (vanityBits > 0) { - fprintf(stderr,"vanity address: found %.10llx !\n",(unsigned long long)id.address().toInt()); - } - break; - } else { - fprintf(stderr,"vanity address: tried %.10llx looking for first %d bits of %.10llx\n",(unsigned long long)id.address().toInt(),vanityBits,(unsigned long long)(vanity << (40 - vanityBits))); - } - } - - std::string idser = id.toString(true); - if (argc >= 3) { - if (!OSUtils::writeFile(argv[2],idser)) { - fprintf(stderr,"Error writing to %s" ZT_EOL_S,argv[2]); - return 1; - } else printf("%s written" ZT_EOL_S,argv[2]); - if (argc >= 4) { - idser = id.toString(false); - if (!OSUtils::writeFile(argv[3],idser)) { - fprintf(stderr,"Error writing to %s" ZT_EOL_S,argv[3]); - return 1; - } else printf("%s written" ZT_EOL_S,argv[3]); - } - } else printf("%s",idser.c_str()); - } else if (!strcmp(argv[1],"validate")) { - if (argc < 3) { - idtoolPrintHelp(stdout,argv[0]); - return 1; - } - - Identity id = getIdFromArg(argv[2]); - if (!id) { - fprintf(stderr,"Identity argument invalid or file unreadable: %s" ZT_EOL_S,argv[2]); - return 1; - } - - if (!id.locallyValidate()) { - fprintf(stderr,"%s FAILED validation." ZT_EOL_S,argv[2]); - return 1; - } else printf("%s is a valid identity" ZT_EOL_S,argv[2]); - } else if (!strcmp(argv[1],"getpublic")) { - if (argc < 3) { - idtoolPrintHelp(stdout,argv[0]); - return 1; - } - - Identity id = getIdFromArg(argv[2]); - if (!id) { - fprintf(stderr,"Identity argument invalid or file unreadable: %s" ZT_EOL_S,argv[2]); - return 1; - } - - printf("%s",id.toString(false).c_str()); - } else if (!strcmp(argv[1],"sign")) { - if (argc < 4) { - idtoolPrintHelp(stdout,argv[0]); - return 1; - } - - Identity id = getIdFromArg(argv[2]); - if (!id) { - fprintf(stderr,"Identity argument invalid or file unreadable: %s" ZT_EOL_S,argv[2]); - return 1; - } - - if (!id.hasPrivate()) { - fprintf(stderr,"%s does not contain a private key (must use private to sign)" ZT_EOL_S,argv[2]); - return 1; - } - - std::string inf; - if (!OSUtils::readFile(argv[3],inf)) { - fprintf(stderr,"%s is not readable" ZT_EOL_S,argv[3]); - return 1; - } - C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length()); - printf("%s",Utils::hex(signature.data,(unsigned int)signature.size()).c_str()); - } else if (!strcmp(argv[1],"verify")) { - if (argc < 4) { - idtoolPrintHelp(stdout,argv[0]); - return 1; - } - - Identity id = getIdFromArg(argv[2]); - if (!id) { - fprintf(stderr,"Identity argument invalid or file unreadable: %s" ZT_EOL_S,argv[2]); - return 1; - } - - std::string inf; - if (!OSUtils::readFile(argv[3],inf)) { - fprintf(stderr,"%s is not readable" ZT_EOL_S,argv[3]); - return 1; - } - - std::string signature(Utils::unhex(argv[4])); - if ((signature.length() > ZT_ADDRESS_LENGTH)&&(id.verify(inf.data(),(unsigned int)inf.length(),signature.data(),(unsigned int)signature.length()))) { - printf("%s signature valid" ZT_EOL_S,argv[3]); - } else { - fprintf(stderr,"%s signature check FAILED" ZT_EOL_S,argv[3]); - return 1; - } - } else if (!strcmp(argv[1],"initmoon")) { - if (argc < 3) { - idtoolPrintHelp(stdout,argv[0]); - } else { - const Identity id = getIdFromArg(argv[2]); - if (!id) { - fprintf(stderr,"%s is not a valid identity" ZT_EOL_S,argv[2]); - return 1; - } - - C25519::Pair kp(C25519::generate()); - - nlohmann::json mj; - mj["objtype"] = "world"; - mj["worldType"] = "moon"; - mj["updatesMustBeSignedBy"] = mj["signingKey"] = Utils::hex(kp.pub.data,(unsigned int)kp.pub.size()); - mj["signingKey_SECRET"] = Utils::hex(kp.priv.data,(unsigned int)kp.priv.size()); - mj["id"] = id.address().toString(); - nlohmann::json seedj; - seedj["identity"] = id.toString(false); - seedj["stableEndpoints"] = nlohmann::json::array(); - (mj["roots"] = nlohmann::json::array()).push_back(seedj); - std::string mjd(OSUtils::jsonDump(mj)); - - printf("%s" ZT_EOL_S,mjd.c_str()); - } - } else if (!strcmp(argv[1],"genmoon")) { - if (argc < 3) { - idtoolPrintHelp(stdout,argv[0]); - } else { - std::string buf; - if (!OSUtils::readFile(argv[2],buf)) { - fprintf(stderr,"cannot read %s" ZT_EOL_S,argv[2]); - return 1; - } - nlohmann::json mj(OSUtils::jsonParse(buf)); - - const uint64_t id = Utils::hexStrToU64(OSUtils::jsonString(mj["id"],"0").c_str()); - if (!id) { - fprintf(stderr,"ID in %s is invalid" ZT_EOL_S,argv[2]); - return 1; - } - - World::Type t; - if (mj["worldType"] == "moon") { - t = World::TYPE_MOON; - } else if (mj["worldType"] == "planet") { - t = World::TYPE_PLANET; - } else { - fprintf(stderr,"invalid worldType" ZT_EOL_S); - return 1; - } - - C25519::Pair signingKey; - C25519::Public updatesMustBeSignedBy; - Utils::unhex(OSUtils::jsonString(mj["signingKey"],""),signingKey.pub.data,(unsigned int)signingKey.pub.size()); - Utils::unhex(OSUtils::jsonString(mj["signingKey_SECRET"],""),signingKey.priv.data,(unsigned int)signingKey.priv.size()); - Utils::unhex(OSUtils::jsonString(mj["updatesMustBeSignedBy"],""),updatesMustBeSignedBy.data,(unsigned int)updatesMustBeSignedBy.size()); - - std::vector roots; - nlohmann::json &rootsj = mj["roots"]; - if (rootsj.is_array()) { - for(unsigned long i=0;i<(unsigned long)rootsj.size();++i) { - nlohmann::json &r = rootsj[i]; - if (r.is_object()) { - roots.push_back(World::Root()); - roots.back().identity = Identity(OSUtils::jsonString(r["identity"],"")); - nlohmann::json &stableEndpointsj = r["stableEndpoints"]; - if (stableEndpointsj.is_array()) { - for(unsigned long k=0;k<(unsigned long)stableEndpointsj.size();++k) - roots.back().stableEndpoints.push_back(InetAddress(OSUtils::jsonString(stableEndpointsj[k],""))); - std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); - } - } - } - } - std::sort(roots.begin(),roots.end()); - - const uint64_t now = OSUtils::now(); - World w(World::make(t,id,now,updatesMustBeSignedBy,roots,signingKey)); - Buffer wbuf; - w.serialize(wbuf); - char fn[128]; - Utils::snprintf(fn,sizeof(fn),"%.16llx.moon",w.id()); - OSUtils::writeFile(fn,wbuf.data(),wbuf.size()); - printf("wrote %s (signed world with timestamp %llu)" ZT_EOL_S,fn,(unsigned long long)now); - } - } else { - idtoolPrintHelp(stdout,argv[0]); - return 1; - } - - return 0; -} - -/****************************************************************************/ -/* Unix helper functions and signal handlers */ -/****************************************************************************/ - -#ifdef __UNIX_LIKE__ -static void _sighandlerHup(int sig) -{ -} -static void _sighandlerQuit(int sig) -{ - OneService *s = zt1Service; - if (s) - s->terminate(); - else exit(0); -} -#endif - -// Drop privileges on Linux, if supported by libc etc. and "zerotier-one" user exists on system -#ifdef __LINUX__ -#ifndef PR_CAP_AMBIENT -#define PR_CAP_AMBIENT 47 -#define PR_CAP_AMBIENT_IS_SET 1 -#define PR_CAP_AMBIENT_RAISE 2 -#define PR_CAP_AMBIENT_LOWER 3 -#define PR_CAP_AMBIENT_CLEAR_ALL 4 -#endif -#define ZT_LINUX_USER "zerotier-one" -#define ZT_HAVE_DROP_PRIVILEGES 1 -namespace { - -// libc doesn't export capset, it is instead located in libcap -// We ignore libcap and call it manually. -struct cap_header_struct { - __u32 version; - int pid; -}; -struct cap_data_struct { - __u32 effective; - __u32 permitted; - __u32 inheritable; -}; -static inline int _zt_capset(cap_header_struct* hdrp, cap_data_struct* datap) { return syscall(SYS_capset, hdrp, datap); } - -static void _notDropping(const char *procName,const std::string &homeDir) -{ - struct stat buf; - if (lstat(homeDir.c_str(),&buf) < 0) { - if (buf.st_uid != 0 || buf.st_gid != 0) { - fprintf(stderr, "%s: FATAL: failed to drop privileges and can't run as root since privileges were previously dropped (home directory not owned by root)" ZT_EOL_S,procName); - exit(1); - } - } - fprintf(stderr, "%s: WARNING: failed to drop privileges (kernel may not support required prctl features), running as root" ZT_EOL_S,procName); -} - -static int _setCapabilities(int flags) -{ - cap_header_struct capheader = {_LINUX_CAPABILITY_VERSION_1, 0}; - cap_data_struct capdata; - capdata.inheritable = capdata.permitted = capdata.effective = flags; - return _zt_capset(&capheader, &capdata); -} - -static void _recursiveChown(const char *path,uid_t uid,gid_t gid) -{ - struct dirent de; - struct dirent *dptr; - lchown(path,uid,gid); - DIR *d = opendir(path); - if (!d) - return; - dptr = (struct dirent *)0; - for(;;) { - if (readdir_r(d,&de,&dptr) != 0) - break; - if (!dptr) - break; - if ((strcmp(dptr->d_name,".") != 0)&&(strcmp(dptr->d_name,"..") != 0)&&(strlen(dptr->d_name) > 0)) { - std::string p(path); - p.push_back(ZT_PATH_SEPARATOR); - p.append(dptr->d_name); - _recursiveChown(p.c_str(),uid,gid); // will just fail and return on regular files - } - } - closedir(d); -} - -static void dropPrivileges(const char *procName,const std::string &homeDir) -{ - if (getuid() != 0) - return; - - // dropPrivileges switches to zerotier-one user while retaining CAP_NET_ADMIN - // and CAP_NET_RAW capabilities. - struct passwd *targetUser = getpwnam(ZT_LINUX_USER); - if (!targetUser) - return; - - if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_RAW, 0, 0) < 0) { - // Kernel has no support for ambient capabilities. - _notDropping(procName,homeDir); - return; - } - if (prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS | SECBIT_NOROOT) < 0) { - _notDropping(procName,homeDir); - return; - } - - // Change ownership of our home directory if everything looks good (does nothing if already chown'd) - _recursiveChown(homeDir.c_str(),targetUser->pw_uid,targetUser->pw_gid); - - if (_setCapabilities((1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID) | (1 << CAP_SETGID)) < 0) { - _notDropping(procName,homeDir); - return; - } - - int oldDumpable = prctl(PR_GET_DUMPABLE); - if (prctl(PR_SET_DUMPABLE, 0) < 0) { - // Disable ptracing. Otherwise there is a small window when previous - // compromised ZeroTier process could ptrace us, when we still have CAP_SETUID. - // (this is mitigated anyway on most distros by ptrace_scope=1) - fprintf(stderr,"%s: FATAL: prctl(PR_SET_DUMPABLE) failed while attempting to relinquish root permissions" ZT_EOL_S,procName); - exit(1); - } - - // Relinquish root - if (setgid(targetUser->pw_gid) < 0) { - perror("setgid"); - exit(1); - } - if (setuid(targetUser->pw_uid) < 0) { - perror("setuid"); - exit(1); - } - - if (_setCapabilities((1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW)) < 0) { - fprintf(stderr,"%s: FATAL: unable to drop capabilities after relinquishing root" ZT_EOL_S,procName); - exit(1); - } - - if (prctl(PR_SET_DUMPABLE, oldDumpable) < 0) { - fprintf(stderr,"%s: FATAL: prctl(PR_SET_DUMPABLE) failed while attempting to relinquish root permissions" ZT_EOL_S,procName); - exit(1); - } - - if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_ADMIN, 0, 0) < 0) { - fprintf(stderr,"%s: FATAL: prctl(PR_CAP_AMBIENT,PR_CAP_AMBIENT_RAISE,CAP_NET_ADMIN) failed while attempting to relinquish root permissions" ZT_EOL_S,procName); - exit(1); - } - if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_RAW, 0, 0) < 0) { - fprintf(stderr,"%s: FATAL: prctl(PR_CAP_AMBIENT,PR_CAP_AMBIENT_RAISE,CAP_NET_RAW) failed while attempting to relinquish root permissions" ZT_EOL_S,procName); - exit(1); - } -} - -} // anonymous namespace -#endif // __LINUX__ - -/****************************************************************************/ -/* Windows helper functions and signal handlers */ -/****************************************************************************/ - -#ifdef __WINDOWS__ -// Console signal handler routine to allow CTRL+C to work, mostly for testing -static BOOL WINAPI _winConsoleCtrlHandler(DWORD dwCtrlType) -{ - switch(dwCtrlType) { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - case CTRL_CLOSE_EVENT: - case CTRL_SHUTDOWN_EVENT: - OneService *s = zt1Service; - if (s) - s->terminate(); - return TRUE; - } - return FALSE; -} - -static void _winPokeAHole() -{ - char myPath[MAX_PATH]; - DWORD ps = GetModuleFileNameA(NULL,myPath,sizeof(myPath)); - if ((ps > 0)&&(ps < (DWORD)sizeof(myPath))) { - STARTUPINFOA startupInfo; - PROCESS_INFORMATION processInfo; - - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall delete rule name=\"ZeroTier One\" program=\"") + myPath + "\"").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall add rule name=\"ZeroTier One\" dir=in action=allow program=\"") + myPath + "\" enable=yes").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall add rule name=\"ZeroTier One\" dir=out action=allow program=\"") + myPath + "\" enable=yes").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - } -} - -// Returns true if this is running as the local administrator -static BOOL IsCurrentUserLocalAdministrator(void) -{ - BOOL fReturn = FALSE; - DWORD dwStatus; - DWORD dwAccessMask; - DWORD dwAccessDesired; - DWORD dwACLSize; - DWORD dwStructureSize = sizeof(PRIVILEGE_SET); - PACL pACL = NULL; - PSID psidAdmin = NULL; - - HANDLE hToken = NULL; - HANDLE hImpersonationToken = NULL; - - PRIVILEGE_SET ps; - GENERIC_MAPPING GenericMapping; - - PSECURITY_DESCRIPTOR psdAdmin = NULL; - SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; - - const DWORD ACCESS_READ = 1; - const DWORD ACCESS_WRITE = 2; - - __try - { - if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE|TOKEN_QUERY,TRUE,&hToken)) - { - if (GetLastError() != ERROR_NO_TOKEN) - __leave; - if (!OpenProcessToken(GetCurrentProcess(),TOKEN_DUPLICATE|TOKEN_QUERY, &hToken)) - __leave; - } - if (!DuplicateToken (hToken, SecurityImpersonation,&hImpersonationToken)) - __leave; - if (!AllocateAndInitializeSid(&SystemSidAuthority, 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, &psidAdmin)) - __leave; - psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); - if (psdAdmin == NULL) - __leave; - if (!InitializeSecurityDescriptor(psdAdmin,SECURITY_DESCRIPTOR_REVISION)) - __leave; - dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidAdmin) - sizeof(DWORD); - pACL = (PACL)LocalAlloc(LPTR, dwACLSize); - if (pACL == NULL) - __leave; - if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2)) - __leave; - dwAccessMask= ACCESS_READ | ACCESS_WRITE; - if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask, psidAdmin)) - __leave; - if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE)) - __leave; - - SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE); - SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE); - - if (!IsValidSecurityDescriptor(psdAdmin)) - __leave; - dwAccessDesired = ACCESS_READ; - - GenericMapping.GenericRead = ACCESS_READ; - GenericMapping.GenericWrite = ACCESS_WRITE; - GenericMapping.GenericExecute = 0; - GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE; - - if (!AccessCheck(psdAdmin, hImpersonationToken, dwAccessDesired, - &GenericMapping, &ps, &dwStructureSize, &dwStatus, - &fReturn)) - { - fReturn = FALSE; - __leave; - } - } - __finally - { - // Clean up. - if (pACL) LocalFree(pACL); - if (psdAdmin) LocalFree(psdAdmin); - if (psidAdmin) FreeSid(psidAdmin); - if (hImpersonationToken) CloseHandle (hImpersonationToken); - if (hToken) CloseHandle (hToken); - } - - return fReturn; -} -#endif // __WINDOWS__ - -/****************************************************************************/ -/* main() and friends */ -/****************************************************************************/ - -static void printHelp(const char *cn,FILE *out) -{ - fprintf(out, - "%s version %d.%d.%d" ZT_EOL_S, - PROGRAM_NAME, - ZEROTIER_ONE_VERSION_MAJOR, ZEROTIER_ONE_VERSION_MINOR, ZEROTIER_ONE_VERSION_REVISION); - fprintf(out, - COPYRIGHT_NOTICE ZT_EOL_S - LICENSE_GRANT ZT_EOL_S); - fprintf(out,"Usage: %s [-switches] [home directory]" ZT_EOL_S"" ZT_EOL_S,cn); - fprintf(out,"Available switches:" ZT_EOL_S); - fprintf(out," -h - Display this help" ZT_EOL_S); - fprintf(out," -v - Show version" ZT_EOL_S); - fprintf(out," -U - Skip privilege check and do not attempt to drop privileges" ZT_EOL_S); - fprintf(out," -p - Port for UDP and TCP/HTTP (default: 9993, 0 for random)" ZT_EOL_S); - -#ifdef __UNIX_LIKE__ - fprintf(out," -d - Fork and run as daemon (Unix-ish OSes)" ZT_EOL_S); -#endif // __UNIX_LIKE__ - -#ifdef __WINDOWS__ - fprintf(out," -C - Run from command line instead of as service (Windows)" ZT_EOL_S); - fprintf(out," -I - Install Windows service (Windows)" ZT_EOL_S); - fprintf(out," -R - Uninstall Windows service (Windows)" ZT_EOL_S); - fprintf(out," -D - Remove all instances of Windows tap device (Windows)" ZT_EOL_S); -#endif // __WINDOWS__ - - fprintf(out," -i - Generate and manage identities (zerotier-idtool)" ZT_EOL_S); - fprintf(out," -q - Query API (zerotier-cli)" ZT_EOL_S); -} - -class _OneServiceRunner -{ -public: - _OneServiceRunner(const char *pn,const std::string &hd,unsigned int p) : progname(pn),returnValue(0),port(p),homeDir(hd) {} - void threadMain() - throw() - { - try { - for(;;) { - zt1Service = OneService::newInstance(homeDir.c_str(),port); - switch(zt1Service->run()) { - case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done - case OneService::ONE_NORMAL_TERMINATION: - break; - case OneService::ONE_UNRECOVERABLE_ERROR: - fprintf(stderr,"%s: fatal error: %s" ZT_EOL_S,progname,zt1Service->fatalErrorMessage().c_str()); - returnValue = 1; - break; - case OneService::ONE_IDENTITY_COLLISION: { - delete zt1Service; - zt1Service = (OneService *)0; - std::string oldid; - OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid); - if (oldid.length()) { - OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid); - OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); - OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); - } - } continue; // restart! - } - break; // terminate loop -- normally we don't keep restarting - } - - delete zt1Service; - zt1Service = (OneService *)0; - } catch ( ... ) { - fprintf(stderr,"%s: unexpected exception starting main OneService instance" ZT_EOL_S,progname); - returnValue = 1; - } - } - const char *progname; - unsigned int returnValue; - unsigned int port; - const std::string &homeDir; -}; - -#ifdef __WINDOWS__ -int _tmain(int argc, _TCHAR* argv[]) -#else -int main(int argc,char **argv) -#endif -{ -#ifdef __UNIX_LIKE__ - signal(SIGHUP,&_sighandlerHup); - signal(SIGPIPE,SIG_IGN); - signal(SIGUSR1,SIG_IGN); - signal(SIGUSR2,SIG_IGN); - signal(SIGALRM,SIG_IGN); - signal(SIGINT,&_sighandlerQuit); - signal(SIGTERM,&_sighandlerQuit); - signal(SIGQUIT,&_sighandlerQuit); - - /* Ensure that there are no inherited file descriptors open from a previous - * incarnation. This is a hack to ensure that GitHub issue #61 or variants - * of it do not return, and should not do anything otherwise bad. */ - { - int mfd = STDIN_FILENO; - if (STDOUT_FILENO > mfd) mfd = STDOUT_FILENO; - if (STDERR_FILENO > mfd) mfd = STDERR_FILENO; - for(int f=mfd+1;f<1024;++f) - ::close(f); - } - - bool runAsDaemon = false; -#endif // __UNIX_LIKE__ - -#ifdef __WINDOWS__ - { - WSADATA wsaData; - WSAStartup(MAKEWORD(2,2),&wsaData); - } - -#ifdef ZT_WIN_RUN_IN_CONSOLE - bool winRunFromCommandLine = true; -#else - bool winRunFromCommandLine = false; -#endif -#endif // __WINDOWS__ - - if ((strstr(argv[0],"zerotier-idtool"))||(strstr(argv[0],"ZEROTIER-IDTOOL"))) - return idtool(argc,argv); - if ((strstr(argv[0],"zerotier-cli"))||(strstr(argv[0],"ZEROTIER-CLI"))) - return cli(argc,argv); - - std::string homeDir; - unsigned int port = ZT_DEFAULT_PORT; - bool skipRootCheck = false; - - for(int i=1;i 0xffff) { - printHelp(argv[0],stdout); - return 1; - } - break; - -#ifdef __UNIX_LIKE__ - case 'd': // Run in background as daemon - runAsDaemon = true; - break; -#endif // __UNIX_LIKE__ - - case 'U': - skipRootCheck = true; - break; - - case 'v': // Display version - printf("%d.%d.%d" ZT_EOL_S,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION); - return 0; - - case 'i': // Invoke idtool personality - if (argv[i][2]) { - printHelp(argv[0],stdout); - return 0; - } else return idtool(argc,argv); - - case 'q': // Invoke cli personality - if (argv[i][2]) { - printHelp(argv[0],stdout); - return 0; - } else return cli(argc,argv); - -#ifdef __WINDOWS__ - case 'C': // Run from command line instead of as Windows service - winRunFromCommandLine = true; - break; - - case 'I': { // Install this binary as a Windows service - if (IsCurrentUserLocalAdministrator() != TRUE) { - fprintf(stderr,"%s: must be run as a local administrator." ZT_EOL_S,argv[0]); - return 1; - } - std::string ret(InstallService(ZT_SERVICE_NAME,ZT_SERVICE_DISPLAY_NAME,ZT_SERVICE_START_TYPE,ZT_SERVICE_DEPENDENCIES,ZT_SERVICE_ACCOUNT,ZT_SERVICE_PASSWORD)); - if (ret.length()) { - fprintf(stderr,"%s: unable to install service: %s" ZT_EOL_S,argv[0],ret.c_str()); - return 3; - } - return 0; - } break; - - case 'R': { // Uninstall this binary as Windows service - if (IsCurrentUserLocalAdministrator() != TRUE) { - fprintf(stderr,"%s: must be run as a local administrator." ZT_EOL_S,argv[0]); - return 1; - } - std::string ret(UninstallService(ZT_SERVICE_NAME)); - if (ret.length()) { - fprintf(stderr,"%s: unable to uninstall service: %s" ZT_EOL_S,argv[0],ret.c_str()); - return 3; - } - return 0; - } break; - - case 'D': { - std::string err = WindowsEthernetTap::destroyAllPersistentTapDevices(); - if (err.length() > 0) { - fprintf(stderr,"%s: unable to uninstall one or more persistent tap devices: %s" ZT_EOL_S,argv[0],err.c_str()); - return 3; - } - return 0; - } break; -#endif // __WINDOWS__ - - case 'h': - case '?': - default: - printHelp(argv[0],stdout); - return 0; - } - } else { - if (homeDir.length()) { - printHelp(argv[0],stdout); - return 0; - } else { - homeDir = argv[i]; - } - } - } - - if (!homeDir.length()) - homeDir = OneService::platformDefaultHomePath(); - if (!homeDir.length()) { - fprintf(stderr,"%s: no home path specified and no platform default available" ZT_EOL_S,argv[0]); - return 1; - } else { - std::vector hpsp(OSUtils::split(homeDir.c_str(),ZT_PATH_SEPARATOR_S,"","")); - std::string ptmp; - if (homeDir[0] == ZT_PATH_SEPARATOR) - ptmp.push_back(ZT_PATH_SEPARATOR); - for(std::vector::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) { - if (ptmp.length() > 0) - ptmp.push_back(ZT_PATH_SEPARATOR); - ptmp.append(*pi); - if ((*pi != ".")&&(*pi != "..")) { - if (!OSUtils::mkdir(ptmp)) - throw std::runtime_error("home path does not exist, and could not create"); - } - } - } - - // This can be removed once the new controller code has been around for many versions - if (OSUtils::fileExists((homeDir + ZT_PATH_SEPARATOR_S + "controller.db").c_str(),true)) { - fprintf(stderr,"%s: FATAL: an old controller.db exists in %s -- see instructions in controller/README.md for how to migrate!" ZT_EOL_S,argv[0],homeDir.c_str()); - return 1; - } - -#ifdef __UNIX_LIKE__ -#ifndef ZT_ONE_NO_ROOT_CHECK - if ((!skipRootCheck)&&(getuid() != 0)) { - fprintf(stderr,"%s: must be run as root (uid 0)" ZT_EOL_S,argv[0]); - return 1; - } -#endif // !ZT_ONE_NO_ROOT_CHECK - if (runAsDaemon) { - long p = (long)fork(); - if (p < 0) { - fprintf(stderr,"%s: could not fork" ZT_EOL_S,argv[0]); - return 1; - } else if (p > 0) - return 0; // forked - // else p == 0, so we are daemonized - } -#endif // __UNIX_LIKE__ - -#ifdef __WINDOWS__ - // Uninstall legacy tap devices. New devices will automatically be installed and configured - // when tap instances are created. - WindowsEthernetTap::destroyAllLegacyPersistentTapDevices(); - - if (winRunFromCommandLine) { - // Running in "interactive" mode (mostly for debugging) - if (IsCurrentUserLocalAdministrator() != TRUE) { - if (!skipRootCheck) { - fprintf(stderr,"%s: must be run as a local administrator." ZT_EOL_S,argv[0]); - return 1; - } - } else { - _winPokeAHole(); - } - SetConsoleCtrlHandler(&_winConsoleCtrlHandler,TRUE); - // continues on to ordinary command line execution code below... - } else { - // Running from service manager - _winPokeAHole(); - ZeroTierOneService zt1WindowsService; - if (CServiceBase::Run(zt1WindowsService) == TRUE) { - return 0; - } else { - fprintf(stderr,"%s: unable to start service (try -h for help)" ZT_EOL_S,argv[0]); - return 1; - } - } -#endif // __WINDOWS__ - -#ifdef __UNIX_LIKE__ -#ifdef ZT_HAVE_DROP_PRIVILEGES - dropPrivileges(argv[0],homeDir); -#endif - - std::string pidPath(homeDir + ZT_PATH_SEPARATOR_S + ZT_PID_PATH); - { - // Write .pid file to home folder - FILE *pf = fopen(pidPath.c_str(),"w"); - if (pf) { - fprintf(pf,"%ld",(long)getpid()); - fclose(pf); - } - } -#endif // __UNIX_LIKE__ - - _OneServiceRunner thr(argv[0],homeDir,port); - thr.threadMain(); - //Thread::join(Thread::start(&thr)); - -#ifdef __UNIX_LIKE__ - OSUtils::rm(pidPath.c_str()); -#endif - - return thr.returnValue; -} diff --git a/zto/osdep/Arp.cpp b/zto/osdep/Arp.cpp deleted file mode 100644 index fcc122f..0000000 --- a/zto/osdep/Arp.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#include "Arp.hpp" -#include "OSUtils.hpp" - -namespace ZeroTier { - -static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x01 }; -static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x02 }; - -Arp::Arp() : - _cache(256), - _lastCleaned(OSUtils::now()) -{ -} - -void Arp::addLocal(uint32_t ip,const MAC &mac) -{ - _ArpEntry &e = _cache[ip]; - e.lastQuerySent = 0; // local IP - e.lastResponseReceived = 0; // local IP - e.mac = mac; - e.local = true; -} - -void Arp::remove(uint32_t ip) -{ - _cache.erase(ip); -} - -uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest) -{ - const uint64_t now = OSUtils::now(); - uint32_t ip = 0; - - responseLen = 0; - responseDest.zero(); - - if (len >= 28) { - if (!memcmp(arp,ARP_REQUEST_HEADER,8)) { - // Respond to ARP requests for locally-known IPs - _ArpEntry *targetEntry = _cache.get(reinterpret_cast(arp)[6]); - if ((targetEntry)&&(targetEntry->local)) { - memcpy(response,ARP_RESPONSE_HEADER,8); - targetEntry->mac.copyTo(reinterpret_cast(response) + 8,6); - memcpy(reinterpret_cast(response) + 14,reinterpret_cast(arp) + 24,4); - memcpy(reinterpret_cast(response) + 18,reinterpret_cast(arp) + 8,10); - responseLen = 28; - responseDest.setTo(reinterpret_cast(arp) + 8,6); - } - } else if (!memcmp(arp,ARP_RESPONSE_HEADER,8)) { - // Learn cache entries for remote IPs from relevant ARP replies - uint32_t responseIp = 0; - memcpy(&responseIp,reinterpret_cast(arp) + 14,4); - _ArpEntry *queryEntry = _cache.get(responseIp); - if ((queryEntry)&&(!queryEntry->local)&&((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) { - queryEntry->lastResponseReceived = now; - queryEntry->mac.setTo(reinterpret_cast(arp) + 8,6); - ip = responseIp; - } - } - } - - if ((now - _lastCleaned) >= ZT_ARP_EXPIRE) { - _lastCleaned = now; - Hashtable< uint32_t,_ArpEntry >::Iterator i(_cache); - uint32_t *k = (uint32_t *)0; - _ArpEntry *v = (_ArpEntry *)0; - while (i.next(k,v)) { - if ((!v->local)&&((now - v->lastResponseReceived) >= ZT_ARP_EXPIRE)) - _cache.erase(*k); - } - } - - return ip; -} - -MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest) -{ - const uint64_t now = OSUtils::now(); - - _ArpEntry &e = _cache[targetIp]; - - if ( ((e.mac)&&((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) || - ((!e.mac)&&((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL)) ) { - e.lastQuerySent = now; - - uint8_t *q = reinterpret_cast(query); - memcpy(q,ARP_REQUEST_HEADER,8); q += 8; // ARP request header information, always the same - localMac.copyTo(q,6); q += 6; // sending host MAC address - memcpy(q,&localIp,4); q += 4; // sending host IP (IP already in big-endian byte order) - memset(q,0,6); q += 6; // sending zeros for target MAC address as thats what we want to find - memcpy(q,&targetIp,4); // target IP address for resolution (IP already in big-endian byte order) - queryLen = 28; - if (e.mac) - queryDest = e.mac; // confirmation query, send directly to address holder - else queryDest = (uint64_t)0xffffffffffffULL; // broadcast query - } else { - queryLen = 0; - queryDest.zero(); - } - - return e.mac; -} - -} // namespace ZeroTier diff --git a/zto/osdep/Arp.hpp b/zto/osdep/Arp.hpp deleted file mode 100644 index 5f0d199..0000000 --- a/zto/osdep/Arp.hpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_ARP_HPP -#define ZT_ARP_HPP - -#include - -#include - -#include "../node/Constants.hpp" -#include "../node/Hashtable.hpp" -#include "../node/MAC.hpp" - -/** - * Maximum possible ARP length - * - * ARPs are 28 bytes in length, but specify a 128 byte buffer since - * some weird extensions we may support in the future can pad them - * out to as long as 72 bytes. - */ -#define ZT_ARP_BUF_LENGTH 128 - -/** - * Minimum permitted interval between sending ARP queries for a given IP - */ -#define ZT_ARP_QUERY_INTERVAL 2000 - -/** - * Maximum time between query and response, otherwise responses are discarded to prevent poisoning - */ -#define ZT_ARP_QUERY_MAX_TTL 5000 - -/** - * ARP expiration time - */ -#define ZT_ARP_EXPIRE 600000 - -namespace ZeroTier { - -/** - * ARP cache and resolver - * - * To implement ARP: - * - * (1) Call processIncomingArp() on all ARP packets received and then always - * check responseLen after calling. If it is non-zero, send the contents - * of response to responseDest. - * - * (2) Call query() to look up IP addresses, and then check queryLen. If it - * is non-zero, send the contents of query to queryDest (usually broadcast). - * - * Note that either of these functions can technically generate a response or - * a query at any time, so their result parameters for sending ARPs should - * always be checked. - * - * This class is not thread-safe and must be guarded if used in multi-threaded - * code. - */ -class Arp -{ -public: - Arp(); - - /** - * Set a local IP entry that we should respond to ARPs for - * - * @param mac Our local MAC address - * @param ip IP in big-endian byte order (sin_addr.s_addr) - */ - void addLocal(uint32_t ip,const MAC &mac); - - /** - * Delete a local IP entry or a cached ARP entry - * - * @param ip IP in big-endian byte order (sin_addr.s_addr) - */ - void remove(uint32_t ip); - - /** - * Process ARP packets - * - * For ARP queries, a response is generated and responseLen is set to its - * frame payload length in bytes. - * - * For ARP responses, the cache is populated and the IP address entry that - * was learned is returned. - * - * @param arp ARP frame data - * @param len Length of ARP frame (usually 28) - * @param response Response buffer -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size - * @param responseLen Response length, or set to 0 if no response - * @param responseDest Destination of response, or set to null if no response - * @return IP address learned or 0 if no new IPs in cache - */ - uint32_t processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest); - - /** - * Get the MAC corresponding to an IP, generating a query if needed - * - * This returns a MAC for a remote IP. The local MAC is returned for local - * IPs as well. It may also generate a query if the IP is not known or the - * entry needs to be refreshed. In this case queryLen will be set to a - * non-zero value, so this should always be checked on return even if the - * MAC returned is non-null. - * - * @param localMac Local MAC address of host interface - * @param localIp Local IP address of host interface - * @param targetIp IP to look up - * @param query Buffer for generated query -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size - * @param queryLen Length of generated query, or set to 0 if no query generated - * @param queryDest Destination of query, or set to null if no query generated - * @return MAC or 0 if no cached entry for this IP - */ - MAC query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest); - -private: - struct _ArpEntry - { - _ArpEntry() : lastQuerySent(0),lastResponseReceived(0),mac(),local(false) {} - uint64_t lastQuerySent; // Time last query was sent or 0 for local IP - uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP - MAC mac; // MAC address of device responsible for IP or null if not known yet - bool local; // True if this is a local ARP entry - }; - - Hashtable< uint32_t,_ArpEntry > _cache; - uint64_t _lastCleaned; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/BSDEthernetTap.cpp b/zto/osdep/BSDEthernetTap.cpp deleted file mode 100644 index 62fabc4..0000000 --- a/zto/osdep/BSDEthernetTap.cpp +++ /dev/null @@ -1,473 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" -#include "OSUtils.hpp" -#include "BSDEthernetTap.hpp" - -#define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv" - -// ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); - -namespace ZeroTier { - -BSDEthernetTap::BSDEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg) : - _handler(handler), - _arg(arg), - _nwid(nwid), - _mtu(mtu), - _metric(metric), - _fd(0), - _enabled(true) -{ - static Mutex globalTapCreateLock; - char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32]; - - Mutex::Lock _gl(globalTapCreateLock); - - if (mtu > 2800) - throw std::runtime_error("max tap MTU is 2800"); - -#ifdef __FreeBSD__ - /* FreeBSD allows long interface names and interface renaming */ - - _dev = "zt"; - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 60) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 55) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 50) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 45) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 40) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 35) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 30) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 25) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 20) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 15) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 10) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 5) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]); - - std::vector devFiles(OSUtils::listDirectory("/dev")); - for(int i=9993;i<(9993+128);++i) { - Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); - Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); - if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - } else throw std::runtime_error("fork() failed"); - - struct stat stattmp; - if (!stat(devpath,&stattmp)) { - cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"name",_dev.c_str(),(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) - throw std::runtime_error("ifconfig rename operation failed"); - } else throw std::runtime_error("fork() failed"); - - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) - break; - else throw std::runtime_error("unable to open created tap device"); - } else { - throw std::runtime_error("cannot find /dev node for newly created tap device"); - } - } - } -#else - /* Other BSDs like OpenBSD only have a limited number of tap devices that cannot be renamed */ - - for(int i=0;i<64;++i) { - Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); - Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) { - _dev = tmpdevname; - break; - } - } -#endif - - if (_fd <= 0) - throw std::runtime_error("unable to open TAP device or no more devices available"); - - if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { - ::close(_fd); - throw std::runtime_error("unable to set flags on file descriptor for TAP device"); - } - - // Configure MAC address and MTU, bring interface up - Utils::snprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu); - Utils::snprintf(metstr,sizeof(metstr),"%u",_metric); - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) { - ::close(_fd); - throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); - } - } - - // Set close-on-exec so that devices cannot persist if we fork/exec for update - fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); - - ::pipe(_shutdownSignalPipe); - - _thread = Thread::start(this); -} - -BSDEthernetTap::~BSDEthernetTap() -{ - ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit - Thread::join(_thread); - ::close(_fd); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); - - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - } -} - -void BSDEthernetTap::setEnabled(bool en) -{ - _enabled = en; -} - -bool BSDEthernetTap::enabled() const -{ - return _enabled; -} - -static bool ___removeIp(const std::string &_dev,const InetAddress &ip) -{ - long cpid = (long)vfork(); - if (cpid == 0) { - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - return false; // never reached, make compiler shut up about return value -} - -bool BSDEthernetTap::addIp(const InetAddress &ip) -{ - if (!ip) - return false; - - std::vector allIps(ips()); - if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) - return true; // IP/netmask already assigned - - // Remove and reconfigure if address is the same but netmask is different - for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { - if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) { - if (___removeIp(_dev,*i)) - break; - } - } - - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - return false; -} - -bool BSDEthernetTap::removeIp(const InetAddress &ip) -{ - if (!ip) - return false; - std::vector allIps(ips()); - if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) { - if (___removeIp(_dev,ip)) - return true; - } - return false; -} - -std::vector BSDEthernetTap::ips() const -{ - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::vector(); - - std::vector r; - - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } - - if (ifa) - freeifaddrs(ifa); - - std::sort(r.begin(),r.end()); - std::unique(r.begin(),r.end()); - - return r; -} - -void BSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - char putBuf[4096]; - if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { - to.copyTo(putBuf,6); - from.copyTo(putBuf + 6,6); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - ::write(_fd,putBuf,len); - } -} - -std::string BSDEthernetTap::deviceName() const -{ - return _dev; -} - -void BSDEthernetTap::setFriendlyName(const char *friendlyName) -{ -} - -void BSDEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) -{ - std::vector newGroups; - -#ifndef __OpenBSD__ - struct ifmaddrs *ifmap = (struct ifmaddrs *)0; - if (!getifmaddrs(&ifmap)) { - struct ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - freeifmaddrs(ifmap); - } -#endif // __OpenBSD__ - - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - - std::sort(newGroups.begin(),newGroups.end()); - std::unique(newGroups.begin(),newGroups.end()); - - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } - - _multicastGroups.swap(newGroups); -} - -/* -bool BSDEthernetTap::updateMulticastGroups(std::set &groups) -{ - std::set newGroups; - struct ifmaddrs *ifmap = (struct ifmaddrs *)0; - if (!getifmaddrs(&ifmap)) { - struct ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.insert(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - freeifmaddrs(ifmap); - } - - { - std::set allIps(ips()); - for(std::set::const_iterator i(allIps.begin());i!=allIps.end();++i) - newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i)); - } - - bool changed = false; - - for(std::set::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) { - if (!groups.count(*mg)) { - groups.insert(*mg); - changed = true; - } - } - for(std::set::iterator mg(groups.begin());mg!=groups.end();) { - if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) { - groups.erase(mg++); - changed = true; - } else ++mg; - } - - return changed; -} -*/ - -void BSDEthernetTap::threadMain() - throw() -{ - fd_set readfds,nullfds; - MAC to,from; - int n,nfds,r; - char getBuf[8194]; - - // Wait for a moment after startup -- wait for Network to finish - // constructing itself. - Thread::sleep(500); - - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; - - r = 0; - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_fd,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); - - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread - break; - - if (FD_ISSET(_fd,&readfds)) { - n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r); - if (n < 0) { - if ((errno != EINTR)&&(errno != ETIMEDOUT)) - break; - } else { - // Some tap drivers like to send the ethernet frame and the - // payload in two chunks, so handle that by accumulating - // data until we have at least a frame. - r += n; - if (r > 14) { - if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms - r = _mtu + 14; - - if (_enabled) { - to.setTo(getBuf,6); - from.setTo(getBuf + 6,6); - unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); - _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); - } - - r = 0; - } - } - } - } -} - -} // namespace ZeroTier diff --git a/zto/osdep/BSDEthernetTap.hpp b/zto/osdep/BSDEthernetTap.hpp deleted file mode 100644 index 8c6314d..0000000 --- a/zto/osdep/BSDEthernetTap.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_BSDETHERNETTAP_HPP -#define ZT_BSDETHERNETTAP_HPP - -#include -#include - -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/MulticastGroup.hpp" -#include "../node/MAC.hpp" -#include "Thread.hpp" - -namespace ZeroTier { - -class BSDEthernetTap -{ -public: - BSDEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); - - ~BSDEthernetTap(); - - void setEnabled(bool en); - bool enabled() const; - bool addIp(const InetAddress &ip); - bool removeIp(const InetAddress &ip); - std::vector ips() const; - void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - std::string deviceName() const; - void setFriendlyName(const char *friendlyName); - void scanMulticastGroups(std::vector &added,std::vector &removed); - - void threadMain() - throw(); - -private: - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - uint64_t _nwid; - Thread _thread; - std::string _dev; - std::vector _multicastGroups; - unsigned int _mtu; - unsigned int _metric; - int _fd; - int _shutdownSignalPipe[2]; - volatile bool _enabled; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/Binder.hpp b/zto/osdep/Binder.hpp deleted file mode 100644 index 9829f17..0000000 --- a/zto/osdep/Binder.hpp +++ /dev/null @@ -1,448 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_BINDER_HPP -#define ZT_BINDER_HPP - -#include "../node/Constants.hpp" - -#include -#include -#include -#include - -#ifdef __WINDOWS__ -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#include -#ifdef __LINUX__ -#include -#include -#endif -#endif - -#include -#include -#include -#include -#include - -#include "../node/NonCopyable.hpp" -#include "../node/InetAddress.hpp" -#include "../node/Mutex.hpp" -#include "../node/Utils.hpp" - -#include "Phy.hpp" -#include "OSUtils.hpp" - -/** - * Period between binder rescans/refreshes - * - * OneService also does this on detected restarts. - */ -#define ZT_BINDER_REFRESH_PERIOD 30000 - -namespace ZeroTier { - -/** - * Enumerates local devices and binds to all potential ZeroTier path endpoints - * - * This replaces binding to wildcard (0.0.0.0 and ::0) with explicit binding - * as part of the path to default gateway support. Under the hood it uses - * different queries on different OSes to enumerate devices, and also exposes - * device enumeration and endpoint IP data for use elsewhere. - * - * On OSes that do not support local port enumeration or where this is not - * meaningful, this degrades to binding to wildcard. - */ -class Binder : NonCopyable -{ -private: - struct _Binding - { - _Binding() : - udpSock((PhySocket *)0), - tcpListenSock((PhySocket *)0), - address() {} - - PhySocket *udpSock; - PhySocket *tcpListenSock; - InetAddress address; - }; - -public: - Binder() {} - - /** - * Close all bound ports - * - * This should be called on shutdown. It closes listen sockets and UDP ports - * but not TCP connections from any TCP listen sockets. - * - * @param phy Physical interface - */ - template - void closeAll(Phy &phy) - { - Mutex::Lock _l(_lock); - for(typename std::vector<_Binding>::const_iterator i(_bindings.begin());i!=_bindings.end();++i) { - phy.close(i->udpSock,false); - phy.close(i->tcpListenSock,false); - } - } - - /** - * Scan local devices and addresses and rebind TCP and UDP - * - * This should be called after wake from sleep, on detected network device - * changes, on startup, or periodically (e.g. every 30-60s). - * - * @param phy Physical interface - * @param port Port to bind to on all interfaces (TCP and UDP) - * @param ignoreInterfacesByName Ignore these interfaces by name - * @param ignoreInterfacesByNamePrefix Ignore these interfaces by name-prefix (starts-with, e.g. zt ignores zt*) - * @param ignoreInterfacesByAddress Ignore these interfaces by address - * @tparam PHY_HANDLER_TYPE Type for Phy<> template - * @tparam INTERFACE_CHECKER Type for class containing shouldBindInterface() method - */ - template - void refresh(Phy &phy,unsigned int port,INTERFACE_CHECKER &ifChecker) - { - std::map localIfAddrs; - PhySocket *udps; - //PhySocket *tcps; - Mutex::Lock _l(_lock); - -#ifdef __WINDOWS__ - - char aabuf[32768]; - ULONG aalen = sizeof(aabuf); - if (GetAdaptersAddresses(AF_UNSPEC,GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER,(void *)0,reinterpret_cast(aabuf),&aalen) == NO_ERROR) { - PIP_ADAPTER_ADDRESSES a = reinterpret_cast(aabuf); - while (a) { - PIP_ADAPTER_UNICAST_ADDRESS ua = a->FirstUnicastAddress; - while (ua) { - InetAddress ip(ua->Address.lpSockaddr); - if (ifChecker.shouldBindInterface("",ip)) { - switch(ip.ipScope()) { - default: break; - case InetAddress::IP_SCOPE_PSEUDOPRIVATE: - case InetAddress::IP_SCOPE_GLOBAL: - case InetAddress::IP_SCOPE_SHARED: - case InetAddress::IP_SCOPE_PRIVATE: - ip.setPort(port); - localIfAddrs.insert(std::pair(ip,std::string())); - break; - } - } - ua = ua->Next; - } - a = a->Next; - } - } - -#else // not __WINDOWS__ - - /* On Linux we use an alternative method if available since getifaddrs() - * gets very slow when there are lots of network namespaces. This won't - * work unless /proc/PID/net/if_inet6 exists and it may not on some - * embedded systems, so revert to getifaddrs() there. */ - -#ifdef __LINUX__ - char fn[256],tmp[256]; - std::set ifnames; - const unsigned long pid = (unsigned long)getpid(); - - // Get all device names - Utils::snprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid); - FILE *procf = fopen(fn,"r"); - if (procf) { - while (fgets(tmp,sizeof(tmp),procf)) { - tmp[255] = 0; - char *saveptr = (char *)0; - for(char *f=Utils::stok(tmp," \t\r\n:|",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n:|",&saveptr)) { - if ((strcmp(f,"Inter-") != 0)&&(strcmp(f,"face") != 0)&&(f[0] != 0)) - ifnames.insert(f); - break; // we only want the first field - } - } - fclose(procf); - } - - // Get IPv6 addresses (and any device names we don't already know) - Utils::snprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid); - procf = fopen(fn,"r"); - if (procf) { - while (fgets(tmp,sizeof(tmp),procf)) { - tmp[255] = 0; - char *saveptr = (char *)0; - unsigned char ipbits[16]; - memset(ipbits,0,sizeof(ipbits)); - char *devname = (char *)0; - int n = 0; - for(char *f=Utils::stok(tmp," \t\r\n",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n",&saveptr)) { - switch(n++) { - case 0: // IP in hex - Utils::unhex(f,32,ipbits,16); - break; - case 5: // device name - devname = f; - break; - } - } - if (devname) { - ifnames.insert(devname); - InetAddress ip(ipbits,16,0); - if (ifChecker.shouldBindInterface(devname,ip)) { - switch(ip.ipScope()) { - default: break; - case InetAddress::IP_SCOPE_PSEUDOPRIVATE: - case InetAddress::IP_SCOPE_GLOBAL: - case InetAddress::IP_SCOPE_SHARED: - case InetAddress::IP_SCOPE_PRIVATE: - ip.setPort(port); - localIfAddrs.insert(std::pair(ip,std::string(devname))); - break; - } - } - } - } - fclose(procf); - } - - // Get IPv4 addresses for each device - if (ifnames.size() > 0) { - const int controlfd = (int)socket(AF_INET,SOCK_DGRAM,0); - struct ifconf configuration; - configuration.ifc_len = 0; - configuration.ifc_buf = nullptr; - - if (controlfd < 0) goto ip4_address_error; - - if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error; - - configuration.ifc_buf = (char*)malloc(configuration.ifc_len); - - if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error; - - for (int i=0; i < (int)(configuration.ifc_len / sizeof(ifreq)); i ++) { - struct ifreq& request = configuration.ifc_req[i]; - struct sockaddr* addr = &request.ifr_ifru.ifru_addr; - if (addr->sa_family != AF_INET) continue; - std::string ifname = request.ifr_ifrn.ifrn_name; - // name can either be just interface name or interface name followed by ':' and arbitrary label - if (ifname.find(':') != std::string::npos) { - ifname = ifname.substr(0, ifname.find(':')); - } - - InetAddress ip(&(((struct sockaddr_in *)addr)->sin_addr),4,0); - if (ifChecker.shouldBindInterface(ifname.c_str(), ip)) { - switch(ip.ipScope()) { - default: break; - case InetAddress::IP_SCOPE_PSEUDOPRIVATE: - case InetAddress::IP_SCOPE_GLOBAL: - case InetAddress::IP_SCOPE_SHARED: - case InetAddress::IP_SCOPE_PRIVATE: - ip.setPort(port); - localIfAddrs.insert(std::pair(ip, ifname)); - break; - } - } - } - - ip4_address_error: - free(configuration.ifc_buf); - if (controlfd > 0) close(controlfd); - } - - const bool gotViaProc = (localIfAddrs.size() > 0); -#else - const bool gotViaProc = false; -#endif - - if (!gotViaProc) { - struct ifaddrs *ifatbl = (struct ifaddrs *)0; - struct ifaddrs *ifa; - if ((getifaddrs(&ifatbl) == 0)&&(ifatbl)) { - ifa = ifatbl; - while (ifa) { - if ((ifa->ifa_name)&&(ifa->ifa_addr)) { - InetAddress ip = *(ifa->ifa_addr); - if (ifChecker.shouldBindInterface(ifa->ifa_name,ip)) { - switch(ip.ipScope()) { - default: break; - case InetAddress::IP_SCOPE_PSEUDOPRIVATE: - case InetAddress::IP_SCOPE_GLOBAL: - case InetAddress::IP_SCOPE_SHARED: - case InetAddress::IP_SCOPE_PRIVATE: - ip.setPort(port); - localIfAddrs.insert(std::pair(ip,std::string(ifa->ifa_name))); - break; - } - } - } - ifa = ifa->ifa_next; - } - freeifaddrs(ifatbl); - } - } - -#endif - - // Default to binding to wildcard if we can't enumerate addresses - if (localIfAddrs.empty()) { - localIfAddrs.insert(std::pair(InetAddress((uint32_t)0,port),std::string())); - localIfAddrs.insert(std::pair(InetAddress((const void *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",16,port),std::string())); - } - - // Close any old bindings to anything that doesn't exist anymore - for(typename std::vector<_Binding>::const_iterator bi(_bindings.begin());bi!=_bindings.end();++bi) { - if (localIfAddrs.find(bi->address) == localIfAddrs.end()) { - phy.close(bi->udpSock,false); - phy.close(bi->tcpListenSock,false); - } - } - - std::vector<_Binding> newBindings; - for(std::map::const_iterator ii(localIfAddrs.begin());ii!=localIfAddrs.end();++ii) { - typename std::vector<_Binding>::const_iterator bi(_bindings.begin()); - while (bi != _bindings.end()) { - if (bi->address == ii->first) { - newBindings.push_back(*bi); - break; - } - ++bi; - } - - if (bi == _bindings.end()) { - udps = phy.udpBind(reinterpret_cast(&(ii->first)),(void *)0,ZT_UDP_DESIRED_BUF_SIZE); - if (udps) { - //tcps = phy.tcpListen(reinterpret_cast(&ii),(void *)0); - //if (tcps) { -#ifdef __LINUX__ - // Bind Linux sockets to their device so routes tha we manage do not override physical routes (wish all platforms had this!) - if (ii->second.length() > 0) { - int fd = (int)Phy::getDescriptor(udps); - char tmp[256]; - Utils::scopy(tmp,sizeof(tmp),ii->second.c_str()); - if (fd >= 0) { - if (setsockopt(fd,SOL_SOCKET,SO_BINDTODEVICE,tmp,strlen(tmp)) != 0) { - fprintf(stderr,"WARNING: unable to set SO_BINDTODEVICE to bind %s to %s\n",ii->first.toIpString().c_str(),ii->second.c_str()); - } - } - } -#endif // __LINUX__ - newBindings.push_back(_Binding()); - newBindings.back().udpSock = udps; - //newBindings.back().tcpListenSock = tcps; - newBindings.back().address = ii->first; - //} else { - // phy.close(udps,false); - //} - } - } - } - - // Swapping pointers and then letting the old one fall out of scope is faster than copying again - _bindings.swap(newBindings); - } - - /** - * Send a UDP packet from the specified local interface, or all - * - * Unfortunately even by examining the routing table there is no ultimately - * robust way to tell where we might reach another host that works in all - * environments. As a result, we send packets with null (wildcard) local - * addresses from *every* bound interface. - * - * These are typically initial HELLOs, path probes, etc., since normal - * conversations will have a local endpoint address. So the cost is low and - * if the peer is not reachable via that route then the packet will go - * nowhere and nothing will happen. - * - * It will of course only send via interface bindings of the same socket - * family. No point in sending V4 via V6 or vice versa. - * - * In any case on most hosts there's only one or two interfaces that we - * will use, so none of this is particularly costly. - * - * @param local Local interface address or null address for 'all' - * @param remote Remote address - * @param data Data to send - * @param len Length of data - * @param v4ttl If non-zero, send this packet with the specified IP TTL (IPv4 only) - */ - template - inline bool udpSend(Phy &phy,const InetAddress &local,const InetAddress &remote,const void *data,unsigned int len,unsigned int v4ttl = 0) const - { - Mutex::Lock _l(_lock); - if (local) { - for(typename std::vector<_Binding>::const_iterator i(_bindings.begin());i!=_bindings.end();++i) { - if (i->address == local) { - if ((v4ttl)&&(local.ss_family == AF_INET)) - phy.setIp4UdpTtl(i->udpSock,v4ttl); - const bool result = phy.udpSend(i->udpSock,reinterpret_cast(&remote),data,len); - if ((v4ttl)&&(local.ss_family == AF_INET)) - phy.setIp4UdpTtl(i->udpSock,255); - return result; - } - } - return false; - } else { - bool result = false; - for(typename std::vector<_Binding>::const_iterator i(_bindings.begin());i!=_bindings.end();++i) { - if (i->address.ss_family == remote.ss_family) { - if ((v4ttl)&&(remote.ss_family == AF_INET)) - phy.setIp4UdpTtl(i->udpSock,v4ttl); - result |= phy.udpSend(i->udpSock,reinterpret_cast(&remote),data,len); - if ((v4ttl)&&(remote.ss_family == AF_INET)) - phy.setIp4UdpTtl(i->udpSock,255); - } - } - return result; - } - } - - /** - * @return All currently bound local interface addresses - */ - inline std::vector allBoundLocalInterfaceAddresses() - { - Mutex::Lock _l(_lock); - std::vector aa; - for(std::vector<_Binding>::const_iterator i(_bindings.begin());i!=_bindings.end();++i) - aa.push_back(i->address); - return aa; - } - -private: - std::vector<_Binding> _bindings; - Mutex _lock; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/BlockingQueue.hpp b/zto/osdep/BlockingQueue.hpp deleted file mode 100644 index 6172f4d..0000000 --- a/zto/osdep/BlockingQueue.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_BLOCKINGQUEUE_HPP -#define ZT_BLOCKINGQUEUE_HPP - -#include -#include -#include - -namespace ZeroTier { - -/** - * Simple C++11 thread-safe queue - * - * Do not use in node/ since we have not gone C++11 there yet. - */ -template -class BlockingQueue -{ -public: - BlockingQueue(void) {} - - inline void post(T t) - { - std::lock_guard lock(m); - q.push(t); - c.notify_one(); - } - - inline T get(void) - { - std::unique_lock lock(m); - while(q.empty()) - c.wait(lock); - T val = q.front(); - q.pop(); - return val; - } - -private: - std::queue q; - mutable std::mutex m; - std::condition_variable c; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/Http.cpp b/zto/osdep/Http.cpp deleted file mode 100644 index d4f43d1..0000000 --- a/zto/osdep/Http.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#include "Http.hpp" -#include "Phy.hpp" -#include "OSUtils.hpp" -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" - -#ifdef ZT_USE_SYSTEM_HTTP_PARSER -#include -#else -#include "../ext/http-parser/http_parser.h" -#endif - -namespace ZeroTier { - -namespace { - -static int ShttpOnMessageBegin(http_parser *parser); -static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length); -#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) -static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length); -#else -static int ShttpOnStatus(http_parser *parser); -#endif -static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnHeadersComplete(http_parser *parser); -static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnMessageComplete(http_parser *parser); - -#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1) -static const struct http_parser_settings HTTP_PARSER_SETTINGS = { - ShttpOnMessageBegin, - ShttpOnUrl, - ShttpOnStatus, - ShttpOnHeaderField, - ShttpOnValue, - ShttpOnHeadersComplete, - ShttpOnBody, - ShttpOnMessageComplete -}; -#else -static const struct http_parser_settings HTTP_PARSER_SETTINGS = { - ShttpOnMessageBegin, - ShttpOnUrl, - ShttpOnHeaderField, - ShttpOnValue, - ShttpOnHeadersComplete, - ShttpOnBody, - ShttpOnMessageComplete -}; -#endif - -struct HttpPhyHandler -{ - // not used - inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) {} - inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) {} - - inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) - { - if (success) { - phy->setNotifyWritable(sock,true); - } else { - *responseBody = "connection failed"; - error = true; - done = true; - } - } - - inline void phyOnTcpClose(PhySocket *sock,void **uptr) - { - done = true; - } - - inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) - { - lastActivity = OSUtils::now(); - http_parser_execute(&parser,&HTTP_PARSER_SETTINGS,(const char *)data,len); - if ((parser.upgrade)||(parser.http_errno != HPE_OK)) - phy->close(sock); - } - - inline void phyOnTcpWritable(PhySocket *sock,void **uptr, bool stack_invoked) - { - if (writePtr < writeSize) { - long n = phy->streamSend(sock,writeBuf + writePtr,writeSize - writePtr,true); - if (n > 0) - writePtr += n; - } - if (writePtr >= writeSize) - phy->setNotifyWritable(sock,false); - } - - inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} -#ifdef __UNIX_LIKE__ - inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {} - inline void phyOnUnixClose(PhySocket *sock,void **uptr) {} - inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} - inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {} -#endif // __UNIX_LIKE__ - - http_parser parser; - std::string currentHeaderField; - std::string currentHeaderValue; - unsigned long messageSize; - unsigned long writePtr; - uint64_t lastActivity; - unsigned long writeSize; - char writeBuf[32768]; - - unsigned long maxResponseSize; - std::map *responseHeaders; - std::string *responseBody; - bool error; - bool done; - - Phy *phy; - PhySocket *sock; -}; - -static int ShttpOnMessageBegin(http_parser *parser) -{ - return 0; -} -static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) -{ - return 0; -} -#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) -static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) -#else -static int ShttpOnStatus(http_parser *parser) -#endif -{ - /* - HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += (unsigned long)length; - if (hh->messageSize > hh->maxResponseSize) - return -1; - */ - return 0; -} -static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) -{ - HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += (unsigned long)length; - if (hh->messageSize > hh->maxResponseSize) - return -1; - if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) { - (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; - hh->currentHeaderField = ""; - hh->currentHeaderValue = ""; - } - for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i])); - return 0; -} -static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) -{ - HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += (unsigned long)length; - if (hh->messageSize > hh->maxResponseSize) - return -1; - hh->currentHeaderValue.append(ptr,length); - return 0; -} -static int ShttpOnHeadersComplete(http_parser *parser) -{ - HttpPhyHandler *hh = reinterpret_cast(parser->data); - if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) - (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; - return 0; -} -static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) -{ - HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += (unsigned long)length; - if (hh->messageSize > hh->maxResponseSize) - return -1; - hh->responseBody->append(ptr,length); - return 0; -} -static int ShttpOnMessageComplete(http_parser *parser) -{ - HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->phy->close(hh->sock); - return 0; -} - -} // anonymous namespace - -unsigned int Http::_do( - const char *method, - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - const void *requestBody, - unsigned long requestBodyLength, - std::map &responseHeaders, - std::string &responseBody) -{ - try { - responseHeaders.clear(); - responseBody = ""; - - HttpPhyHandler handler; - - http_parser_init(&(handler.parser),HTTP_RESPONSE); - handler.parser.data = (void *)&handler; - handler.messageSize = 0; - handler.writePtr = 0; - handler.lastActivity = OSUtils::now(); - - try { - handler.writeSize = Utils::snprintf(handler.writeBuf,sizeof(handler.writeBuf),"%s %s HTTP/1.1\r\n",method,path); - for(std::map::const_iterator h(requestHeaders.begin());h!=requestHeaders.end();++h) - handler.writeSize += Utils::snprintf(handler.writeBuf + handler.writeSize,sizeof(handler.writeBuf) - handler.writeSize,"%s: %s\r\n",h->first.c_str(),h->second.c_str()); - handler.writeSize += Utils::snprintf(handler.writeBuf + handler.writeSize,sizeof(handler.writeBuf) - handler.writeSize,"\r\n"); - if ((requestBody)&&(requestBodyLength)) { - if ((handler.writeSize + requestBodyLength) > sizeof(handler.writeBuf)) { - responseBody = "request too large"; - return 0; - } - memcpy(handler.writeBuf + handler.writeSize,requestBody,requestBodyLength); - handler.writeSize += requestBodyLength; - } - } catch ( ... ) { - responseBody = "request too large"; - return 0; - } - - handler.maxResponseSize = maxResponseSize; - handler.responseHeaders = &responseHeaders; - handler.responseBody = &responseBody; - handler.error = false; - handler.done = false; - - Phy phy(&handler,true,true); - - bool instantConnect = false; - handler.phy = &phy; - handler.sock = phy.tcpConnect((const struct sockaddr *)remoteAddress,instantConnect,(void *)0,true); - if (!handler.sock) { - responseBody = "connection failed (2)"; - return 0; - } - - while (!handler.done) { - phy.poll(timeout / 2); - if ((timeout)&&((unsigned long)(OSUtils::now() - handler.lastActivity) > timeout)) { - phy.close(handler.sock); - responseBody = "timed out"; - return 0; - } - } - - return ((handler.error) ? 0 : ((handler.parser.http_errno != HPE_OK) ? 0 : handler.parser.status_code)); - } catch (std::exception &exc) { - responseBody = exc.what(); - return 0; - } catch ( ... ) { - responseBody = "unknown exception"; - return 0; - } -} - -} // namespace ZeroTier diff --git a/zto/osdep/Http.hpp b/zto/osdep/Http.hpp deleted file mode 100644 index 1ecf4ee..0000000 --- a/zto/osdep/Http.hpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_HTTP_HPP -#define ZT_HTTP_HPP - -#include -#include -#include - -#if defined(_WIN32) || defined(_WIN64) -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -#endif - -namespace ZeroTier { - -/** - * Simple synchronous HTTP client used for updater and cli - */ -class Http -{ -public: - /** - * Make HTTP GET request - * - * The caller must set all headers, including Host. - * - * @return HTTP status code or 0 on error (responseBody will contain error message) - */ - static inline unsigned int GET( - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - std::map &responseHeaders, - std::string &responseBody) - { - return _do( - "GET", - maxResponseSize, - timeout, - remoteAddress, - path, - requestHeaders, - (const void *)0, - 0, - responseHeaders, - responseBody); - } - - /** - * Make HTTP DELETE request - * - * The caller must set all headers, including Host. - * - * @return HTTP status code or 0 on error (responseBody will contain error message) - */ - static inline unsigned int DEL( - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - std::map &responseHeaders, - std::string &responseBody) - { - return _do( - "DELETE", - maxResponseSize, - timeout, - remoteAddress, - path, - requestHeaders, - (const void *)0, - 0, - responseHeaders, - responseBody); - } - - /** - * Make HTTP POST request - * - * It is the responsibility of the caller to set all headers. With POST, the - * Content-Length and Content-Type headers must be set or the POST will not - * work. - * - * @return HTTP status code or 0 on error (responseBody will contain error message) - */ - static inline unsigned int POST( - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - const void *postData, - unsigned long postDataLength, - std::map &responseHeaders, - std::string &responseBody) - { - return _do( - "POST", - maxResponseSize, - timeout, - remoteAddress, - path, - requestHeaders, - postData, - postDataLength, - responseHeaders, - responseBody); - } - -private: - static unsigned int _do( - const char *method, - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - const void *requestBody, - unsigned long requestBodyLength, - std::map &responseHeaders, - std::string &responseBody); -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/LinuxEthernetTap.cpp b/zto/osdep/LinuxEthernetTap.cpp deleted file mode 100644 index c4b978e..0000000 --- a/zto/osdep/LinuxEthernetTap.cpp +++ /dev/null @@ -1,483 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" -#include "../node/Dictionary.hpp" -#include "OSUtils.hpp" -#include "LinuxEthernetTap.hpp" - -// ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); - -namespace ZeroTier { - -static Mutex __tapCreateLock; - -LinuxEthernetTap::LinuxEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg) : - _handler(handler), - _arg(arg), - _nwid(nwid), - _homePath(homePath), - _mtu(mtu), - _fd(0), - _enabled(true) -{ - char procpath[128],nwids[32]; - struct stat sbuf; - - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid); - - Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally - - if (mtu > 2800) - throw std::runtime_error("max tap MTU is 2800"); - - _fd = ::open("/dev/net/tun",O_RDWR); - if (_fd <= 0) { - _fd = ::open("/dev/tun",O_RDWR); - if (_fd <= 0) - throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno)); - } - - struct ifreq ifr; - memset(&ifr,0,sizeof(ifr)); - - // Try to recall our last device name, or pick an unused one if that fails. - bool recalledDevice = false; - std::string devmapbuf; - Dictionary<8194> devmap; - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmapbuf)) { - devmap.load(devmapbuf.c_str()); - char desiredDevice[128]; - if (devmap.get(nwids,desiredDevice,sizeof(desiredDevice)) > 0) { - Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),desiredDevice); - Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); - recalledDevice = (stat(procpath,&sbuf) != 0); - } - } - - if (!recalledDevice) { - int devno = 0; - do { -#ifdef __SYNOLOGY__ - devno+=50; // Arbitrary number to prevent interface name conflicts - Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"eth%d",devno++); -#else - Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"zt%d",devno++); -#endif - Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); - } while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist - } - - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - if (ioctl(_fd,TUNSETIFF,(void *)&ifr) < 0) { - ::close(_fd); - throw std::runtime_error("unable to configure TUN/TAP device for TAP operation"); - } - - _dev = ifr.ifr_name; - - ::ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here - - // Open an arbitrary socket to talk to netlink - int sock = socket(AF_INET,SOCK_DGRAM,0); - if (sock <= 0) { - ::close(_fd); - throw std::runtime_error("unable to open netlink socket"); - } - - // Set MAC address - ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER; - mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data,6); - if (ioctl(sock,SIOCSIFHWADDR,(void *)&ifr) < 0) { - ::close(_fd); - ::close(sock); - throw std::runtime_error("unable to configure TAP hardware (MAC) address"); - return; - } - - // Set MTU - ifr.ifr_ifru.ifru_mtu = (int)mtu; - if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) { - ::close(_fd); - ::close(sock); - throw std::runtime_error("unable to configure TAP MTU"); - } - - if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { - ::close(_fd); - throw std::runtime_error("unable to set flags on file descriptor for TAP device"); - } - - /* Bring interface up */ - if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) { - ::close(_fd); - ::close(sock); - throw std::runtime_error("unable to get TAP interface flags"); - } - ifr.ifr_flags |= IFF_UP; - if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) { - ::close(_fd); - ::close(sock); - throw std::runtime_error("unable to set TAP interface flags"); - } - - ::close(sock); - - // Set close-on-exec so that devices cannot persist if we fork/exec for update - ::fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); - - (void)::pipe(_shutdownSignalPipe); - - devmap.erase(nwids); - devmap.add(nwids,_dev.c_str()); - OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),(const void *)devmap.data(),devmap.sizeBytes()); - - _thread = Thread::start(this); -} - -LinuxEthernetTap::~LinuxEthernetTap() -{ - (void)::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit - Thread::join(_thread); - ::close(_fd); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); -} - -void LinuxEthernetTap::setEnabled(bool en) -{ - _enabled = en; -} - -bool LinuxEthernetTap::enabled() const -{ - return _enabled; -} - -static bool ___removeIp(const std::string &_dev,const InetAddress &ip) -{ - long cpid = (long)vfork(); - if (cpid == 0) { - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1); - ::execlp("ip","ip","addr","del",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0); - ::_exit(-1); - } else { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } -} - -#ifdef __SYNOLOGY__ -bool LinuxEthernetTap::addIpSyn(std::vector ips) -{ - // Here we fill out interface config (ifcfg-dev) to prevent it from being killed - std::string filepath = "/etc/sysconfig/network-scripts/ifcfg-"+_dev; - std::string cfg_contents = "DEVICE="+_dev+"\nBOOTPROTO=static"; - int ip4=0,ip6=0,ip4_tot=0,ip6_tot=0; - - long cpid = (long)vfork(); - if (cpid == 0) { - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1); - // We must know if there is at least (one) of each protocol version so we - // can properly enumerate address/netmask combinations in the ifcfg-dev file - for(int i=0; i<(int)ips.size(); i++) { - if (ips[i].isV4()) - ip4_tot++; - else - ip6_tot++; - } - // Assemble and write contents of ifcfg-dev file - for(int i=0; i<(int)ips.size(); i++) { - if (ips[i].isV4()) { - std::string numstr4 = ip4_tot > 1 ? std::to_string(ip4) : ""; - cfg_contents += "\nIPADDR"+numstr4+"="+ips[i].toIpString() - + "\nNETMASK"+numstr4+"="+ips[i].netmask().toIpString()+"\n"; - ip4++; - } - else { - std::string numstr6 = ip6_tot > 1 ? std::to_string(ip6) : ""; - cfg_contents += "\nIPV6ADDR"+numstr6+"="+ips[i].toIpString() - + "\nNETMASK"+numstr6+"="+ips[i].netmask().toIpString()+"\n"; - ip6++; - } - } - OSUtils::writeFile(filepath.c_str(), cfg_contents.c_str(), cfg_contents.length()); - // Finaly, add IPs - for(int i=0; i<(int)ips.size(); i++){ - if (ips[i].isV4()) - ::execlp("ip","ip","addr","add",ips[i].toString().c_str(),"broadcast",ips[i].broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0); - else - ::execlp("ip","ip","addr","add",ips[i].toString().c_str(),"dev",_dev.c_str(),(const char *)0); - } - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - return true; -} -#endif // __SYNOLOGY__ - -bool LinuxEthernetTap::addIp(const InetAddress &ip) -{ - if (!ip) - return false; - - std::vector allIps(ips()); - if (std::binary_search(allIps.begin(),allIps.end(),ip)) - return true; - - // Remove and reconfigure if address is the same but netmask is different - for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { - if (i->ipsEqual(ip)) - ___removeIp(_dev,*i); - } - - long cpid = (long)vfork(); - if (cpid == 0) { - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1); - if (ip.isV4()) { - ::execlp("ip","ip","addr","add",ip.toString().c_str(),"broadcast",ip.broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0); - } else { - ::execlp("ip","ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0); - } - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - - return false; -} - -bool LinuxEthernetTap::removeIp(const InetAddress &ip) -{ - if (!ip) - return true; - std::vector allIps(ips()); - if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) { - if (___removeIp(_dev,ip)) - return true; - } - return false; -} - -std::vector LinuxEthernetTap::ips() const -{ - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::vector(); - - std::vector r; - - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } - - if (ifa) - freeifaddrs(ifa); - - std::sort(r.begin(),r.end()); - r.erase(std::unique(r.begin(),r.end()),r.end()); - - return r; -} - -void LinuxEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - char putBuf[8194]; - if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { - to.copyTo(putBuf,6); - from.copyTo(putBuf + 6,6); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - (void)::write(_fd,putBuf,len); - } -} - -std::string LinuxEthernetTap::deviceName() const -{ - return _dev; -} - -void LinuxEthernetTap::setFriendlyName(const char *friendlyName) -{ -} - -void LinuxEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) -{ - char *ptr,*ptr2; - unsigned char mac[6]; - std::vector newGroups; - - int fd = ::open("/proc/net/dev_mcast",O_RDONLY); - if (fd > 0) { - char buf[131072]; - int n = (int)::read(fd,buf,sizeof(buf)); - if ((n > 0)&&(n < (int)sizeof(buf))) { - buf[n] = (char)0; - for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) { - int fno = 0; - char *devname = (char *)0; - char *mcastmac = (char *)0; - for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) { - if (fno == 1) - devname = f; - else if (fno == 4) - mcastmac = f; - ++fno; - } - if ((devname)&&(!strcmp(devname,_dev.c_str()))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6)) - newGroups.push_back(MulticastGroup(MAC(mac,6),0)); - } - } - ::close(fd); - } - - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - - std::sort(newGroups.begin(),newGroups.end()); - newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end()); - - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } - - _multicastGroups.swap(newGroups); -} - -void LinuxEthernetTap::threadMain() - throw() -{ - fd_set readfds,nullfds; - MAC to,from; - int n,nfds,r; - char getBuf[8194]; - - Thread::sleep(500); - - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; - - r = 0; - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_fd,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); - - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread - break; - - if (FD_ISSET(_fd,&readfds)) { - n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r); - if (n < 0) { - if ((errno != EINTR)&&(errno != ETIMEDOUT)) - break; - } else { - // Some tap drivers like to send the ethernet frame and the - // payload in two chunks, so handle that by accumulating - // data until we have at least a frame. - r += n; - if (r > 14) { - if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms - r = _mtu + 14; - - if (_enabled) { - to.setTo(getBuf,6); - from.setTo(getBuf + 6,6); - unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); - // TODO: VLAN support - _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); - } - - r = 0; - } - } - } - } -} - -} // namespace ZeroTier diff --git a/zto/osdep/LinuxEthernetTap.hpp b/zto/osdep/LinuxEthernetTap.hpp deleted file mode 100644 index a2a00a7..0000000 --- a/zto/osdep/LinuxEthernetTap.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_LINUXETHERNETTAP_HPP -#define ZT_LINUXETHERNETTAP_HPP - -#include -#include - -#include -#include -#include - -#include "../node/MulticastGroup.hpp" -#include "Thread.hpp" - -namespace ZeroTier { - -/** - * Linux Ethernet tap using kernel tun/tap driver - */ -class LinuxEthernetTap -{ -public: - LinuxEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); - - ~LinuxEthernetTap(); - - void setEnabled(bool en); - bool enabled() const; - bool addIp(const InetAddress &ip); -#ifdef __SYNOLOGY__ - bool addIpSyn(std::vector ips); -#endif - bool removeIp(const InetAddress &ip); - std::vector ips() const; - void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - std::string deviceName() const; - void setFriendlyName(const char *friendlyName); - void scanMulticastGroups(std::vector &added,std::vector &removed); - - void threadMain() - throw(); - -private: - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - uint64_t _nwid; - Thread _thread; - std::string _homePath; - std::string _dev; - std::vector _multicastGroups; - unsigned int _mtu; - int _fd; - int _shutdownSignalPipe[2]; - volatile bool _enabled; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/ManagedRoute.cpp b/zto/osdep/ManagedRoute.cpp deleted file mode 100644 index 1fc6c78..0000000 --- a/zto/osdep/ManagedRoute.cpp +++ /dev/null @@ -1,543 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "../node/Constants.hpp" - -#include -#include -#include -#include - -#ifdef __WINDOWS__ -#include -#include -#include -#include -#endif - -#ifdef __UNIX_LIKE__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __BSD__ -#include -#include -#endif -#include -#endif - -#include -#include -#include - -#include "ManagedRoute.hpp" - -#define ZT_BSD_ROUTE_CMD "/sbin/route" -#define ZT_LINUX_IP_COMMAND "/sbin/ip" -#define ZT_LINUX_IP_COMMAND_2 "/usr/sbin/ip" - -// NOTE: BSD is mostly tested on Apple/Mac but is likely to work on other BSD too - -namespace ZeroTier { - -namespace { - -// Fork a target into two more specific targets e.g. 0.0.0.0/0 -> 0.0.0.0/1, 128.0.0.0/1 -// If the target is already maximally-specific, 'right' will be unchanged and 'left' will be 't' -static void _forkTarget(const InetAddress &t,InetAddress &left,InetAddress &right) -{ - const unsigned int bits = t.netmaskBits() + 1; - left = t; - if (t.ss_family == AF_INET) { - if (bits <= 32) { - left.setPort(bits); - right = t; - reinterpret_cast(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits))); - right.setPort(bits); - } else { - right.zero(); - } - } else if (t.ss_family == AF_INET6) { - if (bits <= 128) { - left.setPort(bits); - right = t; - uint8_t *b = reinterpret_cast(reinterpret_cast(&right)->sin6_addr.s6_addr); - b[bits / 8] ^= 1 << (8 - (bits % 8)); - right.setPort(bits); - } else { - right.zero(); - } - } -} - -struct _RTE -{ - InetAddress target; - InetAddress via; - char device[128]; - int metric; - bool ifscope; -}; - -#ifdef __BSD__ // ------------------------------------------------------------ -#define ZT_ROUTING_SUPPORT_FOUND 1 - -static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains) -{ - std::vector<_RTE> rtes; - int mib[6]; - size_t needed; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = 0; - mib[4] = NET_RT_DUMP; - mib[5] = 0; - if (!sysctl(mib,6,NULL,&needed,NULL,0)) { - if (needed <= 0) - return rtes; - - char *buf = (char *)::malloc(needed); - if (buf) { - if (!sysctl(mib,6,buf,&needed,NULL,0)) { - struct rt_msghdr *rtm; - for(char *next=buf,*end=buf+needed;nextrtm_msglen; - - InetAddress sa_t,sa_v; - int deviceIndex = -9999; - - if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) { - int which = 0; - while (saptr < saend) { - struct sockaddr *sa = (struct sockaddr *)saptr; - unsigned int salen = sa->sa_len; - if (!salen) - break; - - // Skip missing fields in rtm_addrs bit field - while ((rtm->rtm_addrs & 1) == 0) { - rtm->rtm_addrs >>= 1; - ++which; - if (which > 6) - break; - } - if (which > 6) - break; - - rtm->rtm_addrs >>= 1; - switch(which++) { - case 0: - //printf("RTA_DST\n"); - if (sa->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) { - // BSD uses this fucking strange in-band signaling method to encode device scope IDs for IPv6 addresses... probably a holdover from very early versions of the spec. - unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff); - sin6->sin6_addr.s6_addr[2] = 0; - sin6->sin6_addr.s6_addr[3] = 0; - if (!sin6->sin6_scope_id) - sin6->sin6_scope_id = interfaceIndex; - } - } - sa_t = *sa; - break; - case 1: - //printf("RTA_GATEWAY\n"); - switch(sa->sa_family) { - case AF_LINK: - deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index; - break; - case AF_INET: - case AF_INET6: - sa_v = *sa; - break; - } - break; - case 2: { - //printf("RTA_NETMASK\n"); - if (sa_t.ss_family == AF_INET6) { - salen = sizeof(struct sockaddr_in6); - unsigned int bits = 0; - for(int i=0;i<16;++i) { - unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i]; - if (c == 0xff) - bits += 8; - else break; - } - sa_t.setPort(bits); - } else if (sa_t.ss_family == AF_INET) { - salen = sizeof(struct sockaddr_in); - sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr)); - } - } break; - /* - case 3: - //printf("RTA_GENMASK\n"); - break; - case 4: - //printf("RTA_IFP\n"); - break; - case 5: - //printf("RTA_IFA\n"); - break; - case 6: - //printf("RTA_AUTHOR\n"); - break; - */ - } - - saptr += salen; - } - - if (((contains)&&(sa_t.containsAddress(target)))||(sa_t == target)) { - rtes.push_back(_RTE()); - rtes.back().target = sa_t; - rtes.back().via = sa_v; - if (deviceIndex >= 0) { - if_indextoname(deviceIndex,rtes.back().device); - } else { - rtes.back().device[0] = (char)0; - } - rtes.back().metric = ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount; - } - } - - next = saend; - } - } - - ::free(buf); - } - } - - return rtes; -} - -static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *ifscope,const char *localInterface) -{ - //printf("route %s %s %s %s %s\n",op,target.toString().c_str(),(via) ? via.toString().c_str() : "(null)",(ifscope) ? ifscope : "(null)",(localInterface) ? localInterface : "(null)"); - long p = (long)fork(); - if (p > 0) { - int exitcode = -1; - ::waitpid(p,&exitcode,0); - } else if (p == 0) { - ::close(STDOUT_FILENO); - ::close(STDERR_FILENO); - if (via) { - if ((ifscope)&&(ifscope[0])) { - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),via.toIpString().c_str(),(const char *)0); - } else { - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),via.toIpString().c_str(),(const char *)0); - } - } else if ((localInterface)&&(localInterface[0])) { - if ((ifscope)&&(ifscope[0])) { - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),"-interface",localInterface,(const char *)0); - } else { - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),"-interface",localInterface,(const char *)0); - } - } - ::_exit(-1); - } -} - -#endif // __BSD__ ------------------------------------------------------------ - -#ifdef __LINUX__ // ---------------------------------------------------------- -#define ZT_ROUTING_SUPPORT_FOUND 1 - -static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *localInterface) -{ - long p = (long)fork(); - if (p > 0) { - int exitcode = -1; - ::waitpid(p,&exitcode,0); - } else if (p == 0) { - ::close(STDOUT_FILENO); - ::close(STDERR_FILENO); - if (via) { - ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString().c_str(),"via",via.toIpString().c_str(),(const char *)0); - ::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString().c_str(),"via",via.toIpString().c_str(),(const char *)0); - } else if ((localInterface)&&(localInterface[0])) { - ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString().c_str(),"dev",localInterface,(const char *)0); - ::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString().c_str(),"dev",localInterface,(const char *)0); - } - ::_exit(-1); - } -} - -#endif // __LINUX__ ---------------------------------------------------------- - -#ifdef __WINDOWS__ // -------------------------------------------------------- -#define ZT_ROUTING_SUPPORT_FOUND 1 - -static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &interfaceIndex,const InetAddress &target,const InetAddress &via) -{ - MIB_IPFORWARD_ROW2 rtrow; - InitializeIpForwardEntry(&rtrow); - rtrow.InterfaceLuid.Value = interfaceLuid.Value; - rtrow.InterfaceIndex = interfaceIndex; - if (target.ss_family == AF_INET) { - rtrow.DestinationPrefix.Prefix.si_family = AF_INET; - rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; - rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&target)->sin_addr.S_un.S_addr; - if (via.ss_family == AF_INET) { - rtrow.NextHop.si_family = AF_INET; - rtrow.NextHop.Ipv4.sin_family = AF_INET; - rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&via)->sin_addr.S_un.S_addr; - } - } else if (target.ss_family == AF_INET6) { - rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; - rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; - memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,reinterpret_cast(&target)->sin6_addr.u.Byte,16); - if (via.ss_family == AF_INET6) { - rtrow.NextHop.si_family = AF_INET6; - rtrow.NextHop.Ipv6.sin6_family = AF_INET6; - memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte,reinterpret_cast(&via)->sin6_addr.u.Byte,16); - } - } else { - return false; - } - rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); - rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength; - rtrow.ValidLifetime = 0xffffffff; - rtrow.PreferredLifetime = 0xffffffff; - rtrow.Metric = -1; - rtrow.Protocol = MIB_IPPROTO_NETMGMT; - rtrow.Loopback = FALSE; - rtrow.AutoconfigureAddress = FALSE; - rtrow.Publish = FALSE; - rtrow.Immortal = FALSE; - rtrow.Age = 0; - rtrow.Origin = NlroManual; - if (del) { - return (DeleteIpForwardEntry2(&rtrow) == NO_ERROR); - } else { - NTSTATUS r = CreateIpForwardEntry2(&rtrow); - if (r == NO_ERROR) { - return true; - } else if (r == ERROR_OBJECT_ALREADY_EXISTS) { - return (SetIpForwardEntry2(&rtrow) == NO_ERROR); - } else { - return false; - } - } -} - -#endif // __WINDOWS__ -------------------------------------------------------- - -#ifndef ZT_ROUTING_SUPPORT_FOUND -#error "ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a Github pull request if you do this for a new OS." -#endif - -} // anonymous namespace - -/* Linux NOTE: for default route override, some Linux distributions will - * require a change to the rp_filter parameter. A value of '1' will prevent - * default route override from working properly. - * - * sudo sysctl -w net.ipv4.conf.all.rp_filter=2 - * - * Add to /etc/sysctl.conf or /etc/sysctl.d/... to make permanent. - * - * This is true of CentOS/RHEL 6+ and possibly others. This is because - * Linux default route override implies asymmetric routes, which then - * trigger Linux's "martian packet" filter. */ - -bool ManagedRoute::sync() -{ -#ifdef __WINDOWS__ - NET_LUID interfaceLuid; - interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute - NET_IFINDEX interfaceIndex = -1; - if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR) - return false; -#endif - - // Generate two more specific routes than target with one extra bit - InetAddress leftt,rightt; - _forkTarget(_target,leftt,rightt); - -#ifdef __BSD__ // ------------------------------------------------------------ - - // Find lowest metric system route that this route should override (if any) - InetAddress newSystemVia; - char newSystemDevice[128]; - newSystemDevice[0] = (char)0; - int systemMetric = 9999999; - std::vector<_RTE> rtes(_getRTEs(_target,false)); - for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { - if (r->via) { - if ( ((!newSystemVia)||(r->metric < systemMetric)) && (strcmp(r->device,_device) != 0) ) { - newSystemVia = r->via; - Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device); - systemMetric = r->metric; - } - } - } - - // Get device corresponding to route if we don't have that already - if ((newSystemVia)&&(!newSystemDevice[0])) { - rtes = _getRTEs(newSystemVia,true); - for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { - if ( (r->device[0]) && (strcmp(r->device,_device) != 0) ) { - Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device); - break; - } - } - } - if (!newSystemDevice[0]) - newSystemVia.zero(); - - // Shadow system route if it exists, also delete any obsolete shadows - // and replace them with the new state. sync() is called periodically to - // allow us to do that if underlying connectivity changes. - if ((_systemVia != newSystemVia)||(strcmp(_systemDevice,newSystemDevice) != 0)) { - if (_systemVia) { - _routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0); - if (rightt) - _routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0); - } - - _systemVia = newSystemVia; - Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice); - - if (_systemVia) { - _routeCmd("add",leftt,_systemVia,_systemDevice,(const char *)0); - _routeCmd("change",leftt,_systemVia,_systemDevice,(const char *)0); - if (rightt) { - _routeCmd("add",rightt,_systemVia,_systemDevice,(const char *)0); - _routeCmd("change",rightt,_systemVia,_systemDevice,(const char *)0); - } - } - } - - if (!_applied.count(leftt)) { - _applied[leftt] = false; // not ifscoped - _routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device); - _routeCmd("change",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device); - } - if ((rightt)&&(!_applied.count(rightt))) { - _applied[rightt] = false; // not ifscoped - _routeCmd("add",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device); - _routeCmd("change",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device); - } - - // Create a device-bound default target if there is none in the system. This - // is to allow e.g. IPv6 default route to work even if there is no native - // IPv6 on your LAN. - /* - if (_target.isDefaultRoute()) { - if (_systemVia) { - if (_applied.count(_target)) { - _applied.erase(_target); - _routeCmd("delete",_target,_via,_device,(_via) ? (const char *)0 : _device); - } - } else { - if (!_applied.count(_target)) { - _applied[_target] = true; // ifscoped - _routeCmd("add",_target,_via,_device,(_via) ? (const char *)0 : _device); - _routeCmd("change",_target,_via,_device,(_via) ? (const char *)0 : _device); - } - } - } - */ - -#endif // __BSD__ ------------------------------------------------------------ - -#ifdef __LINUX__ // ---------------------------------------------------------- - - if (!_applied.count(leftt)) { - _applied[leftt] = false; // boolean unused - _routeCmd("replace",leftt,_via,(_via) ? (const char *)0 : _device); - } - if ((rightt)&&(!_applied.count(rightt))) { - _applied[rightt] = false; // boolean unused - _routeCmd("replace",rightt,_via,(_via) ? (const char *)0 : _device); - } - -#endif // __LINUX__ ---------------------------------------------------------- - -#ifdef __WINDOWS__ // -------------------------------------------------------- - - if (!_applied.count(leftt)) { - _applied[leftt] = false; // boolean unused - _winRoute(false,interfaceLuid,interfaceIndex,leftt,_via); - } - if ((rightt)&&(!_applied.count(rightt))) { - _applied[rightt] = false; // boolean unused - _winRoute(false,interfaceLuid,interfaceIndex,rightt,_via); - } - -#endif // __WINDOWS__ -------------------------------------------------------- - - return true; -} - -void ManagedRoute::remove() -{ -#ifdef __WINDOWS__ - NET_LUID interfaceLuid; - interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute - NET_IFINDEX interfaceIndex = -1; - if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR) - return; -#endif - -#ifdef __BSD__ - if (_systemVia) { - InetAddress leftt,rightt; - _forkTarget(_target,leftt,rightt); - _routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0); - if (rightt) - _routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0); - } -#endif // __BSD__ ------------------------------------------------------------ - - for(std::map::iterator r(_applied.begin());r!=_applied.end();++r) { -#ifdef __BSD__ // ------------------------------------------------------------ - _routeCmd("delete",r->first,_via,r->second ? _device : (const char *)0,(_via) ? (const char *)0 : _device); -#endif // __BSD__ ------------------------------------------------------------ - -#ifdef __LINUX__ // ---------------------------------------------------------- - _routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device); -#endif // __LINUX__ ---------------------------------------------------------- - -#ifdef __WINDOWS__ // -------------------------------------------------------- - _winRoute(true,interfaceLuid,interfaceIndex,r->first,_via); -#endif // __WINDOWS__ -------------------------------------------------------- - } - - _target.zero(); - _via.zero(); - _systemVia.zero(); - _device[0] = (char)0; - _systemDevice[0] = (char)0; - _applied.clear(); -} - -} // namespace ZeroTier diff --git a/zto/osdep/ManagedRoute.hpp b/zto/osdep/ManagedRoute.hpp deleted file mode 100644 index fd77a79..0000000 --- a/zto/osdep/ManagedRoute.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef ZT_MANAGEDROUTE_HPP -#define ZT_MANAGEDROUTE_HPP - -#include -#include - -#include "../node/InetAddress.hpp" -#include "../node/Utils.hpp" -#include "../node/SharedPtr.hpp" -#include "../node/AtomicCounter.hpp" -#include "../node/NonCopyable.hpp" - -#include -#include -#include - -namespace ZeroTier { - -/** - * A ZT-managed route that used C++ RAII semantics to automatically clean itself up on deallocate - */ -class ManagedRoute : NonCopyable -{ - friend class SharedPtr; - -public: - ManagedRoute(const InetAddress &target,const InetAddress &via,const char *device) - { - _target = target; - _via = via; - if (via.ss_family == AF_INET) - _via.setPort(32); - else if (via.ss_family == AF_INET6) - _via.setPort(128); - Utils::scopy(_device,sizeof(_device),device); - _systemDevice[0] = (char)0; - } - - ~ManagedRoute() - { - this->remove(); - } - - /** - * Set or update currently set route - * - * This must be called periodically for routes that shadow others so that - * shadow routes can be updated. In some cases it has no effect - * - * @return True if route add/update was successful - */ - bool sync(); - - /** - * Remove and clear this ManagedRoute - * - * This does nothing if this ManagedRoute is not set or has already been - * removed. If this is not explicitly called it is called automatically on - * destruct. - */ - void remove(); - - inline const InetAddress &target() const { return _target; } - inline const InetAddress &via() const { return _via; } - inline const char *device() const { return _device; } - -private: - InetAddress _target; - InetAddress _via; - InetAddress _systemVia; // for route overrides - std::map _applied; // routes currently applied - char _device[128]; - char _systemDevice[128]; // for route overrides - - AtomicCounter __refCount; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/NeighborDiscovery.cpp b/zto/osdep/NeighborDiscovery.cpp deleted file mode 100644 index 4f63631..0000000 --- a/zto/osdep/NeighborDiscovery.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "NeighborDiscovery.hpp" -#include "OSUtils.hpp" - -#include "../include/ZeroTierOne.h" - -#include - -namespace ZeroTier { - -uint16_t calc_checksum (uint16_t *addr, int len) -{ - int count = len; - uint32_t sum = 0; - uint16_t answer = 0; - - // Sum up 2-byte values until none or only one byte left. - while (count > 1) { - sum += *(addr++); - count -= 2; - } - - // Add left-over byte, if any. - if (count > 0) { - sum += *(uint8_t *) addr; - } - - // Fold 32-bit sum into 16 bits; we lose information by doing this, - // increasing the chances of a collision. - // sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits) - while (sum >> 16) { - sum = (sum & 0xffff) + (sum >> 16); - } - - // Checksum is one's compliment of sum. - answer = ~sum; - - return (answer); -} - -struct _pseudo_header { - uint8_t sourceAddr[16]; - uint8_t targetAddr[16]; - uint32_t length; - uint8_t zeros[3]; - uint8_t next; // 58 -}; - -struct _option { - _option(int optionType) - : type(optionType) - , length(8) - { - memset(mac, 0, sizeof(mac)); - } - - uint8_t type; - uint8_t length; - uint8_t mac[6]; -}; - -struct _neighbor_solicitation { - _neighbor_solicitation() - : type(135) - , code(0) - , checksum(0) - , option(1) - { - memset(&reserved, 0, sizeof(reserved)); - memset(target, 0, sizeof(target)); - } - - void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) { - _pseudo_header ph; - memset(&ph, 0, sizeof(_pseudo_header)); - const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp; - const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp; - - memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr)); - memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr)); - ph.next = 58; - ph.length = htonl(sizeof(_neighbor_solicitation)); - - size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_solicitation); - uint8_t *tmp = (uint8_t*)malloc(len); - memcpy(tmp, &ph, sizeof(_pseudo_header)); - memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_solicitation)); - - checksum = calc_checksum((uint16_t*)tmp, (int)len); - - free(tmp); - tmp = NULL; - } - - uint8_t type; // 135 - uint8_t code; // 0 - uint16_t checksum; - uint32_t reserved; - uint8_t target[16]; - _option option; -}; - -struct _neighbor_advertisement { - _neighbor_advertisement() - : type(136) - , code(0) - , checksum(0) - , rso(0x40) - , option(2) - { - memset(padding, 0, sizeof(padding)); - memset(target, 0, sizeof(target)); - } - - void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) { - _pseudo_header ph; - memset(&ph, 0, sizeof(_pseudo_header)); - const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp; - const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp; - - memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr)); - memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr)); - ph.next = 58; - ph.length = htonl(sizeof(_neighbor_advertisement)); - - size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_advertisement); - uint8_t *tmp = (uint8_t*)malloc(len); - memcpy(tmp, &ph, sizeof(_pseudo_header)); - memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_advertisement)); - - checksum = calc_checksum((uint16_t*)tmp, (int)len); - - free(tmp); - tmp = NULL; - } - - uint8_t type; // 136 - uint8_t code; // 0 - uint16_t checksum; - uint8_t rso; - uint8_t padding[3]; - uint8_t target[16]; - _option option; -}; - -NeighborDiscovery::NeighborDiscovery() - : _cache(256) - , _lastCleaned(OSUtils::now()) -{} - -void NeighborDiscovery::addLocal(const sockaddr_storage &address, const MAC &mac) -{ - _NDEntry &e = _cache[InetAddress(address)]; - e.lastQuerySent = 0; - e.lastResponseReceived = 0; - e.mac = mac; - e.local = true; -} - -void NeighborDiscovery::remove(const sockaddr_storage &address) -{ - _cache.erase(InetAddress(address)); -} - -sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest) -{ - assert(sizeof(_neighbor_solicitation) == 28); - assert(sizeof(_neighbor_advertisement) == 32); - - const uint64_t now = OSUtils::now(); - sockaddr_storage ip = ZT_SOCKADDR_NULL; - - if (len >= sizeof(_neighbor_solicitation) && nd[0] == 0x87) { - // respond to Neighbor Solicitation request for local address - _neighbor_solicitation solicitation; - memcpy(&solicitation, nd, len); - InetAddress targetAddress(solicitation.target, 16, 0); - _NDEntry *targetEntry = _cache.get(targetAddress); - if (targetEntry && targetEntry->local) { - _neighbor_advertisement adv; - targetEntry->mac.copyTo(adv.option.mac, 6); - memcpy(adv.target, solicitation.target, 16); - adv.calculateChecksum(localIp, targetAddress); - memcpy(response, &adv, sizeof(_neighbor_advertisement)); - responseLen = sizeof(_neighbor_advertisement); - responseDest.setTo(solicitation.option.mac, 6); - } - } else if (len >= sizeof(_neighbor_advertisement) && nd[0] == 0x88) { - _neighbor_advertisement adv; - memcpy(&adv, nd, len); - InetAddress responseAddress(adv.target, 16, 0); - _NDEntry *queryEntry = _cache.get(responseAddress); - if(queryEntry && !queryEntry->local && (now - queryEntry->lastQuerySent <= ZT_ND_QUERY_MAX_TTL)) { - queryEntry->lastResponseReceived = now; - queryEntry->mac.setTo(adv.option.mac, 6); - ip = responseAddress; - } - } - - if ((now - _lastCleaned) >= ZT_ND_EXPIRE) { - _lastCleaned = now; - Hashtable::Iterator i(_cache); - InetAddress *k = NULL; - _NDEntry *v = NULL; - while (i.next(k, v)) { - if(!v->local && (now - v->lastResponseReceived) >= ZT_ND_EXPIRE) { - _cache.erase(*k); - } - } - } - - return ip; -} - -MAC NeighborDiscovery::query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest) -{ - const uint64_t now = OSUtils::now(); - - InetAddress localAddress(localIp); - localAddress.setPort(0); - InetAddress targetAddress(targetIp); - targetAddress.setPort(0); - - _NDEntry &e = _cache[targetAddress]; - - if ( (e.mac && ((now - e.lastResponseReceived) >= (ZT_ND_EXPIRE / 3))) || - (!e.mac && ((now - e.lastQuerySent) >= ZT_ND_QUERY_INTERVAL))) { - e.lastQuerySent = now; - - _neighbor_solicitation ns; - memcpy(ns.target, targetAddress.rawIpData(), 16); - localMac.copyTo(ns.option.mac, 6); - ns.calculateChecksum(localIp, targetIp); - if (e.mac) { - queryDest = e.mac; - } else { - queryDest = (uint64_t)0xffffffffffffULL; - } - } else { - queryLen = 0; - queryDest.zero(); - } - - return e.mac; -} - -} diff --git a/zto/osdep/NeighborDiscovery.hpp b/zto/osdep/NeighborDiscovery.hpp deleted file mode 100644 index 47831bd..0000000 --- a/zto/osdep/NeighborDiscovery.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_NEIGHBORDISCOVERY_HPP -#define ZT_NEIGHBORDISCOVERY_HPP - -#include "../node/Hashtable.hpp" -#include "../node/MAC.hpp" -#include "../node/InetAddress.hpp" - - -#define ZT_ND_QUERY_INTERVAL 2000 - -#define ZT_ND_QUERY_MAX_TTL 5000 - -#define ZT_ND_EXPIRE 600000 - - -namespace ZeroTier { - -class NeighborDiscovery -{ -public: - NeighborDiscovery(); - - /** - * Set a local IP entry that we should respond to Neighbor Requests withPrefix64k - * - * @param mac Our local MAC address - * @param ip Our IPv6 address - */ - void addLocal(const sockaddr_storage &address, const MAC &mac); - - /** - * Delete a local IP entry or cached Neighbor entry - * - * @param address IPv6 address to remove - */ - void remove(const sockaddr_storage &address); - - sockaddr_storage processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest); - - MAC query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest); - -private: - struct _NDEntry - { - _NDEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false) {} - uint64_t lastQuerySent; - uint64_t lastResponseReceived; - MAC mac; - bool local; - }; - - Hashtable _cache; - uint64_t _lastCleaned; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/OSUtils.cpp b/zto/osdep/OSUtils.cpp deleted file mode 100644 index 33e143d..0000000 --- a/zto/osdep/OSUtils.cpp +++ /dev/null @@ -1,470 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" - -#ifdef __UNIX_LIKE__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#ifdef __WINDOWS__ -#include -#include -#include -#include -#include -#endif - -#include "OSUtils.hpp" - -namespace ZeroTier { - -#ifdef __UNIX_LIKE__ -bool OSUtils::redirectUnixOutputs(const char *stdoutPath,const char *stderrPath) - throw() -{ - int fdout = ::open(stdoutPath,O_WRONLY|O_CREAT,0600); - if (fdout > 0) { - int fderr; - if (stderrPath) { - fderr = ::open(stderrPath,O_WRONLY|O_CREAT,0600); - if (fderr <= 0) { - ::close(fdout); - return false; - } - } else fderr = fdout; - ::close(STDOUT_FILENO); - ::close(STDERR_FILENO); - ::dup2(fdout,STDOUT_FILENO); - ::dup2(fderr,STDERR_FILENO); - return true; - } - return false; -} -#endif // __UNIX_LIKE__ - -std::vector OSUtils::listDirectory(const char *path) -{ - std::vector r; - -#ifdef __WINDOWS__ - HANDLE hFind; - WIN32_FIND_DATAA ffd; - if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) { - do { - if ((strcmp(ffd.cFileName,"."))&&(strcmp(ffd.cFileName,".."))&&((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) - r.push_back(std::string(ffd.cFileName)); - } while (FindNextFileA(hFind,&ffd)); - FindClose(hFind); - } -#else - struct dirent de; - struct dirent *dptr; - DIR *d = opendir(path); - if (!d) - return r; - dptr = (struct dirent *)0; - for(;;) { - if (readdir_r(d,&de,&dptr)) - break; - if (dptr) { - if ((strcmp(dptr->d_name,"."))&&(strcmp(dptr->d_name,".."))&&(dptr->d_type != DT_DIR)) - r.push_back(std::string(dptr->d_name)); - } else break; - } - closedir(d); -#endif - - return r; -} - -long OSUtils::cleanDirectory(const char *path,const uint64_t olderThan) -{ - long cleaned = 0; - -#ifdef __WINDOWS__ - HANDLE hFind; - WIN32_FIND_DATAA ffd; - LARGE_INTEGER date,adjust; - adjust.QuadPart = 11644473600000 * 10000; - char tmp[4096]; - if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) { - do { - if ((strcmp(ffd.cFileName,"."))&&(strcmp(ffd.cFileName,".."))&&((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) { - date.HighPart = ffd.ftLastWriteTime.dwHighDateTime; - date.LowPart = ffd.ftLastWriteTime.dwLowDateTime; - if (date.QuadPart > 0) { - date.QuadPart -= adjust.QuadPart; - if ((uint64_t)((date.QuadPart / 10000000) * 1000) < olderThan) { - Utils::snprintf(tmp, sizeof(tmp), "%s\\%s", path, ffd.cFileName); - if (DeleteFileA(tmp)) - ++cleaned; - } - } - } - } while (FindNextFileA(hFind,&ffd)); - FindClose(hFind); - } -#else - struct dirent de; - struct dirent *dptr; - struct stat st; - char tmp[4096]; - DIR *d = opendir(path); - if (!d) - return -1; - dptr = (struct dirent *)0; - for(;;) { - if (readdir_r(d,&de,&dptr)) - break; - if (dptr) { - if ((strcmp(dptr->d_name,"."))&&(strcmp(dptr->d_name,".."))&&(dptr->d_type == DT_REG)) { - Utils::snprintf(tmp,sizeof(tmp),"%s/%s",path,dptr->d_name); - if (stat(tmp,&st) == 0) { - uint64_t mt = (uint64_t)(st.st_mtime); - if ((mt > 0)&&((mt * 1000) < olderThan)) { - if (unlink(tmp) == 0) - ++cleaned; - } - } - } - } else break; - } - closedir(d); -#endif - - return cleaned; -} - -bool OSUtils::rmDashRf(const char *path) -{ -#ifdef __WINDOWS__ - HANDLE hFind; - WIN32_FIND_DATAA ffd; - if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) { - do { - if ((strcmp(ffd.cFileName,".") != 0)&&(strcmp(ffd.cFileName,"..") != 0)) { - if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { - if (DeleteFileA((std::string(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str()) == FALSE) - return false; - } else { - if (!rmDashRf((std::string(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str())) - return false; - } - } - } while (FindNextFileA(hFind,&ffd)); - FindClose(hFind); - } - return (RemoveDirectoryA(path) != FALSE); -#else - struct dirent de; - struct dirent *dptr; - DIR *d = opendir(path); - if (!d) - return true; - dptr = (struct dirent *)0; - for(;;) { - if (readdir_r(d,&de,&dptr) != 0) - break; - if (!dptr) - break; - if ((strcmp(dptr->d_name,".") != 0)&&(strcmp(dptr->d_name,"..") != 0)&&(strlen(dptr->d_name) > 0)) { - std::string p(path); - p.push_back(ZT_PATH_SEPARATOR); - p.append(dptr->d_name); - if (unlink(p.c_str()) != 0) { // unlink first will remove symlinks instead of recursing them - if (!rmDashRf(p.c_str())) - return false; - } - } - } - closedir(d); - return (rmdir(path) == 0); -#endif -} - -void OSUtils::lockDownFile(const char *path,bool isDir) -{ -#ifdef __UNIX_LIKE__ - chmod(path,isDir ? 0700 : 0600); -#else -#ifdef __WINDOWS__ - { - STARTUPINFOA startupInfo; - PROCESS_INFORMATION processInfo; - - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /inheritance:d /Q").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove *S-1-5-32-545 /Q").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - } -#endif -#endif -} - -uint64_t OSUtils::getLastModified(const char *path) -{ - struct stat s; - if (stat(path,&s)) - return 0; - return (((uint64_t)s.st_mtime) * 1000ULL); -} - -bool OSUtils::fileExists(const char *path,bool followLinks) -{ - struct stat s; -#ifdef __UNIX_LIKE__ - if (!followLinks) - return (lstat(path,&s) == 0); -#endif - return (stat(path,&s) == 0); -} - -int64_t OSUtils::getFileSize(const char *path) -{ - struct stat s; - if (stat(path,&s)) - return -1; -#ifdef __WINDOWS__ - return s.st_size; -#else - if (S_ISREG(s.st_mode)) - return s.st_size; -#endif - return -1; -} - -bool OSUtils::readFile(const char *path,std::string &buf) -{ - char tmp[1024]; - FILE *f = fopen(path,"rb"); - if (f) { - for(;;) { - long n = (long)fread(tmp,1,sizeof(tmp),f); - if (n > 0) - buf.append(tmp,n); - else break; - } - fclose(f); - return true; - } - return false; -} - -bool OSUtils::writeFile(const char *path,const void *buf,unsigned int len) -{ - FILE *f = fopen(path,"wb"); - if (f) { - if ((long)fwrite(buf,1,len,f) != (long)len) { - fclose(f); - return false; - } else { - fclose(f); - return true; - } - } - return false; -} - -std::vector OSUtils::split(const char *s,const char *const sep,const char *esc,const char *quot) -{ - std::vector fields; - std::string buf; - - if (!esc) - esc = ""; - if (!quot) - quot = ""; - - bool escapeState = false; - char quoteState = 0; - while (*s) { - if (escapeState) { - escapeState = false; - buf.push_back(*s); - } else if (quoteState) { - if (*s == quoteState) { - quoteState = 0; - fields.push_back(buf); - buf.clear(); - } else buf.push_back(*s); - } else { - const char *quotTmp; - if (strchr(esc,*s)) - escapeState = true; - else if ((buf.size() <= 0)&&((quotTmp = strchr(quot,*s)))) - quoteState = *quotTmp; - else if (strchr(sep,*s)) { - if (buf.size() > 0) { - fields.push_back(buf); - buf.clear(); - } // else skip runs of seperators - } else buf.push_back(*s); - } - ++s; - } - - if (buf.size()) - fields.push_back(buf); - - return fields; -} - -std::string OSUtils::platformDefaultHomePath() -{ -#ifdef __UNIX_LIKE__ - -#ifdef __APPLE__ - // /Library/... on Apple - return std::string("/Library/Application Support/ZeroTier/One"); -#else - -#ifdef __BSD__ - // BSD likes /var/db instead of /var/lib - return std::string("/var/db/zerotier-one"); -#else - // Use /var/lib for Linux and other *nix - return std::string("/var/lib/zerotier-one"); -#endif - -#endif - -#else // not __UNIX_LIKE__ - -#ifdef __WINDOWS__ - // Look up app data folder on Windows, e.g. C:\ProgramData\... - char buf[16384]; - if (SUCCEEDED(SHGetFolderPathA(NULL,CSIDL_COMMON_APPDATA,NULL,0,buf))) - return (std::string(buf) + "\\ZeroTier\\One"); - else return std::string("C:\\ZeroTier\\One"); -#else - - return (std::string(ZT_PATH_SEPARATOR_S) + "ZeroTier" + ZT_PATH_SEPARATOR_S + "One"); // UNKNOWN PLATFORM - -#endif - -#endif // __UNIX_LIKE__ or not... -} - -// Inline these massive JSON operations in one place only to reduce binary footprint and compile time -nlohmann::json OSUtils::jsonParse(const std::string &buf) { return nlohmann::json::parse(buf.c_str()); } -std::string OSUtils::jsonDump(const nlohmann::json &j) { return j.dump(1); } - -uint64_t OSUtils::jsonInt(const nlohmann::json &jv,const uint64_t dfl) -{ - try { - if (jv.is_number()) { - return (uint64_t)jv; - } else if (jv.is_string()) { - std::string s = jv; - return Utils::strToU64(s.c_str()); - } else if (jv.is_boolean()) { - return ((bool)jv ? 1ULL : 0ULL); - } - } catch ( ... ) {} - return dfl; -} - -bool OSUtils::jsonBool(const nlohmann::json &jv,const bool dfl) -{ - try { - if (jv.is_boolean()) { - return (bool)jv; - } else if (jv.is_number()) { - return ((uint64_t)jv > 0ULL); - } else if (jv.is_string()) { - std::string s = jv; - if (s.length() > 0) { - switch(s[0]) { - case 't': - case 'T': - case '1': - return true; - } - } - return false; - } - } catch ( ... ) {} - return dfl; -} - -std::string OSUtils::jsonString(const nlohmann::json &jv,const char *dfl) -{ - try { - if (jv.is_string()) { - return jv; - } else if (jv.is_number()) { - char tmp[64]; - Utils::snprintf(tmp,sizeof(tmp),"%llu",(uint64_t)jv); - return tmp; - } else if (jv.is_boolean()) { - return ((bool)jv ? std::string("1") : std::string("0")); - } - } catch ( ... ) {} - return std::string((dfl) ? dfl : ""); -} - -std::string OSUtils::jsonBinFromHex(const nlohmann::json &jv) -{ - std::string s(jsonString(jv,"")); - if (s.length() > 0) { - char *buf = new char[(s.length() / 2) + 1]; - try { - unsigned int l = Utils::unhex(s,buf,(unsigned int)s.length()); - std::string b(buf,l); - delete [] buf; - return b; - } catch ( ... ) { - delete [] buf; - } - } - return std::string(); -} - -// Used to convert HTTP header names to ASCII lower case -const unsigned char OSUtils::TOLOWER_TABLE[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; - -} // namespace ZeroTier diff --git a/zto/osdep/OSUtils.hpp b/zto/osdep/OSUtils.hpp deleted file mode 100644 index 2e007ef..0000000 --- a/zto/osdep/OSUtils.hpp +++ /dev/null @@ -1,287 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_OSUTILS_HPP -#define ZT_OSUTILS_HPP - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/InetAddress.hpp" - -#ifdef __WINDOWS__ -#include -#include -#include -#else -#include -#include -#include -#include -#include -#endif - -#include "../ext/json/json.hpp" - -namespace ZeroTier { - -/** - * Miscellaneous utility functions and global constants - */ -class OSUtils -{ -public: -#ifdef __UNIX_LIKE__ - /** - * Close STDOUT_FILENO and STDERR_FILENO and replace them with output to given path - * - * This can be called after fork() and prior to exec() to suppress output - * from a subprocess, such as auto-update. - * - * @param stdoutPath Path to file to use for stdout - * @param stderrPath Path to file to use for stderr, or NULL for same as stdout (default) - * @return True on success - */ - static bool redirectUnixOutputs(const char *stdoutPath,const char *stderrPath = (const char *)0) - throw(); -#endif // __UNIX_LIKE__ - - /** - * Delete a file - * - * @param path Path to delete - * @return True if delete was successful - */ - static inline bool rm(const char *path) - throw() - { -#ifdef __WINDOWS__ - return (DeleteFileA(path) != FALSE); -#else - return (unlink(path) == 0); -#endif - } - static inline bool rm(const std::string &path) throw() { return rm(path.c_str()); } - - static inline bool mkdir(const char *path) - { -#ifdef __WINDOWS__ - if (::PathIsDirectoryA(path)) - return true; - return (::CreateDirectoryA(path,NULL) == TRUE); -#else - if (::mkdir(path,0755) != 0) - return (errno == EEXIST); - return true; -#endif - } - static inline bool mkdir(const std::string &path) throw() { return OSUtils::mkdir(path.c_str()); } - - /** - * List a directory's contents - * - * This returns only files, not sub-directories. - * - * @param path Path to list - * @return Names of files in directory (without path prepended) - */ - static std::vector listDirectory(const char *path); - - /** - * Clean a directory of files whose last modified time is older than this - * - * This ignores directories, symbolic links, and other special files. - * - * @param olderThan Last modified older than timestamp (ms since epoch) - * @return Number of cleaned files or negative on fatal error - */ - static long cleanDirectory(const char *path,const uint64_t olderThan); - - /** - * Delete a directory and all its files and subdirectories recursively - * - * @param path Path to delete - * @return True on success - */ - static bool rmDashRf(const char *path); - - /** - * Set modes on a file to something secure - * - * This locks a file so that only the owner can access it. What it actually - * does varies by platform. - * - * @param path Path to lock - * @param isDir True if this is a directory - */ - static void lockDownFile(const char *path,bool isDir); - - /** - * Get file last modification time - * - * Resolution is often only second, not millisecond, but the return is - * always in ms for comparison against now(). - * - * @param path Path to file to get time - * @return Last modification time in ms since epoch or 0 if not found - */ - static uint64_t getLastModified(const char *path); - - /** - * @param path Path to check - * @param followLinks Follow links (on platforms with that concept) - * @return True if file or directory exists at path location - */ - static bool fileExists(const char *path,bool followLinks = true); - - /** - * @param path Path to file - * @return File size or -1 if nonexistent or other failure - */ - static int64_t getFileSize(const char *path); - - /** - * Get IP (v4 and/or v6) addresses for a given host - * - * This is a blocking resolver. - * - * @param name Host name - * @return IP addresses in InetAddress sort order or empty vector if not found - */ - static std::vector resolve(const char *name); - - /** - * @return Current time in milliseconds since epoch - */ - static inline uint64_t now() - throw() - { -#ifdef __WINDOWS__ - FILETIME ft; - SYSTEMTIME st; - ULARGE_INTEGER tmp; - GetSystemTime(&st); - SystemTimeToFileTime(&st,&ft); - tmp.LowPart = ft.dwLowDateTime; - tmp.HighPart = ft.dwHighDateTime; - return ( ((tmp.QuadPart - 116444736000000000ULL) / 10000L) + st.wMilliseconds ); -#else - struct timeval tv; - gettimeofday(&tv,(struct timezone *)0); - return ( (1000ULL * (uint64_t)tv.tv_sec) + (uint64_t)(tv.tv_usec / 1000) ); -#endif - }; - - /** - * @return Current time in seconds since epoch, to the highest available resolution - */ - static inline double nowf() - throw() - { -#ifdef __WINDOWS__ - FILETIME ft; - SYSTEMTIME st; - ULARGE_INTEGER tmp; - GetSystemTime(&st); - SystemTimeToFileTime(&st,&ft); - tmp.LowPart = ft.dwLowDateTime; - tmp.HighPart = ft.dwHighDateTime; - return (((double)(tmp.QuadPart - 116444736000000000ULL)) / 10000000.0); -#else - struct timeval tv; - gettimeofday(&tv,(struct timezone *)0); - return ( ((double)tv.tv_sec) + (((double)tv.tv_usec) / 1000000.0) ); -#endif - } - - /** - * Read the full contents of a file into a string buffer - * - * The buffer isn't cleared, so if it already contains data the file's data will - * be appended. - * - * @param path Path of file to read - * @param buf Buffer to fill - * @return True if open and read successful - */ - static bool readFile(const char *path,std::string &buf); - - /** - * Write a block of data to disk, replacing any current file contents - * - * @param path Path to write - * @param buf Buffer containing data - * @param len Length of buffer - * @return True if entire file was successfully written - */ - static bool writeFile(const char *path,const void *buf,unsigned int len); - - /** - * Split a string by delimiter, with optional escape and quote characters - * - * @param s String to split - * @param sep One or more separators - * @param esc Zero or more escape characters - * @param quot Zero or more quote characters - * @return Vector of tokens - */ - static std::vector split(const char *s,const char *const sep,const char *esc,const char *quot); - - /** - * Write a block of data to disk, replacing any current file contents - * - * @param path Path to write - * @param s Data to write - * @return True if entire file was successfully written - */ - static inline bool writeFile(const char *path,const std::string &s) { return writeFile(path,s.data(),(unsigned int)s.length()); } - - /** - * @param c ASCII character to convert - * @return Lower case ASCII character or unchanged if not a letter - */ - static inline char toLower(char c) throw() { return (char)OSUtils::TOLOWER_TABLE[(unsigned long)c]; } - - /** - * @return Platform default ZeroTier One home path - */ - static std::string platformDefaultHomePath(); - - static nlohmann::json jsonParse(const std::string &buf); - static std::string jsonDump(const nlohmann::json &j); - static uint64_t jsonInt(const nlohmann::json &jv,const uint64_t dfl); - static bool jsonBool(const nlohmann::json &jv,const bool dfl); - static std::string jsonString(const nlohmann::json &jv,const char *dfl); - static std::string jsonBinFromHex(const nlohmann::json &jv); - -private: - static const unsigned char TOLOWER_TABLE[256]; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/OSXEthernetTap.cpp b/zto/osdep/OSXEthernetTap.cpp deleted file mode 100644 index 35eac05..0000000 --- a/zto/osdep/OSXEthernetTap.cpp +++ /dev/null @@ -1,659 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!? -struct prf_ra { - u_char onlink : 1; - u_char autonomous : 1; - u_char reserved : 6; -} prf_ra; - -#include -#include - -// These are KERNEL_PRIVATE... why? -#ifndef SIOCAUTOCONF_START -#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */ -#endif -#ifndef SIOCAUTOCONF_STOP -#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */ -#endif - -// -------------------------------------------------------------------------- -// -------------------------------------------------------------------------- -// This source is from: -// http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt -// It's here because OSX 10.6 does not have this convenience function. - -#define SALIGN (sizeof(uint32_t) - 1) -#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \ -(SALIGN + 1)) -#define MAX_SYSCTL_TRY 5 -#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA) - -/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from */ -/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */ -//#define DARWIN_COMPAT - -//#ifdef DARWIN_COMPAT -#define GIM_SYSCTL_MIB NET_RT_IFLIST2 -#define GIM_RTM_ADDR RTM_NEWMADDR2 -//#else -//#define GIM_SYSCTL_MIB NET_RT_IFMALIST -//#define GIM_RTM_ADDR RTM_NEWMADDR -//#endif - -// Not in 10.6 includes so use our own -struct _intl_ifmaddrs { - struct _intl_ifmaddrs *ifma_next; - struct sockaddr *ifma_name; - struct sockaddr *ifma_addr; - struct sockaddr *ifma_lladdr; -}; - -static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif) -{ - int icnt = 1; - int dcnt = 0; - int ntry = 0; - size_t len; - size_t needed; - int mib[6]; - int i; - char *buf; - char *data; - char *next; - char *p; - struct ifma_msghdr2 *ifmam; - struct _intl_ifmaddrs *ifa, *ift; - struct rt_msghdr *rtm; - struct sockaddr *sa; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; /* protocol */ - mib[3] = 0; /* wildcard address family */ - mib[4] = GIM_SYSCTL_MIB; - mib[5] = 0; /* no flags */ - do { - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) - return (-1); - if ((buf = (char *)malloc(needed)) == NULL) - return (-1); - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { - if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { - free(buf); - return (-1); - } - free(buf); - buf = NULL; - } - } while (buf == NULL); - - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - switch (rtm->rtm_type) { - case GIM_RTM_ADDR: - ifmam = (struct ifma_msghdr2 *)(void *)rtm; - if ((ifmam->ifmam_addrs & RTA_IFA) == 0) - break; - icnt++; - p = (char *)(ifmam + 1); - for (i = 0; i < RTAX_MAX; i++) { - if ((RTA_MASKS & ifmam->ifmam_addrs & - (1 << i)) == 0) - continue; - sa = (struct sockaddr *)(void *)p; - len = SA_RLEN(sa); - dcnt += len; - p += len; - } - break; - } - } - - data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt); - if (data == NULL) { - free(buf); - return (-1); - } - - ifa = (struct _intl_ifmaddrs *)(void *)data; - data += sizeof(struct _intl_ifmaddrs) * icnt; - - memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt); - ift = ifa; - - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - - switch (rtm->rtm_type) { - case GIM_RTM_ADDR: - ifmam = (struct ifma_msghdr2 *)(void *)rtm; - if ((ifmam->ifmam_addrs & RTA_IFA) == 0) - break; - - p = (char *)(ifmam + 1); - for (i = 0; i < RTAX_MAX; i++) { - if ((RTA_MASKS & ifmam->ifmam_addrs & - (1 << i)) == 0) - continue; - sa = (struct sockaddr *)(void *)p; - len = SA_RLEN(sa); - switch (i) { - case RTAX_GATEWAY: - ift->ifma_lladdr = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - case RTAX_IFP: - ift->ifma_name = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - case RTAX_IFA: - ift->ifma_addr = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - default: - data += len; - break; - } - p += len; - } - ift->ifma_next = ift + 1; - ift = ift->ifma_next; - break; - } - } - - free(buf); - - if (ift > ifa) { - ift--; - ift->ifma_next = NULL; - *pif = ifa; - } else { - *pif = NULL; - free(ifa); - } - return (0); -} - -static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp) -{ - free(ifmp); -} - -// -------------------------------------------------------------------------- -// -------------------------------------------------------------------------- - -#include -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" -#include "../node/Dictionary.hpp" -#include "OSUtils.hpp" -#include "OSXEthernetTap.hpp" - -// ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); - -static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts) -{ - struct in6_ndireq nd; - struct in6_ifreq ifr; - - int s = socket(AF_INET6,SOCK_DGRAM,0); - if (s <= 0) - return false; - - memset(&nd,0,sizeof(nd)); - strncpy(nd.ifname,ifname,sizeof(nd.ifname)); - - if (ioctl(s,SIOCGIFINFO_IN6,&nd)) { - close(s); - return false; - } - - unsigned long oldFlags = (unsigned long)nd.ndi.flags; - - if (performNUD) - nd.ndi.flags |= ND6_IFF_PERFORMNUD; - else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD; - - if (oldFlags != (unsigned long)nd.ndi.flags) { - if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) { - close(s); - return false; - } - } - - memset(&ifr,0,sizeof(ifr)); - strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name)); - if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) { - close(s); - return false; - } - - close(s); - return true; -} - -namespace ZeroTier { - -static long globalTapsRunning = 0; -static Mutex globalTapCreateLock; - -OSXEthernetTap::OSXEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), - void *arg) : - _handler(handler), - _arg(arg), - _nwid(nwid), - _homePath(homePath), - _mtu(mtu), - _metric(metric), - _fd(0), - _enabled(true) -{ - char devpath[64],ethaddr[64],mtustr[32],metstr[32],nwids[32]; - struct stat stattmp; - - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid); - - if (mtu > 2800) - throw std::runtime_error("max tap MTU is 2800"); - - Mutex::Lock _gl(globalTapCreateLock); - - if (::stat("/dev/zt0",&stattmp)) { - long kextpid = (long)vfork(); - if (kextpid == 0) { - ::chdir(homePath); - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - ::execl("/sbin/kextload","/sbin/kextload","-q","-repository",homePath,"tap.kext",(const char *)0); - ::_exit(-1); - } else if (kextpid > 0) { - int exitcode = -1; - ::waitpid(kextpid,&exitcode,0); - } - ::usleep(500); // give tap device driver time to start up and try again - if (::stat("/dev/zt0",&stattmp)) - throw std::runtime_error("/dev/zt# tap devices do not exist and cannot load tap.kext"); - } - - // Try to reopen the last device we had, if we had one and it's still unused. - bool recalledDevice = false; - std::string devmapbuf; - Dictionary<8194> devmap; - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmapbuf)) { - devmap.load(devmapbuf.c_str()); - char desiredDevice[128]; - if (devmap.get(nwids,desiredDevice,sizeof(desiredDevice)) > 0) { - Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",desiredDevice); - if (stat(devpath,&stattmp) == 0) { - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) { - _dev = desiredDevice; - recalledDevice = true; - } - } - } - } - - // Open the first unused tap device if we didn't recall a previous one. - if (!recalledDevice) { - for(int i=0;i<64;++i) { - Utils::snprintf(devpath,sizeof(devpath),"/dev/zt%d",i); - if (stat(devpath,&stattmp)) - throw std::runtime_error("no more TAP devices available"); - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) { - char foo[16]; - Utils::snprintf(foo,sizeof(foo),"zt%d",i); - _dev = foo; - break; - } - } - } - - if (_fd <= 0) - throw std::runtime_error("unable to open TAP device or no more devices available"); - - if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { - ::close(_fd); - throw std::runtime_error("unable to set flags on file descriptor for TAP device"); - } - - // Configure MAC address and MTU, bring interface up - Utils::snprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu); - Utils::snprintf(metstr,sizeof(metstr),"%u",_metric); - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) { - ::close(_fd); - throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); - } - } - - _setIpv6Stuff(_dev.c_str(),true,false); - - // Set close-on-exec so that devices cannot persist if we fork/exec for update - fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); - - ::pipe(_shutdownSignalPipe); - - ++globalTapsRunning; - - devmap.erase(nwids); - devmap.add(nwids,_dev.c_str()); - OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),(const void *)devmap.data(),devmap.sizeBytes()); - - _thread = Thread::start(this); -} - -OSXEthernetTap::~OSXEthernetTap() -{ - ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit - Thread::join(_thread); - - ::close(_fd); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); - - { - Mutex::Lock _gl(globalTapCreateLock); - if (--globalTapsRunning <= 0) { - globalTapsRunning = 0; // sanity check -- should not be possible - - char tmp[16384]; - sprintf(tmp,"%s/%s",_homePath.c_str(),"tap.kext"); - long kextpid = (long)vfork(); - if (kextpid == 0) { - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - ::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0); - ::_exit(-1); - } else if (kextpid > 0) { - int exitcode = -1; - ::waitpid(kextpid,&exitcode,0); - } - } - } -} - -void OSXEthernetTap::setEnabled(bool en) -{ - _enabled = en; - // TODO: interface status change -} - -bool OSXEthernetTap::enabled() const -{ - return _enabled; -} - -bool OSXEthernetTap::addIp(const InetAddress &ip) -{ - if (!ip) - return false; - - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toString().c_str(),"alias",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } // else return false... - - return false; -} - -bool OSXEthernetTap::removeIp(const InetAddress &ip) -{ - if (!ip) - return true; - std::vector allIps(ips()); - for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { - if (*i == ip) { - long cpid = (long)vfork(); - if (cpid == 0) { - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toIpString().c_str(),"-alias",(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - } - } - return false; -} - -std::vector OSXEthernetTap::ips() const -{ - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::vector(); - - std::vector r; - - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } - - if (ifa) - freeifaddrs(ifa); - - std::sort(r.begin(),r.end()); - r.erase(std::unique(r.begin(),r.end()),r.end()); - - return r; -} - -void OSXEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - char putBuf[4096]; - if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { - to.copyTo(putBuf,6); - from.copyTo(putBuf + 6,6); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - ::write(_fd,putBuf,len); - } -} - -std::string OSXEthernetTap::deviceName() const -{ - return _dev; -} - -void OSXEthernetTap::setFriendlyName(const char *friendlyName) -{ -} - -void OSXEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) -{ - std::vector newGroups; - - struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0; - if (!_intl_getifmaddrs(&ifmap)) { - struct _intl_ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - _intl_freeifmaddrs(ifmap); - } - - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - - std::sort(newGroups.begin(),newGroups.end()); - std::unique(newGroups.begin(),newGroups.end()); - - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } - - _multicastGroups.swap(newGroups); -} - -void OSXEthernetTap::threadMain() - throw() -{ - fd_set readfds,nullfds; - MAC to,from; - int n,nfds,r; - char getBuf[8194]; - - Thread::sleep(500); - - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; - - r = 0; - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_fd,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); - - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread - break; - - if (FD_ISSET(_fd,&readfds)) { - n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r); - if (n < 0) { - if ((errno != EINTR)&&(errno != ETIMEDOUT)) - break; - } else { - // Some tap drivers like to send the ethernet frame and the - // payload in two chunks, so handle that by accumulating - // data until we have at least a frame. - r += n; - if (r > 14) { - if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms - r = _mtu + 14; - - if (_enabled) { - to.setTo(getBuf,6); - from.setTo(getBuf + 6,6); - unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); - // TODO: VLAN support - _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); - } - - r = 0; - } - } - } - } -} - -} // namespace ZeroTier diff --git a/zto/osdep/OSXEthernetTap.hpp b/zto/osdep/OSXEthernetTap.hpp deleted file mode 100644 index 5a96c21..0000000 --- a/zto/osdep/OSXEthernetTap.hpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_OSXETHERNETTAP_HPP -#define ZT_OSXETHERNETTAP_HPP - -#include -#include - -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/MAC.hpp" -#include "../node/InetAddress.hpp" -#include "../node/MulticastGroup.hpp" - -#include "Thread.hpp" - -namespace ZeroTier { - -/** - * OSX Ethernet tap using ZeroTier kernel extension zt# devices - */ -class OSXEthernetTap -{ -public: - OSXEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); - - ~OSXEthernetTap(); - - void setEnabled(bool en); - bool enabled() const; - bool addIp(const InetAddress &ip); - bool removeIp(const InetAddress &ip); - std::vector ips() const; - void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - std::string deviceName() const; - void setFriendlyName(const char *friendlyName); - void scanMulticastGroups(std::vector &added,std::vector &removed); - - void threadMain() - throw(); - -private: - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - uint64_t _nwid; - Thread _thread; - std::string _homePath; - std::string _dev; - std::vector _multicastGroups; - unsigned int _mtu; - unsigned int _metric; - int _fd; - int _shutdownSignalPipe[2]; - volatile bool _enabled; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/Phy.hpp b/zto/osdep/Phy.hpp deleted file mode 100644 index 5201cff..0000000 --- a/zto/osdep/Phy.hpp +++ /dev/null @@ -1,1115 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_PHY_HPP -#define ZT_PHY_HPP - -#include -#include -#include - -#include -#include - -#if defined(_WIN32) || defined(_WIN64) - -#include -#include -#include - -#define ZT_PHY_SOCKFD_TYPE SOCKET -#define ZT_PHY_SOCKFD_NULL (INVALID_SOCKET) -#define ZT_PHY_SOCKFD_VALID(s) ((s) != INVALID_SOCKET) -#define ZT_PHY_CLOSE_SOCKET(s) ::closesocket(s) -#define ZT_PHY_MAX_SOCKETS (FD_SETSIZE) -#define ZT_PHY_MAX_INTERCEPTS ZT_PHY_MAX_SOCKETS -#define ZT_PHY_SOCKADDR_STORAGE_TYPE struct sockaddr_storage - -#else // not Windows - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) -#ifndef IPV6_DONTFRAG -#define IPV6_DONTFRAG 62 -#endif -#endif - -#define ZT_PHY_SOCKFD_TYPE int -#define ZT_PHY_SOCKFD_NULL (-1) -#define ZT_PHY_SOCKFD_VALID(s) ((s) > -1) -#define ZT_PHY_CLOSE_SOCKET(s) ::close(s) -#define ZT_PHY_MAX_SOCKETS (FD_SETSIZE) -#define ZT_PHY_MAX_INTERCEPTS ZT_PHY_MAX_SOCKETS -#define ZT_PHY_SOCKADDR_STORAGE_TYPE struct sockaddr_storage - -#endif // Windows or not - -namespace ZeroTier { - -/** - * Opaque socket type - */ -typedef void PhySocket; - -/** - * Simple templated non-blocking sockets implementation - * - * Yes there is boost::asio and libuv, but I like small binaries and I hate - * build dependencies. Both drag in a whole bunch of pasta with them. - * - * This class is templated on a pointer to a handler class which must - * implement the following functions: - * - * For all platforms: - * - * phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) - * phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) - * phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) - * phyOnTcpClose(PhySocket *sock,void **uptr) - * phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) - * phyOnTcpWritable(PhySocket *sock,void **uptr) - * phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) - * - * On Linux/OSX/Unix only (not required/used on Windows or elsewhere): - * - * phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) - * phyOnUnixClose(PhySocket *sock,void **uptr) - * phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) - * phyOnUnixWritable(PhySocket *sock,void **uptr) - * - * These templates typically refer to function objects. Templates are used to - * avoid the call overhead of indirection, which is surprisingly high for high - * bandwidth applications pushing a lot of packets. - * - * The 'sock' pointer above is an opaque pointer to a socket. Each socket - * has a 'uptr' user-settable/modifiable pointer associated with it, which - * can be set on bind/connect calls and is passed as a void ** to permit - * resetting at any time. The ACCEPT handler takes two sets of sock and - * uptr: sockL and uptrL for the listen socket, and sockN and uptrN for - * the new TCP connection socket that has just been created. - * - * Handlers are always called. On outgoing TCP connection, CONNECT is always - * called on either success or failure followed by DATA and/or WRITABLE as - * indicated. On socket close, handlers are called unless close() is told - * explicitly not to call handlers. It is safe to close a socket within a - * handler, and in that case close() can be told not to call handlers to - * prevent recursion. - * - * This isn't thread-safe with the exception of whack(), which is safe to - * call from another thread to abort poll(). - */ -template -class Phy -{ -private: - HANDLER_PTR_TYPE _handler; - - enum PhySocketType - { - ZT_PHY_SOCKET_CLOSED = 0x00, // socket is closed, will be removed on next poll() - ZT_PHY_SOCKET_TCP_OUT_PENDING = 0x01, - ZT_PHY_SOCKET_TCP_OUT_CONNECTED = 0x02, - ZT_PHY_SOCKET_TCP_IN = 0x03, - ZT_PHY_SOCKET_TCP_LISTEN = 0x04, - ZT_PHY_SOCKET_UDP = 0x05, - ZT_PHY_SOCKET_FD = 0x06, - ZT_PHY_SOCKET_UNIX_IN = 0x07, - ZT_PHY_SOCKET_UNIX_LISTEN = 0x08 - }; - - struct PhySocketImpl - { - PhySocketType type; - ZT_PHY_SOCKFD_TYPE sock; - void *uptr; // user-settable pointer - ZT_PHY_SOCKADDR_STORAGE_TYPE saddr; // remote for TCP_OUT and TCP_IN, local for TCP_LISTEN, RAW, and UDP - }; - - std::list _socks; - fd_set _readfds; - fd_set _writefds; -#if defined(_WIN32) || defined(_WIN64) - fd_set _exceptfds; -#endif - long _nfds; - - ZT_PHY_SOCKFD_TYPE _whackReceiveSocket; - ZT_PHY_SOCKFD_TYPE _whackSendSocket; - - bool _noDelay; - bool _noCheck; - -public: - /** - * @param handler Pointer of type HANDLER_PTR_TYPE to handler - * @param noDelay If true, disable TCP NAGLE algorithm on TCP sockets - * @param noCheck If true, attempt to set UDP SO_NO_CHECK option to disable sending checksums - */ - Phy(HANDLER_PTR_TYPE handler,bool noDelay,bool noCheck) : - _handler(handler) - { - FD_ZERO(&_readfds); - FD_ZERO(&_writefds); - -#if defined(_WIN32) || defined(_WIN64) - FD_ZERO(&_exceptfds); - - SOCKET pipes[2]; - { // hack copied from StackOverflow, behaves a bit like pipe() on *nix systems - struct sockaddr_in inaddr; - struct sockaddr addr; - SOCKET lst=::socket(AF_INET, SOCK_STREAM,IPPROTO_TCP); - if (lst == INVALID_SOCKET) - throw std::runtime_error("unable to create pipes for select() abort"); - memset(&inaddr, 0, sizeof(inaddr)); - memset(&addr, 0, sizeof(addr)); - inaddr.sin_family = AF_INET; - inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - inaddr.sin_port = 0; - int yes=1; - setsockopt(lst,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes)); - bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr)); - listen(lst,1); - int len=sizeof(inaddr); - getsockname(lst, &addr,&len); - pipes[0]=::socket(AF_INET, SOCK_STREAM,0); - if (pipes[0] == INVALID_SOCKET) - throw std::runtime_error("unable to create pipes for select() abort"); - connect(pipes[0],&addr,len); - pipes[1]=accept(lst,0,0); - closesocket(lst); - } -#else // not Windows - int pipes[2]; - if (::pipe(pipes)) - throw std::runtime_error("unable to create pipes for select() abort"); -#endif // Windows or not - - _nfds = (pipes[0] > pipes[1]) ? (long)pipes[0] : (long)pipes[1]; - _whackReceiveSocket = pipes[0]; - _whackSendSocket = pipes[1]; - _noDelay = noDelay; - _noCheck = noCheck; - } - - ~Phy() - { - for(typename std::list::const_iterator s(_socks.begin());s!=_socks.end();++s) { - if (s->type != ZT_PHY_SOCKET_CLOSED) - this->close((PhySocket *)&(*s),true); - } - ZT_PHY_CLOSE_SOCKET(_whackReceiveSocket); - ZT_PHY_CLOSE_SOCKET(_whackSendSocket); - } - - /** - * @param s Socket object - * @return Underlying OS-type (usually int or long) file descriptor associated with object - */ - static inline ZT_PHY_SOCKFD_TYPE getDescriptor(PhySocket *s) throw() { return reinterpret_cast(s)->sock; } - - /** - * @param s Socket object - * @return Pointer to user object - */ - static inline void** getuptr(PhySocket *s) throw() { return &(reinterpret_cast(s)->uptr); } - - /** - * Cause poll() to stop waiting immediately - * - * This can be used to reset the polling loop after changes that require - * attention, or to shut down a background thread that is waiting, etc. - */ - inline void whack() - { -#if defined(_WIN32) || defined(_WIN64) - ::send(_whackSendSocket,(const char *)this,1,0); -#else - (void)(::write(_whackSendSocket,(PhySocket *)this,1)); -#endif - } - - /** - * @return Number of open sockets - */ - inline unsigned long count() const throw() { return _socks.size(); } - - /** - * @return Maximum number of sockets allowed - */ - inline unsigned long maxCount() const throw() { return ZT_PHY_MAX_SOCKETS; } - - /** - * Wrap a raw file descriptor in a PhySocket structure - * - * This can be used to select/poll on a raw file descriptor as part of this - * class's I/O loop. By default the fd is set for read notification but - * this can be controlled with setNotifyReadable(). When any detected - * condition is present, the phyOnFileDescriptorActivity() callback is - * called with one or both of its arguments 'true'. - * - * The Phy<>::close() method *must* be called when you're done with this - * file descriptor to remove it from the select/poll set, but unlike other - * types of sockets Phy<> does not actually close the underlying fd or - * otherwise manage its life cycle. There is also no close notification - * callback for this fd, since Phy<> doesn't actually perform reading or - * writing or detect error conditions. This is only useful for adding a - * file descriptor to Phy<> to select/poll on it. - * - * @param fd Raw file descriptor - * @param uptr User pointer to supply to callbacks - * @return PhySocket wrapping fd or NULL on failure (out of memory or too many sockets) - */ - inline PhySocket *wrapSocket(ZT_PHY_SOCKFD_TYPE fd,void *uptr = (void *)0) - { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) - return (PhySocket *)0; - try { - _socks.push_back(PhySocketImpl()); - } catch ( ... ) { - return (PhySocket *)0; - } - PhySocketImpl &sws = _socks.back(); - if ((long)fd > _nfds) - _nfds = (long)fd; - FD_SET(fd,&_readfds); - sws.type = ZT_PHY_SOCKET_UNIX_IN; /* TODO: Type was changed to allow for CBs with new RPC model */ - sws.sock = fd; - sws.uptr = uptr; - memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); - // no sockaddr for this socket type, leave saddr null - return (PhySocket *)&sws; - } - - /** - * Bind a UDP socket - * - * @param localAddress Local endpoint address and port - * @param uptr Initial value of user pointer associated with this socket (default: NULL) - * @param bufferSize Desired socket receive/send buffer size -- will set as close to this as possible (default: 0, leave alone) - * @return Socket or NULL on failure to bind - */ - inline PhySocket *udpBind(const struct sockaddr *localAddress,void *uptr = (void *)0,int bufferSize = 0) - { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) - return (PhySocket *)0; - - ZT_PHY_SOCKFD_TYPE s = ::socket(localAddress->sa_family,SOCK_DGRAM,0); - if (!ZT_PHY_SOCKFD_VALID(s)) - return (PhySocket *)0; - - if (bufferSize > 0) { - int bs = bufferSize; - while (bs >= 65536) { - int tmpbs = bs; - if (setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0) - break; - bs -= 16384; - } - bs = bufferSize; - while (bs >= 65536) { - int tmpbs = bs; - if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0) - break; - bs -= 16384; - } - } - -#if defined(_WIN32) || defined(_WIN64) - { - BOOL f; - if (localAddress->sa_family == AF_INET6) { - f = TRUE; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f)); - f = FALSE; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,(const char *)&f,sizeof(f)); - } - f = FALSE; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f)); - f = TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char *)&f,sizeof(f)); - } -#else // not Windows - { - int f; - if (localAddress->sa_family == AF_INET6) { - f = 1; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f)); -#ifdef IPV6_MTU_DISCOVER - f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&f,sizeof(f)); -#endif -#ifdef IPV6_DONTFRAG - f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,&f,sizeof(f)); -#endif - } - f = 0; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f)); - f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f)); -#ifdef IP_DONTFRAG - f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f)); -#endif -#ifdef IP_MTU_DISCOVER - f = 0; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f)); -#endif -#ifdef SO_NO_CHECK - // For now at least we only set SO_NO_CHECK on IPv4 sockets since some - // IPv6 stacks incorrectly discard zero checksum packets. May remove - // this restriction later once broken stuff dies more. - if ((localAddress->sa_family == AF_INET)&&(_noCheck)) { - f = 1; setsockopt(s,SOL_SOCKET,SO_NO_CHECK,(void *)&f,sizeof(f)); - } -#endif - } -#endif // Windows or not - - if (::bind(s,localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - -#if defined(_WIN32) || defined(_WIN64) - { u_long iMode=1; ioctlsocket(s,FIONBIO,&iMode); } -#else - fcntl(s,F_SETFL,O_NONBLOCK); -#endif - - try { - _socks.push_back(PhySocketImpl()); - } catch ( ... ) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - PhySocketImpl &sws = _socks.back(); - - if ((long)s > _nfds) - _nfds = (long)s; - FD_SET(s,&_readfds); - sws.type = ZT_PHY_SOCKET_UDP; - sws.sock = s; - sws.uptr = uptr; - memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); - memcpy(&(sws.saddr),localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); - - return (PhySocket *)&sws; - } - - /** - * Set the IP TTL for the next outgoing packet (for IPv4 UDP sockets only) - * - * @param ttl New TTL (0 or >255 will set it to 255) - * @return True on success - */ - inline bool setIp4UdpTtl(PhySocket *sock,unsigned int ttl) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); -#if defined(_WIN32) || defined(_WIN64) - DWORD tmp = ((ttl == 0)||(ttl > 255)) ? 255 : (DWORD)ttl; - return (::setsockopt(sws.sock,IPPROTO_IP,IP_TTL,(const char *)&tmp,sizeof(tmp)) == 0); -#else - int tmp = ((ttl == 0)||(ttl > 255)) ? 255 : (int)ttl; - return (::setsockopt(sws.sock,IPPROTO_IP,IP_TTL,(void *)&tmp,sizeof(tmp)) == 0); -#endif - } - - /** - * Send a UDP packet - * - * @param sock UDP socket - * @param remoteAddress Destination address (must be correct type for socket) - * @param data Data to send - * @param len Length of packet - * @return True if packet appears to have been sent successfully - */ - inline bool udpSend(PhySocket *sock,const struct sockaddr *remoteAddress,const void *data,unsigned long len) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); -#if defined(_WIN32) || defined(_WIN64) - return ((long)::sendto(sws.sock,reinterpret_cast(data),len,0,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); -#else - return ((long)::sendto(sws.sock,data,len,0,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); -#endif - } - -#ifdef __UNIX_LIKE__ - /** - * Listen for connections on a Unix domain socket - * - * @param path Path to Unix domain socket - * @param uptr Arbitrary pointer to associate - * @return PhySocket or NULL if cannot bind - */ - inline PhySocket *unixListen(const char *path,void *uptr = (void *)0) - { - struct sockaddr_un sun; - - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) - return (PhySocket *)0; - - memset(&sun,0,sizeof(sun)); - sun.sun_family = AF_UNIX; - if (strlen(path) >= sizeof(sun.sun_path)) - return (PhySocket *)0; - strcpy(sun.sun_path,path); - - ZT_PHY_SOCKFD_TYPE s = ::socket(PF_UNIX,SOCK_STREAM,0); - if (!ZT_PHY_SOCKFD_VALID(s)) - return (PhySocket *)0; - - ::fcntl(s,F_SETFL,O_NONBLOCK); - - ::unlink(path); - if (::bind(s,(struct sockaddr *)&sun,sizeof(struct sockaddr_un)) != 0) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - if (::listen(s,128) != 0) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - - try { - _socks.push_back(PhySocketImpl()); - } catch ( ... ) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - PhySocketImpl &sws = _socks.back(); - - if ((long)s > _nfds) - _nfds = (long)s; - FD_SET(s,&_readfds); - sws.type = ZT_PHY_SOCKET_UNIX_LISTEN; - sws.sock = s; - sws.uptr = uptr; - memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); - memcpy(&(sws.saddr),&sun,sizeof(struct sockaddr_un)); - - return (PhySocket *)&sws; - } -#endif // __UNIX_LIKE__ - - /** - * Bind a local listen socket to listen for new TCP connections - * - * @param localAddress Local address and port - * @param uptr Initial value of uptr for new socket (default: NULL) - * @return Socket or NULL on failure to bind - */ - inline PhySocket *tcpListen(const struct sockaddr *localAddress,void *uptr = (void *)0) - { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) - return (PhySocket *)0; - - ZT_PHY_SOCKFD_TYPE s = ::socket(localAddress->sa_family,SOCK_STREAM,0); - if (!ZT_PHY_SOCKFD_VALID(s)) - return (PhySocket *)0; - -#if defined(_WIN32) || defined(_WIN64) - { - BOOL f; - f = TRUE; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f)); - f = TRUE; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f)); - f = (_noDelay ? TRUE : FALSE); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); - u_long iMode=1; - ioctlsocket(s,FIONBIO,&iMode); - } -#else - { - int f; - f = 1; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f)); - f = 1; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f)); - f = (_noDelay ? 1 : 0); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); - fcntl(s,F_SETFL,O_NONBLOCK); - } -#endif - - if (::bind(s,localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - - if (::listen(s,1024)) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - - try { - _socks.push_back(PhySocketImpl()); - } catch ( ... ) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - PhySocketImpl &sws = _socks.back(); - - if ((long)s > _nfds) - _nfds = (long)s; - FD_SET(s,&_readfds); - sws.type = ZT_PHY_SOCKET_TCP_LISTEN; - sws.sock = s; - sws.uptr = uptr; - memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); - memcpy(&(sws.saddr),localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); - - return (PhySocket *)&sws; - } - - /** - * Start a non-blocking connect; CONNECT handler is called on success or failure - * - * A return value of NULL indicates a synchronous failure such as a - * failure to open a socket. The TCP connection handler is not called - * in this case. - * - * It is possible on some platforms for an "instant connect" to occur, - * such as when connecting to a loopback address. In this case, the - * 'connected' result parameter will be set to 'true' and if the - * 'callConnectHandler' flag is true (the default) the TCP connect - * handler will be called before the function returns. - * - * These semantics can be a bit confusing, but they're less so than - * the underlying semantics of asynchronous TCP connect. - * - * @param remoteAddress Remote address - * @param connected Result parameter: set to whether an "instant connect" has occurred (true if yes) - * @param uptr Initial value of uptr for new socket (default: NULL) - * @param callConnectHandler If true, call TCP connect handler even if result is known before function exit (default: true) - * @return New socket or NULL on failure - */ - inline PhySocket *tcpConnect(const struct sockaddr *remoteAddress,bool &connected,void *uptr = (void *)0,bool callConnectHandler = true) - { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) - return (PhySocket *)0; - - ZT_PHY_SOCKFD_TYPE s = ::socket(remoteAddress->sa_family,SOCK_STREAM,0); - if (!ZT_PHY_SOCKFD_VALID(s)) { - connected = false; - return (PhySocket *)0; - } - -#if defined(_WIN32) || defined(_WIN64) - { - BOOL f; - if (remoteAddress->sa_family == AF_INET6) { f = TRUE; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f)); } - f = TRUE; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f)); - f = (_noDelay ? TRUE : FALSE); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); - u_long iMode=1; - ioctlsocket(s,FIONBIO,&iMode); - } -#else - { - int f; - if (remoteAddress->sa_family == AF_INET6) { f = 1; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f)); } - f = 1; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f)); - f = (_noDelay ? 1 : 0); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); - fcntl(s,F_SETFL,O_NONBLOCK); - } -#endif - - connected = true; - if (::connect(s,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { - connected = false; -#if defined(_WIN32) || defined(_WIN64) - if (WSAGetLastError() != WSAEWOULDBLOCK) { -#else - if (errno != EINPROGRESS) { -#endif - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } // else connection is proceeding asynchronously... - } - - try { - _socks.push_back(PhySocketImpl()); - } catch ( ... ) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - PhySocketImpl &sws = _socks.back(); - - if ((long)s > _nfds) - _nfds = (long)s; - if (connected) { - FD_SET(s,&_readfds); - sws.type = ZT_PHY_SOCKET_TCP_OUT_CONNECTED; - } else { - FD_SET(s,&_writefds); -#if defined(_WIN32) || defined(_WIN64) - FD_SET(s,&_exceptfds); -#endif - sws.type = ZT_PHY_SOCKET_TCP_OUT_PENDING; - } - sws.sock = s; - sws.uptr = uptr; - memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); - memcpy(&(sws.saddr),remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); - - if ((callConnectHandler)&&(connected)) { - try { - _handler->phyOnTcpConnect((PhySocket *)&sws,&(sws.uptr),true); - } catch ( ... ) {} - } - - return (PhySocket *)&sws; - } - - /** - * Try to set buffer sizes as close to the given value as possible - * - * This will try the specified value and then lower values in 16K increments - * until one works. - * - * @param sock Socket - * @param bufferSize Desired buffer sizes - */ - inline void setBufferSizes(const PhySocket *sock,int bufferSize) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); - if (bufferSize > 0) { - int bs = bufferSize; - while (bs >= 65536) { - int tmpbs = bs; - if (::setsockopt(sws.sock,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0) - break; - bs -= 16384; - } - bs = bufferSize; - while (bs >= 65536) { - int tmpbs = bs; - if (::setsockopt(sws.sock,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0) - break; - bs -= 16384; - } - } - } - - /** - * Attempt to send data to a stream socket (non-blocking) - * - * If -1 is returned, the socket should no longer be used as it is now - * destroyed. If callCloseHandler is true, the close handler will be - * called before the function returns. - * - * This can be used with TCP, Unix, or socket pair sockets. - * - * @param sock An open stream socket (other socket types will fail) - * @param data Data to send - * @param len Length of data - * @param callCloseHandler If true, call close handler on socket closing failure condition (default: true) - * @return Number of bytes actually sent or -1 on fatal error (socket closure) - */ - inline long streamSend(PhySocket *sock,const void *data,unsigned long len,bool callCloseHandler = true) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); -#if defined(_WIN32) || defined(_WIN64) - long n = (long)::send(sws.sock,reinterpret_cast(data),len,0); - if (n == SOCKET_ERROR) { - switch(WSAGetLastError()) { - case WSAEINTR: - case WSAEWOULDBLOCK: - return 0; - default: - this->close(sock,callCloseHandler); - return -1; - } - } -#else // not Windows - long n = (long)::send(sws.sock,data,len,0); - if (n < 0) { - switch(errno) { -#ifdef EAGAIN - case EAGAIN: -#endif -#if defined(EWOULDBLOCK) && ( !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) ) - case EWOULDBLOCK: -#endif -#ifdef EINTR - case EINTR: -#endif - return 0; - default: - this->close(sock,callCloseHandler); - return -1; - } - } -#endif // Windows or not - return n; - } - -#ifdef __UNIX_LIKE__ - /** - * Attempt to send data to a Unix domain socket connection (non-blocking) - * - * If -1 is returned, the socket should no longer be used as it is now - * destroyed. If callCloseHandler is true, the close handler will be - * called before the function returns. - * - * @param sock An open Unix socket (other socket types will fail) - * @param data Data to send - * @param len Length of data - * @param callCloseHandler If true, call close handler on socket closing failure condition (default: true) - * @return Number of bytes actually sent or -1 on fatal error (socket closure) - */ - inline long unixSend(PhySocket *sock,const void *data,unsigned long len,bool callCloseHandler = true) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); - long n = (long)::write(sws.sock,data,len); - if (n < 0) { - switch(errno) { -#ifdef EAGAIN - case EAGAIN: -#endif -#if defined(EWOULDBLOCK) && ( !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) ) - case EWOULDBLOCK: -#endif -#ifdef EINTR - case EINTR: -#endif - return 0; - default: - this->close(sock,callCloseHandler); - return -1; - } - } - return n; - } -#endif // __UNIX_LIKE__ - - /** - * For streams, sets whether we want to be notified that the socket is writable - * - * This can be used with TCP, Unix, or socket pair sockets. - * - * Call whack() if this is being done from another thread and you want - * it to take effect immediately. Otherwise it is only guaranteed to - * take effect on the next poll(). - * - * @param sock Stream connection socket - * @param notifyWritable Want writable notifications? - */ - inline const void setNotifyWritable(PhySocket *sock,bool notifyWritable) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); - if (notifyWritable) { - FD_SET(sws.sock,&_writefds); - } else { - FD_CLR(sws.sock,&_writefds); - } - } - - /** - * Set whether we want to be notified that a socket is readable - * - * This is primarily for raw sockets added with wrapSocket(). It could be - * used with others, but doing so would essentially lock them and prevent - * data from being read from them until this is set to 'true' again. - * - * @param sock Socket to modify - * @param notifyReadable True if socket should be monitored for readability - */ - inline const void setNotifyReadable(PhySocket *sock,bool notifyReadable) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); - if (notifyReadable) { - FD_SET(sws.sock,&_readfds); - } else { - FD_CLR(sws.sock,&_readfds); - } - } - - /** - * Wait for activity and handle one or more events - * - * Note that this is not guaranteed to wait up to 'timeout' even - * if nothing happens, as whack() or other events such as signals - * may cause premature termination. - * - * @param timeout Timeout in milliseconds or 0 for none (forever) - */ - inline void poll(unsigned long timeout) - { - char buf[131072]; - struct sockaddr_storage ss; - struct timeval tv; - fd_set rfds,wfds,efds; - - memcpy(&rfds,&_readfds,sizeof(rfds)); - memcpy(&wfds,&_writefds,sizeof(wfds)); -#if defined(_WIN32) || defined(_WIN64) - memcpy(&efds,&_exceptfds,sizeof(efds)); -#else - FD_ZERO(&efds); -#endif - - tv.tv_sec = (long)(timeout / 1000); - tv.tv_usec = (long)((timeout % 1000) * 1000); - if (::select((int)_nfds + 1,&rfds,&wfds,&efds,(timeout > 0) ? &tv : (struct timeval *)0) <= 0) - return; - - if (FD_ISSET(_whackReceiveSocket,&rfds)) { - char tmp[16]; -#if defined(_WIN32) || defined(_WIN64) - ::recv(_whackReceiveSocket,tmp,16,0); -#else - ::read(_whackReceiveSocket,tmp,16); -#endif - } - - for(typename std::list::iterator s(_socks.begin());s!=_socks.end();) { - switch (s->type) { - - case ZT_PHY_SOCKET_TCP_OUT_PENDING: -#if defined(_WIN32) || defined(_WIN64) - if (FD_ISSET(s->sock,&efds)) { - this->close((PhySocket *)&(*s),true); - } else // ... if -#endif - if (FD_ISSET(s->sock,&wfds)) { - socklen_t slen = sizeof(ss); - if (::getpeername(s->sock,(struct sockaddr *)&ss,&slen) != 0) { - this->close((PhySocket *)&(*s),true); - } else { - s->type = ZT_PHY_SOCKET_TCP_OUT_CONNECTED; - FD_SET(s->sock,&_readfds); - FD_CLR(s->sock,&_writefds); -#if defined(_WIN32) || defined(_WIN64) - FD_CLR(s->sock,&_exceptfds); -#endif - try { - _handler->phyOnTcpConnect((PhySocket *)&(*s),&(s->uptr),true); - } catch ( ... ) {} - } - } - break; - - case ZT_PHY_SOCKET_TCP_OUT_CONNECTED: - case ZT_PHY_SOCKET_TCP_IN: { - ZT_PHY_SOCKFD_TYPE sock = s->sock; // if closed, s->sock becomes invalid as s is no longer dereferencable - if (FD_ISSET(sock,&rfds)) { - long n = (long)::recv(sock,buf,sizeof(buf),0); - if (n <= 0) { - this->close((PhySocket *)&(*s),true); - } else { - try { - _handler->phyOnTcpData((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n); - } catch ( ... ) {} - } - } - if ((FD_ISSET(sock,&wfds))&&(FD_ISSET(sock,&_writefds))) { - try { - _handler->phyOnTcpWritable((PhySocket *)&(*s),&(s->uptr), false); - } catch ( ... ) {} - } - } break; - - case ZT_PHY_SOCKET_TCP_LISTEN: - if (FD_ISSET(s->sock,&rfds)) { - memset(&ss,0,sizeof(ss)); - socklen_t slen = sizeof(ss); - ZT_PHY_SOCKFD_TYPE newSock = ::accept(s->sock,(struct sockaddr *)&ss,&slen); - if (ZT_PHY_SOCKFD_VALID(newSock)) { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) { - ZT_PHY_CLOSE_SOCKET(newSock); - } else { -#if defined(_WIN32) || defined(_WIN64) - { BOOL f = (_noDelay ? TRUE : FALSE); setsockopt(newSock,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); } - { u_long iMode=1; ioctlsocket(newSock,FIONBIO,&iMode); } -#else - { int f = (_noDelay ? 1 : 0); setsockopt(newSock,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); } - fcntl(newSock,F_SETFL,O_NONBLOCK); -#endif - _socks.push_back(PhySocketImpl()); - PhySocketImpl &sws = _socks.back(); - FD_SET(newSock,&_readfds); - if ((long)newSock > _nfds) - _nfds = (long)newSock; - sws.type = ZT_PHY_SOCKET_TCP_IN; - sws.sock = newSock; - sws.uptr = (void *)0; - memcpy(&(sws.saddr),&ss,sizeof(struct sockaddr_storage)); - try { - _handler->phyOnTcpAccept((PhySocket *)&(*s),(PhySocket *)&(_socks.back()),&(s->uptr),&(sws.uptr),(const struct sockaddr *)&(sws.saddr)); - } catch ( ... ) {} - } - } - } - break; - - case ZT_PHY_SOCKET_UDP: - if (FD_ISSET(s->sock,&rfds)) { - for(;;) { - memset(&ss,0,sizeof(ss)); - socklen_t slen = sizeof(ss); - long n = (long)::recvfrom(s->sock,buf,sizeof(buf),0,(struct sockaddr *)&ss,&slen); - if (n > 0) { - try { - _handler->phyOnDatagram((PhySocket *)&(*s),&(s->uptr),(const struct sockaddr *)&(s->saddr),(const struct sockaddr *)&ss,(void *)buf,(unsigned long)n); - } catch ( ... ) {} - } else if (n < 0) - break; - } - } - break; - - case ZT_PHY_SOCKET_UNIX_IN: { -#ifdef __UNIX_LIKE__ - ZT_PHY_SOCKFD_TYPE sock = s->sock; // if closed, s->sock becomes invalid as s is no longer dereferencable - if ((FD_ISSET(sock,&wfds))&&(FD_ISSET(sock,&_writefds))) { - try { - _handler->phyOnUnixWritable((PhySocket *)&(*s),&(s->uptr),false); - } catch ( ... ) {} - } - if (FD_ISSET(sock,&rfds)) { - long n = (long)::read(sock,buf,sizeof(buf)); - if (n <= 0) { - this->close((PhySocket *)&(*s),true); - } else { - try { - _handler->phyOnUnixData((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n); - } catch ( ... ) {} - } - } -#endif // __UNIX_LIKE__ - } break; - - case ZT_PHY_SOCKET_UNIX_LISTEN: -#ifdef __UNIX_LIKE__ - if (FD_ISSET(s->sock,&rfds)) { - memset(&ss,0,sizeof(ss)); - socklen_t slen = sizeof(ss); - ZT_PHY_SOCKFD_TYPE newSock = ::accept(s->sock,(struct sockaddr *)&ss,&slen); - if (ZT_PHY_SOCKFD_VALID(newSock)) { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) { - ZT_PHY_CLOSE_SOCKET(newSock); - } else { - fcntl(newSock,F_SETFL,O_NONBLOCK); - _socks.push_back(PhySocketImpl()); - PhySocketImpl &sws = _socks.back(); - FD_SET(newSock,&_readfds); - if ((long)newSock > _nfds) - _nfds = (long)newSock; - sws.type = ZT_PHY_SOCKET_UNIX_IN; - sws.sock = newSock; - sws.uptr = (void *)0; - memcpy(&(sws.saddr),&ss,sizeof(struct sockaddr_storage)); - try { - //_handler->phyOnUnixAccept((PhySocket *)&(*s),(PhySocket *)&(_socks.back()),&(s->uptr),&(sws.uptr)); - } catch ( ... ) {} - } - } - } -#endif // __UNIX_LIKE__ - break; - - case ZT_PHY_SOCKET_FD: { - ZT_PHY_SOCKFD_TYPE sock = s->sock; - const bool readable = ((FD_ISSET(sock,&rfds))&&(FD_ISSET(sock,&_readfds))); - const bool writable = ((FD_ISSET(sock,&wfds))&&(FD_ISSET(sock,&_writefds))); - if ((readable)||(writable)) { - try { - //_handler->phyOnFileDescriptorActivity((PhySocket *)&(*s),&(s->uptr),readable,writable); - } catch ( ... ) {} - } - } break; - - default: - break; - - } - - if (s->type == ZT_PHY_SOCKET_CLOSED) - _socks.erase(s++); - else ++s; - } - } - - /** - * @param sock Socket to close - * @param callHandlers If true, call handlers for TCP connect (success: false) or close (default: true) - */ - inline void close(PhySocket *sock,bool callHandlers = true) - { - if (!sock) - return; - PhySocketImpl &sws = *(reinterpret_cast(sock)); - if (sws.type == ZT_PHY_SOCKET_CLOSED) - return; - - FD_CLR(sws.sock,&_readfds); - FD_CLR(sws.sock,&_writefds); -#if defined(_WIN32) || defined(_WIN64) - FD_CLR(sws.sock,&_exceptfds); -#endif - - if (sws.type != ZT_PHY_SOCKET_FD) - ZT_PHY_CLOSE_SOCKET(sws.sock); - -#ifdef __UNIX_LIKE__ - if (sws.type == ZT_PHY_SOCKET_UNIX_LISTEN) - ::unlink(((struct sockaddr_un *)(&(sws.saddr)))->sun_path); -#endif // __UNIX_LIKE__ - - if (callHandlers) { - switch(sws.type) { - case ZT_PHY_SOCKET_TCP_OUT_PENDING: - try { - _handler->phyOnTcpConnect(sock,&(sws.uptr),false); - } catch ( ... ) {} - break; - case ZT_PHY_SOCKET_TCP_OUT_CONNECTED: - case ZT_PHY_SOCKET_TCP_IN: - try { - _handler->phyOnTcpClose(sock,&(sws.uptr)); - } catch ( ... ) {} - break; - case ZT_PHY_SOCKET_UNIX_IN: -#ifdef __UNIX_LIKE__ - try { - _handler->phyOnUnixClose(sock,&(sws.uptr)); - } catch ( ... ) {} -#endif // __UNIX_LIKE__ - break; - default: - break; - } - } - - // Causes entry to be deleted from list in poll(), ignored elsewhere - sws.type = ZT_PHY_SOCKET_CLOSED; - - if ((long)sws.sock >= (long)_nfds) { - long nfds = (long)_whackSendSocket; - if ((long)_whackReceiveSocket > nfds) - nfds = (long)_whackReceiveSocket; - for(typename std::list::iterator s(_socks.begin());s!=_socks.end();++s) { - if ((s->type != ZT_PHY_SOCKET_CLOSED)&&((long)s->sock > nfds)) - nfds = (long)s->sock; - } - _nfds = nfds; - } - } -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/osdep/PortMapper.cpp b/zto/osdep/PortMapper.cpp deleted file mode 100644 index d3a1938..0000000 --- a/zto/osdep/PortMapper.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifdef ZT_USE_MINIUPNPC - -// Uncomment to dump debug messages -//#define ZT_PORTMAPPER_TRACE 1 - -#include -#include -#include - -#include - -#include "../node/Utils.hpp" -#include "OSUtils.hpp" -#include "PortMapper.hpp" - -// These must be defined to get rid of dynamic export stuff in libminiupnpc and libnatpmp -#ifdef __WINDOWS__ -#ifndef MINIUPNP_STATICLIB -#define MINIUPNP_STATICLIB -#endif -#ifndef STATICLIB -#define STATICLIB -#endif -#endif - -#ifdef ZT_USE_SYSTEM_MINIUPNPC -#include -#include -#else -#include "../ext/miniupnpc/miniupnpc.h" -#include "../ext/miniupnpc/upnpcommands.h" -#endif - -#ifdef ZT_USE_SYSTEM_NATPMP -#include -#else -#include "../ext/libnatpmp/natpmp.h" -#endif - -namespace ZeroTier { - -class PortMapperImpl -{ -public: - PortMapperImpl(int localUdpPortToMap,const char *un) : - run(true), - localPort(localUdpPortToMap), - uniqueName(un) - { - } - - ~PortMapperImpl() {} - - void threadMain() - throw() - { - int mode = 0; // 0 == NAT-PMP, 1 == UPnP - -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: started for UDP port %d"ZT_EOL_S,localPort); -#endif - - while (run) { - - // --------------------------------------------------------------------- - // NAT-PMP mode (preferred) - // --------------------------------------------------------------------- - if (mode == 0) { - natpmp_t natpmp; - natpmpresp_t response; - int r = 0; - - bool natPmpSuccess = false; - for(int tries=0;tries<60;++tries) { - int tryPort = (int)localPort + tries; - if (tryPort >= 65535) - tryPort = (tryPort - 65535) + 1025; - - memset(&natpmp,0,sizeof(natpmp)); - memset(&response,0,sizeof(response)); - - if (initnatpmp(&natpmp,0,0) != 0) { - mode = 1; -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: NAT-PMP: init failed, switching to UPnP mode"ZT_EOL_S); -#endif - break; - } - - InetAddress publicAddress; - sendpublicaddressrequest(&natpmp); - uint64_t myTimeout = OSUtils::now() + 5000; - do { - fd_set fds; - struct timeval timeout; - FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); - select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); - if (OSUtils::now() >= myTimeout) - break; - } while (r == NATPMP_TRYAGAIN); - if (r == 0) { - publicAddress = InetAddress((uint32_t)response.pnu.publicaddress.addr.s_addr,0); - } else { -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: NAT-PMP: request for external address failed, aborting..."ZT_EOL_S); -#endif - closenatpmp(&natpmp); - break; - } - - sendnewportmappingrequest(&natpmp,NATPMP_PROTOCOL_UDP,localPort,tryPort,(ZT_PORTMAPPER_REFRESH_DELAY * 2) / 1000); - myTimeout = OSUtils::now() + 10000; - do { - fd_set fds; - struct timeval timeout; - FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); - select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); - if (OSUtils::now() >= myTimeout) - break; - } while (r == NATPMP_TRYAGAIN); - if (r == 0) { - publicAddress.setPort(response.pnu.newportmapping.mappedpublicport); -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: NAT-PMP: mapped %u to %s"ZT_EOL_S,(unsigned int)localPort,publicAddress.toString().c_str()); -#endif - Mutex::Lock sl(surface_l); - surface.clear(); - surface.push_back(publicAddress); - natPmpSuccess = true; - closenatpmp(&natpmp); - break; - } else { - closenatpmp(&natpmp); - // continue - } - } - - if (!natPmpSuccess) { - mode = 1; -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: NAT-PMP: request failed, switching to UPnP mode"ZT_EOL_S); -#endif - } - } - // --------------------------------------------------------------------- - - // --------------------------------------------------------------------- - // UPnP mode - // --------------------------------------------------------------------- - if (mode == 1) { - char lanaddr[4096]; - char externalip[4096]; // no range checking? so make these buffers larger than any UDP packet a uPnP server could send us as a precaution :P - char inport[16]; - char outport[16]; - struct UPNPUrls urls; - struct IGDdatas data; - - int upnpError = 0; - UPNPDev *devlist = upnpDiscoverAll(5000,(const char *)0,(const char *)0,0,0,2,&upnpError); - if (devlist) { - -#ifdef ZT_PORTMAPPER_TRACE - { - UPNPDev *dev = devlist; - while (dev) { - fprintf(stderr,"PortMapper: found UPnP device at URL '%s': %s"ZT_EOL_S,dev->descURL,dev->st); - dev = dev->pNext; - } - } -#endif - - memset(lanaddr,0,sizeof(lanaddr)); - memset(externalip,0,sizeof(externalip)); - memset(&urls,0,sizeof(urls)); - memset(&data,0,sizeof(data)); - Utils::snprintf(inport,sizeof(inport),"%d",localPort); - - if ((UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) { -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: UPnP: my LAN IP address: %s"ZT_EOL_S,lanaddr); -#endif - if ((UPNP_GetExternalIPAddress(urls.controlURL,data.first.servicetype,externalip) == UPNPCOMMAND_SUCCESS)&&(externalip[0])) { -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: UPnP: my external IP address: %s"ZT_EOL_S,externalip); -#endif - - for(int tries=0;tries<60;++tries) { - int tryPort = (int)localPort + tries; - if (tryPort >= 65535) - tryPort = (tryPort - 65535) + 1025; - Utils::snprintf(outport,sizeof(outport),"%u",tryPort); - - // First check and see if this port is already mapped to the - // same unique name. If so, keep this mapping and don't try - // to map again since this can break buggy routers. But don't - // fail if this command fails since not all routers support it. - { - char haveIntClient[128]; // 128 == big enough for all these as per miniupnpc "documentation" - char haveIntPort[128]; - char haveDesc[128]; - char haveEnabled[128]; - char haveLeaseDuration[128]; - memset(haveIntClient,0,sizeof(haveIntClient)); - memset(haveIntPort,0,sizeof(haveIntPort)); - memset(haveDesc,0,sizeof(haveDesc)); - memset(haveEnabled,0,sizeof(haveEnabled)); - memset(haveLeaseDuration,0,sizeof(haveLeaseDuration)); - if ((UPNP_GetSpecificPortMappingEntry(urls.controlURL,data.first.servicetype,outport,"UDP",(const char *)0,haveIntClient,haveIntPort,haveDesc,haveEnabled,haveLeaseDuration) == UPNPCOMMAND_SUCCESS)&&(uniqueName == haveDesc)) { -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: UPnP: reusing previously reserved external port: %s"ZT_EOL_S,outport); -#endif - Mutex::Lock sl(surface_l); - surface.clear(); - InetAddress tmp(externalip); - tmp.setPort(tryPort); - surface.push_back(tmp); - break; - } - } - - // Try to map this port - int mapResult = 0; - if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,uniqueName.c_str(),"UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) { -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: UPnP: reserved external port: %s"ZT_EOL_S,outport); -#endif - Mutex::Lock sl(surface_l); - surface.clear(); - InetAddress tmp(externalip); - tmp.setPort(tryPort); - surface.push_back(tmp); - break; - } else { -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d"ZT_EOL_S,outport,mapResult); -#endif - Thread::sleep(1000); - } - } - - } else { - mode = 0; -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode"ZT_EOL_S); -#endif - } - } else { - mode = 0; -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode"ZT_EOL_S); -#endif - } - - freeUPNPDevlist(devlist); - - } else { - mode = 0; -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d"ZT_EOL_S,upnpError); -#endif - } - } - // --------------------------------------------------------------------- - -#ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"UPNPClient: rescanning in %d ms"ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY); -#endif - Thread::sleep(ZT_PORTMAPPER_REFRESH_DELAY); - } - - delete this; - } - - volatile bool run; - int localPort; - std::string uniqueName; - - Mutex surface_l; - std::vector surface; -}; - -PortMapper::PortMapper(int localUdpPortToMap,const char *uniqueName) -{ - _impl = new PortMapperImpl(localUdpPortToMap,uniqueName); - Thread::start(_impl); -} - -PortMapper::~PortMapper() -{ - _impl->run = false; -} - -std::vector PortMapper::get() const -{ - Mutex::Lock _l(_impl->surface_l); - return _impl->surface; -} - -} // namespace ZeroTier - -#endif // ZT_USE_MINIUPNPC diff --git a/zto/osdep/PortMapper.hpp b/zto/osdep/PortMapper.hpp deleted file mode 100644 index 0b8d15f..0000000 --- a/zto/osdep/PortMapper.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifdef ZT_USE_MINIUPNPC - -#ifndef ZT_PORTMAPPER_HPP -#define ZT_PORTMAPPER_HPP - -#include - -#include "../node/Constants.hpp" -#include "../node/InetAddress.hpp" -#include "../node/Mutex.hpp" -#include "Thread.hpp" - -/** - * How frequently should we refresh our UPNP/NAT-PnP/whatever state? - */ -#define ZT_PORTMAPPER_REFRESH_DELAY 300000 - -namespace ZeroTier { - -class PortMapperImpl; - -/** - * UPnP/NAT-PnP port mapping "daemon" - */ -class PortMapper -{ - friend class PortMapperImpl; - -public: - /** - * Create and start port mapper service - * - * @param localUdpPortToMap Port we want visible to the outside world - * @param name Unique name of this endpoint (based on ZeroTier address) - */ - PortMapper(int localUdpPortToMap,const char *uniqueName); - - ~PortMapper(); - - /** - * @return All current external mappings for our port - */ - std::vector get() const; - -private: - PortMapperImpl *_impl; -}; - -} // namespace ZeroTier - -#endif - -#endif // ZT_USE_MINIUPNPC diff --git a/zto/osdep/README.md b/zto/osdep/README.md deleted file mode 100644 index a77297a..0000000 --- a/zto/osdep/README.md +++ /dev/null @@ -1,6 +0,0 @@ -OS-Dependent and OS-Interface Things -====== - -This folder contains stuff that interfaces with the base operating system -like Phy for network access and the various OS-specific Ethernet tap -drivers. diff --git a/zto/osdep/Thread.hpp b/zto/osdep/Thread.hpp deleted file mode 100644 index 227c2cf..0000000 --- a/zto/osdep/Thread.hpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_THREAD_HPP -#define ZT_THREAD_HPP - -#include - -#include "../node/Constants.hpp" - -#ifdef __WINDOWS__ - -#include -#include -#include - -#include "../node/Mutex.hpp" - -namespace ZeroTier { - -template -static DWORD WINAPI ___zt_threadMain(LPVOID lpParam) -{ - try { - ((C *)lpParam)->threadMain(); - } catch ( ... ) {} - return 0; -} - -class Thread -{ -public: - Thread() - throw() - { - _th = NULL; - _tid = 0; - } - - template - static inline Thread start(C *instance) - throw(std::runtime_error) - { - Thread t; - t._th = CreateThread(NULL,0,&___zt_threadMain,(LPVOID)instance,0,&t._tid); - if (t._th == NULL) - throw std::runtime_error("CreateThread() failed"); - return t; - } - - static inline void join(const Thread &t) - { - if (t._th != NULL) { - for(;;) { - DWORD ec = STILL_ACTIVE; - GetExitCodeThread(t._th,&ec); - if (ec == STILL_ACTIVE) - WaitForSingleObject(t._th,1000); - else break; - } - } - } - - static inline void sleep(unsigned long ms) - { - Sleep((DWORD)ms); - } - - // Not available on *nix platforms - static inline void cancelIO(const Thread &t) - { - if (t._th != NULL) - CancelSynchronousIo(t._th); - } - - inline operator bool() const throw() { return (_th != NULL); } - -private: - HANDLE _th; - DWORD _tid; -}; - -} // namespace ZeroTier - -#else - -#include -#include -#include -#include -#include - -namespace ZeroTier { - -template -static void *___zt_threadMain(void *instance) -{ - try { - ((C *)instance)->threadMain(); - } catch ( ... ) {} - return (void *)0; -} - -/** - * A thread identifier, and static methods to start and join threads - */ -class Thread -{ -public: - Thread() - throw() - { - memset(&_tid,0,sizeof(_tid)); - pthread_attr_init(&_tattr); - // This corrects for systems with abnormally small defaults (musl) and also - // shrinks the stack on systems with large defaults to save a bit of memory. - pthread_attr_setstacksize(&_tattr,ZT_THREAD_MIN_STACK_SIZE); - _started = false; - } - - ~Thread() - { - pthread_attr_destroy(&_tattr); - } - - Thread(const Thread &t) - throw() - { - memcpy(&_tid,&(t._tid),sizeof(_tid)); - _started = t._started; - } - - inline Thread &operator=(const Thread &t) - throw() - { - memcpy(&_tid,&(t._tid),sizeof(_tid)); - _started = t._started; - return *this; - } - - /** - * Start a new thread - * - * @param instance Instance whose threadMain() method gets called by new thread - * @return Thread identifier - * @throws std::runtime_error Unable to create thread - * @tparam C Class containing threadMain() - */ - template - static inline Thread start(C *instance) - throw(std::runtime_error) - { - Thread t; - t._started = true; - if (pthread_create(&t._tid,&t._tattr,&___zt_threadMain,instance)) - throw std::runtime_error("pthread_create() failed, unable to create thread"); - return t; - } - - /** - * Join to a thread, waiting for it to terminate (does nothing on null Thread values) - * - * @param t Thread to join - */ - static inline void join(const Thread &t) - { - if (t._started) - pthread_join(t._tid,(void **)0); - } - - /** - * Sleep the current thread - * - * @param ms Number of milliseconds to sleep - */ - static inline void sleep(unsigned long ms) { usleep(ms * 1000); } - - inline operator bool() const throw() { return (_started); } - -private: - pthread_t _tid; - pthread_attr_t _tattr; - volatile bool _started; -}; - -} // namespace ZeroTier - -#endif // __WINDOWS__ / !__WINDOWS__ - -#endif diff --git a/zto/osdep/WindowsEthernetTap.cpp b/zto/osdep/WindowsEthernetTap.cpp deleted file mode 100644 index 79b9d35..0000000 --- a/zto/osdep/WindowsEthernetTap.cpp +++ /dev/null @@ -1,1222 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" - -#include "WindowsEthernetTap.hpp" -#include "OSUtils.hpp" - -#include "..\windows\TapDriver6\tap-windows.h" - -// Create a fake unused default route to force detection of network type on networks without gateways -#define ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE - -// Function signatures of dynamically loaded functions, from newdev.h, setupapi.h, and cfgmgr32.h -typedef BOOL (WINAPI *UpdateDriverForPlugAndPlayDevicesA_t)(_In_opt_ HWND hwndParent,_In_ LPCSTR HardwareId,_In_ LPCSTR FullInfPath,_In_ DWORD InstallFlags,_Out_opt_ PBOOL bRebootRequired); -typedef BOOL (WINAPI *SetupDiGetINFClassA_t)(_In_ PCSTR InfName,_Out_ LPGUID ClassGuid,_Out_writes_(ClassNameSize) PSTR ClassName,_In_ DWORD ClassNameSize,_Out_opt_ PDWORD RequiredSize); -typedef HDEVINFO (WINAPI *SetupDiCreateDeviceInfoList_t)(_In_opt_ CONST GUID *ClassGuid,_In_opt_ HWND hwndParent); -typedef BOOL (WINAPI *SetupDiCreateDeviceInfoA_t)(_In_ HDEVINFO DeviceInfoSet,_In_ PCSTR DeviceName,_In_ CONST GUID *ClassGuid,_In_opt_ PCSTR DeviceDescription,_In_opt_ HWND hwndParent,_In_ DWORD CreationFlags,_Out_opt_ PSP_DEVINFO_DATA DeviceInfoData); -typedef BOOL (WINAPI *SetupDiSetDeviceRegistryPropertyA_t)(_In_ HDEVINFO DeviceInfoSet,_Inout_ PSP_DEVINFO_DATA DeviceInfoData,_In_ DWORD Property,_In_reads_bytes_opt_(PropertyBufferSize) CONST BYTE *PropertyBuffer,_In_ DWORD PropertyBufferSize); -typedef BOOL (WINAPI *SetupDiCallClassInstaller_t)(_In_ DI_FUNCTION InstallFunction,_In_ HDEVINFO DeviceInfoSet,_In_opt_ PSP_DEVINFO_DATA DeviceInfoData); -typedef BOOL (WINAPI *SetupDiDestroyDeviceInfoList_t)(_In_ HDEVINFO DeviceInfoSet); -typedef HDEVINFO (WINAPI *SetupDiGetClassDevsExA_t)(_In_opt_ CONST GUID *ClassGuid,_In_opt_ PCSTR Enumerator,_In_opt_ HWND hwndParent,_In_ DWORD Flags,_In_opt_ HDEVINFO DeviceInfoSet,_In_opt_ PCSTR MachineName,_Reserved_ PVOID Reserved); -typedef BOOL (WINAPI *SetupDiOpenDeviceInfoA_t)(_In_ HDEVINFO DeviceInfoSet,_In_ PCSTR DeviceInstanceId,_In_opt_ HWND hwndParent,_In_ DWORD OpenFlags,_Out_opt_ PSP_DEVINFO_DATA DeviceInfoData); -typedef BOOL (WINAPI *SetupDiEnumDeviceInfo_t)(_In_ HDEVINFO DeviceInfoSet,_In_ DWORD MemberIndex,_Out_ PSP_DEVINFO_DATA DeviceInfoData); -typedef BOOL (WINAPI *SetupDiSetClassInstallParamsA_t)(_In_ HDEVINFO DeviceInfoSet,_In_opt_ PSP_DEVINFO_DATA DeviceInfoData,_In_reads_bytes_opt_(ClassInstallParamsSize) PSP_CLASSINSTALL_HEADER ClassInstallParams,_In_ DWORD ClassInstallParamsSize); -typedef CONFIGRET (WINAPI *CM_Get_Device_ID_ExA_t)(_In_ DEVINST dnDevInst,_Out_writes_(BufferLen) PSTR Buffer,_In_ ULONG BufferLen,_In_ ULONG ulFlags,_In_opt_ HMACHINE hMachine); -typedef BOOL (WINAPI *SetupDiGetDeviceInstanceIdA_t)(_In_ HDEVINFO DeviceInfoSet,_In_ PSP_DEVINFO_DATA DeviceInfoData,_Out_writes_opt_(DeviceInstanceIdSize) PSTR DeviceInstanceId,_In_ DWORD DeviceInstanceIdSize,_Out_opt_ PDWORD RequiredSize); - -namespace ZeroTier { - -namespace { - -// Static/singleton class that when initialized loads a bunch of environment information and a few dynamically loaded DLLs -class WindowsEthernetTapEnv -{ -public: - WindowsEthernetTapEnv() - { -#ifdef _WIN64 - is64Bit = TRUE; - tapDriverPath = "\\tap-windows\\x64\\zttap300.inf"; -#else - is64Bit = FALSE; - IsWow64Process(GetCurrentProcess(),&is64Bit); - if (is64Bit) { - fprintf(stderr,"FATAL: you must use the 64-bit ZeroTier One service on 64-bit Windows systems\r\n"); - _exit(1); - } - tapDriverPath = "\\tap-windows\\x86\\zttap300.inf"; -#endif - tapDriverName = "zttap300"; - - setupApiMod = LoadLibraryA("setupapi.dll"); - if (!setupApiMod) { - fprintf(stderr,"FATAL: unable to dynamically load setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiGetINFClassA = (SetupDiGetINFClassA_t)GetProcAddress(setupApiMod,"SetupDiGetINFClassA"))) { - fprintf(stderr,"FATAL: SetupDiGetINFClassA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiCreateDeviceInfoList = (SetupDiCreateDeviceInfoList_t)GetProcAddress(setupApiMod,"SetupDiCreateDeviceInfoList"))) { - fprintf(stderr,"FATAL: SetupDiCreateDeviceInfoList not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiCreateDeviceInfoA = (SetupDiCreateDeviceInfoA_t)GetProcAddress(setupApiMod,"SetupDiCreateDeviceInfoA"))) { - fprintf(stderr,"FATAL: SetupDiCreateDeviceInfoA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiSetDeviceRegistryPropertyA = (SetupDiSetDeviceRegistryPropertyA_t)GetProcAddress(setupApiMod,"SetupDiSetDeviceRegistryPropertyA"))) { - fprintf(stderr,"FATAL: SetupDiSetDeviceRegistryPropertyA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiCallClassInstaller = (SetupDiCallClassInstaller_t)GetProcAddress(setupApiMod,"SetupDiCallClassInstaller"))) { - fprintf(stderr,"FATAL: SetupDiCallClassInstaller not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiDestroyDeviceInfoList = (SetupDiDestroyDeviceInfoList_t)GetProcAddress(setupApiMod,"SetupDiDestroyDeviceInfoList"))) { - fprintf(stderr,"FATAL: SetupDiDestroyDeviceInfoList not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiGetClassDevsExA = (SetupDiGetClassDevsExA_t)GetProcAddress(setupApiMod,"SetupDiGetClassDevsExA"))) { - fprintf(stderr,"FATAL: SetupDiGetClassDevsExA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiOpenDeviceInfoA = (SetupDiOpenDeviceInfoA_t)GetProcAddress(setupApiMod,"SetupDiOpenDeviceInfoA"))) { - fprintf(stderr,"FATAL: SetupDiOpenDeviceInfoA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiEnumDeviceInfo = (SetupDiEnumDeviceInfo_t)GetProcAddress(setupApiMod,"SetupDiEnumDeviceInfo"))) { - fprintf(stderr,"FATAL: SetupDiEnumDeviceInfo not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiSetClassInstallParamsA = (SetupDiSetClassInstallParamsA_t)GetProcAddress(setupApiMod,"SetupDiSetClassInstallParamsA"))) { - fprintf(stderr,"FATAL: SetupDiSetClassInstallParamsA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiGetDeviceInstanceIdA = (SetupDiGetDeviceInstanceIdA_t)GetProcAddress(setupApiMod,"SetupDiGetDeviceInstanceIdA"))) { - fprintf(stderr,"FATAL: SetupDiGetDeviceInstanceIdA not found in setupapi.dll\r\n"); - _exit(1); - } - - newDevMod = LoadLibraryA("newdev.dll"); - if (!newDevMod) { - fprintf(stderr,"FATAL: unable to dynamically load newdev.dll\r\n"); - _exit(1); - } - if (!(this->UpdateDriverForPlugAndPlayDevicesA = (UpdateDriverForPlugAndPlayDevicesA_t)GetProcAddress(newDevMod,"UpdateDriverForPlugAndPlayDevicesA"))) { - fprintf(stderr,"FATAL: UpdateDriverForPlugAndPlayDevicesA not found in newdev.dll\r\n"); - _exit(1); - } - - cfgMgrMod = LoadLibraryA("cfgmgr32.dll"); - if (!cfgMgrMod) { - fprintf(stderr,"FATAL: unable to dynamically load cfgmgr32.dll\r\n"); - _exit(1); - } - if (!(this->CM_Get_Device_ID_ExA = (CM_Get_Device_ID_ExA_t)GetProcAddress(cfgMgrMod,"CM_Get_Device_ID_ExA"))) { - fprintf(stderr,"FATAL: CM_Get_Device_ID_ExA not found in cfgmgr32.dll\r\n"); - _exit(1); - } - } - - BOOL is64Bit; // is the system 64-bit, regardless of whether this binary is or not - std::string tapDriverPath; - std::string tapDriverName; - - UpdateDriverForPlugAndPlayDevicesA_t UpdateDriverForPlugAndPlayDevicesA; - - SetupDiGetINFClassA_t SetupDiGetINFClassA; - SetupDiCreateDeviceInfoList_t SetupDiCreateDeviceInfoList; - SetupDiCreateDeviceInfoA_t SetupDiCreateDeviceInfoA; - SetupDiSetDeviceRegistryPropertyA_t SetupDiSetDeviceRegistryPropertyA; - SetupDiCallClassInstaller_t SetupDiCallClassInstaller; - SetupDiDestroyDeviceInfoList_t SetupDiDestroyDeviceInfoList; - SetupDiGetClassDevsExA_t SetupDiGetClassDevsExA; - SetupDiOpenDeviceInfoA_t SetupDiOpenDeviceInfoA; - SetupDiEnumDeviceInfo_t SetupDiEnumDeviceInfo; - SetupDiSetClassInstallParamsA_t SetupDiSetClassInstallParamsA; - SetupDiGetDeviceInstanceIdA_t SetupDiGetDeviceInstanceIdA; - - CM_Get_Device_ID_ExA_t CM_Get_Device_ID_ExA; - -private: - HMODULE setupApiMod; - HMODULE newDevMod; - HMODULE cfgMgrMod; -}; -static const WindowsEthernetTapEnv WINENV; - -// Only create or delete devices one at a time -static Mutex _systemTapInitLock; - -// Only perform installation or uninstallation options one at a time -static Mutex _systemDeviceManagementLock; - -} // anonymous namespace - -std::string WindowsEthernetTap::addNewPersistentTapDevice(const char *pathToInf,std::string &deviceInstanceId) -{ - Mutex::Lock _l(_systemDeviceManagementLock); - - GUID classGuid; - char className[1024]; - if (!WINENV.SetupDiGetINFClassA(pathToInf,&classGuid,className,sizeof(className),(PDWORD)0)) { - return std::string("SetupDiGetINFClassA() failed -- unable to read zttap driver INF file"); - } - - HDEVINFO deviceInfoSet = WINENV.SetupDiCreateDeviceInfoList(&classGuid,(HWND)0); - if (deviceInfoSet == INVALID_HANDLE_VALUE) { - return std::string("SetupDiCreateDeviceInfoList() failed"); - } - - SP_DEVINFO_DATA deviceInfoData; - memset(&deviceInfoData,0,sizeof(deviceInfoData)); - deviceInfoData.cbSize = sizeof(deviceInfoData); - if (!WINENV.SetupDiCreateDeviceInfoA(deviceInfoSet,className,&classGuid,(PCSTR)0,(HWND)0,DICD_GENERATE_ID,&deviceInfoData)) { - WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); - return std::string("SetupDiCreateDeviceInfoA() failed"); - } - - if (!WINENV.SetupDiSetDeviceRegistryPropertyA(deviceInfoSet,&deviceInfoData,SPDRP_HARDWAREID,(const BYTE *)WINENV.tapDriverName.c_str(),(DWORD)(WINENV.tapDriverName.length() + 1))) { - WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); - return std::string("SetupDiSetDeviceRegistryPropertyA() failed"); - } - - if (!WINENV.SetupDiCallClassInstaller(DIF_REGISTERDEVICE,deviceInfoSet,&deviceInfoData)) { - WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); - return std::string("SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed"); - } - - // HACK: During upgrades, this can fail while the installer is still running. So make 60 attempts - // with a 1s delay between each attempt. - bool driverInstalled = false; - for(int retryCounter=0;retryCounter<60;++retryCounter) { - BOOL rebootRequired = FALSE; - if (WINENV.UpdateDriverForPlugAndPlayDevicesA((HWND)0,WINENV.tapDriverName.c_str(),pathToInf,INSTALLFLAG_FORCE|INSTALLFLAG_NONINTERACTIVE,&rebootRequired)) { - driverInstalled = true; - break; - } else Sleep(1000); - } - if (!driverInstalled) { - WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); - return std::string("UpdateDriverForPlugAndPlayDevices() failed (made 60 attempts)"); - } - - char iidbuf[1024]; - DWORD iidReqSize = sizeof(iidbuf); - if (WINENV.SetupDiGetDeviceInstanceIdA(deviceInfoSet,&deviceInfoData,iidbuf,sizeof(iidbuf),&iidReqSize)) { - deviceInstanceId = iidbuf; - } // failure here is not fatal since we only need this on Vista and 2008 -- other versions fill it into the registry automatically - - WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); - - return std::string(); -} - -std::string WindowsEthernetTap::destroyAllLegacyPersistentTapDevices() -{ - char subkeyName[1024]; - char subkeyClass[1024]; - char data[1024]; - - std::set instanceIdPathsToRemove; - { - HKEY nwAdapters; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) - return std::string("Could not open registry key"); - - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; - - if ((!strnicmp(data,"zttap",5))&&(WINENV.tapDriverName != data)) { - std::string instanceIdPath; - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - instanceIdPath.assign(data,dataLen); - if (instanceIdPath.length() != 0) - instanceIdPathsToRemove.insert(instanceIdPath); - } - } - } else break; // end of list or failure - } - - RegCloseKey(nwAdapters); - } - - std::string errlist; - for(std::set::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) { - std::string err = deletePersistentTapDevice(iidp->c_str()); - if (err.length() > 0) { - if (errlist.length() > 0) - errlist.push_back(','); - errlist.append(err); - } - } - return errlist; -} - -std::string WindowsEthernetTap::destroyAllPersistentTapDevices() -{ - char subkeyName[1024]; - char subkeyClass[1024]; - char data[1024]; - - std::set instanceIdPathsToRemove; - { - HKEY nwAdapters; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) - return std::string("Could not open registry key"); - - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; - - if (!strnicmp(data,"zttap",5)) { - std::string instanceIdPath; - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - instanceIdPath.assign(data,dataLen); - if (instanceIdPath.length() != 0) - instanceIdPathsToRemove.insert(instanceIdPath); - } - } - } else break; // end of list or failure - } - - RegCloseKey(nwAdapters); - } - - std::string errlist; - for(std::set::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) { - std::string err = deletePersistentTapDevice(iidp->c_str()); - if (err.length() > 0) { - if (errlist.length() > 0) - errlist.push_back(','); - errlist.append(err); - } - } - return errlist; -} - -std::string WindowsEthernetTap::deletePersistentTapDevice(const char *instanceId) -{ - char iid[256]; - SP_REMOVEDEVICE_PARAMS rmdParams; - - memset(&rmdParams,0,sizeof(rmdParams)); - rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); - rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE; - rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL; - rmdParams.HwProfile = 0; - - Mutex::Lock _l(_systemDeviceManagementLock); - - HDEVINFO devInfo = WINENV.SetupDiGetClassDevsExA((const GUID *)0,(PCSTR)0,(HWND)0,DIGCF_ALLCLASSES,(HDEVINFO)0,(PCSTR)0,(PVOID)0); - if (devInfo == INVALID_HANDLE_VALUE) - return std::string("SetupDiGetClassDevsExA() failed"); - WINENV.SetupDiOpenDeviceInfoA(devInfo,instanceId,(HWND)0,0,(PSP_DEVINFO_DATA)0); - - SP_DEVINFO_DATA devInfoData; - memset(&devInfoData,0,sizeof(devInfoData)); - devInfoData.cbSize = sizeof(devInfoData); - for(DWORD devIndex=0;WINENV.SetupDiEnumDeviceInfo(devInfo,devIndex,&devInfoData);devIndex++) { - if ((WINENV.CM_Get_Device_ID_ExA(devInfoData.DevInst,iid,sizeof(iid),0,(HMACHINE)0) == CR_SUCCESS)&&(!strcmp(iid,instanceId))) { - if (!WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,&rmdParams.ClassInstallHeader,sizeof(rmdParams))) { - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return std::string("SetupDiSetClassInstallParams() failed"); - } - - if (!WINENV.SetupDiCallClassInstaller(DIF_REMOVE,devInfo,&devInfoData)) { - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return std::string("SetupDiCallClassInstaller(DIF_REMOVE) failed"); - } - - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return std::string(); - } - } - - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return std::string("instance ID not found"); -} - -bool WindowsEthernetTap::setPersistentTapDeviceState(const char *instanceId,bool enabled) -{ - char iid[256]; - SP_PROPCHANGE_PARAMS params; - - Mutex::Lock _l(_systemDeviceManagementLock); - - HDEVINFO devInfo = WINENV.SetupDiGetClassDevsExA((const GUID *)0,(PCSTR)0,(HWND)0,DIGCF_ALLCLASSES,(HDEVINFO)0,(PCSTR)0,(PVOID)0); - if (devInfo == INVALID_HANDLE_VALUE) - return false; - WINENV.SetupDiOpenDeviceInfoA(devInfo,instanceId,(HWND)0,0,(PSP_DEVINFO_DATA)0); - - SP_DEVINFO_DATA devInfoData; - memset(&devInfoData,0,sizeof(devInfoData)); - devInfoData.cbSize = sizeof(devInfoData); - for(DWORD devIndex=0;WINENV.SetupDiEnumDeviceInfo(devInfo,devIndex,&devInfoData);devIndex++) { - if ((WINENV.CM_Get_Device_ID_ExA(devInfoData.DevInst,iid,sizeof(iid),0,(HMACHINE)0) == CR_SUCCESS)&&(!strcmp(iid,instanceId))) { - memset(¶ms,0,sizeof(params)); - params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); - params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; - params.StateChange = enabled ? DICS_ENABLE : DICS_DISABLE; - params.Scope = DICS_FLAG_GLOBAL; - params.HwProfile = 0; - - WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,¶ms.ClassInstallHeader,sizeof(params)); - WINENV.SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,devInfo,&devInfoData); - - memset(¶ms,0,sizeof(params)); - params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); - params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; - params.StateChange = enabled ? DICS_ENABLE : DICS_DISABLE; - params.Scope = DICS_FLAG_CONFIGSPECIFIC; - params.HwProfile = 0; - - WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,¶ms.ClassInstallHeader,sizeof(params)); - WINENV.SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,devInfo,&devInfoData); - - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return true; - } - } - - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return false; -} - -WindowsEthernetTap::WindowsEthernetTap( - const char *hp, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg) : - _handler(handler), - _arg(arg), - _mac(mac), - _nwid(nwid), - _tap(INVALID_HANDLE_VALUE), - _injectSemaphore(INVALID_HANDLE_VALUE), - _pathToHelpers(hp), - _run(true), - _initialized(false), - _enabled(true) -{ - char subkeyName[1024]; - char subkeyClass[1024]; - char data[1024]; - char tag[24]; - std::string mySubkeyName; - - if (mtu > 2800) - throw std::runtime_error("MTU too large."); - - // We "tag" registry entries with the network ID to identify persistent devices - Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid); - - Mutex::Lock _l(_systemTapInitLock); - - HKEY nwAdapters; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) - throw std::runtime_error("unable to open registry key for network adapter enumeration"); - - // Look for the tap instance that corresponds with this network - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = (char)0; - - if (WINENV.tapDriverName == data) { - std::string instanceId; - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - instanceId.assign(data,dataLen); - - std::string instanceIdPath; - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - instanceIdPath.assign(data,dataLen); - - if ((_netCfgInstanceId.length() == 0)&&(instanceId.length() != 0)&&(instanceIdPath.length() != 0)) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; - if (!strcmp(data,tag)) { - _netCfgInstanceId = instanceId; - _deviceInstanceId = instanceIdPath; - - mySubkeyName = subkeyName; - break; // found it! - } - } - } - } - } - } else break; // no more subkeys or error occurred enumerating them - } - - // If there is no device, try to create one - bool creatingNewDevice = (_netCfgInstanceId.length() == 0); - std::string newDeviceInstanceId; - if (creatingNewDevice) { - for(int getNewAttemptCounter=0;getNewAttemptCounter<2;++getNewAttemptCounter) { - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; - - if (WINENV.tapDriverName == data) { - type = 0; - dataLen = sizeof(data); - if ((RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) != ERROR_SUCCESS)||(dataLen <= 0)) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - RegSetKeyValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",REG_SZ,tag,(DWORD)(strlen(tag)+1)); - - _netCfgInstanceId.assign(data,dataLen); - - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - _deviceInstanceId.assign(data,dataLen); - - mySubkeyName = subkeyName; - - // Disable DHCP by default on new devices - HKEY tcpIpInterfaces; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) { - DWORD enable = 0; - RegSetKeyValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable)); - RegCloseKey(tcpIpInterfaces); - } - - break; // found an unused zttap device - } - } - } - } - } else break; // no more keys or error occurred - } - - if (_netCfgInstanceId.length() > 0) { - break; // found an unused zttap device - } else { - // no unused zttap devices, so create one - std::string errm = addNewPersistentTapDevice((std::string(_pathToHelpers) + WINENV.tapDriverPath).c_str(),newDeviceInstanceId); - if (errm.length() > 0) - throw std::runtime_error(std::string("unable to create new device instance: ")+errm); - } - } - } - - if (_netCfgInstanceId.length() > 0) { - char tmps[64]; - unsigned int tmpsl = Utils::snprintf(tmps,sizeof(tmps),"%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",(unsigned int)mac[0],(unsigned int)mac[1],(unsigned int)mac[2],(unsigned int)mac[3],(unsigned int)mac[4],(unsigned int)mac[5]) + 1; - RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"NetworkAddress",REG_SZ,tmps,tmpsl); - RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"MAC",REG_SZ,tmps,tmpsl); - tmpsl = Utils::snprintf(tmps, sizeof(tmps), "%d", mtu); - RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"MTU",REG_SZ,tmps,tmpsl); - - DWORD tmp = 0; - RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"*NdisDeviceType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); - tmp = IF_TYPE_ETHERNET_CSMACD; - RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"*IfType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); - - if (creatingNewDevice) { - // Vista/2008 does not set this - if (newDeviceInstanceId.length() > 0) - RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"DeviceInstanceID",REG_SZ,newDeviceInstanceId.c_str(),(DWORD)newDeviceInstanceId.length()); - - // Set EnableDHCP to 0 by default on new devices - tmp = 0; - RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"EnableDHCP",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); - } - RegCloseKey(nwAdapters); - } else { - RegCloseKey(nwAdapters); - throw std::runtime_error("unable to find or create tap adapter"); - } - - { - char nobraces[128]; // strip braces from GUID before converting it, because Windows - const char *nbtmp1 = _netCfgInstanceId.c_str(); - char *nbtmp2 = nobraces; - while (*nbtmp1) { - if ((*nbtmp1 != '{')&&(*nbtmp1 != '}')) - *nbtmp2++ = *nbtmp1; - ++nbtmp1; - } - *nbtmp2 = (char)0; - if (UuidFromStringA((RPC_CSTR)nobraces,&_deviceGuid) != RPC_S_OK) - throw std::runtime_error("unable to convert instance ID GUID to native GUID (invalid NetCfgInstanceId in registry?)"); - } - - // Get the LUID, which is one of like four fucking ways to refer to a network device in Windows - if (ConvertInterfaceGuidToLuid(&_deviceGuid,&_deviceLuid) != NO_ERROR) - throw std::runtime_error("unable to convert device interface GUID to LUID"); - - //_initialized = true; - - if (friendlyName) - setFriendlyName(friendlyName); - - _injectSemaphore = CreateSemaphore(NULL,0,1,NULL); - _thread = Thread::start(this); -} - -WindowsEthernetTap::~WindowsEthernetTap() -{ - _run = false; - ReleaseSemaphore(_injectSemaphore,1,NULL); - Thread::join(_thread); - CloseHandle(_injectSemaphore); - setPersistentTapDeviceState(_deviceInstanceId.c_str(),false); -} - -void WindowsEthernetTap::setEnabled(bool en) -{ - _enabled = en; -} - -bool WindowsEthernetTap::enabled() const -{ - return _enabled; -} - -bool WindowsEthernetTap::addIp(const InetAddress &ip) -{ - if (!ip.netmaskBits()) // sanity check... netmask of 0.0.0.0 is WUT? - return false; - - Mutex::Lock _l(_assignedIps_m); - if (std::find(_assignedIps.begin(),_assignedIps.end(),ip) != _assignedIps.end()) - return true; - _assignedIps.push_back(ip); - _syncIps(); - return true; -} - -bool WindowsEthernetTap::removeIp(const InetAddress &ip) -{ - if (ip.isV6()) - return true; - - { - Mutex::Lock _l(_assignedIps_m); - std::vector::iterator aip(std::find(_assignedIps.begin(),_assignedIps.end(),ip)); - if (aip != _assignedIps.end()) - _assignedIps.erase(aip); - } - - if (!_initialized) - return false; - - try { - MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0; - if (GetUnicastIpAddressTable(AF_UNSPEC,&ipt) == NO_ERROR) { - if ((ipt)&&(ipt->NumEntries > 0)) { - for(DWORD i=0;i<(DWORD)ipt->NumEntries;++i) { - if (ipt->Table[i].InterfaceLuid.Value == _deviceLuid.Value) { - InetAddress addr; - switch(ipt->Table[i].Address.si_family) { - case AF_INET: - addr.set(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr),4,ipt->Table[i].OnLinkPrefixLength); - break; - case AF_INET6: - addr.set(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength); - if (addr.ipScope() == InetAddress::IP_SCOPE_LINK_LOCAL) - continue; // can't remove link-local IPv6 addresses - break; - } - if (addr == ip) { - DeleteUnicastIpAddressEntry(&(ipt->Table[i])); - FreeMibTable(ipt); - - if (ip.isV4()) { - std::vector regIps(_getRegistryIPv4Value("IPAddress")); - std::vector regSubnetMasks(_getRegistryIPv4Value("SubnetMask")); - std::string ipstr(ip.toIpString()); - for (std::vector::iterator rip(regIps.begin()), rm(regSubnetMasks.begin()); ((rip != regIps.end()) && (rm != regSubnetMasks.end())); ++rip, ++rm) { - if (*rip == ipstr) { - regIps.erase(rip); - regSubnetMasks.erase(rm); - _setRegistryIPv4Value("IPAddress", regIps); - _setRegistryIPv4Value("SubnetMask", regSubnetMasks); - break; - } - } - } - - return true; - } - } - } - } - FreeMibTable((PVOID)ipt); - } - } catch ( ... ) {} - return false; -} - -std::vector WindowsEthernetTap::ips() const -{ - static const InetAddress linkLocalLoopback("fe80::1",64); // what is this and why does Windows assign it? - std::vector addrs; - - if (!_initialized) - return addrs; - - try { - MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0; - if (GetUnicastIpAddressTable(AF_UNSPEC,&ipt) == NO_ERROR) { - if ((ipt)&&(ipt->NumEntries > 0)) { - for(DWORD i=0;i<(DWORD)ipt->NumEntries;++i) { - if (ipt->Table[i].InterfaceLuid.Value == _deviceLuid.Value) { - switch(ipt->Table[i].Address.si_family) { - case AF_INET: { - InetAddress ip(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr),4,ipt->Table[i].OnLinkPrefixLength); - if (ip != InetAddress::LO4) - addrs.push_back(ip); - } break; - case AF_INET6: { - InetAddress ip(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength); - if ((ip != linkLocalLoopback)&&(ip != InetAddress::LO6)) - addrs.push_back(ip); - } break; - } - } - } - } - FreeMibTable(ipt); - } - } catch ( ... ) {} // sanity check, shouldn't happen unless out of memory - - std::sort(addrs.begin(),addrs.end()); - addrs.erase(std::unique(addrs.begin(),addrs.end()),addrs.end()); - - return addrs; -} - -void WindowsEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - if ((!_initialized)||(!_enabled)||(_tap == INVALID_HANDLE_VALUE)||(len > (ZT_IF_MTU))) - return; - - Mutex::Lock _l(_injectPending_m); - _injectPending.push( std::pair,unsigned int>(Array(),len + 14) ); - char *d = _injectPending.back().first.data; - to.copyTo(d,6); - from.copyTo(d + 6,6); - d[12] = (char)((etherType >> 8) & 0xff); - d[13] = (char)(etherType & 0xff); - memcpy(d + 14,data,len); - - ReleaseSemaphore(_injectSemaphore,1,NULL); -} - -std::string WindowsEthernetTap::deviceName() const -{ - char tmp[1024]; - if (ConvertInterfaceLuidToNameA(&_deviceLuid,tmp,sizeof(tmp)) != NO_ERROR) - return std::string("[ConvertInterfaceLuidToName() failed]"); - return std::string(tmp); -} - -void WindowsEthernetTap::setFriendlyName(const char *dn) -{ - if (!_initialized) - return; - HKEY ifp; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,(std::string("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\") + _netCfgInstanceId).c_str(),0,KEY_READ|KEY_WRITE,&ifp) == ERROR_SUCCESS) { - RegSetKeyValueA(ifp,"Connection","Name",REG_SZ,(LPCVOID)dn,(DWORD)(strlen(dn)+1)); - RegCloseKey(ifp); - } -} - -void WindowsEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) -{ - if (!_initialized) - return; - HANDLE t = _tap; - if (t == INVALID_HANDLE_VALUE) - return; - - std::vector newGroups; - - // The ZT1 tap driver supports an IOCTL to get multicast memberships at the L2 - // level... something Windows does not seem to expose ordinarily. This lets - // pretty much anything work... IPv4, IPv6, IPX, oldskool Netbios, who knows... - unsigned char mcastbuf[TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE]; - DWORD bytesReturned = 0; - if (DeviceIoControl(t,TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS,(LPVOID)0,0,(LPVOID)mcastbuf,sizeof(mcastbuf),&bytesReturned,NULL)) { - if ((bytesReturned > 0)&&(bytesReturned <= TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE)) { // sanity check - MAC mac; - DWORD i = 0; - while ((i + 6) <= bytesReturned) { - mac.setTo(mcastbuf + i,6); - i += 6; - if ((mac.isMulticast())&&(!mac.isBroadcast())) { - // exclude the nulls that may be returned or any other junk Windows puts in there - newGroups.push_back(MulticastGroup(mac,0)); - } - } - } - } - - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - - std::sort(newGroups.begin(),newGroups.end()); - newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end()); - - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } - - _multicastGroups.swap(newGroups); -} - -NET_IFINDEX WindowsEthernetTap::interfaceIndex() const -{ - NET_IFINDEX idx = -1; - if (ConvertInterfaceLuidToIndex(&_deviceLuid,&idx) == NO_ERROR) - return idx; - return -1; -} - -void WindowsEthernetTap::threadMain() - throw() -{ - char tapReadBuf[ZT_IF_MTU + 32]; - char tapPath[128]; - HANDLE wait4[3]; - OVERLAPPED tapOvlRead,tapOvlWrite; - - Utils::snprintf(tapPath,sizeof(tapPath),"\\\\.\\Global\\%s.tap",_netCfgInstanceId.c_str()); - - try { - while (_run) { - // Because Windows - Sleep(250); - setPersistentTapDeviceState(_deviceInstanceId.c_str(),false); - Sleep(250); - setPersistentTapDeviceState(_deviceInstanceId.c_str(),true); - Sleep(250); - setPersistentTapDeviceState(_deviceInstanceId.c_str(),false); - Sleep(250); - setPersistentTapDeviceState(_deviceInstanceId.c_str(),true); - Sleep(250); - - _tap = CreateFileA(tapPath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,NULL); - if (_tap == INVALID_HANDLE_VALUE) { - Sleep(250); - continue; - } - - { - uint32_t tmpi = 1; - DWORD bytesReturned = 0; - DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL); - } - -#ifdef ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE - { - /* This inserts a fake default route and a fake ARP entry, forcing - * Windows to detect this as a "real" network and apply proper - * firewall rules. - * - * This hack is completely stupid, but Windows made me do it - * by being broken and insane. - * - * Background: Windows tries to detect its network location by - * matching it to the ARP address of the default route. Networks - * without default routes are "unidentified networks" and cannot - * have their firewall classification changed by the user (easily). - * - * Yes, you read that right. - * - * The common workaround is to set *NdisDeviceType to 1, which - * totally disables all Windows firewall functionality. This is - * the answer you'll find on most forums for things like OpenVPN. - * - * Yes, you read that right. - * - * The default route workaround is also known, but for this to - * work there must be a known default IP that resolves to a known - * ARP address. This works for an OpenVPN tunnel, but not here - * because this isn't a tunnel. It's a mesh. There is no "other - * end," or any other known always on IP. - * - * So let's make a fake one and shove it in there along with its - * fake static ARP entry. Also makes it instant-on and static. - * - * We'll have to see what DHCP does with this. In the future we - * probably will not want to do this on DHCP-enabled networks, so - * when we enable DHCP we will go in and yank this wacko hacko from - * the routing table before doing so. - * - * Like Jesse Pinkman would say: "YEEEEAAH BITCH!" */ - const uint32_t fakeIp = htonl(0x19fffffe); // 25.255.255.254 -- unrouted IPv4 block - for(int i=0;i<8;++i) { - MIB_IPNET_ROW2 ipnr; - memset(&ipnr,0,sizeof(ipnr)); - ipnr.Address.si_family = AF_INET; - ipnr.Address.Ipv4.sin_addr.s_addr = fakeIp; - ipnr.InterfaceLuid.Value = _deviceLuid.Value; - ipnr.PhysicalAddress[0] = _mac[0] ^ 0x10; // just make something up that's consistent and not part of this net - ipnr.PhysicalAddress[1] = 0x00; - ipnr.PhysicalAddress[2] = (UCHAR)((_deviceGuid.Data1 >> 24) & 0xff); - ipnr.PhysicalAddress[3] = (UCHAR)((_deviceGuid.Data1 >> 16) & 0xff); - ipnr.PhysicalAddress[4] = (UCHAR)((_deviceGuid.Data1 >> 8) & 0xff); - ipnr.PhysicalAddress[5] = (UCHAR)(_deviceGuid.Data1 & 0xff); - ipnr.PhysicalAddressLength = 6; - ipnr.State = NlnsPermanent; - ipnr.IsRouter = 1; - ipnr.IsUnreachable = 0; - ipnr.ReachabilityTime.LastReachable = 0x0fffffff; - ipnr.ReachabilityTime.LastUnreachable = 1; - DWORD result = CreateIpNetEntry2(&ipnr); - if (result != NO_ERROR) - Sleep(250); - else break; - } - for(int i=0;i<8;++i) { - MIB_IPFORWARD_ROW2 nr; - memset(&nr,0,sizeof(nr)); - InitializeIpForwardEntry(&nr); - nr.InterfaceLuid.Value = _deviceLuid.Value; - nr.DestinationPrefix.Prefix.si_family = AF_INET; // rest is left as 0.0.0.0/0 - nr.NextHop.si_family = AF_INET; - nr.NextHop.Ipv4.sin_addr.s_addr = fakeIp; - nr.Metric = 9999; // do not use as real default route - nr.Protocol = MIB_IPPROTO_NETMGMT; - DWORD result = CreateIpForwardEntry2(&nr); - if (result != NO_ERROR) - Sleep(250); - else break; - } - } -#endif - - // Assign or re-assign any should-be-assigned IPs in case we have restarted - { - Mutex::Lock _l(_assignedIps_m); - _syncIps(); - } - - memset(&tapOvlRead,0,sizeof(tapOvlRead)); - tapOvlRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); - memset(&tapOvlWrite,0,sizeof(tapOvlWrite)); - tapOvlWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); - - wait4[0] = _injectSemaphore; - wait4[1] = tapOvlRead.hEvent; - wait4[2] = tapOvlWrite.hEvent; // only included if writeInProgress is true - - ReadFile(_tap,tapReadBuf,sizeof(tapReadBuf),NULL,&tapOvlRead); - bool writeInProgress = false; - ULONGLONG timeOfLastBorkCheck = GetTickCount64(); - - - _initialized = true; - - while (_run) { - DWORD waitResult = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,2500,TRUE); - if (!_run) break; // will also break outer while(_run) - - // Check for issues with adapter and close/reopen if any are detected. This - // check fixes a while boatload of Windows adapter 'coma' issues after - // sleep/wake and when adapters are added/removed. Basically if the tap - // device is borked, whack it. - { - ULONGLONG tc = GetTickCount64(); - if ((tc - timeOfLastBorkCheck) >= 2500) { - timeOfLastBorkCheck = tc; - char aabuf[16384]; - ULONG aalen = sizeof(aabuf); - if (GetAdaptersAddresses(AF_UNSPEC,GAA_FLAG_SKIP_UNICAST|GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_FRIENDLY_NAME,(void *)0,reinterpret_cast(aabuf),&aalen) == NO_ERROR) { - bool isBorked = false; - - PIP_ADAPTER_ADDRESSES aa = reinterpret_cast(aabuf); - while (aa) { - if (_deviceLuid.Value == aa->Luid.Value) { - isBorked = (aa->OperStatus != IfOperStatusUp); - break; - } - aa = aa->Next; - } - - if (isBorked) { - // Close and reopen tap device if there's an issue (outer loop) - break; - } - } - } - } - - if ((waitResult == WAIT_TIMEOUT)||(waitResult == WAIT_FAILED)) { - Sleep(250); // guard against spinning under some conditions - continue; - } - - if (HasOverlappedIoCompleted(&tapOvlRead)) { - DWORD bytesRead = 0; - if (GetOverlappedResult(_tap,&tapOvlRead,&bytesRead,FALSE)) { - if ((bytesRead > 14)&&(_enabled)) { - MAC to(tapReadBuf,6); - MAC from(tapReadBuf + 6,6); - unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff); - try { - _handler(_arg,(void *)0,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14); - } catch ( ... ) {} // handlers should not throw - } - } - ReadFile(_tap,tapReadBuf,ZT_IF_MTU + 32,NULL,&tapOvlRead); - } - - if (writeInProgress) { - if (HasOverlappedIoCompleted(&tapOvlWrite)) { - writeInProgress = false; - _injectPending_m.lock(); - _injectPending.pop(); - } else continue; // still writing, so skip code below and wait - } else _injectPending_m.lock(); - - if (!_injectPending.empty()) { - WriteFile(_tap,_injectPending.front().first.data,_injectPending.front().second,NULL,&tapOvlWrite); - writeInProgress = true; - } - - _injectPending_m.unlock(); - } - - CancelIo(_tap); - - CloseHandle(tapOvlRead.hEvent); - CloseHandle(tapOvlWrite.hEvent); - CloseHandle(_tap); - _tap = INVALID_HANDLE_VALUE; - - // We will restart and re-open the tap unless _run == false - } - } catch ( ... ) {} // catch unexpected exceptions -- this should not happen but would prevent program crash or other weird issues since threads should not throw -} - -NET_IFINDEX WindowsEthernetTap::_getDeviceIndex() -{ - MIB_IF_TABLE2 *ift = (MIB_IF_TABLE2 *)0; - - if (GetIfTable2Ex(MibIfTableRaw,&ift) != NO_ERROR) - throw std::runtime_error("GetIfTable2Ex() failed"); - - if (ift->NumEntries > 0) { - for(ULONG i=0;iNumEntries;++i) { - if (ift->Table[i].InterfaceLuid.Value == _deviceLuid.Value) { - NET_IFINDEX idx = ift->Table[i].InterfaceIndex; - FreeMibTable(ift); - return idx; - } - } - } - - FreeMibTable(&ift); - - throw std::runtime_error("interface not found"); -} - -std::vector WindowsEthernetTap::_getRegistryIPv4Value(const char *regKey) -{ - std::vector value; - HKEY tcpIpInterfaces; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) { - char buf[16384]; - DWORD len = sizeof(buf); - DWORD kt = REG_MULTI_SZ; - if (RegGetValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),regKey,0,&kt,&buf,&len) == ERROR_SUCCESS) { - switch(kt) { - case REG_SZ: - if (len > 0) - value.push_back(std::string(buf)); - break; - case REG_MULTI_SZ: { - for(DWORD k=0,s=0;k &value) -{ - std::string regMulti; - for(std::vector::const_iterator s(value.begin());s!=value.end();++s) { - regMulti.append(*s); - regMulti.push_back((char)0); - } - HKEY tcpIpInterfaces; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) { - if (regMulti.length() > 0) { - regMulti.push_back((char)0); - RegSetKeyValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),regKey,REG_MULTI_SZ,regMulti.data(),(DWORD)regMulti.length()); - } else { - RegDeleteKeyValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),regKey); - } - RegCloseKey(tcpIpInterfaces); - } -} - -void WindowsEthernetTap::_syncIps() -{ - // assumes _assignedIps_m is locked - - if (!_initialized) - return; - - std::vector haveIps(ips()); - - for(std::vector::const_iterator aip(_assignedIps.begin());aip!=_assignedIps.end();++aip) { - if (std::find(haveIps.begin(),haveIps.end(),*aip) == haveIps.end()) { - MIB_UNICASTIPADDRESS_ROW ipr; - - InitializeUnicastIpAddressEntry(&ipr); - if (aip->isV4()) { - ipr.Address.Ipv4.sin_family = AF_INET; - ipr.Address.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)aip->rawIpData()); - ipr.OnLinkPrefixLength = aip->netmaskBits(); - if (ipr.OnLinkPrefixLength >= 32) - continue; - } else if (aip->isV6()) { - ipr.Address.Ipv6.sin6_family = AF_INET6; - memcpy(ipr.Address.Ipv6.sin6_addr.u.Byte,aip->rawIpData(),16); - ipr.OnLinkPrefixLength = aip->netmaskBits(); - if (ipr.OnLinkPrefixLength >= 128) - continue; - } else continue; - - ipr.PrefixOrigin = IpPrefixOriginManual; - ipr.SuffixOrigin = IpSuffixOriginManual; - ipr.ValidLifetime = 0xffffffff; - ipr.PreferredLifetime = 0xffffffff; - - ipr.InterfaceLuid = _deviceLuid; - ipr.InterfaceIndex = _getDeviceIndex(); - - CreateUnicastIpAddressEntry(&ipr); - } - - if (aip->isV4()) - { - std::string ipStr(aip->toIpString()); - std::vector regIps(_getRegistryIPv4Value("IPAddress")); - if (std::find(regIps.begin(), regIps.end(), ipStr) == regIps.end()) { - std::vector regSubnetMasks(_getRegistryIPv4Value("SubnetMask")); - regIps.push_back(ipStr); - regSubnetMasks.push_back(aip->netmask().toIpString()); - _setRegistryIPv4Value("IPAddress", regIps); - _setRegistryIPv4Value("SubnetMask", regSubnetMasks); - } - } - } -} - -} // namespace ZeroTier diff --git a/zto/osdep/WindowsEthernetTap.hpp b/zto/osdep/WindowsEthernetTap.hpp deleted file mode 100644 index f2cf73f..0000000 --- a/zto/osdep/WindowsEthernetTap.hpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_WINDOWSETHERNETTAP_HPP -#define ZT_WINDOWSETHERNETTAP_HPP - -#include -#include - -#include - -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Mutex.hpp" -#include "../node/Array.hpp" -#include "../node/MulticastGroup.hpp" -#include "../node/InetAddress.hpp" -#include "../osdep/Thread.hpp" - -namespace ZeroTier { - -class WindowsEthernetTap -{ -public: - /** - * Installs a new instance of the ZT tap driver - * - * @param pathToInf Path to zttap driver .inf file - * @param deviceInstanceId Buffer to fill with device instance ID on success (and if SetupDiGetDeviceInstanceIdA succeeds, which it should) - * @return Empty string on success, otherwise an error message - */ - static std::string addNewPersistentTapDevice(const char *pathToInf,std::string &deviceInstanceId); - - /** - * Uninstalls all persistent tap devices that have legacy drivers - * - * @return Empty string on success, otherwise an error message - */ - static std::string destroyAllLegacyPersistentTapDevices(); - - /** - * Uninstalls all persistent tap devices on the system - * - * @return Empty string on success, otherwise an error message - */ - static std::string destroyAllPersistentTapDevices(); - - /** - * Uninstall a specific persistent tap device by instance ID - * - * @param instanceId Device instance ID - * @return Empty string on success, otherwise an error message - */ - static std::string deletePersistentTapDevice(const char *instanceId); - - /** - * Disable a persistent tap device by instance ID - * - * @param instanceId Device instance ID - * @param enabled Enable device? - * @return True if device was found and disabled - */ - static bool setPersistentTapDeviceState(const char *instanceId,bool enabled); - - WindowsEthernetTap( - const char *hp, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); - - ~WindowsEthernetTap(); - - void setEnabled(bool en); - bool enabled() const; - bool addIp(const InetAddress &ip); - bool removeIp(const InetAddress &ip); - std::vector ips() const; - void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - std::string deviceName() const; - void setFriendlyName(const char *friendlyName); - void scanMulticastGroups(std::vector &added,std::vector &removed); - - inline const NET_LUID &luid() const { return _deviceLuid; } - inline const GUID &guid() const { return _deviceGuid; } - inline const std::string &instanceId() const { return _deviceInstanceId; } - NET_IFINDEX interfaceIndex() const; - - void threadMain() - throw(); - - bool isInitialized() const { return _initialized; }; - -private: - NET_IFINDEX _getDeviceIndex(); // throws on failure - std::vector _getRegistryIPv4Value(const char *regKey); - void _setRegistryIPv4Value(const char *regKey,const std::vector &value); - void _syncIps(); - - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - MAC _mac; - uint64_t _nwid; - Thread _thread; - - volatile HANDLE _tap; - HANDLE _injectSemaphore; - - GUID _deviceGuid; - NET_LUID _deviceLuid; - std::string _netCfgInstanceId; - std::string _deviceInstanceId; - - std::vector _assignedIps; // IPs assigned with addIp - Mutex _assignedIps_m; - - std::vector _multicastGroups; - - std::queue< std::pair< Array,unsigned int > > _injectPending; - Mutex _injectPending_m; - - std::string _pathToHelpers; - - volatile bool _run; - volatile bool _initialized; - volatile bool _enabled; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/selftest.cpp b/zto/selftest.cpp deleted file mode 100644 index 48625d5..0000000 --- a/zto/selftest.cpp +++ /dev/null @@ -1,1163 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "node/Constants.hpp" -#include "node/Hashtable.hpp" -#include "node/RuntimeEnvironment.hpp" -#include "node/InetAddress.hpp" -#include "node/Utils.hpp" -#include "node/Identity.hpp" -#include "node/Buffer.hpp" -#include "node/Packet.hpp" -#include "node/Salsa20.hpp" -#include "node/MAC.hpp" -#include "node/NetworkConfig.hpp" -#include "node/Peer.hpp" -#include "node/Dictionary.hpp" -#include "node/SHA512.hpp" -#include "node/C25519.hpp" -#include "node/Poly1305.hpp" -#include "node/CertificateOfMembership.hpp" -#include "node/Node.hpp" -#include "node/IncomingPacket.hpp" - -#include "osdep/OSUtils.hpp" -#include "osdep/Phy.hpp" -#include "osdep/Http.hpp" -#include "osdep/PortMapper.hpp" -#include "osdep/Thread.hpp" - -#include "controller/JSONDB.hpp" - -#ifdef __WINDOWS__ -#include -#endif - -using namespace ZeroTier; - -////////////////////////////////////////////////////////////////////////////// - -#define KNOWN_GOOD_IDENTITY "8e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e" -#define KNOWN_BAD_IDENTITY "9e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e" - -static const unsigned char s20TV0Key[32] = { 0x0f,0x62,0xb5,0x08,0x5b,0xae,0x01,0x54,0xa7,0xfa,0x4d,0xa0,0xf3,0x46,0x99,0xec,0x3f,0x92,0xe5,0x38,0x8b,0xde,0x31,0x84,0xd7,0x2a,0x7d,0xd0,0x23,0x76,0xc9,0x1c }; -static const unsigned char s20TV0Iv[8] = { 0x28,0x8f,0xf6,0x5d,0xc4,0x2b,0x92,0xf9 }; -static const unsigned char s20TV0Ks[64] = { 0x5e,0x5e,0x71,0xf9,0x01,0x99,0x34,0x03,0x04,0xab,0xb2,0x2a,0x37,0xb6,0x62,0x5b,0xf8,0x83,0xfb,0x89,0xce,0x3b,0x21,0xf5,0x4a,0x10,0xb8,0x10,0x66,0xef,0x87,0xda,0x30,0xb7,0x76,0x99,0xaa,0x73,0x79,0xda,0x59,0x5c,0x77,0xdd,0x59,0x54,0x2d,0xa2,0x08,0xe5,0x95,0x4f,0x89,0xe4,0x0e,0xb7,0xaa,0x80,0xa8,0x4a,0x61,0x76,0x66,0x3f }; - -static const unsigned char s2012TV0Key[32] = { 0x0f,0x62,0xb5,0x08,0x5b,0xae,0x01,0x54,0xa7,0xfa,0x4d,0xa0,0xf3,0x46,0x99,0xec,0x3f,0x92,0xe5,0x38,0x8b,0xde,0x31,0x84,0xd7,0x2a,0x7d,0xd0,0x23,0x76,0xc9,0x1c }; -static const unsigned char s2012TV0Iv[8] = { 0x28,0x8f,0xf6,0x5d,0xc4,0x2b,0x92,0xf9 }; -static const unsigned char s2012TV0Ks[64] = { 0x99,0xDB,0x33,0xAD,0x11,0xCE,0x0C,0xCB,0x3B,0xFD,0xBF,0x8D,0x0C,0x18,0x16,0x04,0x52,0xD0,0x14,0xCD,0xE9,0x89,0xB4,0xC4,0x11,0xA5,0x59,0xFF,0x7C,0x20,0xA1,0x69,0xE6,0xDC,0x99,0x09,0xD8,0x16,0xBE,0xCE,0xDC,0x40,0x63,0xCE,0x07,0xCE,0xA8,0x28,0xF4,0x4B,0xF9,0xB6,0xC9,0xA0,0xA0,0xB2,0x00,0xE1,0xB5,0x2A,0xF4,0x18,0x59,0xC5 }; - -static const unsigned char poly1305TV0Input[32] = { 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 unsigned char poly1305TV0Key[32] = { 0x74,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x33,0x32,0x2d,0x62,0x79,0x74,0x65,0x20,0x6b,0x65,0x79,0x20,0x66,0x6f,0x72,0x20,0x50,0x6f,0x6c,0x79,0x31,0x33,0x30,0x35 }; -static const unsigned char poly1305TV0Tag[16] = { 0x49,0xec,0x78,0x09,0x0e,0x48,0x1e,0xc6,0xc2,0x6b,0x33,0xb9,0x1c,0xcc,0x03,0x07 }; - -static const unsigned char poly1305TV1Input[12] = { 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x77,0x6f,0x72,0x6c,0x64,0x21 }; -static const unsigned char poly1305TV1Key[32] = { 0x74,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x33,0x32,0x2d,0x62,0x79,0x74,0x65,0x20,0x6b,0x65,0x79,0x20,0x66,0x6f,0x72,0x20,0x50,0x6f,0x6c,0x79,0x31,0x33,0x30,0x35 }; -static const unsigned char poly1305TV1Tag[16] = { 0xa6,0xf7,0x45,0x00,0x8f,0x81,0xc9,0x16,0xa2,0x0d,0xcc,0x74,0xee,0xf2,0xb2,0xf0 }; - -static const char *sha512TV0Input = "supercalifragilisticexpealidocious"; -static const unsigned char sha512TV0Digest[64] = { 0x18,0x2a,0x85,0x59,0x69,0xe5,0xd3,0xe6,0xcb,0xf6,0x05,0x24,0xad,0xf2,0x88,0xd1,0xbb,0xf2,0x52,0x92,0x81,0x24,0x31,0xf6,0xd2,0x52,0xf1,0xdb,0xc1,0xcb,0x44,0xdf,0x21,0x57,0x3d,0xe1,0xb0,0x6b,0x68,0x75,0x95,0x9f,0x3b,0x6f,0x87,0xb1,0x13,0x81,0xd0,0xbc,0x79,0x2c,0x43,0x3a,0x13,0x55,0x3c,0xe0,0x84,0xc2,0x92,0x55,0x31,0x1c }; - -struct C25519TestVector -{ - unsigned char pub1[64]; - unsigned char priv1[64]; - unsigned char pub2[64]; - unsigned char priv2[64]; - unsigned char agreement[64]; - unsigned char agreementSignedBy1[96]; - unsigned char agreementSignedBy2[96]; -}; - -#define ZT_NUM_C25519_TEST_VECTORS 32 - -static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] = { - {{0xa1,0xfc,0x7a,0xb4,0x6d,0xdf,0x7d,0xcf,0xe7,0xec,0x75,0xe5,0xfa,0xdd,0x11,0xcb,0xcc,0x37,0xf8,0x84,0x5d,0x1c,0x92,0x4e,0x09,0x89,0x65,0xfc,0xd8,0xe9,0x5a,0x30,0xda,0xe4,0x86,0xa3,0x35,0xb4,0x19,0x0c,0xbc,0x7b,0xcb,0x3e,0xb9,0x4c,0xbd,0x16,0xe8,0x3d,0x13,0x2b,0xc9,0xc3,0x39,0xea,0xf1,0x42,0xe7,0x6f,0x69,0x78,0x9a,0xb7},{0xe5,0xf3,0x7b,0xd4,0x0e,0xc9,0xdc,0x77,0x50,0x86,0xdc,0xf4,0x2e,0xbc,0xdb,0x27,0xf0,0x73,0xd4,0x58,0x73,0xc4,0x4b,0x71,0x8b,0x3c,0xc5,0x4f,0xa8,0x7c,0xa4,0x84,0xd9,0x96,0x23,0x73,0xb4,0x03,0x16,0xbf,0x1e,0xa1,0x2d,0xd8,0xc4,0x8a,0xe7,0x82,0x10,0xda,0xc9,0xe5,0x45,0x9b,0x01,0xdc,0x73,0xa6,0xc9,0x17,0xa8,0x15,0x31,0x6d},{0x3e,0x49,0xa4,0x0e,0x3a,0xaf,0xa3,0x07,0x3d,0xf7,0x2a,0xec,0x43,0xb1,0xd4,0x09,0x1a,0xcb,0x8e,0x92,0xf9,0x65,0x95,0x04,0x6d,0x2d,0x9b,0x34,0xa3,0xbf,0x51,0x00,0xe2,0xee,0x23,0xf5,0x28,0x0a,0xa9,0xb1,0x57,0x0b,0x96,0x56,0x62,0xba,0x12,0x94,0xaf,0xc6,0x5f,0xb5,0x61,0x43,0x0f,0xde,0x0b,0xab,0xfa,0x4f,0xfe,0xc5,0xe7,0x18},{0x00,0x4d,0x41,0x8d,0xe4,0x69,0x23,0xae,0x98,0xc4,0x3e,0x77,0x0f,0x1d,0x94,0x5d,0x29,0x3e,0x94,0x5a,0x38,0x39,0x20,0x0f,0xd3,0x6f,0x76,0xa2,0x29,0x02,0x03,0xcb,0x0b,0x7f,0x4f,0x1a,0x29,0x51,0x13,0x33,0x7c,0x99,0xb3,0x81,0x82,0x39,0x44,0x05,0x97,0xfb,0x0d,0xf2,0x93,0xa2,0x40,0x94,0xf4,0xff,0x5d,0x09,0x61,0xe4,0x5f,0x76},{0xab,0xce,0xd2,0x24,0xe8,0x93,0xb0,0xe7,0x72,0x14,0xdc,0xbb,0x7d,0x0f,0xd8,0x94,0x16,0x9e,0xb5,0x7f,0xd7,0x19,0x5f,0x3e,0x2d,0x45,0xd5,0xf7,0x90,0x0b,0x3e,0x05,0x18,0x2e,0x2b,0xf4,0xfa,0xd4,0xec,0x62,0x4a,0x4f,0x48,0x50,0xaf,0x1c,0xe8,0x9f,0x1a,0xe1,0x3d,0x70,0x49,0x00,0xa7,0xe3,0x5b,0x1e,0xa1,0x9b,0x68,0x1e,0xa1,0x73},{0xed,0xb6,0xd0,0xf0,0x06,0x6e,0x33,0x9c,0x86,0xfb,0xe8,0xc3,0x6c,0x8d,0xde,0xdd,0xa6,0xa0,0x2d,0xb9,0x07,0x29,0xa3,0x13,0xbb,0xa4,0xba,0xec,0x48,0xc8,0xf4,0x56,0x82,0x79,0xe2,0xb1,0xd3,0x3d,0x83,0x9f,0x10,0xe8,0x52,0xe6,0x8b,0x1c,0x33,0x9e,0x2b,0xd2,0xdb,0x62,0x1c,0x56,0xfd,0x50,0x40,0x77,0x81,0xab,0x21,0x67,0x3e,0x09,0x4f,0xf2,0x51,0xac,0x7d,0xe7,0xd1,0x5d,0x4b,0xe2,0x08,0xc6,0x3f,0x6a,0x4d,0xc8,0x5d,0x74,0xf6,0x3b,0xec,0x8e,0xc6,0x0c,0x32,0x27,0x2f,0x9c,0x09,0x48,0x59,0x10},{0x23,0x0f,0xa3,0xe2,0x69,0xce,0xb9,0xb9,0xd1,0x1c,0x4e,0xab,0x63,0xc9,0x2e,0x1e,0x7e,0xa2,0xa2,0xa0,0x49,0x2e,0x78,0xe4,0x8a,0x02,0x3b,0xa7,0xab,0x1f,0xd4,0xce,0x05,0xe2,0x80,0x09,0x09,0x3c,0x61,0xc7,0x10,0x3a,0x9c,0xf4,0x95,0xac,0x89,0x6f,0x23,0xb3,0x09,0xe2,0x24,0x3f,0xf6,0x96,0x02,0x36,0x41,0x16,0x32,0xe1,0x66,0x05,0x4f,0xf2,0x51,0xac,0x7d,0xe7,0xd1,0x5d,0x4b,0xe2,0x08,0xc6,0x3f,0x6a,0x4d,0xc8,0x5d,0x74,0xf6,0x3b,0xec,0x8e,0xc6,0x0c,0x32,0x27,0x2f,0x9c,0x09,0x48,0x59,0x10}}, - {{0xfd,0x81,0x14,0xf1,0x67,0x07,0x44,0xbb,0x93,0x84,0xa2,0xdc,0x36,0xdc,0xcc,0xb3,0x9e,0x82,0xd4,0x8b,0x42,0x56,0xfb,0xf2,0x6e,0x83,0x3b,0x16,0x2c,0x29,0xfb,0x39,0x29,0x48,0x85,0xe3,0xe3,0xf7,0xe7,0x80,0x49,0xd3,0x01,0x30,0x5a,0x2c,0x3f,0x4c,0xea,0x13,0xeb,0xda,0xf4,0x56,0x75,0x8d,0x50,0x1e,0x19,0x2d,0x29,0x2b,0xfb,0xdb},{0x85,0x34,0x4d,0xf7,0x39,0xbf,0x98,0x79,0x8c,0x98,0xeb,0x8d,0x61,0x27,0xec,0x87,0x56,0xcd,0xd0,0xa6,0x55,0x77,0xee,0xf0,0x20,0xd0,0x59,0x39,0x95,0xab,0x29,0x82,0x8e,0x61,0xf8,0xad,0xed,0xb6,0x27,0xc3,0xd8,0x16,0xce,0x67,0x78,0xe2,0x04,0x4b,0x0c,0x2d,0x2f,0xc3,0x24,0x72,0xbc,0x53,0xbd,0xfe,0x39,0x23,0xd4,0xaf,0x27,0x84},{0x11,0xbe,0x5f,0x5a,0x73,0xe7,0x42,0xef,0xff,0x3c,0x47,0x6a,0x0e,0x6b,0x9e,0x96,0x21,0xa3,0xdf,0x49,0xe9,0x3f,0x40,0xfc,0xab,0xb3,0x66,0xd3,0x3d,0xfa,0x02,0x29,0xf3,0x43,0x45,0x3c,0x70,0xa3,0x5d,0x39,0xf7,0xc0,0x6a,0xcd,0xfa,0x1d,0xbe,0x3b,0x91,0x41,0xe4,0xb0,0x60,0xc0,0x22,0xf7,0x2c,0x11,0x2b,0x1c,0x5f,0x24,0xef,0x53},{0xfd,0x3f,0x09,0x06,0xc9,0x39,0x8d,0x48,0xfa,0x6b,0xc9,0x80,0xbf,0xf6,0xd6,0x76,0xb3,0x62,0x70,0x88,0x4f,0xde,0xde,0xb9,0xb4,0xf0,0xce,0xf3,0x74,0x0d,0xea,0x00,0x9e,0x9c,0x29,0xe1,0xa2,0x1b,0xbd,0xb5,0x83,0xcc,0x12,0xd8,0x48,0x08,0x5b,0xe5,0xd6,0xf9,0x11,0x5c,0xe0,0xd9,0xc3,0x3c,0x26,0xbd,0x69,0x9f,0x5c,0x6f,0x0c,0x6f},{0xca,0xd4,0x76,0x32,0x8b,0xbe,0x0c,0x65,0x75,0x43,0x73,0xc2,0xf2,0xfd,0x7f,0xeb,0xe4,0x62,0xc5,0x0d,0x0f,0xf9,0x01,0xc8,0xb9,0xfa,0xca,0xb4,0x12,0x1c,0xb4,0xac,0x0e,0x5f,0x18,0xfc,0x0c,0x7f,0x2a,0x55,0xc5,0xfd,0x4d,0x83,0xb2,0x02,0x31,0x6a,0x3f,0x14,0xee,0x9d,0x11,0xa8,0x06,0xad,0xeb,0x93,0x19,0x79,0xb1,0xf2,0x78,0x05},{0x85,0xe6,0xe2,0xf2,0x96,0xe7,0xa2,0x8b,0x7e,0x36,0xbd,0x7b,0xf4,0x28,0x6a,0xd7,0xbc,0x2a,0x6a,0x59,0xfd,0xc0,0xc8,0x3d,0x50,0x0f,0x0c,0x2b,0x12,0x3a,0x75,0xc7,0x56,0xbb,0x7f,0x7d,0x4e,0xd4,0x03,0xb8,0x7b,0xde,0xde,0x99,0x65,0x9e,0xc4,0xa6,0x6e,0xfe,0x00,0x88,0xeb,0x9d,0xa4,0xa9,0x9d,0x37,0xc9,0x4a,0xcf,0x69,0xc4,0x01,0xba,0xa8,0xce,0xeb,0x72,0xcb,0x64,0x8b,0x9f,0xc1,0x1f,0x9a,0x9e,0x99,0xcc,0x39,0xec,0xd9,0xbb,0xd9,0xce,0xc2,0x74,0x6f,0xd0,0x2a,0xb9,0xc6,0xe3,0xf5,0xe7,0xf4},{0xb1,0x39,0x50,0xb1,0x1a,0x08,0x42,0x2b,0xdd,0x6d,0x20,0x9f,0x0f,0x37,0xba,0x69,0x97,0x21,0x30,0x7a,0x71,0x2f,0xce,0x98,0x09,0x04,0xa2,0x98,0x6a,0xed,0x02,0x1d,0x5d,0x30,0x8f,0x03,0x47,0x6b,0x89,0xfd,0xf7,0x1a,0xca,0x46,0x6f,0x51,0x69,0x9a,0x2b,0x18,0x77,0xe4,0xad,0x0d,0x7a,0x66,0xd2,0x2c,0x28,0xa0,0xd3,0x0a,0x99,0x0d,0xba,0xa8,0xce,0xeb,0x72,0xcb,0x64,0x8b,0x9f,0xc1,0x1f,0x9a,0x9e,0x99,0xcc,0x39,0xec,0xd9,0xbb,0xd9,0xce,0xc2,0x74,0x6f,0xd0,0x2a,0xb9,0xc6,0xe3,0xf5,0xe7,0xf4}}, - {{0x02,0x3a,0x7e,0x0c,0x6d,0x96,0x3c,0x5d,0x44,0x56,0x5d,0xc1,0x49,0x94,0x35,0x12,0x9d,0xff,0x8a,0x5d,0x91,0x74,0xa8,0x15,0xee,0x5d,0x1e,0x72,0xbe,0x86,0x15,0x68,0xe7,0x36,0xa2,0x4a,0xb8,0xa2,0xa4,0x4c,0xd8,0x95,0xe3,0xc7,0xbb,0x32,0x21,0x90,0x64,0x52,0x32,0xeb,0x26,0xd3,0x4f,0xf0,0x8e,0x27,0x40,0xea,0xed,0xdb,0xf5,0xc4},{0x76,0x99,0x64,0x70,0xf4,0x50,0xc8,0xcc,0x4a,0x5a,0xa5,0x0f,0xeb,0x2d,0xc7,0x0e,0x73,0xd0,0x65,0x7d,0xc3,0xce,0x73,0x03,0x20,0x2f,0xad,0x65,0xfd,0x12,0xe4,0x7f,0xfd,0x45,0x3a,0x6e,0xc5,0x9a,0x06,0x67,0x0e,0xa6,0x7b,0x21,0x49,0x2d,0x01,0x1b,0x8e,0x03,0x6e,0x10,0x08,0x0c,0x68,0xd9,0x60,0x47,0xa4,0xe2,0x52,0xfd,0x3c,0xf4},{0xa3,0xe2,0x5f,0x16,0x39,0x78,0x96,0xf7,0x47,0x6f,0x93,0x5d,0x27,0x7b,0x58,0xe0,0xc5,0xdb,0x71,0x7d,0xa9,0x6f,0xf8,0x8b,0x69,0xdd,0x50,0xea,0x91,0x0d,0x66,0x77,0xaf,0x8f,0xd5,0x9f,0x8a,0x26,0x69,0x4c,0x64,0x37,0x62,0x81,0x6f,0x05,0x9a,0x08,0x0d,0xe1,0x69,0x24,0x77,0x3f,0x50,0xb2,0x49,0x4d,0x93,0xef,0x2e,0x87,0xff,0xde},{0xb3,0x32,0xe2,0x67,0x79,0x32,0x5f,0x64,0x47,0x49,0x1c,0xd3,0x8f,0x95,0x44,0xfd,0x4c,0x7e,0xbf,0x6b,0xb7,0xaf,0x2c,0xdd,0x8f,0xa5,0xd8,0x2f,0xbf,0xa0,0x8a,0x6b,0x58,0x25,0xc9,0x12,0x23,0x6f,0xe6,0x05,0xa8,0xd0,0x68,0x6e,0x0c,0xee,0x70,0xe4,0xa3,0x86,0x51,0x04,0x6d,0xca,0xd5,0xed,0xcf,0x74,0x1d,0x60,0x9e,0x86,0x2d,0x05},{0x91,0xf4,0x5f,0x4a,0xcb,0xd8,0xfd,0x5f,0xb9,0x3d,0x04,0xb8,0xec,0x35,0x85,0x4f,0x58,0x20,0xd1,0x1f,0x47,0xc4,0xf4,0xcb,0x21,0x4e,0x9a,0xf1,0x6e,0xbf,0xe3,0xd3,0x62,0xe3,0x82,0xf6,0xba,0xa8,0xdf,0x92,0xe2,0x3c,0xe5,0xf0,0x16,0x8a,0xeb,0xa4,0xbb,0xc7,0x81,0xaf,0x15,0x19,0x87,0x5f,0xb7,0xe0,0x4c,0x12,0xff,0x2c,0xa9,0xc8},{0xaf,0x85,0xe0,0x36,0x43,0xdf,0x41,0x17,0xda,0xde,0x5e,0xb6,0x33,0xd0,0xce,0x62,0x70,0x5f,0x85,0x24,0x6c,0x3e,0x1b,0xe1,0x52,0xc1,0x9b,0x1c,0xcd,0x61,0x80,0x9c,0xa0,0xe8,0x18,0xee,0x40,0x91,0x93,0x82,0xdb,0x33,0x44,0xff,0xd4,0xf6,0x6f,0x5d,0xf0,0x0e,0x92,0x92,0x81,0x55,0x46,0x06,0xac,0x58,0x81,0x3b,0x04,0xc7,0xf7,0x0d,0xd2,0x0c,0x08,0x6d,0x46,0xdb,0x43,0x28,0x31,0xd8,0xcd,0x87,0x50,0xbb,0xd3,0x07,0xf5,0x72,0x0b,0x15,0x7c,0x16,0xab,0x03,0xd9,0x4b,0x07,0x38,0x97,0xe8,0xd6,0xb5},{0x93,0xff,0x6d,0xc3,0x62,0xf7,0xcc,0x20,0x95,0xc2,0x2f,0x7d,0x1d,0x9b,0xd1,0x63,0xfc,0x61,0x47,0xb3,0x22,0x0f,0xca,0xb0,0x16,0xcf,0x29,0x53,0x46,0x97,0xb1,0x36,0x46,0xac,0x48,0x13,0x92,0xe4,0x46,0x68,0xcf,0x09,0x4e,0xfa,0x59,0x45,0x24,0x08,0xdb,0xb4,0x6f,0x20,0x55,0x12,0xd9,0x75,0x9d,0x8e,0x0b,0xf8,0x63,0xe0,0xf9,0x01,0xd2,0x0c,0x08,0x6d,0x46,0xdb,0x43,0x28,0x31,0xd8,0xcd,0x87,0x50,0xbb,0xd3,0x07,0xf5,0x72,0x0b,0x15,0x7c,0x16,0xab,0x03,0xd9,0x4b,0x07,0x38,0x97,0xe8,0xd6,0xb5}}, - {{0x14,0x35,0xa6,0x7d,0xc1,0xb5,0x71,0xca,0x42,0x50,0x90,0xa7,0x72,0x85,0xbe,0x78,0x7a,0x5f,0x83,0x1e,0xbe,0xef,0x6a,0xbe,0x48,0xc5,0x68,0x14,0x0c,0xf7,0x44,0x5c,0x2e,0xfd,0x1b,0xcc,0xee,0x09,0x23,0x82,0x31,0xad,0xaf,0x4b,0x73,0x9c,0xf2,0x88,0x3c,0xf3,0xb5,0x43,0x8b,0x53,0xf9,0xac,0x17,0x86,0x1c,0xc2,0x53,0x43,0xec,0x03},{0x7b,0x36,0x6c,0xcc,0xb5,0xb2,0x23,0x3d,0x7c,0xe5,0xe7,0xcf,0x06,0xe2,0x32,0x0b,0xc5,0x3b,0x7f,0x86,0x40,0xfc,0xaf,0xba,0x94,0xe0,0x88,0x58,0x5b,0xac,0xe8,0xc3,0xe8,0xc3,0xdf,0xc4,0x45,0x29,0xe8,0xf0,0x1c,0x10,0x0d,0x50,0x81,0x29,0x30,0xa8,0x27,0xb5,0x3e,0xb8,0x25,0xf1,0x17,0x30,0xc6,0x05,0xe3,0x3e,0x45,0x38,0xa8,0x3c},{0xce,0xd9,0x45,0x28,0xb0,0xce,0xa5,0x47,0xa8,0x29,0x32,0x76,0x99,0x73,0x8d,0x74,0xf9,0xed,0x0a,0xd0,0xf1,0xd8,0x7e,0x44,0x63,0x9e,0x9a,0xcf,0x7c,0x35,0x8a,0x29,0xbb,0x71,0x66,0x8d,0xa7,0xfc,0x05,0x3d,0xd4,0x4b,0x65,0x20,0xf5,0xa4,0x64,0xd8,0x9d,0x16,0x80,0x9c,0xb2,0x3c,0x3e,0xd4,0x9d,0x09,0x88,0x8e,0xbb,0x58,0xf8,0x77},{0xe1,0x29,0xb3,0x16,0xe6,0xa0,0xdb,0x64,0x08,0x36,0xdc,0x33,0xad,0x8b,0x30,0x26,0x17,0x56,0xd7,0x34,0x17,0xd1,0xdd,0x23,0x38,0x58,0x25,0x01,0x42,0x5a,0x9d,0x18,0x3e,0xac,0x31,0xfa,0x43,0x28,0xc4,0x65,0xfb,0x30,0x2f,0x8c,0x16,0x52,0x32,0x1b,0x19,0xb7,0x31,0xf6,0x67,0xa7,0xd8,0xed,0x9a,0xa3,0x95,0x01,0xd7,0xb9,0xe7,0xcc},{0x81,0x2d,0x11,0xa9,0x11,0xf1,0x22,0xe2,0x67,0x70,0xc4,0xba,0x34,0xa1,0x75,0x8c,0xf6,0x0c,0x63,0xe7,0x01,0x3c,0x64,0x6c,0xe8,0xd0,0xf8,0x8e,0x88,0xdf,0x5c,0x61,0x68,0x5d,0x1f,0xeb,0x83,0x1f,0x40,0xb8,0xa8,0x56,0x57,0x26,0x81,0x2c,0xa3,0x0e,0x48,0x4c,0x45,0x4d,0x0d,0x3d,0x6e,0x99,0x52,0xbd,0x0b,0xd8,0x05,0xc5,0xf9,0x61},{0x92,0x45,0xbe,0xe6,0xb4,0x7a,0xfa,0x28,0xd4,0x5b,0x6b,0x17,0xc6,0x13,0x61,0x5d,0x5f,0xd7,0x90,0xbb,0x89,0x35,0x7a,0x02,0x50,0x57,0x56,0x5f,0x19,0xb5,0xb6,0xc5,0x77,0x1e,0x1b,0xc0,0xd7,0x7a,0x29,0xbd,0xe7,0x24,0x01,0x2d,0x37,0xc0,0x38,0x6f,0xc8,0x35,0xa1,0x1b,0xe0,0xea,0x16,0xad,0xbc,0xdc,0xd4,0x8d,0x4e,0x71,0xdb,0x05,0x9e,0xb5,0x53,0x6b,0x5c,0xf1,0x7d,0x15,0x8b,0xd7,0xc7,0x8b,0x89,0x9d,0xfd,0x28,0x7c,0xa1,0x31,0xe2,0xf0,0x2c,0x3a,0x8d,0x0e,0x23,0x85,0x4e,0xf0,0xd1,0xc0,0x83},{0x7b,0x88,0xeb,0x45,0x1c,0x7f,0xfd,0xbe,0xba,0xac,0x53,0x28,0x59,0xe8,0xad,0x28,0xf1,0x97,0x2d,0x6c,0x31,0xa6,0xae,0x47,0x10,0x69,0x68,0x55,0xa6,0x9c,0x03,0x62,0xb7,0x2f,0x31,0x46,0x2a,0x2b,0x98,0xdd,0xe9,0xf9,0xfe,0x77,0x71,0x41,0x54,0xf8,0x59,0x02,0x7a,0xe3,0x45,0x67,0xb6,0xf7,0x94,0x31,0x3e,0x62,0x62,0x2a,0xf9,0x0a,0x9e,0xb5,0x53,0x6b,0x5c,0xf1,0x7d,0x15,0x8b,0xd7,0xc7,0x8b,0x89,0x9d,0xfd,0x28,0x7c,0xa1,0x31,0xe2,0xf0,0x2c,0x3a,0x8d,0x0e,0x23,0x85,0x4e,0xf0,0xd1,0xc0,0x83}}, - {{0x27,0x4d,0x84,0x08,0x95,0x84,0xc8,0xeb,0x1c,0x9a,0x0f,0xca,0x09,0x6f,0x48,0x8b,0x2b,0x06,0xa0,0xae,0xf2,0xe3,0x8a,0xfe,0xd7,0x52,0x4b,0xf2,0xc6,0x7c,0xc1,0x55,0x87,0x2e,0x5a,0xb4,0xc2,0x43,0x0a,0x0d,0xd0,0x00,0xa8,0xe1,0x46,0x68,0x79,0xd8,0x8c,0x01,0x36,0xb7,0x5a,0x61,0x04,0xe9,0x7e,0xbb,0xc9,0xee,0xaa,0x12,0x13,0xda},{0x78,0x66,0xd0,0xa2,0x50,0x82,0x8d,0xb0,0xa0,0x20,0xac,0xa4,0xb6,0xa0,0x31,0xf7,0x7d,0x93,0x37,0x67,0xbb,0x60,0xa2,0x1e,0x36,0xce,0x3d,0x48,0x1d,0x79,0x99,0xa5,0x19,0xd8,0x89,0x1b,0xcb,0x14,0x87,0xb7,0x62,0xfd,0xd2,0xef,0xbb,0x13,0x41,0x4d,0xf1,0x77,0x5c,0x7f,0x6c,0x3b,0x94,0x7d,0xb4,0xba,0x87,0x3e,0xc8,0xe1,0x3c,0x0a},{0xd9,0x9e,0x14,0x89,0xd6,0xf8,0x49,0xa2,0xe2,0x19,0xfe,0x94,0xaa,0xf7,0x35,0xf9,0x4a,0xf8,0xf3,0x18,0x68,0x96,0x47,0xc6,0x23,0x7c,0xb0,0x53,0xcb,0xd8,0x90,0x31,0xb7,0x50,0x0e,0x06,0xc3,0x84,0x75,0xf1,0xac,0x16,0x4d,0xc1,0xbe,0xf1,0x80,0x33,0x47,0x56,0x6f,0x33,0x94,0x5c,0x81,0x03,0x4c,0x2f,0x6d,0xac,0x73,0xba,0x91,0x3c},{0x2f,0xa9,0xb6,0xe8,0x73,0xe2,0xef,0x6d,0x6d,0xd7,0x2e,0xa0,0x51,0x61,0x24,0x81,0x8c,0xa8,0x47,0x40,0xe1,0xc7,0x75,0x79,0xc8,0xec,0xb2,0x23,0x41,0xad,0x61,0x3b,0xea,0x8a,0xdf,0x63,0xed,0xe1,0x8e,0x50,0x70,0x6e,0x86,0xed,0xb0,0xba,0x27,0x48,0x8e,0xb9,0x63,0x39,0x78,0x58,0x4f,0x1e,0xbc,0x45,0xf3,0xf2,0x3a,0x73,0x9b,0x8c},{0xad,0x42,0xc5,0x84,0xca,0xe1,0xe1,0x23,0x2a,0x73,0x15,0x3c,0x9a,0xfe,0x85,0x8d,0xa3,0x2c,0xcf,0x46,0x8d,0x7f,0x1c,0x61,0xd7,0x0e,0xb1,0xa6,0xb4,0xae,0xab,0x63,0xc4,0x0e,0xf2,0xa0,0x5d,0xa6,0xf3,0x5d,0x35,0x41,0xea,0x03,0x91,0xb1,0x3a,0x07,0xe6,0xed,0x6c,0x8c,0xcb,0x75,0x27,0xf1,0x26,0x58,0xf0,0x62,0x57,0xe4,0x33,0x00},{0x1f,0xed,0x53,0xc6,0xef,0x38,0x26,0xa4,0x18,0x88,0x8f,0x5c,0x49,0x1c,0x15,0x7d,0x77,0x90,0x06,0x39,0xe0,0x7c,0x25,0xed,0x79,0x05,0x66,0xe0,0x5e,0x94,0xe3,0x46,0x6f,0x96,0xd8,0xc1,0x11,0xa4,0x11,0x6f,0x78,0x42,0x8e,0x89,0xc7,0xc3,0xed,0xd2,0x9e,0x68,0x47,0x79,0x89,0x23,0x70,0x14,0x21,0x60,0x2d,0xfe,0x37,0x4b,0xc8,0x0a,0x16,0x73,0x7c,0xc4,0x55,0x3f,0x25,0x04,0x08,0x75,0x74,0x68,0xbc,0xe4,0x3a,0xae,0x4c,0x0e,0xd2,0x85,0xa1,0xbc,0x81,0xc0,0xc9,0xfe,0x9a,0x44,0x7b,0x83,0xdf,0xc7},{0x27,0x77,0x97,0x84,0x0f,0x2d,0x8d,0x33,0xb8,0x4e,0xdb,0x8b,0xea,0x58,0x52,0x88,0x95,0x88,0x55,0x5f,0xb8,0xc4,0xc9,0xd6,0x1f,0x1e,0xee,0x60,0xb5,0xeb,0x78,0x72,0xb5,0xe5,0x22,0x2b,0x7f,0x5e,0xc7,0x9b,0x29,0x55,0x8e,0x2a,0xfc,0x65,0x55,0x4a,0x02,0xad,0x64,0x06,0xd4,0x25,0xe1,0x96,0x6f,0xee,0x96,0xcd,0x29,0xc6,0x64,0x00,0x16,0x73,0x7c,0xc4,0x55,0x3f,0x25,0x04,0x08,0x75,0x74,0x68,0xbc,0xe4,0x3a,0xae,0x4c,0x0e,0xd2,0x85,0xa1,0xbc,0x81,0xc0,0xc9,0xfe,0x9a,0x44,0x7b,0x83,0xdf,0xc7}}, - {{0x5e,0xc5,0x5b,0x9c,0xdb,0x14,0x05,0x18,0x6b,0xe2,0x1d,0x16,0x77,0x22,0x0e,0xd2,0xe4,0x57,0x82,0x6e,0x5b,0xc5,0x6a,0xb9,0x34,0x20,0xdb,0x72,0xe2,0xe1,0xeb,0x1b,0x34,0x00,0x04,0xbf,0x83,0xf6,0x4f,0x12,0x45,0x08,0xf0,0x95,0x2a,0xdc,0x3a,0x14,0xb3,0x29,0x0b,0x99,0xcd,0x73,0x31,0xbd,0x04,0xbb,0x49,0x1c,0xde,0xcf,0x09,0x9e},{0x15,0x80,0x3e,0x2a,0xfb,0xc0,0x8d,0x62,0x19,0x27,0x83,0x04,0xcc,0xf5,0xd1,0xbb,0x40,0x41,0xbe,0x93,0x59,0x6e,0x27,0x6d,0x95,0x24,0x0a,0x07,0x27,0x86,0x10,0x75,0xf7,0x0a,0x11,0xfc,0x53,0xd0,0x4c,0x15,0xf8,0x6e,0x22,0x3f,0xeb,0x12,0x97,0x8a,0x3d,0x69,0xd8,0x96,0xc9,0x53,0x10,0x9c,0x02,0x95,0xe4,0xd3,0x1a,0xd5,0x43,0x82},{0x40,0x09,0x2c,0x17,0x7e,0xba,0xce,0x1f,0xfc,0xc1,0x8e,0xc3,0x1c,0xa2,0x34,0x52,0x78,0x16,0x23,0x71,0x82,0x40,0xf8,0x6d,0x67,0x65,0x67,0x50,0x53,0xd9,0xc8,0x5e,0x7e,0x8a,0x98,0xa3,0xc6,0x2a,0x4d,0x27,0xf3,0xb9,0xbb,0xae,0x43,0x29,0x6e,0x02,0x1c,0xe9,0x01,0xd6,0xcd,0xd8,0x91,0x44,0x95,0x2b,0x9e,0xa5,0x4f,0xd0,0x00,0xb9},{0x3a,0xe8,0x3d,0xb3,0x32,0xdc,0xc2,0xc8,0xe3,0x36,0x2f,0xc9,0x30,0x3a,0xc0,0x76,0x56,0xd3,0x0b,0x06,0xbe,0x8f,0xe7,0xf1,0x66,0x61,0x25,0x42,0x28,0xdc,0x08,0x81,0x84,0x3a,0x57,0x96,0x27,0xa6,0xcf,0xd6,0x8f,0x35,0xa2,0xc3,0x76,0x86,0x4f,0xcf,0x5f,0xa1,0x85,0x28,0x4f,0x4a,0x3a,0xbb,0x5c,0x25,0x4b,0xcc,0x46,0xfe,0xf2,0x04},{0x62,0xc8,0xa2,0x0a,0x59,0xb8,0x97,0xd2,0x68,0x94,0x00,0x3b,0x01,0xac,0x91,0x6e,0x97,0x8e,0x08,0xe3,0xfe,0x9f,0x9e,0x9f,0x4b,0xcc,0x5d,0x1d,0xb9,0xbf,0x07,0x83,0xfe,0x51,0x2a,0xdf,0x79,0x2e,0x07,0xc9,0x98,0x9b,0xbe,0xb6,0xe4,0x0a,0x20,0x44,0x86,0xea,0xb1,0x61,0x58,0x11,0x32,0x8e,0x7b,0xb9,0x67,0x2d,0xf0,0x78,0xb2,0x93},{0x1a,0x65,0xb3,0x6f,0xa2,0x45,0x29,0x53,0xd7,0x23,0x4d,0xff,0x8e,0xe9,0xb9,0xef,0x16,0xa0,0xdd,0x48,0xdf,0x70,0xd2,0xe1,0x56,0xca,0xd1,0xd0,0x4a,0x9d,0x63,0x92,0x2b,0xfd,0x7b,0x87,0x39,0x3c,0x12,0xc7,0xe5,0x91,0x31,0x95,0x78,0xc4,0x58,0x95,0x89,0x6e,0x2c,0x90,0xb4,0x0b,0xb2,0xfe,0x52,0xc0,0x86,0xc4,0x2e,0x56,0x97,0x0c,0x20,0xf2,0xbc,0x6a,0x9b,0x89,0xfb,0xe9,0x85,0x95,0xd6,0x22,0x5e,0x4d,0x6d,0x83,0x9d,0xf4,0xbe,0x66,0x05,0x32,0xb6,0xe2,0xf1,0x96,0x42,0xa4,0xc8,0x8c,0x1b,0xec},{0x43,0x85,0xff,0xb9,0xcf,0x04,0x83,0x40,0x70,0x3a,0x9c,0x48,0xb4,0xc2,0x99,0x3b,0xa0,0x39,0xf1,0x39,0x58,0x7f,0xd2,0x49,0x94,0x3c,0xc3,0xe1,0xb6,0x56,0x38,0x55,0x6f,0xb5,0x1a,0x90,0xa2,0x04,0x2f,0x19,0xf8,0xb1,0x65,0x5a,0xad,0xcd,0x1c,0x56,0x42,0x38,0xc2,0x52,0x09,0xd6,0x41,0x98,0x5d,0x5f,0xa5,0xe7,0xc2,0x55,0xa1,0x09,0x20,0xf2,0xbc,0x6a,0x9b,0x89,0xfb,0xe9,0x85,0x95,0xd6,0x22,0x5e,0x4d,0x6d,0x83,0x9d,0xf4,0xbe,0x66,0x05,0x32,0xb6,0xe2,0xf1,0x96,0x42,0xa4,0xc8,0x8c,0x1b,0xec}}, - {{0xf2,0x4a,0x96,0x57,0xc3,0x2f,0xe6,0x9f,0xed,0x7f,0xcc,0xe9,0xea,0xbe,0xd2,0x23,0x4e,0x47,0x13,0xd9,0x53,0x19,0x31,0x14,0x0a,0xd3,0x9b,0x95,0xa7,0x9c,0x88,0x5e,0x08,0xb2,0x16,0xda,0x45,0x61,0x1d,0x6b,0xdf,0xb1,0x14,0x0c,0x66,0xfd,0x3a,0xbe,0x25,0xdc,0xfd,0xcd,0xcc,0x5e,0x28,0x77,0x5a,0xa9,0x8b,0x84,0x77,0x26,0x9d,0xa6},{0xea,0xde,0x4d,0xab,0x09,0x02,0xbf,0x90,0xf8,0xae,0x8b,0x50,0x01,0xb2,0x9d,0x7c,0x0a,0x3b,0x60,0xda,0x34,0xa9,0xbb,0x4d,0xa5,0x53,0x18,0x65,0xec,0xaa,0xc9,0x29,0xb2,0xf7,0x74,0x14,0x63,0x5f,0x88,0xcf,0x4e,0x70,0x1b,0x11,0x64,0x73,0x15,0x6b,0x5a,0x8c,0xb8,0x4e,0x0f,0x83,0xae,0x4b,0x5c,0x52,0x1c,0x6a,0x0f,0x54,0x77,0xc8},{0xae,0xff,0x55,0xbf,0x78,0xb5,0xde,0x33,0xeb,0x87,0xea,0x13,0x7d,0x36,0x22,0x06,0x32,0xc4,0x7e,0xca,0x65,0x37,0xcc,0x83,0x0e,0xda,0x54,0xb3,0xd2,0xe6,0xe7,0x7f,0xe1,0x90,0x11,0x25,0x16,0x83,0x25,0x43,0xb4,0x38,0x06,0xbb,0x6c,0x62,0x7d,0x84,0x1f,0xf3,0x7b,0xeb,0xae,0x50,0xd8,0xfb,0xb9,0xf2,0xf9,0xc3,0x6f,0x59,0xb7,0xb0},{0x95,0x15,0x83,0x19,0x56,0x9c,0x11,0xd8,0x31,0x87,0x1d,0xe3,0x3f,0x07,0x89,0xb2,0xcb,0x81,0xf0,0xeb,0x0b,0x1e,0x74,0x08,0xa2,0x4a,0x0e,0x82,0xc6,0x45,0x8c,0x32,0xb4,0x8f,0xfd,0x76,0xeb,0x5e,0xc7,0x62,0xdc,0xcb,0xee,0xad,0xcf,0xcf,0xea,0x33,0x9d,0xb0,0x02,0x64,0x66,0x77,0x14,0x97,0x0c,0x6e,0x79,0xe8,0x58,0x32,0x0f,0xe6},{0xcb,0x2f,0xaf,0x53,0xd8,0x41,0x48,0x41,0x6f,0x36,0x78,0x80,0x83,0x5c,0x0d,0x4c,0x1b,0xf4,0x39,0xe0,0x34,0x4f,0xc2,0xb2,0x4e,0xf0,0xac,0xc2,0xf8,0x15,0x7a,0x81,0x9f,0x46,0x2b,0xe3,0xb9,0x39,0x05,0x89,0xa2,0xda,0x1a,0x63,0x51,0xb4,0x78,0x0f,0xfe,0x2f,0x9d,0xce,0x99,0x38,0xa9,0x7e,0xcb,0x80,0x57,0x9f,0xa2,0x28,0x0f,0x6a},{0x1b,0xec,0x67,0x50,0xd1,0x28,0x65,0x55,0xb8,0xde,0x3b,0x2e,0x1e,0x33,0xd8,0x1b,0xba,0x2e,0x78,0x6a,0xb8,0x0b,0x8c,0xa0,0x55,0x34,0x25,0x90,0x9a,0xe2,0xf5,0xaa,0x95,0x0c,0x6f,0x2a,0xb0,0x92,0x1d,0x48,0x5b,0x56,0x8c,0x82,0x8f,0xa7,0x15,0x75,0x26,0x61,0x85,0xc8,0x7d,0xda,0xf5,0x2a,0xf3,0x3c,0x34,0xc1,0x20,0x67,0xbb,0x04,0xec,0x7c,0xe2,0xcb,0x31,0xcf,0x23,0xda,0x5d,0x8a,0x05,0x00,0x9b,0x23,0x34,0xd0,0xed,0x56,0x10,0x0a,0x90,0x6b,0x73,0x26,0x6b,0xf0,0xd7,0xbc,0xd8,0xc7,0x89,0xc8},{0x90,0x43,0x54,0x87,0x44,0x00,0x07,0xca,0xa8,0x2b,0xec,0x55,0xa0,0xd2,0x8c,0x07,0x03,0xaa,0x61,0x1a,0x7d,0x0f,0x90,0x13,0x67,0x99,0x46,0x20,0xcd,0x70,0xcb,0xa7,0x96,0xdf,0x0c,0x13,0xc4,0x41,0x11,0xd6,0xc3,0x33,0x02,0x96,0x4f,0x1d,0xbd,0x06,0xa9,0xa1,0x31,0x0a,0xc3,0xdf,0x6d,0x52,0x6c,0xc6,0xbe,0xc5,0xb6,0x2a,0xb1,0x0f,0xec,0x7c,0xe2,0xcb,0x31,0xcf,0x23,0xda,0x5d,0x8a,0x05,0x00,0x9b,0x23,0x34,0xd0,0xed,0x56,0x10,0x0a,0x90,0x6b,0x73,0x26,0x6b,0xf0,0xd7,0xbc,0xd8,0xc7,0x89,0xc8}}, - {{0x4f,0x3a,0xdd,0x0f,0xcf,0x7f,0x27,0xda,0x27,0xc4,0xa6,0x2b,0x6b,0xd1,0x9f,0x59,0x73,0x5f,0xd4,0xb7,0xf0,0x86,0x16,0xc9,0xdd,0xa6,0xf9,0x9b,0x17,0xb2,0xb9,0x71,0xe7,0x4c,0xa1,0x17,0x79,0xe0,0xcc,0xae,0x10,0xec,0x28,0x3a,0x09,0xf2,0x8b,0x34,0x9c,0xac,0x16,0x2a,0xa9,0x21,0xe8,0xa7,0x18,0xc0,0xc4,0x9f,0x30,0xa0,0x25,0x62},{0x23,0x4c,0xd4,0xae,0x52,0x30,0xf6,0x64,0xb9,0xe1,0x47,0xca,0xf8,0xf3,0x3a,0x6b,0x8b,0xf3,0x29,0xe2,0x9b,0x5d,0xbb,0x0a,0x60,0x52,0x03,0x40,0x53,0x5c,0x9e,0x35,0x03,0xd4,0xec,0xd7,0x67,0xf4,0x92,0xd2,0x98,0x96,0xf2,0xa7,0xf4,0x25,0x6a,0x80,0x9c,0x75,0xc6,0xf2,0x1f,0x67,0x11,0x00,0x0d,0xda,0x1e,0xb2,0x58,0xa7,0x8c,0x39},{0x55,0x1b,0x80,0xbb,0xf3,0xc5,0x1a,0x84,0x34,0xf5,0x0a,0x8a,0x8a,0xe1,0x8c,0xea,0xa6,0xfb,0xd0,0x26,0xc9,0xa2,0x30,0x37,0x3e,0xba,0x98,0xfe,0x81,0x8a,0x52,0x37,0x0b,0x74,0x4e,0x3d,0x26,0x8f,0x82,0x4b,0xc0,0x6a,0x01,0x10,0x91,0x8f,0x89,0xb5,0x62,0x3f,0x1e,0x70,0xcc,0x25,0x77,0x39,0x74,0x88,0xdd,0xbc,0xbe,0x72,0x08,0x63},{0xe2,0x9a,0x46,0xd2,0x74,0xdc,0x0f,0x8a,0xa3,0xbd,0x20,0xb7,0xc7,0xd9,0x83,0x4b,0x58,0xa6,0xe3,0xbd,0xc5,0x00,0xb6,0x18,0x04,0x25,0x81,0xbd,0x99,0xb3,0xb1,0x2a,0x7a,0x68,0x6d,0xe1,0x3e,0x23,0x8d,0x29,0x9e,0x7a,0x30,0x56,0x4c,0x22,0xb6,0xf4,0x7d,0x7d,0x4f,0xfd,0x76,0xa5,0x9d,0x05,0x41,0x7c,0x7a,0x2d,0x7b,0xbe,0xcf,0x73},{0x7b,0xae,0x11,0x86,0x8a,0x38,0xbd,0x56,0x3c,0xf3,0x3c,0x9c,0x49,0xa4,0x68,0x0f,0x2b,0xdf,0xf2,0xa1,0xbc,0xc2,0xed,0x08,0x09,0x96,0xd0,0x7e,0x9b,0xe3,0x0a,0x72,0x13,0x03,0xd4,0x35,0x0a,0x94,0x60,0x09,0x4a,0xaa,0xca,0x35,0x8e,0xed,0x12,0xdd,0x26,0x8f,0xf8,0xa9,0xa2,0x8a,0x7f,0xac,0xf3,0x09,0xc7,0x22,0xc5,0x73,0xec,0xa0},{0xe9,0xc5,0x57,0x0d,0x85,0xbf,0x10,0xe2,0xd1,0xf5,0xd7,0x22,0xe9,0x6a,0x67,0x8d,0xd3,0x9f,0x1a,0xef,0x7f,0xc0,0x2b,0xe1,0xfd,0x2c,0xc2,0x5f,0x39,0xf9,0x34,0xd0,0x87,0x94,0x41,0x8a,0x65,0xa5,0x20,0x48,0xa4,0x20,0x5f,0x7a,0xc7,0x37,0x00,0x60,0x59,0x84,0x2a,0x1d,0xff,0x02,0xc3,0xe8,0x20,0xaa,0x39,0x13,0xac,0xf3,0xd7,0x05,0xbd,0xef,0x11,0x66,0x71,0xb8,0x9f,0x1e,0xe5,0xee,0x2e,0x37,0xfb,0x34,0xed,0xc5,0xa4,0x40,0x6e,0x38,0x31,0x0a,0x1c,0xaf,0x0d,0xd3,0x98,0xac,0x12,0x40,0xea,0x9c},{0xc6,0xcd,0x7a,0xbd,0x14,0xdb,0xe4,0xed,0xbf,0x46,0x70,0x23,0xbd,0xdb,0xc3,0xce,0x60,0xd5,0x6b,0x17,0x4c,0x23,0xfa,0x78,0x05,0xcc,0x18,0xed,0x42,0x03,0xa5,0xb7,0xdf,0x28,0x0e,0xd4,0x5d,0x31,0xd8,0xb9,0xdc,0xe9,0xf6,0x26,0xc5,0xe1,0xb3,0x80,0x0d,0x62,0xaf,0x2d,0xbd,0xd6,0xe4,0xbb,0x16,0x82,0xc8,0x13,0x2a,0x6f,0xb9,0x06,0xbd,0xef,0x11,0x66,0x71,0xb8,0x9f,0x1e,0xe5,0xee,0x2e,0x37,0xfb,0x34,0xed,0xc5,0xa4,0x40,0x6e,0x38,0x31,0x0a,0x1c,0xaf,0x0d,0xd3,0x98,0xac,0x12,0x40,0xea,0x9c}}, - {{0x6f,0x46,0xcd,0x96,0xc4,0x13,0xf4,0x11,0x62,0x49,0x8c,0x5c,0x78,0x27,0xef,0xc8,0xb9,0xe2,0x7d,0xf1,0x0d,0x37,0xf2,0xfe,0x85,0x35,0x82,0x60,0x23,0xb6,0x7b,0x17,0xd2,0x91,0xef,0x01,0x9e,0x99,0x35,0xab,0xc7,0xfb,0xa1,0xa3,0x13,0x44,0x3f,0x3c,0x16,0xcb,0xd8,0xf0,0xbf,0x9e,0x65,0x4d,0x07,0xe0,0xfd,0x8e,0x32,0x61,0x95,0xd5},{0xb7,0x81,0x16,0x2f,0xcb,0xa4,0x30,0x4e,0x6d,0xf5,0xf0,0x3f,0xfe,0xd9,0x81,0x20,0xa6,0x0e,0x2b,0xa8,0xc5,0xed,0x0d,0x9a,0x28,0x9c,0xe3,0xa9,0xb7,0xbf,0x87,0x0f,0xa5,0xf9,0x33,0xe7,0xa6,0x7f,0x9b,0xac,0xb6,0xcc,0xaf,0xfc,0xa7,0x4a,0x4d,0x36,0x39,0xa9,0xb6,0xf5,0x09,0xde,0x8d,0x37,0x11,0x07,0xd1,0x8a,0xf5,0x7b,0x66,0xe1},{0xcc,0xe0,0x07,0x62,0xbe,0x10,0x8c,0x3a,0xa2,0x96,0x5d,0x11,0xc7,0xd5,0x50,0xc3,0xbb,0x55,0x21,0xc5,0x40,0x27,0x7d,0xdb,0xad,0xd2,0x61,0x2a,0x42,0x5f,0x94,0x23,0x77,0x83,0x3a,0x99,0xe8,0xda,0x79,0x8c,0x1e,0xa8,0x44,0x04,0xec,0xf5,0xd1,0x55,0x1e,0x58,0xf1,0x6e,0x4d,0x27,0xa4,0x91,0xec,0x59,0xc8,0x17,0x36,0x58,0x2a,0x1f},{0x6d,0xf8,0x73,0xa3,0x38,0x61,0x1d,0x95,0x09,0xde,0xe5,0x26,0x1b,0x15,0x16,0xfb,0xf5,0x16,0xa8,0xf3,0x9e,0x3a,0x6b,0xb5,0x8c,0xee,0xa8,0x66,0x79,0xc3,0x9e,0xb4,0xe1,0xc2,0x85,0x0e,0x86,0x10,0x5a,0x4e,0x8b,0x4c,0x0a,0x7a,0xd8,0x8a,0x48,0xf4,0xa0,0x79,0x37,0xe3,0xa5,0x90,0x05,0x5e,0xbd,0xa1,0xf6,0x09,0x58,0x9c,0x6f,0x09},{0x66,0x47,0x6d,0x60,0x06,0x2d,0x90,0x8f,0xae,0x6c,0x01,0xe9,0xb0,0xf9,0x6b,0xa5,0x4a,0xe1,0xdb,0xd3,0x64,0x42,0x37,0x5c,0x11,0x40,0x7a,0xce,0x4e,0x83,0xc3,0x2c,0x2e,0xd2,0x67,0x76,0xfb,0x8c,0x5d,0xab,0xe8,0xb8,0xd6,0x2b,0xf8,0x86,0xff,0x96,0xf3,0xa8,0x0e,0x2b,0x1a,0x68,0xf5,0xe4,0xee,0x49,0xa6,0x8c,0x41,0x1f,0x97,0xbf},{0x81,0x92,0x4e,0xc6,0xab,0x00,0xdd,0xf9,0xf9,0xb7,0xe0,0x0a,0xa9,0x3f,0x0a,0xf9,0x32,0x73,0xf6,0x22,0xec,0x95,0xd9,0x20,0x8a,0x3f,0xeb,0x0d,0xc7,0x79,0x6f,0xb3,0x85,0xf4,0xe1,0x11,0xe1,0xcc,0xaa,0x1b,0xfd,0xf3,0x43,0xff,0x66,0x73,0x0f,0x09,0xcc,0xa4,0x6c,0xb8,0x2a,0x0f,0x53,0x58,0x63,0x32,0x06,0xd9,0x6b,0x1a,0x14,0x04,0x85,0x3f,0x2f,0x2b,0x05,0xfb,0xed,0xe9,0x08,0x0d,0x21,0x49,0xc9,0x79,0xdf,0x6f,0x77,0x89,0xd7,0x74,0x09,0x57,0x1a,0xd2,0xa7,0x43,0xbf,0x08,0x8e,0x98,0xbc,0x2f},{0xe3,0xb1,0xc4,0x81,0xe6,0xec,0x07,0x58,0xa4,0xcb,0x7e,0xd5,0xae,0x9d,0x43,0xf1,0xb7,0xe2,0x0a,0x1f,0xd5,0xe8,0x14,0xba,0x22,0xff,0xb7,0x20,0x76,0x08,0xdc,0x9a,0x44,0x4c,0x1c,0xcd,0x38,0x4d,0xb5,0xd8,0xa9,0x1b,0x9d,0xbb,0x13,0x5a,0x6c,0xe9,0x5d,0xa4,0x42,0x0e,0xde,0x9a,0x47,0x8a,0x2a,0x97,0x42,0x86,0x87,0x98,0x3f,0x04,0x85,0x3f,0x2f,0x2b,0x05,0xfb,0xed,0xe9,0x08,0x0d,0x21,0x49,0xc9,0x79,0xdf,0x6f,0x77,0x89,0xd7,0x74,0x09,0x57,0x1a,0xd2,0xa7,0x43,0xbf,0x08,0x8e,0x98,0xbc,0x2f}}, - {{0xff,0xe3,0x69,0x7b,0x62,0x45,0x40,0x5f,0x1c,0x49,0x65,0xd6,0xae,0x24,0x16,0x84,0xfa,0x69,0x6c,0x1f,0x6c,0x65,0xee,0x52,0xe9,0x6c,0x54,0xc7,0x31,0x9b,0xc2,0x74,0x4f,0xc0,0x16,0xb8,0xf8,0x75,0x5f,0x45,0xb5,0xf3,0xa0,0xd9,0xbe,0x25,0x82,0xbd,0x3c,0x03,0xe0,0x14,0x15,0x6a,0xd5,0x64,0x08,0x65,0x13,0x33,0xc2,0xab,0xe0,0x45},{0x6f,0x5a,0x90,0x80,0x25,0x13,0xc2,0xa7,0xfe,0x1c,0xa1,0x07,0x81,0x4b,0x09,0xd3,0xbd,0xda,0x55,0xa8,0xaa,0x62,0x19,0x03,0xe9,0x9f,0x77,0xef,0xff,0xd4,0x5e,0x53,0xbc,0x9d,0x71,0xb8,0xc4,0xc2,0x85,0xb9,0xb4,0x3d,0x95,0xb8,0xfd,0x44,0xb7,0xc8,0x6f,0x93,0x15,0x04,0x16,0x7e,0x01,0xf2,0x09,0x23,0x96,0x69,0xe5,0x65,0x52,0x34},{0xaf,0xfe,0x4f,0x34,0x4e,0xfe,0x51,0xa5,0xb2,0xd8,0x31,0x74,0x7b,0xae,0xfb,0xb9,0x33,0xc1,0xdc,0x66,0xe6,0x95,0x9e,0xce,0x77,0x7d,0x55,0x3c,0xa6,0x6c,0x09,0x23,0x5a,0x1a,0x5e,0x1a,0x41,0xd3,0xad,0x5f,0x86,0xd0,0x14,0xf5,0xe0,0xda,0xf1,0xce,0x19,0x90,0x45,0x0c,0x4c,0xb1,0xd3,0xc8,0x4c,0xdb,0x7e,0x49,0xf5,0xac,0xde,0xff},{0x1b,0x9b,0x6b,0x30,0xd3,0x19,0x37,0x83,0xad,0x05,0xca,0xba,0x22,0x85,0x33,0x7f,0x55,0x60,0xe3,0x14,0x8c,0x39,0x87,0xd1,0x4c,0x21,0x27,0xa0,0xae,0x4a,0x56,0x15,0x50,0x6c,0x99,0xca,0xff,0xde,0x10,0xc6,0x9f,0x6c,0x70,0xd1,0x66,0xb4,0x87,0xd8,0xfc,0x46,0xf2,0xcf,0x0c,0xd8,0xc3,0x14,0x5d,0x27,0xbd,0xed,0x32,0x36,0x7c,0xed},{0x64,0x6b,0x74,0xc7,0x60,0x36,0xc5,0xe4,0xb6,0xde,0x02,0x1a,0x09,0xaf,0x65,0xb1,0x94,0xa3,0xf4,0x95,0xf5,0xb0,0xef,0x86,0xb5,0x13,0x26,0x0b,0xe8,0xc5,0x5c,0x77,0xf5,0xe6,0xb6,0x10,0x36,0x87,0xa3,0xd2,0x7c,0x17,0x2c,0xb9,0xb0,0x90,0x9e,0x8c,0x0a,0x7d,0x73,0xb2,0x29,0xeb,0xa7,0x85,0xd7,0x04,0x14,0xf9,0x77,0xb7,0xf4,0x89},{0x7f,0x1c,0x5a,0x57,0x14,0xf6,0x30,0x07,0xf9,0xfe,0x42,0x98,0xcb,0x3d,0xac,0x04,0x30,0x0d,0xc6,0xd0,0x4f,0x8a,0xbc,0xdd,0x3e,0xc3,0xb7,0x74,0xc8,0x3b,0x1a,0xcc,0x6a,0x54,0x9e,0xb9,0xbe,0xf0,0x7c,0x35,0x35,0x1a,0x50,0x4c,0xc2,0x38,0x41,0x46,0xc8,0xc4,0x81,0x2b,0x26,0x56,0x6f,0x8a,0x9f,0x74,0x87,0xe0,0x01,0x82,0xe2,0x09,0xf3,0x9a,0xc5,0x33,0x5a,0x7d,0xb6,0xbb,0xff,0x20,0x4d,0xc1,0x99,0x3d,0xcc,0x5a,0xc7,0xd1,0xbe,0x4c,0xcf,0xc8,0x09,0x79,0x15,0x5e,0x0c,0xc6,0x26,0x36,0xe6,0xd9},{0x4d,0x2f,0x08,0x84,0x32,0xcf,0xe0,0x3b,0xa8,0x3e,0xa5,0xf8,0x3a,0xe8,0xa9,0x04,0x5a,0x74,0x67,0xcb,0x41,0x22,0xc5,0xc4,0x9a,0xa5,0xc1,0xa7,0x94,0x8b,0xa5,0x35,0x00,0x00,0x1a,0xaf,0xfb,0xed,0x40,0xb8,0x2b,0x28,0xf1,0xb1,0x02,0xd3,0x8b,0xc0,0x32,0x4a,0xa5,0x0a,0xa4,0xc3,0xbf,0xb3,0xf5,0xb7,0x65,0x8e,0x88,0xdf,0xd0,0x0e,0xf3,0x9a,0xc5,0x33,0x5a,0x7d,0xb6,0xbb,0xff,0x20,0x4d,0xc1,0x99,0x3d,0xcc,0x5a,0xc7,0xd1,0xbe,0x4c,0xcf,0xc8,0x09,0x79,0x15,0x5e,0x0c,0xc6,0x26,0x36,0xe6,0xd9}}, - {{0xc8,0x8e,0x1c,0xea,0x02,0x6a,0xfd,0x88,0x8b,0xa9,0x9d,0xdd,0xba,0xea,0x77,0x30,0x88,0x1a,0x93,0x49,0xda,0x05,0x18,0xbb,0x4a,0x6a,0x11,0xc4,0x48,0x72,0x77,0x1f,0x6e,0x2b,0x9a,0xe3,0x27,0xbe,0xe1,0x75,0x32,0x30,0xa6,0x12,0x26,0x44,0xbf,0xb2,0xa5,0x51,0x0b,0x48,0x3a,0xea,0xc5,0xd4,0x24,0x3f,0x4e,0xe8,0xe5,0xc3,0xfb,0xc2},{0xcb,0x56,0x3c,0x00,0x28,0x15,0x72,0x16,0x23,0x4e,0x2e,0x2c,0x8c,0xe8,0x7c,0x44,0x82,0x2a,0xe0,0x57,0xa3,0x0a,0xc4,0x42,0xb5,0x07,0xe1,0x1b,0x78,0x8b,0x3d,0x4d,0xcb,0xe4,0x56,0x72,0x0b,0x85,0x52,0xd8,0x55,0xe2,0xcd,0x38,0xd2,0x83,0xb6,0x05,0xd2,0x9f,0x63,0x9e,0x7f,0xca,0xe5,0x95,0x36,0x61,0x9b,0xca,0x09,0x27,0x53,0x82},{0x24,0x67,0x10,0xd6,0x8a,0x1a,0x8e,0xb8,0x53,0xef,0xb7,0x67,0x2a,0xfd,0xb8,0xd6,0xe3,0xf7,0x41,0x95,0x8c,0x50,0xca,0x1d,0x21,0x21,0x41,0xd1,0xef,0x2d,0x9b,0x53,0xa9,0x42,0xcd,0xda,0x6d,0x12,0x1b,0xbd,0x0a,0xe1,0x4d,0x95,0xc6,0xaa,0x40,0xfd,0x98,0xfb,0x26,0x21,0x5e,0xaf,0x8e,0x6b,0xc9,0x36,0x2c,0x66,0x31,0x24,0x45,0x87},{0x5e,0xf9,0x1d,0x10,0xb5,0x79,0x1f,0x80,0x85,0x90,0xc3,0x7f,0x2b,0x73,0xbf,0x83,0x0b,0x5d,0x46,0xae,0x79,0xef,0x09,0x71,0x29,0xfb,0x83,0xde,0x1f,0xe2,0xdb,0x1b,0xa2,0x22,0xee,0x50,0x21,0x9d,0x9c,0x35,0x14,0x48,0x13,0xa5,0xd1,0x68,0xf4,0x61,0x1f,0xd7,0xe2,0xd6,0x42,0x1c,0xdc,0x58,0xec,0x8b,0x03,0x6b,0xdf,0x64,0x06,0x30},{0xf9,0xa6,0x88,0x74,0x07,0x19,0x15,0x38,0xaf,0xac,0x07,0x10,0xe0,0xd9,0x22,0xf3,0x78,0xb0,0xbf,0x60,0xa3,0x0f,0xea,0x0f,0xa8,0x64,0xa9,0xa3,0x82,0xe1,0x4c,0x29,0x36,0x22,0x6d,0x43,0x9c,0xde,0x22,0xbf,0xc6,0x85,0xf7,0xe9,0xe0,0x79,0x80,0xfe,0x9d,0xd6,0x24,0xbd,0x29,0xa4,0x8c,0x35,0x21,0x87,0x45,0x7f,0x88,0xd9,0x9a,0x9d},{0x49,0x43,0x19,0x14,0xcc,0x4a,0x11,0x01,0x05,0xd1,0x4e,0x39,0x6d,0xb0,0x22,0x65,0x32,0x6e,0x67,0x04,0x50,0x85,0x53,0x42,0x90,0x2c,0xc0,0x63,0x2f,0xbd,0x15,0x90,0x1b,0x3f,0x03,0x90,0x16,0x7f,0x7b,0x49,0x74,0xd0,0x3d,0x81,0x80,0x1e,0x9e,0x2e,0xa9,0x13,0x6a,0x10,0x14,0xc1,0xfd,0xf9,0x25,0x3a,0x1d,0x52,0x93,0x0a,0x77,0x03,0xa2,0xdd,0xce,0x9f,0x2a,0x35,0xc9,0x93,0x7c,0xa2,0x2c,0xf6,0x38,0x73,0xb3,0xab,0x7f,0x55,0xb6,0x62,0xa2,0x8d,0x6a,0x3e,0x88,0x04,0x9b,0xa2,0x19,0x64,0x55,0x01},{0x22,0x03,0x49,0x58,0x76,0x3c,0x85,0x45,0x5e,0x73,0x78,0x8f,0x65,0xc9,0x50,0xf8,0xd7,0x16,0x92,0xa4,0xd1,0x79,0xce,0xf3,0x00,0x34,0x38,0xb8,0xcc,0x96,0x9f,0xa6,0x87,0x28,0xcb,0x19,0x28,0xad,0x83,0xb5,0x09,0x96,0x54,0xe8,0x2a,0xb9,0x9b,0xff,0x60,0x85,0x31,0x28,0x62,0x36,0xd2,0x0e,0xad,0x2a,0xe1,0x84,0x80,0xeb,0x6f,0x00,0xa2,0xdd,0xce,0x9f,0x2a,0x35,0xc9,0x93,0x7c,0xa2,0x2c,0xf6,0x38,0x73,0xb3,0xab,0x7f,0x55,0xb6,0x62,0xa2,0x8d,0x6a,0x3e,0x88,0x04,0x9b,0xa2,0x19,0x64,0x55,0x01}}, - {{0xeb,0x18,0x95,0x94,0x5f,0x15,0x8c,0xb8,0x4d,0x6e,0x7d,0xc0,0x96,0x6c,0x52,0xa2,0x5f,0x43,0x67,0xc2,0x3a,0x10,0x5b,0xf1,0x8f,0x21,0x89,0x06,0x77,0xe9,0xab,0x2e,0xcd,0x17,0x9c,0x9a,0xd7,0x89,0x7e,0x53,0x58,0x60,0x9b,0xce,0x90,0xd9,0x13,0x2d,0x78,0xc4,0x2c,0x1c,0x4c,0xe8,0x23,0x70,0xff,0xa0,0x42,0x98,0x25,0x40,0xd6,0xd8},{0xb6,0xfb,0xdd,0x5d,0x35,0xf2,0x2b,0x89,0xda,0x8e,0x90,0xee,0x03,0x4e,0x75,0xdb,0x4c,0x45,0xc8,0x00,0xde,0x06,0x27,0xde,0x44,0xb5,0x5b,0xc7,0x56,0xc3,0xf5,0xbb,0xee,0xa6,0x21,0xd4,0xd9,0xb9,0x24,0x9c,0x4c,0xbc,0x23,0xe5,0xeb,0x05,0xb6,0xd0,0xd0,0xbf,0x49,0x95,0x01,0xb4,0x97,0xad,0xb5,0x71,0x8d,0x4b,0x32,0xd0,0xdd,0x1a},{0xfd,0x11,0xd7,0xe4,0x46,0xcd,0xd8,0x44,0x89,0x0a,0xe7,0x44,0x59,0xe9,0xcf,0x9f,0xd6,0xf1,0x74,0x56,0x04,0x78,0xfa,0x29,0x46,0x8a,0x8d,0x1b,0xbe,0x41,0x92,0x1c,0x8d,0x74,0x01,0x1b,0xc1,0xf8,0x26,0xf4,0xc2,0x68,0xc3,0x23,0x8c,0x68,0x7c,0x0a,0xad,0xdd,0x50,0x10,0xcf,0xdb,0x78,0xc5,0x79,0x28,0x37,0x63,0x92,0x1a,0x1d,0xea},{0xd2,0x2a,0xf0,0x66,0x15,0x8b,0xcb,0x83,0xcf,0x34,0xa1,0x33,0x6b,0xd5,0xa8,0x98,0x3b,0xd7,0x09,0x0d,0x70,0xa5,0x8a,0xc0,0x73,0xcf,0xde,0x59,0xd5,0x13,0x41,0xd2,0x43,0x8b,0xb4,0xc3,0x5b,0x6f,0xf1,0xed,0x47,0x76,0xe6,0x5e,0xb8,0x2a,0x7e,0x20,0x91,0xa0,0x9d,0xc1,0xa2,0x0a,0x6d,0x97,0x7d,0xeb,0xe3,0x64,0x5f,0x86,0xff,0x3e},{0x45,0xd8,0xdc,0xe4,0x3a,0x3a,0x44,0xdc,0x7f,0xa8,0x92,0x11,0x1b,0x4f,0xfa,0xcf,0x21,0xff,0xfb,0x20,0xb0,0x02,0x6d,0x0e,0x1c,0xde,0xe8,0x51,0xd8,0x2c,0x72,0x0e,0xbf,0xf6,0x9a,0xd3,0xd3,0xfe,0xfa,0x98,0x4e,0xc2,0xf0,0x16,0xda,0x39,0x93,0xc4,0xe0,0x33,0x9a,0x43,0xe8,0x7a,0xc5,0x0f,0x0b,0xa4,0x45,0xf0,0x5e,0x7a,0xa9,0x42},{0xdb,0x4e,0x17,0x76,0x8b,0x3c,0x98,0x7f,0x58,0x76,0x97,0xc9,0x3f,0x99,0x01,0x05,0x42,0x7e,0xfd,0x83,0x99,0xaa,0x19,0xb5,0x72,0x4c,0x69,0xed,0x6e,0x21,0x79,0x6e,0x3b,0x71,0xe5,0xab,0x23,0x84,0xe7,0xfe,0x58,0x2b,0x0d,0x1e,0x75,0x7c,0x29,0xb3,0x2d,0x66,0xc2,0x45,0x88,0xac,0x86,0x29,0xe4,0xaa,0x9e,0x71,0xa1,0x88,0xf9,0x06,0xda,0xa3,0xdd,0x7b,0x6c,0xd9,0xc9,0x73,0xe9,0x56,0xd1,0xee,0x5b,0xf9,0xae,0xc0,0x29,0xbe,0x20,0x6c,0xc7,0xf9,0xc5,0x2d,0x6d,0xad,0x8f,0x49,0xf8,0x17,0xdb,0x7a},{0xb8,0xb7,0xec,0xeb,0x3e,0x40,0x77,0x6c,0xab,0x10,0xfe,0x9f,0xd1,0x40,0xfe,0xd2,0x88,0x8e,0xb0,0x55,0xae,0x75,0xb1,0xcc,0x9d,0x6c,0x11,0x28,0x95,0x38,0x9f,0xb9,0x59,0xe2,0x29,0xc3,0xbc,0x09,0x16,0x1f,0x17,0x9e,0x15,0x78,0x09,0x61,0x07,0x9e,0xad,0x67,0x98,0xa9,0x24,0xff,0xf9,0x4b,0xa2,0x76,0x09,0xa0,0xd7,0x1b,0xed,0x05,0xda,0xa3,0xdd,0x7b,0x6c,0xd9,0xc9,0x73,0xe9,0x56,0xd1,0xee,0x5b,0xf9,0xae,0xc0,0x29,0xbe,0x20,0x6c,0xc7,0xf9,0xc5,0x2d,0x6d,0xad,0x8f,0x49,0xf8,0x17,0xdb,0x7a}}, - {{0xc3,0x92,0x4d,0x01,0x9c,0xea,0x5a,0x8d,0xbd,0x5c,0x12,0x58,0x6d,0x03,0x26,0xbf,0xa4,0xdd,0xf7,0x26,0xa4,0x0d,0x22,0xe0,0xbd,0xcc,0x6f,0x30,0x9e,0xf9,0x4c,0x1f,0x03,0x52,0xab,0x38,0xe9,0x9c,0x08,0x9c,0x09,0xe5,0x87,0x5c,0x24,0x1a,0xe2,0x75,0xcb,0x18,0x8a,0x63,0x50,0xd1,0x23,0x45,0x49,0x93,0x40,0x2c,0x09,0xd4,0xac,0x39},{0xd4,0xe7,0xb7,0x05,0xfd,0xd6,0xf3,0x57,0xfb,0xc2,0x2f,0x2c,0x71,0x80,0xf5,0xc3,0xa6,0x0a,0x23,0x9d,0x1d,0xa8,0x68,0x10,0x8a,0xfa,0x68,0x9d,0x2b,0xcf,0x96,0xa9,0xe6,0x0e,0x07,0x32,0x23,0x09,0x87,0x16,0xc5,0xbb,0x76,0x22,0xfc,0xb4,0x59,0x6d,0x67,0xfd,0x29,0x51,0x95,0x4c,0xe2,0x8c,0x18,0xab,0xda,0x84,0xc3,0x62,0x80,0x14},{0xc9,0xa1,0xfe,0xc3,0x48,0x0d,0xee,0x54,0x44,0xff,0x9c,0x46,0x04,0x0e,0x74,0xda,0xa4,0x6a,0x56,0x02,0x5f,0x76,0x0e,0xb5,0xc1,0xc9,0xe9,0xb2,0x6e,0x07,0x49,0x0c,0xf7,0x4b,0xee,0xd6,0x0a,0xad,0x94,0x03,0x58,0x2d,0x60,0x95,0xf8,0x16,0x7b,0x49,0x0b,0x01,0x66,0x3e,0x17,0x01,0xe5,0x54,0x7d,0xd7,0xbb,0x10,0xd1,0xad,0xad,0x79},{0xb2,0xd8,0x10,0x29,0xeb,0xb8,0x4e,0x2b,0x39,0x85,0x5c,0xb3,0xdc,0xf5,0x87,0xca,0xca,0x9c,0x7a,0x8c,0x2b,0x08,0xe8,0x25,0xe2,0xcf,0x70,0xe2,0xe6,0xfb,0xdb,0x0c,0xc3,0x0d,0x71,0x11,0x83,0x65,0xf2,0x71,0x08,0x1b,0x32,0x6e,0x6c,0x51,0x50,0xf1,0xf6,0x4b,0x54,0x63,0x16,0x7f,0xfd,0x80,0x05,0x61,0x63,0xf1,0x80,0x6a,0x0b,0xfd},{0xa7,0x4b,0x75,0x38,0x90,0x64,0x96,0x7b,0xda,0x5e,0x08,0x9b,0x80,0xc4,0x72,0x3f,0x73,0xb2,0xdb,0xd3,0x4a,0xed,0xa4,0xdc,0x5c,0x79,0xe5,0x0f,0x7a,0xd3,0x0c,0xac,0xf9,0x99,0x5c,0x1a,0x0f,0xb3,0x1a,0x0f,0x5c,0xc3,0x9e,0x1a,0x2b,0xfa,0xc3,0xf0,0x40,0xe5,0x5f,0x36,0xd2,0x98,0x31,0xa1,0xaf,0x18,0x5f,0xae,0x92,0xf3,0x9e,0xc0},{0xf9,0xbf,0x52,0xe6,0xd3,0xe1,0x5d,0xd3,0x30,0xf3,0xa1,0x0c,0xc8,0x5a,0x97,0x55,0xab,0x67,0x67,0xd0,0x00,0x62,0x7b,0x80,0x70,0xbf,0x24,0xd0,0x09,0x8b,0x07,0x77,0xeb,0x3e,0xf0,0x5d,0xdf,0x7b,0xa9,0x7d,0xa4,0x6a,0x0d,0xf1,0xac,0x83,0x7d,0x64,0xb5,0xf4,0xc6,0xc4,0x12,0x0c,0x55,0x9f,0x67,0xbb,0xd5,0xe3,0xd3,0xdb,0x17,0x0f,0x90,0x2f,0x8f,0xc9,0xfd,0x4e,0x6c,0x8b,0xe6,0x99,0xfa,0xda,0x8f,0x1f,0xe6,0xc3,0xeb,0xd8,0x14,0x20,0xcc,0x3c,0x1c,0x23,0x77,0x28,0x9b,0x22,0x9a,0x5a,0x0c,0x43},{0xa2,0x78,0x37,0xc9,0x63,0xe1,0x31,0x36,0xc2,0x58,0xac,0xca,0xbb,0xa2,0x84,0xaa,0xb3,0x82,0xe2,0x19,0xb7,0x14,0x96,0x27,0x77,0xfa,0xa1,0x02,0xaa,0xff,0x55,0x82,0xba,0xc0,0x38,0x1a,0x69,0x35,0x48,0x87,0xc2,0xeb,0x48,0x08,0xea,0xc5,0x6b,0xfc,0x84,0x60,0x4e,0xce,0xd7,0xd2,0x86,0x8b,0x76,0xf3,0x46,0xe1,0x87,0x1f,0xff,0x09,0x90,0x2f,0x8f,0xc9,0xfd,0x4e,0x6c,0x8b,0xe6,0x99,0xfa,0xda,0x8f,0x1f,0xe6,0xc3,0xeb,0xd8,0x14,0x20,0xcc,0x3c,0x1c,0x23,0x77,0x28,0x9b,0x22,0x9a,0x5a,0x0c,0x43}}, - {{0x0e,0xa6,0x0c,0xef,0x12,0xd6,0x7d,0x71,0xd4,0x88,0x73,0x86,0x9a,0x88,0x8f,0x5b,0xd1,0xb6,0x12,0xc4,0x93,0x8b,0x5f,0xee,0xdd,0x9c,0x2a,0x7f,0x4d,0xfd,0xba,0x00,0x09,0x45,0x77,0xd2,0xcf,0xcd,0x3a,0x6f,0x27,0x44,0xe2,0x55,0x3e,0x79,0x88,0x4d,0x5f,0x38,0x34,0xe8,0xe7,0xc6,0x3a,0xde,0xef,0x99,0x15,0xea,0x88,0x79,0xd7,0xca},{0xa0,0x9a,0x0a,0x3a,0x42,0x35,0x54,0x78,0xb9,0x82,0x52,0xb4,0xc8,0x5c,0x4a,0x03,0xa1,0xb9,0x27,0xcc,0x99,0xec,0x03,0xdf,0xdd,0x6e,0xde,0xef,0x8f,0x7f,0xdc,0x5a,0xc3,0xcb,0x0e,0xa2,0x7e,0x93,0xe6,0xdd,0xbd,0xf1,0x1b,0x03,0x29,0x63,0x72,0x11,0x72,0x3d,0x24,0x6f,0xdf,0x8e,0xed,0xa4,0xe2,0x2a,0x4c,0x00,0xe2,0xc4,0x55,0x1b},{0xb2,0xf1,0xff,0xf6,0x3a,0x26,0xe1,0x74,0x52,0xba,0xee,0x28,0xb6,0x56,0x90,0x59,0xde,0x92,0x5f,0x84,0xd1,0x87,0xe2,0x64,0xce,0xdc,0x94,0x3c,0xb4,0xf8,0x01,0x0a,0x86,0x2f,0xfe,0x79,0x03,0x72,0xfc,0x26,0x21,0xc3,0x1e,0xec,0x63,0x29,0x64,0xcb,0x5f,0xcc,0xb6,0x78,0xf7,0xc8,0xd1,0xf8,0x5c,0xc4,0x4b,0xc0,0xc3,0x75,0x3e,0x46},{0x03,0x4b,0xb9,0xd1,0x50,0xa3,0x79,0xbe,0x74,0xa3,0xb5,0xd8,0x28,0x1b,0x6d,0x72,0x68,0x0a,0x9b,0x19,0xc9,0x13,0xc4,0x04,0x94,0x0a,0xcb,0x72,0xff,0x7d,0xb6,0x9a,0x1c,0xfd,0xe4,0xa3,0x75,0x13,0x57,0x36,0xfe,0x4a,0xf6,0xbc,0xca,0xd9,0x34,0x9b,0xef,0x90,0x02,0xd9,0xbd,0xdd,0x6f,0x22,0x54,0x36,0xb2,0x3f,0x22,0x65,0xef,0xe7},{0x04,0xd4,0x43,0xe8,0x8c,0xc4,0xfb,0xe5,0x55,0xd0,0xa4,0xea,0x20,0xf8,0xe1,0x8f,0xc2,0xbc,0x1f,0x55,0xf1,0x8d,0xda,0xc0,0x85,0xa4,0xef,0x36,0x97,0x22,0x8b,0x8e,0x77,0x4c,0x1a,0xa4,0xa0,0x6f,0xe1,0xdc,0x32,0x47,0xc4,0x3a,0xd8,0x8a,0xbd,0x19,0x30,0x1c,0x96,0x7a,0xb2,0x23,0x7c,0x16,0x03,0xa7,0x4f,0xfd,0xa6,0x50,0xd9,0xf7},{0xdf,0xc2,0x59,0xd2,0xa9,0x9b,0x1e,0xca,0xf0,0x39,0x2f,0xf8,0xc2,0xf3,0x91,0x55,0x1b,0xba,0x81,0x3a,0x67,0x1a,0xd4,0xf4,0xb0,0x9f,0xb6,0x18,0x38,0x65,0x3e,0x67,0xa0,0x37,0xc2,0x9a,0xc7,0xee,0x72,0x8e,0x13,0x64,0xd1,0x0a,0xda,0xbd,0x8d,0xa4,0x28,0x55,0x3a,0x2c,0x78,0x41,0xc6,0xfc,0x1c,0x0f,0xf8,0xd7,0x5f,0xe6,0xde,0x0b,0xd5,0xc0,0xaa,0x2c,0x5c,0xac,0x46,0xeb,0xa4,0x35,0x2a,0xab,0x00,0x2e,0xc0,0x8b,0x42,0x65,0x2f,0x2f,0x13,0x84,0x60,0x15,0xa3,0x69,0xee,0xab,0x0e,0x50,0xbf,0x5f},{0xc1,0xb0,0xac,0x4c,0xfa,0x62,0x52,0x22,0xae,0x8c,0x94,0x38,0xd9,0x6e,0x10,0x94,0xe7,0xaa,0xc0,0x92,0x93,0x06,0x55,0xf9,0x2e,0xd9,0x10,0x4d,0xcb,0x82,0x19,0x1f,0x27,0x16,0x81,0xdd,0xea,0x7a,0xa8,0xce,0x5a,0xdd,0x37,0x77,0x24,0x57,0xfb,0x40,0x3d,0x1b,0x48,0x88,0xda,0xce,0xe8,0xd2,0xed,0xe0,0x6e,0x29,0xeb,0xdb,0x95,0x09,0xd5,0xc0,0xaa,0x2c,0x5c,0xac,0x46,0xeb,0xa4,0x35,0x2a,0xab,0x00,0x2e,0xc0,0x8b,0x42,0x65,0x2f,0x2f,0x13,0x84,0x60,0x15,0xa3,0x69,0xee,0xab,0x0e,0x50,0xbf,0x5f}}, - {{0x3a,0x79,0x39,0x60,0xe9,0x93,0xad,0x78,0xf9,0x0b,0x99,0x64,0x71,0x76,0xad,0xdc,0x63,0xa3,0x38,0xbf,0x0a,0x36,0x22,0xcf,0x4f,0x84,0x3e,0x34,0xaf,0x0b,0xd4,0x5c,0xc0,0xa4,0x01,0x7c,0x07,0xc3,0xb4,0xcb,0xdb,0x39,0xdd,0x39,0xc7,0x5c,0xbd,0xcf,0x61,0x8b,0x72,0x74,0xd6,0x85,0xdc,0x5c,0x08,0x93,0x6d,0xe6,0xf1,0xeb,0xb9,0x7c},{0x71,0x12,0x20,0xbb,0x37,0xa6,0xd8,0x71,0xf7,0x58,0xaa,0xbd,0x30,0xfb,0xac,0x94,0x62,0x45,0xf0,0x1a,0xc3,0x4a,0x07,0x78,0x6d,0x17,0xf5,0x8d,0x69,0x3d,0x2e,0x15,0x96,0x48,0x1a,0xb0,0x7e,0xdd,0xf5,0x2d,0xe1,0x56,0xfc,0xe9,0x26,0x91,0x51,0xfe,0x5e,0x2a,0xdc,0x23,0x89,0x09,0x14,0xe6,0x17,0xa9,0x14,0x8c,0x8c,0xe8,0xe3,0x71},{0xe4,0xd0,0xa7,0x5a,0xce,0x93,0x1d,0x55,0xa2,0x3d,0xdd,0x7e,0x10,0x66,0x6d,0xc6,0x5c,0x87,0x9f,0x7a,0x52,0x5e,0x76,0x3f,0x09,0x9e,0xe5,0x8e,0x60,0x39,0x5e,0x3c,0x28,0x31,0xa4,0x12,0x39,0xfd,0xba,0xda,0xc8,0x59,0xdd,0x5b,0x26,0x78,0x8f,0x33,0xd2,0xc8,0x22,0x77,0x49,0xcf,0x34,0x61,0xbe,0x7a,0xa6,0x31,0xbe,0xe5,0xab,0xc2},{0x60,0xf5,0x52,0xbd,0xb1,0x9e,0x06,0xa3,0x94,0xad,0xe0,0x82,0x33,0x7c,0x41,0x17,0x5b,0x8a,0xbc,0x7c,0xce,0xd1,0x7e,0xfd,0x39,0x17,0xfd,0x90,0x5a,0x53,0x89,0x27,0x9f,0x27,0x7a,0x08,0xb2,0x66,0xda,0xb5,0xbf,0x3b,0x80,0xe2,0x1a,0x30,0x80,0x45,0x13,0xf3,0x4b,0x0c,0x4a,0xe9,0x0a,0x6e,0xf2,0x3e,0xa3,0x70,0x3d,0x89,0xd3,0xb2},{0x23,0x41,0x08,0x8d,0xa8,0x0b,0x6a,0xe0,0x65,0xb1,0x42,0x50,0x49,0xdd,0xd3,0xe8,0x89,0x13,0x7a,0x04,0xf0,0xd6,0x2f,0x6e,0x73,0xcd,0xdc,0x10,0xbb,0x02,0x6b,0xa2,0x25,0x58,0xa3,0x08,0x37,0x7c,0x8b,0x1f,0x4a,0x81,0x38,0x88,0xbd,0xf4,0x4f,0x24,0xe8,0xd6,0x9f,0x2f,0x13,0xeb,0x79,0x60,0x80,0x90,0x52,0x6b,0x8e,0xed,0xcb,0x77},{0x5b,0x88,0x63,0xaf,0xf9,0xe2,0x44,0x23,0xc8,0x02,0xe0,0x22,0x15,0x3d,0x2a,0xb7,0x40,0x76,0xe8,0x95,0xfd,0xa9,0xe3,0x85,0x94,0xa3,0xbb,0xce,0x61,0x19,0x0d,0xe2,0x95,0xdf,0x81,0x11,0x53,0x77,0xcd,0xf2,0xd8,0x4f,0xbf,0x19,0x6a,0x3d,0x4b,0xda,0xa4,0x56,0xa4,0xcd,0x9d,0x4f,0x52,0x53,0x7d,0xd8,0xac,0xe0,0xfb,0x9a,0x71,0x0c,0x59,0xf9,0x0b,0x03,0xf1,0x7b,0xaf,0x33,0xc3,0xe5,0x1e,0x8d,0x4f,0xbe,0x21,0xed,0x6b,0x15,0xdd,0xd2,0xeb,0x7c,0xe4,0x59,0x6c,0xf9,0x91,0xc1,0x3a,0x3a,0xb6,0x2b},{0x5e,0x54,0xe5,0x1b,0x3d,0x2c,0x00,0x80,0xdd,0xe4,0x10,0x50,0x98,0xb6,0x0e,0x3a,0xf7,0xde,0x67,0x2c,0x8e,0x7b,0xb4,0x73,0x0b,0xc7,0x12,0xb0,0x66,0x6b,0x3b,0x99,0xd9,0x33,0x78,0x5f,0x45,0xe5,0xec,0x15,0x02,0xfa,0x8b,0x86,0xfd,0xe0,0xb7,0x84,0x72,0xf2,0x68,0x5c,0xd6,0x2e,0x37,0xe9,0x49,0x32,0x2f,0xcd,0xcd,0x1e,0x99,0x0f,0x59,0xf9,0x0b,0x03,0xf1,0x7b,0xaf,0x33,0xc3,0xe5,0x1e,0x8d,0x4f,0xbe,0x21,0xed,0x6b,0x15,0xdd,0xd2,0xeb,0x7c,0xe4,0x59,0x6c,0xf9,0x91,0xc1,0x3a,0x3a,0xb6,0x2b}}, - {{0xfc,0xb9,0x4e,0x4e,0x11,0xfe,0xe1,0xc5,0xc7,0x49,0x54,0xd2,0x2f,0x13,0x34,0x7c,0x91,0x7d,0x98,0x43,0xe4,0xb7,0x48,0xea,0xe8,0x26,0xcb,0x26,0x1f,0xe4,0x99,0x10,0xb9,0x34,0xc2,0xac,0xa3,0x2c,0xbd,0x9e,0x80,0xd4,0x12,0x3b,0xb3,0xf0,0x01,0xae,0x91,0x9f,0xba,0x77,0x32,0x4d,0x9d,0xac,0x1f,0x8d,0xad,0xa7,0x46,0x44,0x85,0xfb},{0x65,0x05,0x0b,0xd2,0x41,0xd3,0x58,0x2a,0x14,0xbc,0x7b,0x15,0x4a,0x6a,0x6a,0x18,0x71,0x09,0x25,0x33,0xac,0x73,0x53,0xab,0xd9,0x0d,0x8d,0xdf,0x95,0x59,0x7e,0x02,0x4c,0x03,0x11,0x5c,0xdc,0x80,0x19,0xd5,0x13,0x66,0x7f,0xf7,0xd7,0x23,0x18,0x40,0x84,0x16,0x6b,0x52,0x82,0x96,0x05,0x1b,0xfa,0xcb,0x4b,0x77,0x00,0x12,0xa0,0x28},{0x13,0xe0,0x16,0x1e,0x24,0x24,0xe9,0xde,0x9c,0x86,0xa9,0xcf,0x02,0x96,0xdf,0x8c,0x64,0xcb,0x3d,0x7d,0x8a,0x2a,0x73,0x18,0x20,0xc8,0xb0,0xac,0x10,0xa0,0x52,0x0c,0x6c,0x17,0xd9,0xbd,0x3c,0x3e,0xe5,0x0c,0x4a,0xdb,0x59,0xcc,0x59,0x15,0x08,0x1e,0xfe,0xaa,0xe3,0xd6,0xa1,0x37,0xd6,0xd5,0x6d,0x8e,0xcd,0x57,0xa9,0x81,0xb3,0x43},{0x46,0x28,0x2b,0xa0,0xe5,0xe3,0xf0,0x72,0xa7,0xbc,0x8d,0xec,0x45,0x31,0x6e,0xdb,0xb2,0x4b,0x20,0xbf,0x64,0x74,0x26,0x70,0x9b,0xd6,0xd3,0x7f,0x9f,0xc1,0x59,0x03,0x2d,0xda,0x6f,0xaa,0x7c,0x92,0xc6,0xe0,0xe8,0xaa,0x1e,0x26,0xf0,0x1e,0xcc,0xef,0x6d,0x87,0x04,0x3c,0xed,0x52,0x15,0xb3,0x9f,0x01,0x4e,0xe3,0x3c,0xb6,0xbb,0xac},{0x86,0x1a,0x25,0x8e,0x41,0x85,0xf9,0xba,0x98,0x15,0xb1,0xec,0x50,0xb4,0xd0,0xab,0x55,0x54,0xbb,0x3b,0x61,0xfc,0x54,0xf3,0x09,0xea,0xaa,0x6e,0xbf,0x03,0xc3,0x58,0x1d,0x24,0xb5,0xd5,0x45,0x5a,0x7a,0x14,0xc3,0x6a,0xa9,0xd8,0x6f,0x41,0xc3,0xb4,0x9a,0x05,0x71,0xbc,0x23,0x67,0xc2,0xa8,0xf5,0x7b,0x69,0xa5,0xe1,0x7a,0x35,0x1d},{0x3b,0xf5,0xa8,0xc0,0x2a,0x7d,0x85,0x88,0xd4,0xf4,0x26,0xd3,0xf4,0xe3,0x52,0x35,0x37,0x06,0x1e,0x71,0xc2,0x3b,0x7b,0xeb,0xf0,0x07,0x30,0x6b,0x37,0x31,0xb9,0x27,0xd8,0x0b,0x17,0xae,0xff,0xd4,0x7c,0x59,0xd7,0x2d,0xea,0xcb,0x92,0x2f,0x93,0xc7,0xd7,0xc3,0xaf,0x75,0x73,0x6a,0x3f,0x89,0xe5,0x13,0x0c,0x28,0x47,0xf4,0xa4,0x07,0xfb,0xd9,0x77,0xb4,0x1e,0xb2,0x70,0xca,0x85,0x22,0x58,0xc6,0x0b,0x19,0xc2,0xa5,0xba,0xc3,0xc9,0xb6,0x4a,0xdb,0x7d,0x4d,0x66,0xde,0xeb,0x8c,0x1a,0x23,0xb8,0x4c},{0x8c,0x57,0x0e,0x9f,0x0a,0xb2,0xf4,0x07,0xdd,0x7b,0x46,0xf8,0xa0,0xb1,0x33,0x4c,0x2b,0x1e,0x1a,0xe0,0x28,0x17,0x14,0xba,0x14,0x06,0x40,0x1f,0x30,0x0a,0x19,0xcd,0xe7,0xca,0xfb,0xdb,0xb9,0x76,0xf8,0x8a,0x81,0x3d,0x03,0x86,0x7e,0x66,0x75,0x1d,0xec,0xff,0x6b,0xa7,0xea,0x4c,0x8c,0x60,0xd2,0x1f,0x72,0x11,0x4c,0x5d,0xeb,0x01,0xfb,0xd9,0x77,0xb4,0x1e,0xb2,0x70,0xca,0x85,0x22,0x58,0xc6,0x0b,0x19,0xc2,0xa5,0xba,0xc3,0xc9,0xb6,0x4a,0xdb,0x7d,0x4d,0x66,0xde,0xeb,0x8c,0x1a,0x23,0xb8,0x4c}}, - {{0x05,0x64,0x16,0x53,0xbb,0xb2,0x6e,0x81,0xfc,0xe6,0xec,0xc8,0x0c,0xc1,0x75,0x59,0x23,0xe2,0x4b,0xd8,0x6a,0x70,0x34,0x50,0x37,0xc6,0xc2,0xbd,0x27,0xfd,0xad,0x4c,0xee,0xe4,0xf7,0xfc,0x91,0x05,0x48,0x3c,0xd4,0x09,0x78,0x00,0xce,0x15,0x37,0xdc,0xe7,0xce,0x48,0x09,0x3e,0x7f,0x01,0x9b,0x03,0xc8,0x2f,0x9b,0xe6,0x42,0xe1,0x71},{0x64,0xbf,0x63,0x91,0xe5,0x3e,0x90,0x89,0x96,0xea,0x59,0x51,0x60,0x7b,0x5f,0xfe,0x0f,0x76,0x86,0x19,0x45,0x82,0xd9,0x5e,0x1a,0xd1,0xf6,0x04,0xc6,0xaa,0x71,0xda,0x80,0xed,0x75,0x51,0xc8,0x9a,0x27,0x09,0xc3,0x50,0xe4,0x14,0xa1,0xc3,0xf8,0x3a,0x6c,0x84,0xff,0x87,0xd5,0xf0,0xb0,0x3c,0x5a,0x57,0x14,0x90,0xc7,0x31,0xf8,0x47},{0x88,0x7d,0xcc,0x81,0x2b,0xbb,0x7e,0x96,0xbe,0x78,0xe1,0xb1,0xf2,0xed,0x6f,0xd8,0xff,0xbd,0x7f,0x8e,0xe5,0xeb,0x7f,0x7b,0xca,0xaf,0x9b,0x08,0x1a,0x77,0x69,0x1d,0xc2,0xa4,0x7c,0x4d,0xa6,0x74,0x8e,0x33,0x24,0xff,0x43,0xe1,0x8c,0x59,0xae,0x5f,0x95,0xa4,0x35,0x9e,0x61,0xb8,0xcc,0x4c,0x87,0xb9,0x76,0x53,0x20,0xa3,0xf3,0xf5},{0x13,0x2a,0xcc,0x07,0xb1,0x5f,0xc7,0xf1,0x08,0x0e,0x7d,0x7e,0x26,0x56,0xd8,0x16,0x9c,0xae,0xac,0xc4,0xf5,0x9c,0x15,0x67,0xae,0xc4,0xcc,0x3f,0xc0,0xaf,0x53,0x28,0x1f,0x65,0x14,0xe5,0x7f,0x0c,0xf5,0x7a,0xe3,0x93,0xc1,0xa3,0xd1,0x4a,0x09,0x7d,0x24,0xab,0x22,0xc4,0xc4,0xce,0x85,0x37,0x86,0xa8,0x9c,0x39,0x33,0xba,0x1b,0x83},{0x6d,0x3e,0x92,0x5a,0xa8,0xfa,0xe6,0x71,0x98,0xa8,0x82,0x38,0xcc,0xed,0xd6,0x92,0x7e,0x3e,0xcb,0xb2,0x82,0x92,0x7a,0x56,0x9e,0xd6,0x29,0x45,0x42,0x04,0x76,0x82,0xa5,0xfc,0xd9,0x0c,0x12,0x4c,0x98,0x04,0x2a,0x3a,0x98,0x01,0xb8,0x62,0xe8,0xe6,0x7c,0x51,0xe3,0x7d,0x97,0xf5,0x45,0xb4,0x13,0xdf,0x15,0x68,0xc3,0x00,0x75,0x40},{0x7e,0x89,0x3d,0x7c,0x78,0x36,0x3c,0x85,0xda,0xb6,0x9b,0x6d,0xbc,0x52,0x7d,0xc6,0xaa,0xfd,0x90,0x62,0xe4,0xc4,0x1a,0x5a,0x2e,0xa1,0x57,0xd7,0xda,0x57,0xf4,0x58,0xc5,0x23,0x61,0x21,0xe1,0x93,0xfa,0x06,0x22,0xed,0x41,0x66,0x24,0x47,0xb9,0xed,0xc8,0x84,0x25,0x28,0x39,0xec,0xfb,0x29,0xa1,0xcd,0xe1,0x9d,0x02,0x48,0x6f,0x0a,0xe2,0x9f,0x98,0xfd,0x3d,0x18,0xa1,0x24,0x9c,0xc6,0x75,0xb8,0x99,0x76,0x2a,0xa4,0x9e,0xb1,0x97,0x2d,0x1c,0x99,0x65,0x5f,0x1f,0xda,0x14,0x4f,0x10,0x49,0xf1,0x7a},{0x2c,0xec,0x27,0x63,0xd2,0x77,0x14,0x2d,0x01,0x18,0x10,0xe0,0x23,0x1b,0xa2,0x25,0x61,0xd4,0x52,0xd9,0x90,0xde,0x97,0x7e,0xb8,0xfa,0x38,0x25,0xf2,0x91,0x07,0x3e,0xc4,0xa9,0x3e,0xb5,0x67,0x02,0x28,0x94,0x5c,0x34,0xa1,0x0a,0x5c,0x54,0x53,0xd9,0xb4,0xc4,0x5a,0x8e,0x57,0x18,0xc3,0x35,0xea,0x47,0x75,0xe0,0x44,0x01,0x71,0x09,0xe2,0x9f,0x98,0xfd,0x3d,0x18,0xa1,0x24,0x9c,0xc6,0x75,0xb8,0x99,0x76,0x2a,0xa4,0x9e,0xb1,0x97,0x2d,0x1c,0x99,0x65,0x5f,0x1f,0xda,0x14,0x4f,0x10,0x49,0xf1,0x7a}}, - {{0x41,0x10,0xd9,0x7f,0xb8,0x83,0x9e,0x42,0x43,0x7a,0xb0,0x6d,0xa6,0xcf,0xa5,0x7a,0x50,0x93,0x2d,0x13,0x94,0x37,0xa8,0x92,0x26,0x1f,0xad,0xe0,0x25,0x19,0x91,0x62,0x28,0xfb,0x18,0xbf,0x89,0xb0,0x42,0x80,0x14,0xcd,0xd2,0x72,0x84,0x1c,0xfd,0xe5,0xc3,0x71,0x3c,0x3f,0x12,0x5e,0xdd,0x53,0x39,0xf6,0x4b,0x9f,0xb3,0x5c,0xe3,0x15},{0xd0,0xc7,0x18,0x4d,0x68,0x9f,0xdd,0xec,0x81,0xf8,0xc6,0x0e,0x83,0x43,0x23,0x3d,0xfc,0xf3,0x66,0x55,0xa8,0x65,0x8b,0xd7,0x9b,0x3c,0x74,0x23,0xcd,0xae,0x60,0xe7,0x61,0xed,0x2c,0x7e,0xe7,0xa7,0x63,0x7d,0x72,0x47,0x6a,0x33,0x1c,0xaa,0x81,0xba,0x6f,0xd4,0x00,0xe7,0xa9,0x58,0xb2,0xad,0xee,0x3f,0x9c,0x70,0xff,0x2f,0x13,0x6f},{0x56,0x7b,0x19,0x66,0x42,0x9a,0x99,0x51,0x23,0x4f,0xb6,0xe7,0xcf,0x98,0xff,0x20,0x5a,0xc3,0x0e,0x36,0xc9,0xc6,0x20,0x25,0x0c,0x56,0x98,0xfb,0xbd,0xd6,0x66,0x4f,0x6f,0x94,0x85,0x8a,0x35,0xf3,0x50,0xad,0x87,0xde,0x95,0x9e,0xae,0x2a,0xd8,0xdd,0x78,0x87,0x96,0x2b,0xe0,0x12,0x95,0xd9,0x3b,0xb2,0x2a,0x06,0xe2,0xf0,0x06,0xd4},{0x42,0x24,0xdd,0x0a,0xd1,0x11,0x31,0x7e,0x56,0x45,0xb0,0x0e,0x86,0xc1,0x5d,0x8c,0x03,0x01,0xb8,0x33,0x20,0xbd,0x08,0x10,0xe5,0x70,0x92,0x2b,0x5b,0x86,0xd3,0x50,0x4c,0x1e,0xe3,0xd1,0x2a,0x4e,0x40,0x02,0x19,0x0b,0xf6,0x91,0xd9,0x9e,0xaa,0x54,0x7c,0x3d,0xba,0xc5,0x5a,0x9e,0xb2,0xbb,0x4e,0x0d,0x5b,0xdd,0x90,0xc9,0x7b,0xc2},{0x54,0x95,0xd5,0xdc,0x7e,0x7e,0xec,0xd4,0x67,0x08,0xdc,0x58,0xa9,0x80,0x8a,0x03,0x6a,0xf8,0x40,0xca,0x0d,0x5b,0x6c,0xe4,0xc9,0x71,0xa5,0xaf,0x2a,0xaa,0xe8,0x95,0x45,0xe7,0xe2,0xc3,0x47,0x84,0xc6,0xbe,0xe5,0x65,0xaf,0xcd,0x7c,0x20,0x5f,0x8b,0x19,0x61,0xe4,0xc9,0xc1,0x86,0xa5,0x6f,0x96,0xf3,0x9c,0x13,0x28,0x1b,0xcf,0x07},{0xc4,0x7f,0xf2,0x6f,0xcc,0x4a,0xf8,0xa4,0x1f,0x1d,0x6e,0x5e,0x30,0xb2,0x99,0x8f,0x5d,0x7c,0x26,0x1c,0x52,0x6f,0xd0,0x33,0xa7,0xf8,0xca,0x2a,0xc3,0x8c,0xa8,0xd1,0x50,0x4f,0xa7,0xe8,0xf2,0x10,0x4c,0xcd,0x8a,0x31,0x03,0xc8,0x93,0x2c,0xd7,0xe4,0x21,0xdb,0xa2,0x62,0x7b,0x1f,0x28,0x14,0x69,0x7e,0x87,0xac,0xf9,0xb4,0x97,0x00,0x62,0x86,0x14,0xd7,0xe4,0x65,0xdd,0x9e,0x1c,0x64,0x5f,0x3e,0xef,0xfe,0xa6,0x60,0x68,0x91,0x94,0x8a,0x1c,0x89,0xae,0xe4,0xcf,0x3a,0xdd,0xc0,0xb4,0x47,0xe8,0x8f},{0x12,0x80,0x00,0xda,0xce,0xc4,0x80,0x8f,0xa9,0xa1,0x5d,0x98,0x7d,0x2c,0xb2,0x9c,0x71,0xde,0x62,0x89,0x6a,0xe1,0x92,0xd7,0x96,0xdc,0xcd,0xc8,0x08,0x0e,0x48,0xbf,0x2a,0x53,0x72,0x90,0x31,0x71,0x49,0x02,0xda,0x4e,0x19,0x05,0x10,0xcb,0x41,0x97,0x44,0xdc,0x2d,0x1e,0x48,0xe5,0x0e,0x41,0x9d,0x7d,0x03,0xa3,0xe2,0x65,0xd4,0x01,0x62,0x86,0x14,0xd7,0xe4,0x65,0xdd,0x9e,0x1c,0x64,0x5f,0x3e,0xef,0xfe,0xa6,0x60,0x68,0x91,0x94,0x8a,0x1c,0x89,0xae,0xe4,0xcf,0x3a,0xdd,0xc0,0xb4,0x47,0xe8,0x8f}}, - {{0x00,0x4b,0x0b,0xf5,0x1f,0x07,0x1e,0x23,0xe3,0x93,0x7b,0x31,0x41,0x2a,0x0a,0x50,0x35,0xe2,0xbb,0xfe,0x51,0x77,0x6c,0xc9,0xc5,0x13,0xb9,0x87,0x79,0x65,0x68,0x20,0xcc,0x09,0x90,0xa9,0xe4,0xef,0x9f,0x1a,0xe1,0x69,0x76,0x14,0x82,0x42,0x88,0x4b,0xdc,0xe0,0x10,0x22,0xe2,0xd6,0x36,0x7c,0x0b,0xd9,0x08,0xea,0xfa,0xe4,0xfd,0x45},{0x57,0x5c,0x1e,0x20,0xb4,0xae,0x9e,0x9d,0x04,0xfb,0x1a,0xd7,0x23,0xd8,0x8a,0x6b,0x1b,0xb2,0xef,0xa9,0x06,0x38,0xbb,0x9b,0x43,0x2e,0xf1,0x81,0x0b,0x76,0xec,0x20,0x46,0x1b,0xc4,0x71,0x19,0x3e,0x79,0xe8,0xcf,0xea,0xdc,0x4b,0x3f,0x0b,0xeb,0x05,0x13,0x1a,0x2c,0xfe,0x16,0xe9,0xf0,0xc4,0x9c,0x41,0xab,0x45,0x1b,0xba,0x05,0xec},{0x06,0x0b,0x73,0xec,0x30,0x74,0x0d,0x8d,0x13,0x4b,0xef,0xac,0x3b,0x05,0xb6,0xed,0x2b,0x05,0xd1,0xa7,0x65,0xb0,0xcb,0x69,0x00,0xeb,0x47,0xe3,0x1c,0x07,0x8b,0x15,0xbf,0x69,0xff,0x27,0xb4,0xdb,0x77,0xaf,0xe9,0x9a,0xfb,0xb2,0x28,0xa4,0xf9,0x05,0xe4,0x3c,0x66,0x56,0x00,0x1a,0x2c,0x41,0xf2,0xe1,0x11,0x09,0xfa,0xe1,0x50,0x49},{0xbc,0x4d,0x6f,0x75,0x79,0x77,0x64,0x6b,0xec,0xac,0x1a,0x26,0x73,0x9c,0xf3,0xf1,0x4d,0x79,0xbe,0x6f,0x0c,0x07,0x22,0xd1,0xa1,0x31,0x75,0xa8,0x9c,0xb6,0x00,0x63,0x0d,0x40,0x17,0xec,0x83,0xda,0x82,0x2c,0x3b,0xfd,0x90,0xe3,0xbc,0xc2,0x2c,0xf5,0x3e,0x41,0xe9,0x98,0x57,0xa2,0xb7,0xce,0x5f,0x31,0xbb,0x0b,0x05,0x61,0x0f,0x55},{0xb7,0xab,0xb2,0x84,0xf1,0x67,0x24,0x16,0x61,0xe9,0x20,0x33,0x0b,0xff,0x22,0x61,0x70,0xa0,0x5d,0xf6,0xa8,0x33,0xc9,0x30,0x73,0xe5,0x89,0x36,0x59,0xea,0xa8,0xe7,0x03,0xf6,0x14,0xc1,0x79,0xb6,0x42,0xa5,0xc8,0x6c,0xb8,0x94,0x29,0x24,0x00,0x09,0xb5,0x54,0x3f,0xe1,0x6b,0xfb,0x4d,0x2d,0xa9,0x9a,0x02,0xa1,0xa5,0x09,0xf4,0xcb},{0x92,0xfa,0x18,0x84,0x3e,0xdb,0xdf,0x7d,0x87,0xd6,0x2d,0x07,0x05,0x2c,0xba,0xe4,0x30,0x76,0xa2,0xe8,0x71,0x3b,0x1b,0x93,0x5b,0xce,0x2e,0xec,0x50,0x6e,0x4a,0x0b,0x2d,0xbe,0xa3,0x76,0x92,0xf8,0xc8,0x4a,0x71,0x66,0xec,0xfa,0x36,0xc5,0xdb,0xab,0x99,0x9c,0xbf,0x99,0x07,0xe8,0xfe,0xf4,0x2f,0x90,0x16,0x5d,0xdc,0xbe,0xfa,0x08,0x93,0xde,0x13,0xf5,0x32,0x45,0x9a,0xde,0xa2,0x5d,0xb9,0xe0,0x38,0x4c,0x6a,0xcc,0x13,0x46,0x27,0x28,0xbf,0xf8,0x7a,0x9c,0x2e,0xde,0x6f,0xfe,0xe1,0x86,0x41,0x79},{0xa7,0x32,0x52,0x76,0x4f,0x3e,0x1b,0xab,0x82,0x18,0x14,0xe7,0x42,0x32,0xb8,0xa4,0x98,0xde,0xa4,0xd7,0xae,0x42,0x84,0xda,0x71,0xf7,0x78,0x40,0x56,0x94,0x64,0x49,0x34,0x37,0xeb,0xe3,0x05,0x4c,0xb9,0xbb,0xce,0xb2,0x72,0xc0,0x75,0x1c,0xc4,0xd5,0x1e,0x3a,0xc1,0x43,0xda,0xd1,0x81,0x82,0xa9,0xd5,0x0e,0x0a,0x5e,0xc2,0xd7,0x04,0x93,0xde,0x13,0xf5,0x32,0x45,0x9a,0xde,0xa2,0x5d,0xb9,0xe0,0x38,0x4c,0x6a,0xcc,0x13,0x46,0x27,0x28,0xbf,0xf8,0x7a,0x9c,0x2e,0xde,0x6f,0xfe,0xe1,0x86,0x41,0x79}}, - {{0xa3,0xdf,0x4a,0xfd,0xe6,0x74,0xb8,0xeb,0xed,0xe7,0x7e,0xd2,0xae,0xf8,0x40,0x80,0x3a,0x55,0x58,0x1d,0x6b,0xa4,0x32,0x6c,0x15,0xbb,0x67,0xdf,0x9e,0xb5,0x70,0x4b,0x7f,0x4d,0xfe,0x34,0x42,0x0c,0x4d,0xe3,0x97,0x87,0x6d,0x08,0xe8,0x4d,0x8a,0xa9,0xbc,0xbf,0x1b,0xb7,0x66,0x32,0xf4,0x7f,0x93,0xca,0xa4,0xd2,0x8f,0x02,0x7b,0xfa},{0xea,0xac,0xdf,0x25,0x39,0xf3,0x28,0xb6,0xbe,0xa8,0x4a,0x32,0x59,0x4b,0x4f,0xb5,0xd2,0xf7,0xf5,0x75,0x43,0x8b,0xb3,0x6a,0x98,0x8c,0x14,0xc9,0x3f,0x7e,0x5c,0x05,0xf0,0xeb,0x1d,0xc5,0xe6,0x1b,0x5d,0x7f,0x38,0x5d,0x9a,0xbe,0xc8,0x97,0x09,0x65,0x62,0x88,0x99,0xda,0x95,0x13,0x93,0xd9,0xa3,0x19,0x0a,0xa7,0x4a,0xb2,0x81,0xa4},{0x6e,0x70,0x65,0xaa,0x1b,0x16,0xcb,0xc1,0x59,0x6b,0xc9,0x4d,0xd1,0x0a,0x9d,0x8c,0x76,0x70,0x3c,0xc1,0xc1,0x66,0xa6,0x9f,0xfc,0xca,0xb0,0x3f,0x0e,0xe9,0xa9,0x36,0x09,0x4f,0x94,0xf3,0x32,0x25,0x34,0xf6,0xe4,0xf9,0x0b,0x0c,0xe6,0xe0,0x6d,0x9e,0xa5,0x52,0x82,0x9c,0xd4,0x43,0xa4,0xd1,0xd1,0x63,0x20,0xce,0xbc,0x4f,0x43,0xdc},{0x35,0xd6,0xc1,0x68,0xa6,0xd7,0xd3,0x36,0x82,0x2a,0x0f,0x29,0x3e,0xd6,0x15,0x29,0x19,0x73,0x14,0x78,0x87,0x86,0xca,0x9f,0x6e,0x17,0xea,0xaf,0x24,0x37,0xd6,0xb4,0xb0,0xee,0x84,0x90,0x2d,0x18,0xbd,0x26,0xc3,0xd4,0x39,0x4f,0x45,0xfa,0x2f,0x70,0xf2,0xe2,0x2a,0x2a,0x5c,0x65,0x15,0xcb,0xaf,0x92,0x9a,0xfc,0x06,0xe0,0x8a,0x1b},{0x5d,0xfa,0xc0,0x2b,0xc3,0x94,0x19,0xb4,0xd6,0x13,0xe3,0xcf,0x91,0xad,0x8c,0xe1,0x97,0x46,0xfe,0xea,0x74,0xe0,0x0c,0x03,0xf7,0x2e,0x51,0xa7,0xf2,0xbc,0xce,0xe8,0x6b,0xfd,0x2f,0x54,0x52,0x12,0x00,0x8d,0x95,0x91,0xc3,0xf6,0x25,0xf8,0x65,0x6a,0x9c,0x79,0x6b,0x71,0xc0,0x0c,0x29,0xfb,0xe7,0x14,0x9f,0x2f,0x1a,0x07,0x53,0x50},{0xe9,0xd4,0x46,0x0b,0x51,0x3f,0xf1,0xbe,0x0a,0x23,0xa5,0x38,0xa0,0xe3,0x70,0x14,0x63,0xf0,0x94,0xbb,0x1c,0x4f,0x23,0x05,0x1b,0x62,0x40,0x9b,0xf9,0x52,0x1b,0x41,0x51,0x57,0x2a,0x99,0x73,0xda,0xe1,0xcf,0xc5,0x4c,0x65,0x3a,0xc2,0x9d,0x73,0xda,0xc9,0x59,0xf1,0xdf,0xab,0x2b,0x27,0xe1,0x59,0x8b,0xa7,0x48,0xf9,0x36,0xcb,0x08,0xe3,0x5e,0x1d,0xdd,0xf9,0x20,0x4f,0x64,0xa9,0x26,0x74,0x97,0xf2,0x2d,0x31,0xac,0x8c,0x20,0x77,0x09,0xa9,0x8f,0xed,0x23,0x77,0x7e,0xd7,0x34,0x93,0x84,0xe7,0xaa},{0xaa,0xf7,0x64,0xdf,0x34,0x59,0x1c,0x2c,0xbc,0x47,0x08,0x6a,0x25,0xbf,0x9d,0x48,0x54,0xcf,0xa0,0x6c,0xfc,0xd4,0x10,0x39,0x9f,0x64,0x46,0xce,0xd9,0x95,0x28,0x89,0xdf,0x94,0x5e,0x74,0x0b,0x55,0x46,0x82,0xd9,0x3d,0x82,0x97,0x7d,0xd0,0x3e,0xd7,0xf6,0x6f,0xaa,0x97,0x3e,0xdf,0xa7,0xde,0xe3,0xc5,0xaf,0xd3,0xa0,0x5a,0x30,0x0d,0xe3,0x5e,0x1d,0xdd,0xf9,0x20,0x4f,0x64,0xa9,0x26,0x74,0x97,0xf2,0x2d,0x31,0xac,0x8c,0x20,0x77,0x09,0xa9,0x8f,0xed,0x23,0x77,0x7e,0xd7,0x34,0x93,0x84,0xe7,0xaa}}, - {{0x96,0x4e,0xf2,0x1e,0x3a,0xe5,0x77,0xbf,0xa7,0x1c,0x3d,0x66,0x08,0x06,0xca,0x55,0x43,0x7a,0x08,0xf8,0xff,0x55,0xb3,0xbc,0x9a,0x83,0x9a,0x2e,0xe6,0x97,0x14,0x32,0x36,0x57,0x5c,0xa4,0x04,0x78,0xb1,0x92,0xf4,0x23,0x94,0xe6,0x2a,0xef,0xd4,0xe7,0xc4,0x02,0x9f,0xa9,0x79,0x77,0x61,0x90,0xd6,0xdb,0x6e,0x28,0x7e,0xc0,0x1d,0x70},{0xc5,0xd1,0x5c,0x34,0x15,0xa9,0x1e,0x42,0x2a,0x1b,0x0d,0xf0,0x56,0x83,0x10,0xc3,0xc9,0x21,0xfd,0x05,0xfa,0x51,0x0e,0x11,0x28,0xcc,0x84,0xac,0x35,0xb5,0xd8,0xc8,0x5c,0x80,0x11,0x1f,0x60,0x1c,0x72,0x25,0x82,0x45,0xb5,0x4f,0x66,0x6b,0x52,0xb1,0xf7,0x28,0x0f,0x80,0x76,0x44,0xdc,0x15,0x70,0x39,0xe9,0xaf,0xc7,0x0a,0xa0,0x43},{0xff,0x20,0x5e,0x3b,0x75,0xe9,0x38,0x7c,0xa3,0x5c,0x8b,0x1a,0xec,0x17,0x8d,0xf0,0xef,0xb3,0x53,0x9b,0x16,0xa9,0x44,0xf9,0x34,0x45,0x13,0x66,0x80,0x24,0xdc,0x22,0x0e,0x51,0x94,0xed,0xe6,0x83,0x36,0x32,0x63,0x23,0x1b,0xf8,0x78,0xb4,0x04,0x7f,0x5a,0x50,0x54,0x12,0x19,0x04,0x61,0xdd,0x25,0xf0,0x48,0x29,0x04,0xc1,0x44,0xe2},{0x46,0x32,0x2d,0xc7,0xbc,0x05,0x2a,0xd3,0xb5,0xce,0x7d,0x47,0x5e,0xfc,0x90,0x38,0xef,0xfa,0x6f,0x42,0xf0,0x66,0x05,0x89,0x7c,0x9a,0xc1,0xfd,0xa2,0xe8,0xa7,0x38,0x18,0x6d,0x7f,0x9e,0xfb,0xbd,0x06,0x0c,0x70,0xd7,0x29,0x10,0x88,0x04,0x9f,0x24,0x28,0x9d,0xc7,0x84,0xdf,0xb6,0xec,0xb2,0xc7,0x1b,0xd1,0xc1,0x9d,0x56,0xb0,0x83},{0xda,0xd7,0x34,0xee,0x62,0x13,0x8f,0x47,0xad,0xb4,0x9c,0x98,0xe4,0xc5,0xb3,0x29,0x31,0x11,0x64,0xad,0xf5,0x0b,0x60,0xe1,0x0e,0x18,0x28,0x30,0x3c,0xa2,0xe3,0x29,0x89,0x0a,0x7e,0x18,0xba,0x30,0x9e,0x7d,0x53,0xf1,0x82,0xd5,0x27,0xe5,0xf3,0xab,0x15,0xcd,0x62,0x7e,0xdf,0xf0,0x0e,0x42,0xfa,0x6b,0x7b,0x54,0xd2,0x74,0x19,0x8f},{0x29,0x4d,0x28,0x80,0x62,0xb5,0x77,0xbb,0x69,0x70,0xb0,0xb7,0x10,0x2e,0xed,0xfc,0x13,0x34,0x93,0x7f,0xd8,0xfc,0xb5,0x7b,0xfe,0x34,0x0a,0xa3,0x95,0x5b,0xb1,0xa7,0xc6,0xab,0x82,0x79,0x25,0x23,0x94,0x12,0xa4,0x34,0xec,0x23,0xca,0xcb,0xd0,0xa3,0xf9,0x31,0x32,0xce,0x50,0x31,0x73,0x23,0x98,0x94,0xe3,0x08,0xd9,0x1e,0xc3,0x0b,0x39,0xe3,0x3b,0xf2,0xe8,0xb7,0x26,0x28,0x9d,0xb3,0x12,0x8d,0x16,0xca,0x89,0x26,0xa9,0x1c,0xa3,0x1f,0x36,0x10,0x60,0x6a,0x29,0x85,0xe7,0x2c,0xee,0xc1,0xb6,0xae},{0x68,0xed,0x3c,0x64,0xe6,0x87,0xf0,0x14,0x64,0xfc,0x38,0x3a,0x0f,0xd9,0x7a,0x5b,0x52,0x32,0x10,0xca,0xc6,0x83,0x0b,0xae,0x17,0x0e,0xfe,0x77,0xe0,0xe7,0x83,0xa1,0x2c,0x78,0x62,0x9c,0x79,0x08,0x2b,0xd4,0x85,0x72,0x27,0x8d,0x97,0x78,0x62,0x33,0x34,0xeb,0x5c,0xde,0x5d,0xaa,0x4d,0xfa,0xd1,0x67,0xa4,0xea,0x45,0xad,0xf9,0x06,0x39,0xe3,0x3b,0xf2,0xe8,0xb7,0x26,0x28,0x9d,0xb3,0x12,0x8d,0x16,0xca,0x89,0x26,0xa9,0x1c,0xa3,0x1f,0x36,0x10,0x60,0x6a,0x29,0x85,0xe7,0x2c,0xee,0xc1,0xb6,0xae}}, - {{0xd9,0x64,0xb2,0xe1,0x9f,0x0a,0x35,0xfc,0x9f,0xc3,0xa5,0x2a,0xa3,0x84,0xb4,0xf3,0x23,0xc4,0xf3,0x5a,0x9d,0xf8,0x7f,0x35,0xa9,0xf5,0x5b,0x68,0xfc,0x19,0x69,0x63,0x6a,0x13,0x19,0x32,0xcc,0x9d,0x0c,0x3c,0x7d,0xdd,0x85,0x16,0xa8,0xd9,0x2b,0x75,0x08,0x4b,0x9a,0xa5,0x6e,0xf3,0xe9,0xeb,0xed,0x5d,0x2e,0xfd,0x2e,0x0c,0x60,0xa2},{0x0f,0xf6,0x8c,0x3f,0x6e,0xee,0x56,0x4f,0x43,0x6f,0x54,0xbd,0x7a,0xe4,0xbe,0xa8,0x77,0x05,0x99,0xe7,0x9e,0x59,0x22,0x85,0x9b,0xc6,0xe4,0x2a,0x61,0x9c,0x19,0xb1,0x5a,0xeb,0x7a,0xf8,0x41,0x4e,0xe5,0x2a,0xd0,0xf7,0x44,0xf0,0x16,0xea,0x0c,0x04,0x19,0x6c,0xb6,0x30,0x3c,0x6e,0x2d,0x79,0x9a,0x8f,0x08,0x90,0x11,0xf1,0xc0,0x4d},{0x68,0xe7,0x1d,0x40,0xf1,0x07,0xc0,0xc6,0xb2,0x87,0x9c,0xa2,0x19,0x43,0x7a,0xdf,0x8a,0x5a,0x0f,0xe2,0x24,0x97,0xa0,0x38,0x79,0x20,0x38,0xa9,0x9c,0x77,0xc4,0x37,0xa6,0x02,0xe0,0x93,0x47,0xa4,0x55,0x21,0xc2,0x69,0xbe,0x09,0x05,0xaa,0x87,0x28,0xf1,0x95,0x2f,0xdb,0xf0,0xbf,0xd2,0x9e,0x5e,0x3a,0xfa,0xc6,0x2f,0x13,0x09,0xaf},{0xe1,0x9e,0xc8,0x4f,0xc9,0xdd,0x61,0x60,0x94,0xbc,0xd3,0xd6,0xde,0x11,0x6e,0xec,0x84,0xc4,0xdd,0xbe,0x20,0x46,0x6c,0xef,0xf6,0x9d,0x37,0x07,0x53,0x72,0x57,0xf9,0x02,0xb5,0x64,0x1f,0xe2,0x56,0xa4,0x38,0x6d,0xa4,0xed,0x23,0x9e,0xa3,0xf4,0x4d,0x77,0x52,0xdc,0x8c,0x51,0xfc,0x88,0x18,0xbc,0x83,0x2a,0xac,0xc1,0x1d,0x3d,0x59},{0x08,0x4f,0x78,0x21,0xfd,0x4b,0x85,0x86,0x4e,0x25,0xdd,0x47,0x60,0x7f,0x7e,0xc6,0xd3,0xa1,0xab,0x91,0x3f,0xeb,0xf6,0x40,0x7e,0x1b,0xbd,0x99,0x9c,0x7c,0x2f,0x4f,0xca,0x68,0xa5,0xf6,0x8c,0x1e,0xcb,0xb8,0x76,0xe2,0x87,0x5b,0x49,0x68,0x97,0x2c,0x21,0x5c,0x7c,0x93,0x79,0x9a,0x95,0xa1,0x3a,0x49,0xc9,0x6d,0x34,0x6b,0xa1,0x98},{0xb9,0x88,0x25,0x9a,0x3b,0x53,0x56,0xa1,0x48,0x0f,0xf0,0x92,0xde,0x4e,0x3e,0x3a,0xcf,0x02,0xdc,0x5c,0xc2,0xc3,0x78,0xad,0x8a,0x0c,0x3c,0xc7,0xdd,0xdd,0x71,0x6e,0x3f,0xd9,0x3a,0x57,0x2a,0x19,0xa5,0x3b,0x5c,0x46,0x7b,0xc9,0x0f,0x16,0xb3,0x58,0xa6,0x85,0xfa,0x91,0x2c,0x9a,0x9c,0x12,0xb6,0xd6,0x7d,0x9a,0xf0,0x9d,0xe9,0x02,0xad,0x12,0x87,0xda,0x85,0x58,0x6b,0xff,0x68,0x96,0x05,0x33,0xba,0x7f,0x08,0xf9,0xa9,0xa2,0xa9,0x46,0x43,0xe5,0x03,0x12,0xe4,0xbe,0x74,0xaa,0x46,0x4e,0x51,0xb3},{0x61,0x70,0x17,0x50,0x26,0xfa,0x51,0x83,0xe0,0xca,0xa9,0xb1,0xc3,0xc4,0x83,0xa9,0xb6,0x43,0x6b,0x7a,0x5b,0xe4,0x21,0x5a,0x6b,0xd4,0x34,0xf8,0xee,0x95,0x86,0x2d,0x03,0xbf,0xca,0xd0,0xfa,0x68,0x53,0xb2,0x97,0x50,0xad,0x89,0x2f,0x99,0x63,0x67,0x18,0x57,0x1f,0x57,0x41,0xbc,0xb7,0xc0,0x18,0xe7,0xb6,0xf3,0x0f,0xc4,0x49,0x0d,0xad,0x12,0x87,0xda,0x85,0x58,0x6b,0xff,0x68,0x96,0x05,0x33,0xba,0x7f,0x08,0xf9,0xa9,0xa2,0xa9,0x46,0x43,0xe5,0x03,0x12,0xe4,0xbe,0x74,0xaa,0x46,0x4e,0x51,0xb3}}, - {{0xc5,0xdf,0x86,0x8f,0xf1,0xa7,0xad,0x57,0xfd,0xb4,0x53,0xc3,0x92,0x1b,0x9e,0x2e,0xdd,0xc5,0xa4,0x3b,0x72,0xa6,0x9b,0x4a,0x15,0xca,0x35,0xed,0x3c,0x1a,0x3b,0x38,0x36,0xd6,0xf2,0x03,0xb6,0x97,0x1f,0xcb,0x40,0x5d,0x3c,0x25,0xfc,0xe7,0xff,0xc6,0xbe,0x61,0xe1,0x98,0x31,0x13,0xa9,0xbe,0x05,0x86,0xfe,0x5c,0xf6,0xcc,0xaa,0xf5},{0xd2,0x57,0x19,0x98,0xf8,0x74,0x90,0xb7,0x69,0x6e,0xdd,0x44,0xf1,0x8b,0xb1,0x9c,0xfd,0x5b,0x6b,0xc0,0x45,0xf2,0x49,0xa5,0x4b,0xff,0x8b,0x7f,0x87,0xe3,0xf9,0x71,0xab,0xfa,0xc8,0x17,0xed,0xeb,0x19,0xc6,0x3c,0xee,0x78,0xba,0x89,0x97,0x49,0x85,0x39,0x68,0x29,0x88,0x0b,0x1c,0xd1,0x42,0x8b,0xe8,0x1a,0x3b,0xeb,0x4d,0xef,0x3b},{0xea,0xfb,0xec,0x27,0xc3,0x92,0xc3,0x68,0x0d,0x3c,0x5b,0x20,0x20,0x9c,0x96,0xa7,0x39,0xfa,0x80,0x91,0xef,0x86,0x7d,0xa8,0x87,0xf6,0xef,0x14,0x01,0x46,0xf0,0x68,0x0a,0x8b,0xae,0x83,0x91,0x7e,0xa0,0x14,0x14,0xde,0xf9,0xa8,0xfd,0x67,0x57,0x17,0x20,0x46,0x43,0x49,0x07,0xf0,0x3e,0xc8,0xbe,0x66,0xaf,0x58,0x3a,0xbd,0xd8,0x00},{0x35,0xf5,0xc8,0x2c,0x0e,0x4b,0x56,0xe0,0xef,0x08,0x34,0x38,0x57,0xe9,0xde,0xdb,0x1d,0xe1,0x28,0x05,0x01,0xed,0x62,0x3d,0xa9,0x6e,0xea,0x5b,0x95,0x09,0xe0,0x04,0x46,0xff,0xdc,0x34,0xf6,0xf7,0x63,0xb1,0x76,0xb8,0x3c,0x03,0xef,0x36,0x0f,0x82,0x1b,0x5b,0x6f,0xe2,0x86,0xd9,0x10,0x01,0xe6,0x73,0x75,0x0d,0x50,0x30,0x11,0x68},{0x27,0xb6,0x3b,0x78,0x79,0xf3,0x22,0x78,0x8f,0x0c,0x14,0x8b,0x3f,0x68,0xc2,0xab,0x9f,0x9f,0x05,0x70,0x7e,0xee,0x4b,0x1b,0x6b,0xfc,0x04,0x72,0xca,0xf1,0x9a,0xba,0xe3,0x65,0x9d,0xdb,0x01,0x33,0xc5,0xdb,0xf6,0x87,0xe4,0x73,0x5a,0x0f,0x94,0xa9,0x2e,0xfe,0x8f,0x3e,0xd1,0x0a,0x6d,0xa1,0x21,0x2a,0x92,0x8c,0x4b,0x43,0x13,0x2f},{0xa3,0xa8,0x3b,0xb4,0x4f,0x8a,0xac,0xab,0x8a,0x4c,0x39,0x7e,0xb8,0x2f,0xb1,0x01,0x2e,0xbe,0x0e,0x7d,0x28,0x8a,0x18,0x4a,0xda,0x58,0x1a,0xfb,0x95,0x97,0xf3,0x63,0x58,0xbe,0x8c,0x30,0x13,0x9b,0xba,0x9f,0x4e,0xac,0x8d,0x95,0xf2,0x07,0xbb,0x85,0xa1,0x41,0x4c,0x33,0xe3,0x58,0x8e,0x5c,0xa1,0x05,0x45,0xab,0x5c,0x0c,0xe4,0x02,0xc3,0xa0,0xa0,0x72,0xdb,0x9a,0x9d,0xbf,0x13,0x29,0x94,0x70,0x8b,0xe4,0xe8,0xdb,0x0e,0x0b,0xd0,0xa0,0x25,0xad,0x71,0xa0,0x27,0x9c,0x1d,0x77,0xb0,0x98,0xa8,0x03},{0xe1,0x84,0xa5,0xea,0xa5,0xd8,0x1b,0x29,0xce,0xd7,0xa3,0x72,0xa7,0xc9,0xa5,0xea,0xf1,0x02,0xf3,0x0c,0xb0,0x65,0x12,0xbc,0xa4,0xf2,0x5d,0x69,0x00,0xa4,0x7f,0x5a,0x52,0x09,0xb6,0x7b,0x30,0xf2,0x99,0x03,0x39,0x9d,0xee,0x6f,0xb5,0xf7,0x9e,0x7a,0x97,0x8b,0x81,0x03,0x8c,0xdd,0x35,0xfc,0x1f,0x0a,0xc6,0xa4,0x60,0x7b,0xc8,0x0a,0xc3,0xa0,0xa0,0x72,0xdb,0x9a,0x9d,0xbf,0x13,0x29,0x94,0x70,0x8b,0xe4,0xe8,0xdb,0x0e,0x0b,0xd0,0xa0,0x25,0xad,0x71,0xa0,0x27,0x9c,0x1d,0x77,0xb0,0x98,0xa8,0x03}}, - {{0x67,0xe9,0x62,0x76,0x3a,0x90,0x9b,0x6b,0x19,0x1d,0x65,0xb2,0x2a,0x2f,0xf7,0x50,0xaa,0x54,0xa5,0xbb,0x53,0xb5,0xf9,0xee,0x0c,0x04,0x3a,0x3c,0x29,0x4b,0x66,0x3e,0x7b,0xb6,0xaa,0xd2,0x10,0x89,0xcc,0x89,0x2c,0x47,0xbe,0x23,0xd6,0x52,0x81,0x5d,0xc8,0xbc,0x49,0xd6,0x6a,0xcd,0x62,0x99,0x30,0xff,0x16,0xa5,0x50,0x44,0xd8,0x7a},{0xd6,0xcd,0xfe,0xd4,0x44,0x4a,0x9e,0x90,0x44,0x73,0x8a,0xff,0xbb,0x82,0x08,0xb6,0x7f,0xf2,0x87,0xcb,0xa5,0x0b,0x56,0xd3,0x9e,0x91,0xb8,0x52,0x6b,0x25,0xa6,0x5d,0x50,0xaf,0x9b,0xd5,0xfb,0x9f,0x7e,0x2d,0x57,0xdf,0x30,0x78,0x8d,0x1a,0xc3,0xac,0x9c,0x5a,0xbf,0xab,0x5a,0x0d,0xc9,0xb6,0x4b,0x18,0xd4,0xe7,0x55,0x40,0xde,0x7e},{0xc2,0xa9,0x7e,0x5c,0x26,0xf4,0x7d,0xce,0x9e,0x73,0xae,0x50,0xde,0xe7,0xa6,0xf9,0x8b,0x57,0xf9,0x7a,0x4c,0x38,0x82,0xf6,0x30,0x80,0x12,0xf7,0xf6,0x66,0x80,0x46,0x4d,0x41,0x53,0x63,0xd9,0x65,0x90,0xe7,0xee,0x24,0x07,0xb0,0x4f,0xeb,0x3e,0x8e,0x83,0x21,0xa3,0x40,0x03,0xc0,0x64,0x52,0xc6,0xb2,0x12,0x9d,0x8d,0x86,0xdd,0x19},{0xe2,0xd5,0x49,0x5e,0x2a,0x6e,0x4e,0xd9,0x31,0x26,0x53,0x13,0x98,0x5e,0x2f,0x23,0xea,0xa0,0x30,0xee,0xef,0x62,0x2b,0xdc,0x93,0x65,0x90,0xad,0x9a,0xf1,0x74,0x12,0xf5,0x24,0x33,0xcc,0xc3,0xda,0x42,0x54,0xa6,0x6c,0x86,0x99,0xb9,0xb5,0xf7,0x07,0x90,0xd8,0x85,0x7f,0x69,0xfb,0x19,0x2a,0x2c,0xc0,0x11,0x81,0x64,0x37,0x38,0x07},{0xc7,0xb3,0xf5,0xe4,0x4b,0x55,0xcf,0xd8,0x2b,0x72,0xde,0x62,0xfc,0x66,0xea,0x82,0xee,0x2e,0xe5,0x4f,0x66,0xba,0x19,0x63,0x01,0x0b,0x2d,0x89,0xb4,0xaa,0x76,0xb3,0x7e,0xc5,0xbe,0xdd,0x57,0x90,0x5e,0xff,0x5b,0x9a,0x71,0xe1,0x47,0xf9,0xec,0xe5,0xf0,0x19,0x89,0x17,0x65,0x3e,0x56,0x4a,0x98,0xb2,0x3c,0x3b,0xf0,0x14,0x13,0x1b},{0xc0,0x72,0x26,0x96,0x6b,0xf5,0x50,0xa1,0x65,0xcd,0xfe,0x92,0xa5,0x5a,0xb3,0x56,0x27,0x5b,0x2f,0x4a,0x8f,0x67,0xaa,0xf4,0xa1,0x6e,0x3c,0x66,0xcc,0xb7,0x71,0x70,0xff,0x70,0x1f,0x9e,0x09,0xae,0x31,0xcb,0x2a,0xd5,0x8a,0x38,0xa9,0xaf,0xbc,0x94,0xa2,0xa8,0xe9,0x77,0x1c,0xc3,0xfa,0xd1,0x45,0xd2,0xe2,0xff,0x7d,0xf2,0x44,0x00,0xa0,0xc3,0xc1,0xdd,0xa0,0x4c,0xfb,0xed,0x1a,0xbd,0x0c,0x05,0x3b,0xa9,0xc8,0x98,0xb0,0x7d,0x6a,0x77,0xcb,0x08,0x70,0x64,0x31,0x9d,0x9c,0x7b,0x40,0x9e,0xbb,0xf4},{0xbc,0x88,0x9d,0x36,0xae,0xbc,0x92,0x47,0x63,0x85,0x41,0xe3,0x1e,0x1c,0x39,0xf5,0xd3,0xc2,0x0a,0x7d,0x18,0x7a,0x8f,0xd3,0x0c,0x37,0x50,0x28,0x35,0x93,0x77,0x4b,0xcb,0xba,0x35,0x4e,0x94,0x48,0xe4,0x0c,0xa7,0x36,0x4f,0x74,0x2b,0xf9,0xb5,0xb5,0xeb,0x91,0x50,0x3c,0x67,0x9b,0x4d,0x25,0xd4,0x0e,0x0d,0xb9,0x5b,0x77,0xf3,0x0e,0xa0,0xc3,0xc1,0xdd,0xa0,0x4c,0xfb,0xed,0x1a,0xbd,0x0c,0x05,0x3b,0xa9,0xc8,0x98,0xb0,0x7d,0x6a,0x77,0xcb,0x08,0x70,0x64,0x31,0x9d,0x9c,0x7b,0x40,0x9e,0xbb,0xf4}}, - {{0x44,0xdd,0x62,0x9e,0x0f,0xee,0x20,0x11,0x37,0xfc,0xd0,0x5c,0xe4,0xe1,0x0a,0xb8,0xc2,0xe0,0x9c,0x2c,0x3e,0x1b,0x31,0x1c,0xdb,0xa3,0x84,0x9a,0xb7,0x4e,0x40,0x74,0x21,0xfd,0xfc,0x65,0xbd,0x38,0x8a,0x55,0x6f,0x1e,0xc3,0x14,0xfc,0x66,0x04,0x7b,0xc4,0x61,0xb0,0xcb,0xfa,0xdd,0x50,0x45,0x4b,0x2e,0xf0,0x6d,0x0f,0x26,0x6d,0xbf},{0xe6,0xbc,0x35,0x73,0xb3,0x11,0x38,0xc6,0x31,0x82,0x96,0x80,0x1d,0xa9,0xd9,0x17,0x85,0x4e,0xad,0x0f,0x5c,0xb7,0xe8,0x78,0x62,0x2f,0x3c,0x10,0x0e,0xdc,0xf2,0x7e,0xf5,0x02,0x6d,0x1a,0x50,0xc2,0x50,0x7d,0x0d,0x14,0x77,0x77,0xfc,0xbe,0x23,0x02,0x81,0x0a,0xdc,0xa3,0x16,0xfd,0xab,0xb9,0x7c,0xb6,0x7e,0x8a,0xde,0x1f,0x22,0xeb},{0xab,0xf3,0xea,0x63,0xc0,0x25,0xa2,0xc7,0x6a,0xfe,0x91,0x4a,0x0a,0x91,0xdd,0x6d,0x6f,0x8c,0xf9,0xa8,0x1c,0x9f,0xb5,0xe5,0xd2,0xac,0xe6,0x51,0x9a,0xd3,0x87,0x17,0x82,0x12,0x0a,0x58,0x99,0x7f,0x81,0x2d,0x8d,0x27,0x2d,0x1b,0xb0,0x02,0x7e,0x0d,0xd6,0x18,0x89,0x5e,0x0c,0x2b,0x57,0xa6,0x56,0x35,0xff,0x71,0x4e,0xb0,0x49,0x38},{0x36,0xdf,0x1d,0x1c,0xf6,0xa7,0x4d,0x87,0x7e,0x2c,0x3f,0xb4,0xda,0xd7,0x80,0x71,0x0b,0xf3,0x2a,0x47,0x20,0xe6,0x9a,0x3d,0x17,0x9a,0x97,0xc9,0x4e,0x53,0xa6,0xe2,0x23,0xea,0x94,0x4d,0xf9,0xeb,0x2c,0x03,0x2c,0x88,0xa2,0xe6,0xc5,0x94,0xa5,0x6f,0xc3,0x98,0xa9,0x8b,0xa7,0x41,0x7d,0xd3,0x82,0x01,0x13,0xb6,0x0f,0x39,0x1e,0xd2},{0x08,0x28,0xc3,0x1c,0xec,0x21,0x3a,0xb4,0x4c,0xb1,0xfa,0xb9,0x0c,0xfe,0xc2,0x50,0xc5,0x99,0x62,0xa0,0x11,0x74,0xcf,0x05,0x1e,0x2b,0xdf,0x6d,0x22,0x8e,0x6e,0x55,0x19,0x21,0x9c,0xa1,0x98,0x56,0x45,0x90,0x40,0x3a,0x8e,0xad,0x76,0x4d,0xd3,0x95,0x27,0x67,0x4e,0x02,0x16,0xc3,0xfe,0x5a,0x79,0x4e,0x2d,0x6f,0xd0,0xe4,0x4f,0x62},{0x40,0x14,0xe1,0x88,0x3d,0xcc,0x51,0xcb,0x98,0x86,0x06,0x4d,0xe4,0x52,0x71,0xe2,0x2e,0x2b,0x80,0xfd,0x81,0x65,0xaf,0x93,0x31,0x87,0xe0,0xff,0x31,0xab,0xff,0x53,0x0e,0x2d,0xb1,0x47,0xe6,0x44,0xb7,0x29,0xab,0x0f,0x51,0x3a,0x53,0x84,0x36,0x58,0x8c,0x5f,0x7b,0x65,0x6a,0xb7,0x6f,0xdc,0xad,0xc1,0xa3,0xe4,0x21,0xfc,0x22,0x0e,0xc1,0x10,0xd1,0x7d,0x9f,0xd3,0x1e,0x33,0xb4,0xca,0xb9,0xff,0xd8,0x27,0xb8,0xca,0xde,0x49,0x6f,0xdc,0xf0,0xe8,0x70,0x36,0xdb,0x90,0x00,0x07,0x9e,0x77,0x39,0xfe},{0xc9,0x93,0x4b,0xe6,0x47,0x7e,0x1d,0x86,0x15,0x46,0xe8,0x27,0xf5,0x84,0x67,0x4e,0x42,0xe3,0x2b,0x8a,0x4e,0x90,0x7b,0x87,0xcc,0xdf,0xaa,0x04,0x06,0x05,0xe6,0x72,0xff,0x6f,0x44,0x1b,0x08,0xad,0x79,0x3e,0xb7,0xdd,0xd7,0x2c,0x73,0xf0,0xf0,0xc4,0x6e,0xb7,0x37,0xe1,0x02,0xf5,0x42,0xe7,0xef,0xa1,0xdd,0x50,0x9a,0xc5,0x8d,0x00,0xc1,0x10,0xd1,0x7d,0x9f,0xd3,0x1e,0x33,0xb4,0xca,0xb9,0xff,0xd8,0x27,0xb8,0xca,0xde,0x49,0x6f,0xdc,0xf0,0xe8,0x70,0x36,0xdb,0x90,0x00,0x07,0x9e,0x77,0x39,0xfe}}, - {{0x3e,0x0c,0x21,0xc4,0x3d,0x64,0x61,0xc1,0x9d,0xa1,0x83,0x10,0x74,0x1d,0x56,0x12,0xaf,0x29,0x5c,0x6c,0x12,0x48,0x0a,0xc7,0xe5,0x12,0xb6,0x42,0x6b,0x54,0xf4,0x42,0x0c,0x43,0x42,0x2e,0x78,0xc2,0xe7,0x26,0x09,0x41,0x4a,0x2f,0xa1,0xb0,0x1f,0xcd,0x63,0x76,0x1e,0xa1,0x6f,0xf6,0xe2,0xc2,0x08,0x89,0x0d,0x28,0xbf,0x1b,0x56,0x5b},{0x3e,0x2e,0xf2,0xcc,0x81,0xca,0xa7,0x5d,0x01,0xd2,0x82,0xfd,0x45,0xee,0xc0,0xf5,0x49,0x3b,0xe2,0xa4,0x2a,0x4d,0x5f,0x40,0x0d,0xbc,0xb9,0x3d,0x6e,0xda,0xe2,0x86,0xe1,0x23,0x8b,0x5f,0x0d,0xa2,0x35,0x15,0x1d,0x22,0x23,0xa5,0x69,0x56,0x34,0x78,0xb3,0xb3,0x55,0xef,0x63,0x8a,0x17,0x63,0xda,0xf0,0x64,0x99,0x8a,0x8a,0xba,0xd6},{0x68,0x79,0x36,0xa7,0x6b,0xe3,0x76,0x1c,0xe3,0x38,0x0b,0xa3,0x91,0xb6,0xb0,0x82,0x37,0xfa,0x52,0x74,0xf1,0xb5,0xd5,0xd9,0x07,0x06,0x9e,0xda,0x87,0x6b,0x0f,0x24,0x4f,0xbe,0xc9,0xff,0x03,0x41,0xaf,0x77,0x68,0xed,0xe7,0x71,0xba,0x2d,0xde,0x27,0xa1,0xbf,0xa8,0xa7,0x30,0x7c,0xcb,0x79,0x72,0x89,0x1a,0xdc,0xc1,0xe4,0xb2,0x9d},{0x94,0xa3,0x11,0xf4,0x44,0x80,0xd0,0xa3,0x47,0x93,0x36,0xe2,0xbd,0x04,0xe4,0x74,0x3d,0x00,0x60,0xad,0xd0,0x2d,0x86,0x66,0xa1,0x72,0x1a,0xb9,0x1c,0x14,0xa2,0x9b,0x4b,0x04,0x7d,0x5b,0xcd,0xf8,0x01,0x33,0xde,0x34,0x10,0x29,0xc4,0x72,0x56,0xff,0x11,0xcd,0xd8,0x61,0x2c,0xb6,0xb7,0xf4,0x24,0x8b,0x44,0xb4,0xe7,0x34,0x50,0xb8},{0x72,0xf6,0xd4,0xa3,0x24,0xf9,0xef,0xf4,0x55,0x8d,0x3c,0x07,0xca,0x10,0xdd,0x54,0x87,0x13,0x32,0x78,0x5c,0x64,0x10,0x08,0x62,0x7e,0xf4,0x34,0x0f,0x1c,0xcd,0xcc,0x3b,0x42,0xfe,0x60,0x41,0x70,0x2c,0x6b,0xd4,0x6c,0xf7,0xb8,0x24,0xf6,0xd7,0x07,0xb3,0x46,0xb0,0x7d,0x14,0x24,0x9b,0x72,0x79,0xf4,0x23,0x2a,0xec,0x02,0xe7,0x69},{0xe5,0xbe,0x84,0xc3,0x92,0x47,0x15,0xd3,0xac,0x06,0x44,0x72,0x41,0xeb,0xb6,0x5a,0x17,0x06,0x90,0xd9,0x55,0x3d,0xe4,0x87,0x7d,0x5a,0x11,0x9f,0x02,0x6d,0xd3,0x4e,0x71,0xd1,0x5e,0x16,0x9f,0xb2,0xc0,0x7f,0xcb,0x78,0x8b,0x89,0x11,0xae,0x43,0xe8,0x85,0xb7,0xf9,0xc8,0x48,0x5a,0xb2,0x96,0xaf,0x8f,0xab,0x71,0x84,0x9d,0x40,0x09,0x30,0xd4,0x32,0x6e,0xa2,0x77,0x97,0x71,0x37,0xce,0x22,0x6b,0xca,0xc9,0x79,0xef,0xc0,0xb2,0xb4,0x3d,0x30,0xbf,0x77,0xe9,0xc3,0x8d,0xec,0x15,0x04,0x08,0xfa,0x15},{0x4b,0xf3,0x7f,0xb2,0x78,0x75,0x45,0xd4,0xce,0x5e,0x3d,0xaf,0x92,0x63,0x3d,0x90,0xc0,0xa7,0x23,0x62,0x7f,0x37,0x58,0x8d,0x12,0xe0,0xb8,0x6c,0x46,0x38,0xaa,0xf7,0xe1,0x03,0x9e,0x1f,0x31,0xf9,0x5a,0xa4,0x59,0x0d,0xec,0xc5,0x1f,0x17,0x88,0x25,0xcc,0xed,0x69,0x2b,0x91,0x73,0x6a,0x3f,0xcb,0xe5,0x9c,0x1e,0x26,0x3e,0xec,0x0b,0x30,0xd4,0x32,0x6e,0xa2,0x77,0x97,0x71,0x37,0xce,0x22,0x6b,0xca,0xc9,0x79,0xef,0xc0,0xb2,0xb4,0x3d,0x30,0xbf,0x77,0xe9,0xc3,0x8d,0xec,0x15,0x04,0x08,0xfa,0x15}}, - {{0xc5,0x1d,0xcd,0x70,0xb2,0x9e,0x53,0x29,0x05,0x78,0x83,0x5d,0x56,0x30,0x89,0xee,0x02,0xd7,0xac,0x57,0x0a,0xd2,0xa0,0x9c,0x96,0x0c,0xbf,0xf2,0x30,0xbf,0x1a,0x2b,0xee,0x0e,0x9f,0x1e,0x1c,0x65,0x7d,0xb5,0x48,0xad,0x6f,0x51,0xa0,0x91,0x61,0xe4,0xe6,0x83,0x9f,0x58,0x7c,0x76,0x2b,0x52,0x94,0x87,0x3c,0x8d,0x36,0x4c,0x37,0x3c},{0x59,0x3b,0x0d,0x38,0xab,0x93,0xca,0xfb,0x67,0x44,0x30,0x96,0xec,0xbd,0x00,0x1d,0x93,0xd0,0xb3,0x3d,0x3c,0xd4,0x4e,0x3d,0xd8,0x29,0x93,0xb2,0xb3,0x77,0xfc,0x57,0x31,0x20,0xe3,0x90,0x0d,0xf4,0x91,0x2f,0x8b,0x43,0xce,0xfe,0x99,0x03,0x03,0xa2,0x90,0x8d,0xcf,0xa8,0xc0,0x21,0x00,0xca,0xcc,0xcb,0x4b,0x2f,0xa5,0x39,0xa8,0x0b},{0xca,0xf6,0xf9,0xbb,0x53,0xcb,0x97,0x76,0xb6,0x9c,0x2c,0x18,0x21,0x43,0x13,0x48,0x13,0xc9,0x0e,0xeb,0x40,0xea,0xce,0x1f,0x3a,0xe9,0xd2,0x9e,0x29,0xdb,0xe2,0x79,0xe2,0x1a,0x9f,0x84,0x9d,0xe4,0x55,0x82,0x17,0xeb,0x87,0xf6,0xc3,0xef,0xcd,0x54,0x14,0xee,0xc8,0x5b,0xd7,0x67,0x05,0xe2,0x34,0xa2,0x7e,0x81,0x83,0x21,0x7a,0x02},{0xc5,0x03,0xd9,0x75,0xdf,0x17,0x15,0xe3,0x5b,0x7b,0x4f,0x66,0x9c,0x15,0x4e,0x01,0xdf,0x3d,0x16,0xb6,0x52,0xcc,0xcf,0x28,0x40,0xdb,0x20,0xee,0x8b,0x69,0xb1,0x2b,0xc0,0x6e,0xe4,0xd2,0xf5,0xd1,0x49,0x3f,0xf3,0x0a,0x12,0xcd,0x13,0xbd,0x9d,0x3d,0x5b,0x28,0x5c,0xb0,0x0d,0x0e,0xb6,0xed,0xec,0x65,0xeb,0x25,0x28,0x2e,0x65,0x2f},{0xed,0xa7,0x05,0xc1,0xa6,0x81,0xf2,0x7a,0x69,0x68,0x17,0x8e,0xf7,0xc9,0x14,0x80,0x9f,0x81,0xfe,0x16,0xfd,0x81,0x93,0xb4,0x0b,0x05,0x5b,0x4e,0xef,0x6e,0x7a,0x67,0x9d,0x99,0x4c,0x17,0xcd,0x1c,0x16,0xfd,0x31,0x35,0xd5,0x3e,0xa3,0x00,0xbf,0xbe,0xda,0xd6,0xe2,0x37,0x9b,0x13,0x1b,0xca,0x29,0x90,0x4b,0xf2,0x09,0x57,0x2f,0xe9},{0xd7,0xba,0x23,0xd3,0xa0,0x6e,0x14,0x6a,0xf0,0x77,0xb7,0xe6,0xe3,0xc9,0x3b,0x38,0xbb,0xe7,0xbe,0x54,0x75,0xf8,0xb7,0x42,0x29,0xe2,0x83,0xde,0x20,0x22,0x41,0xcf,0x5f,0x6f,0x80,0x60,0xf3,0x44,0x04,0x21,0xd5,0x03,0x68,0x42,0xde,0x81,0xea,0xe8,0x7e,0x5b,0x80,0x0f,0x1b,0x2d,0x06,0xc7,0xce,0xe9,0x46,0xc7,0xf7,0xb3,0xa2,0x02,0x21,0xb5,0x4d,0xc2,0x36,0xea,0xe6,0x7b,0xb3,0x61,0xe6,0x18,0x40,0x5b,0xce,0x5b,0xc2,0xee,0xa5,0xde,0xe9,0xe6,0xe0,0xa8,0x58,0x58,0x03,0x34,0x26,0x27,0x65,0x2a},{0xfa,0x43,0xa6,0xc4,0x32,0xa1,0x2f,0xb6,0x37,0x05,0xf4,0xa4,0xa7,0x36,0xdd,0x1c,0x45,0x10,0x95,0x83,0x67,0x89,0x79,0x18,0x34,0xad,0xe7,0x57,0x7f,0x0d,0x48,0x9b,0x14,0xdf,0x5f,0xc8,0xd7,0x0f,0x78,0x47,0x88,0x20,0xff,0x7f,0xb1,0x21,0x27,0x14,0x58,0x32,0x12,0xfb,0x97,0xe0,0x81,0x0e,0x92,0xf4,0x5c,0x0e,0x44,0x48,0x4e,0x01,0x21,0xb5,0x4d,0xc2,0x36,0xea,0xe6,0x7b,0xb3,0x61,0xe6,0x18,0x40,0x5b,0xce,0x5b,0xc2,0xee,0xa5,0xde,0xe9,0xe6,0xe0,0xa8,0x58,0x58,0x03,0x34,0x26,0x27,0x65,0x2a}}, - {{0x1e,0x89,0x12,0xe8,0xab,0xca,0xeb,0x96,0x78,0x43,0x89,0x79,0x26,0x61,0x86,0x2e,0x37,0xd7,0x94,0xb5,0xb9,0xf7,0xc9,0xe7,0x04,0x6c,0x96,0x1c,0x54,0x0d,0xb0,0x6c,0xd3,0x68,0x9b,0x53,0xa7,0x56,0x34,0x1b,0x65,0xff,0xf9,0xee,0xf1,0xc6,0xfd,0x7e,0xa8,0x42,0x59,0x60,0x06,0x5f,0xc2,0x89,0x8b,0xfc,0xf8,0x6c,0x9a,0x0d,0xb1,0x36},{0x52,0x3d,0x83,0x25,0x0f,0x57,0x81,0x76,0x7b,0x21,0xf7,0x96,0xd6,0x1f,0xfe,0xd7,0x7c,0xc1,0x32,0xb5,0xbc,0x05,0x46,0xdb,0x6f,0x25,0xd8,0x7a,0x68,0xe2,0x01,0x81,0xf8,0x9a,0xc5,0x29,0x78,0x1c,0x01,0xc5,0x4d,0x61,0x4e,0x75,0xdf,0x9f,0xc3,0x22,0x96,0x7c,0xf9,0xa7,0xed,0x41,0x6f,0x64,0xfd,0xd4,0x61,0x58,0x0d,0x49,0xc9,0xa4},{0x4a,0xf7,0xda,0xef,0xe0,0x3b,0x33,0x19,0x79,0x02,0x7a,0xbb,0xd3,0x53,0xf4,0x8c,0x8a,0x16,0xfb,0xbd,0x35,0xd9,0x70,0xb2,0x0a,0x06,0x05,0x14,0xd0,0x9e,0xf6,0x13,0x44,0xbb,0xb7,0x93,0x86,0x1b,0x3c,0xb0,0x54,0xa7,0x48,0xc2,0xa7,0x10,0xda,0x65,0xb2,0xdb,0x0f,0x85,0x23,0x57,0x77,0x44,0x23,0x20,0x6d,0x2e,0xde,0x20,0x01,0xed},{0x9c,0xb8,0x68,0xeb,0xbb,0x8b,0xaf,0x81,0x9c,0x2f,0x90,0x4c,0xc2,0x62,0x17,0xfc,0xf2,0xa5,0xab,0x4c,0x2e,0x69,0xcb,0x82,0x5f,0x4c,0x3c,0x82,0xcd,0x6a,0xcb,0x15,0xa2,0xfc,0x50,0x54,0x5e,0x2e,0x83,0x52,0x48,0x29,0x51,0xcc,0x50,0xaa,0x27,0xa3,0xf3,0x71,0xdb,0x2c,0x1c,0xa9,0x8a,0xa5,0x95,0xab,0x3e,0x6f,0xcd,0xba,0x22,0x7c},{0xf7,0x5d,0xb5,0x20,0x65,0xfe,0xa9,0xe7,0x1f,0x8e,0xd6,0xc0,0xf2,0x3f,0x1b,0x8c,0x7a,0x02,0x54,0xd8,0xa7,0x0e,0x6f,0x68,0x94,0x81,0xff,0x30,0x0e,0x6d,0x1a,0x96,0x1b,0x86,0x07,0xaa,0xbf,0x37,0xc5,0x5e,0x26,0xa2,0xdf,0x0b,0xd0,0x7f,0x94,0x35,0x30,0xa4,0x9e,0x47,0xaf,0xad,0x9c,0xc9,0x02,0x21,0x55,0x94,0x04,0x13,0xff,0x64},{0x9c,0x8d,0x18,0x63,0x83,0xad,0x01,0xcc,0xbb,0xe6,0x00,0xda,0x15,0xce,0xc6,0x6e,0x7a,0x37,0x6a,0x81,0x44,0xb3,0xfc,0xb7,0xcd,0x05,0xee,0x4a,0x6f,0x29,0xe4,0x79,0x63,0x52,0x7e,0x14,0xc9,0x14,0x77,0xa8,0x19,0x94,0x03,0xc6,0x51,0x57,0xf1,0xcc,0x11,0x29,0xde,0x86,0x08,0xfe,0x41,0x02,0x71,0xb7,0xbf,0xd7,0xe7,0x83,0x3e,0x0c,0x9a,0x59,0x7e,0xe8,0x61,0x36,0x56,0x9a,0xbf,0x64,0xfd,0xf3,0xb7,0xb9,0x2f,0x9e,0x56,0x1f,0x57,0x45,0x2e,0x19,0x0f,0x6f,0x70,0x01,0xc2,0x48,0x05,0x23,0x9b,0x2f},{0xb5,0x4e,0xe7,0xcc,0x7b,0x66,0x7a,0xf8,0xec,0xcd,0x1b,0x0c,0x0f,0xec,0x04,0x27,0xa0,0x61,0xfd,0x12,0x2d,0xab,0xc9,0xc5,0x8e,0xee,0x36,0xc2,0xef,0x67,0xd5,0x87,0x95,0x6c,0x12,0xb7,0x12,0x81,0x55,0xe0,0x7b,0xdb,0x8f,0x67,0xea,0x04,0x55,0x91,0x9b,0x50,0x65,0x05,0xc1,0xf1,0x0b,0x04,0x91,0x66,0x3c,0x32,0x53,0x72,0x01,0x04,0x9a,0x59,0x7e,0xe8,0x61,0x36,0x56,0x9a,0xbf,0x64,0xfd,0xf3,0xb7,0xb9,0x2f,0x9e,0x56,0x1f,0x57,0x45,0x2e,0x19,0x0f,0x6f,0x70,0x01,0xc2,0x48,0x05,0x23,0x9b,0x2f}}, - {{0xc8,0x37,0x10,0xdc,0xdb,0xfc,0x51,0x91,0xae,0x37,0xa4,0xe0,0xcf,0xbb,0xdd,0x92,0x93,0x5f,0x6b,0xd6,0x81,0xbf,0x9b,0x24,0x5e,0x0d,0xf1,0xe4,0x04,0x89,0xd1,0x1b,0xb2,0x68,0x56,0x3a,0xdc,0x59,0xd0,0x8a,0x93,0x37,0x5d,0xa5,0x40,0x5e,0xfe,0xc9,0x41,0x0b,0x8a,0x50,0xd2,0xa0,0x94,0x86,0xf7,0x46,0x3b,0x7e,0x1d,0xea,0x2b,0xa8},{0x1b,0xe2,0xe6,0x48,0x86,0xa8,0x65,0xfd,0x2b,0xae,0xc7,0x7d,0x41,0xee,0xb2,0x80,0x33,0x1c,0x0a,0xdc,0x42,0xea,0x99,0xd0,0x1f,0x6d,0xc8,0x80,0x51,0x70,0xd4,0x19,0xae,0xfc,0x66,0x16,0xa2,0x53,0x27,0x19,0x7a,0xf2,0x9a,0x25,0x0c,0x39,0x8c,0xbf,0xe7,0xa3,0x7a,0xd6,0xa3,0x43,0x62,0xd2,0x4a,0xc2,0xf1,0x96,0x7e,0xe3,0x83,0x13},{0xf5,0xb1,0x2a,0xc5,0x4d,0xcc,0xdf,0x56,0xde,0x92,0x96,0x46,0x03,0x11,0xfc,0xa0,0xbc,0xa2,0x22,0xf7,0x25,0x74,0x2a,0x1f,0x27,0x34,0x18,0xe8,0x06,0xa4,0x77,0x26,0x1a,0x51,0x5e,0xfb,0x77,0xbc,0x55,0xb1,0xf8,0xa5,0x19,0x23,0x00,0x97,0xf7,0xbb,0xe4,0xcd,0x41,0x9e,0xd9,0x5e,0x0c,0x6b,0x1b,0x8a,0xba,0x52,0x93,0xbe,0x2c,0xf3},{0xb3,0x02,0xeb,0x44,0x3c,0x05,0xae,0x9c,0x94,0xa9,0x1f,0x72,0x41,0xbc,0x81,0x66,0x5f,0x50,0xc0,0x57,0xb4,0x44,0xf0,0xe1,0x2a,0xa9,0x88,0x69,0xa6,0x1c,0x05,0x85,0xda,0xc7,0xb2,0xe1,0x8c,0x2f,0x7c,0x49,0x37,0xa2,0xf2,0x56,0xab,0x12,0x9f,0x12,0x4b,0x1b,0x73,0x75,0x3f,0x30,0x0f,0x40,0xf1,0xf9,0x1d,0xa7,0x2c,0x98,0x8c,0x91},{0xcb,0xd3,0x39,0x60,0x56,0xe3,0xbd,0x65,0x86,0x1a,0x58,0x40,0xc0,0xa4,0xc4,0x8b,0xe5,0xf7,0x49,0x0a,0xf2,0x09,0x51,0x32,0x6e,0x06,0x5a,0x27,0x19,0x78,0x2e,0x3a,0x04,0xf9,0x34,0x80,0x49,0x39,0x93,0xcd,0x89,0x67,0x7b,0xc0,0x8d,0x9d,0x8d,0x4c,0x83,0x20,0x80,0xfc,0x00,0xf2,0x8a,0x8f,0xa4,0x4d,0x8e,0x8f,0x58,0x51,0x5b,0x71},{0x71,0x3f,0x90,0x41,0xb8,0x74,0xbc,0x7a,0x85,0xf5,0xab,0xca,0x7e,0xf2,0x70,0x41,0xbc,0x36,0xb5,0xc3,0x4e,0xf1,0x2b,0x17,0x35,0x40,0xdb,0x3c,0xdb,0xd2,0xec,0x0b,0x99,0xc1,0x43,0x17,0xad,0x38,0x45,0x2d,0x07,0x31,0xd7,0xb6,0x95,0x1c,0x89,0x25,0xe4,0x89,0x97,0xd3,0xcf,0x11,0x2f,0x63,0x31,0x51,0xa2,0x18,0xfc,0x12,0x04,0x0a,0xb0,0x33,0xce,0x0b,0x57,0xc0,0x8c,0x58,0x25,0xf8,0x9b,0x50,0x22,0x1c,0x5c,0x7b,0x02,0xc7,0xed,0xfc,0x98,0x8b,0xbd,0xd2,0x4e,0xfc,0x78,0x91,0x7f,0x4c,0x99,0x24},{0xfc,0x46,0xe4,0x85,0x0c,0x52,0x14,0xf8,0x8a,0xa4,0x97,0x17,0x10,0xb2,0x93,0xef,0xa0,0x66,0x3c,0xfd,0x61,0x42,0x24,0x30,0x70,0x4b,0xfd,0x0b,0x86,0xc8,0x97,0xd7,0x04,0xc2,0xa6,0x61,0x41,0xaf,0xcc,0x1d,0x52,0xc9,0xf3,0xca,0xe1,0x90,0x7c,0xbd,0xce,0xaf,0x30,0xc4,0xb4,0x7d,0x81,0x7e,0xbd,0xe2,0x09,0x70,0x1e,0x6b,0xb9,0x03,0xb0,0x33,0xce,0x0b,0x57,0xc0,0x8c,0x58,0x25,0xf8,0x9b,0x50,0x22,0x1c,0x5c,0x7b,0x02,0xc7,0xed,0xfc,0x98,0x8b,0xbd,0xd2,0x4e,0xfc,0x78,0x91,0x7f,0x4c,0x99,0x24}}, - {{0x5f,0x01,0x6d,0xec,0x82,0x02,0x96,0x47,0x74,0xd9,0x73,0x2e,0x2e,0x17,0x00,0xb6,0xe0,0xa4,0x13,0x17,0xae,0x7f,0x85,0xcb,0xff,0xe7,0x96,0x99,0xdb,0x9f,0xad,0x21,0x60,0xd9,0x12,0xdc,0x41,0x01,0x33,0x66,0x4c,0x24,0x8b,0x25,0x17,0xd7,0x22,0x14,0x12,0x4d,0xad,0x82,0x9a,0x85,0x69,0x5e,0x35,0x10,0xe0,0xd7,0x1a,0x82,0x88,0x14},{0xab,0x5f,0x2c,0x7d,0xa2,0xe5,0x67,0x5f,0xe4,0x92,0x03,0x93,0xd7,0x13,0xa1,0xfa,0x4a,0xb7,0x18,0x4a,0x8e,0x8c,0x78,0x9a,0x0c,0x60,0x02,0xe8,0x2d,0x50,0x05,0x0f,0x92,0xee,0x9f,0x81,0xde,0x6b,0x20,0xe4,0x9b,0x17,0x2e,0x99,0x0f,0x01,0x31,0xa7,0xc5,0xc4,0x53,0x70,0xda,0x03,0xc6,0xf7,0x22,0x87,0x98,0x87,0x19,0x36,0xa6,0x49},{0x93,0xab,0x22,0xc4,0x39,0x6c,0x97,0x80,0xd2,0xe2,0x36,0xfa,0x31,0x74,0x67,0xcc,0x50,0x1b,0x95,0xbe,0x77,0xe0,0xd1,0x00,0x74,0x04,0xe1,0x4d,0xca,0x44,0x35,0x72,0x74,0x69,0x82,0x23,0x56,0x9b,0xcc,0x34,0x5a,0xcb,0xa2,0xa3,0x31,0x12,0x4a,0x84,0x4c,0xe9,0x37,0x3a,0x58,0xf8,0x79,0x65,0x4a,0x66,0x79,0x82,0xf4,0x5d,0x75,0xc3},{0x2d,0x5d,0xac,0x4f,0xb5,0x00,0x68,0x3b,0x5f,0x2e,0xdd,0xcb,0x14,0x4a,0x7f,0xad,0x12,0x45,0x91,0xd1,0x84,0xd8,0x14,0xff,0xcb,0x64,0x43,0x6d,0x65,0xe7,0x19,0x68,0x2b,0x5e,0x53,0x05,0x74,0x66,0xed,0xac,0x2f,0x5a,0x8f,0x70,0x96,0xab,0x29,0xf3,0x9a,0x59,0xa2,0xe2,0xef,0xd3,0xc9,0xd7,0x53,0xf8,0xf5,0xa3,0xd6,0xf4,0x34,0xf8},{0x1d,0x14,0xf3,0xfd,0xb0,0x66,0x20,0xff,0xfc,0x79,0x47,0xc7,0x4c,0xe9,0x45,0x67,0xf5,0x97,0x14,0xea,0x7c,0x63,0xc5,0x3f,0x0b,0x46,0xe0,0x88,0xd6,0x9b,0x67,0x71,0xba,0xa6,0x15,0x28,0x94,0x54,0x83,0x68,0x00,0x3a,0x33,0xa6,0x1a,0x05,0x6a,0x68,0x72,0x98,0x48,0x71,0xea,0x5b,0x47,0xf5,0x80,0x46,0xa9,0x57,0x84,0xec,0xad,0xfc},{0xa3,0x1d,0x87,0xd3,0x28,0x62,0xc6,0xf7,0xdb,0xfb,0xfa,0xfc,0xf3,0x27,0x5c,0x31,0xd3,0x32,0x26,0x0e,0x0f,0x41,0x49,0xec,0x05,0x16,0xf7,0xa5,0x63,0xb3,0xbc,0xe5,0x0d,0x1e,0x6f,0x97,0x4f,0x68,0x40,0xc0,0xd4,0x6c,0x4f,0x9e,0x25,0xd0,0xab,0x8d,0x2a,0xb9,0x3e,0x06,0x4d,0x9d,0x3d,0x2d,0x79,0x8d,0x93,0xdc,0xfc,0x6f,0x0b,0x04,0x48,0x7c,0x19,0x5c,0xa9,0xc8,0x44,0xe5,0xf6,0x4f,0x51,0xd8,0x72,0x63,0x41,0xda,0x62,0xac,0x78,0x73,0xb3,0x3e,0xc8,0xb2,0xf1,0x3f,0x89,0xf2,0x0e,0x95,0xdf,0xed},{0xfd,0x69,0xb1,0x9a,0xdb,0xae,0x95,0x87,0xe2,0xc6,0x8a,0x97,0x0c,0xee,0xc4,0x22,0x60,0x4e,0x96,0xa9,0x72,0xb9,0x6f,0x86,0x97,0xa8,0xdf,0x83,0xc5,0x18,0x18,0x6e,0xc9,0x43,0x30,0x7e,0x5b,0xcf,0x37,0x0f,0xc1,0xd7,0xe5,0xab,0xb1,0x31,0xe0,0x97,0xc7,0x53,0xb7,0xfd,0xd7,0xdf,0x00,0x43,0x0e,0x41,0x62,0x80,0x0b,0xe3,0xe0,0x06,0x48,0x7c,0x19,0x5c,0xa9,0xc8,0x44,0xe5,0xf6,0x4f,0x51,0xd8,0x72,0x63,0x41,0xda,0x62,0xac,0x78,0x73,0xb3,0x3e,0xc8,0xb2,0xf1,0x3f,0x89,0xf2,0x0e,0x95,0xdf,0xed}}, - {{0x98,0x29,0xf7,0x57,0xfd,0xbd,0x44,0x3f,0xd9,0x90,0x98,0x19,0x97,0xf2,0x60,0x27,0xfd,0x08,0xfc,0x8a,0xc6,0xaf,0x87,0x22,0x7f,0x74,0x4a,0x80,0xaf,0x72,0x00,0x01,0x70,0x9b,0x47,0x2a,0xd2,0x8e,0x41,0x0a,0xea,0x6a,0xdf,0xb7,0x61,0x54,0x89,0x5e,0x01,0x9f,0x76,0x64,0x29,0xee,0x8d,0x85,0x20,0xff,0x30,0x58,0xc2,0xa3,0x2a,0x56},{0xea,0x69,0x8e,0x6b,0x8e,0xdd,0x55,0x22,0x45,0x61,0xd4,0x92,0x66,0x8e,0x96,0xaf,0x7e,0x40,0x28,0x72,0xc4,0x46,0xe7,0x88,0xd4,0x6c,0x74,0xb7,0x48,0x7f,0xe8,0xe1,0x5e,0xa5,0x85,0x62,0x8f,0xd6,0xfc,0x27,0x0a,0xb2,0x4b,0x38,0x94,0x59,0x52,0x0d,0x6a,0x4d,0xe5,0x61,0xce,0x0d,0x44,0x03,0xa6,0x2a,0xc2,0xd4,0xd4,0xe2,0x71,0xe3},{0x40,0xf0,0x82,0xf0,0x8d,0xaa,0xad,0xa9,0x9f,0x9b,0x85,0x02,0xcf,0x57,0x15,0x41,0x13,0x59,0xf2,0xba,0xdd,0xbf,0x93,0xe5,0x40,0x2e,0xaf,0xdd,0x43,0x52,0xc8,0x7f,0x40,0xad,0x91,0x5b,0x58,0xd1,0xa1,0xe8,0x6f,0x77,0xc3,0x41,0x35,0x5e,0xf7,0x03,0xba,0xe4,0xed,0x2c,0x28,0x59,0xd6,0x48,0xfe,0x50,0xcc,0xf9,0x80,0xd1,0x49,0xd1},{0xd7,0xa5,0xd9,0x13,0xdf,0x7d,0xf6,0xc6,0x25,0x0f,0x52,0xc2,0x57,0x61,0x20,0xf2,0xf0,0xdb,0x47,0x49,0x56,0xaf,0x89,0x11,0xa7,0x8d,0x09,0x3a,0xfe,0x45,0x43,0xef,0x9f,0x0c,0x42,0xaf,0xa8,0xcc,0x60,0x48,0xc0,0x1c,0x7c,0xbe,0x01,0xe2,0x88,0xcc,0x6c,0x3e,0x97,0x91,0xf3,0xd9,0xb2,0xb2,0x09,0x7e,0x35,0xb1,0x78,0xb4,0x03,0xf6},{0x08,0xc4,0x1a,0x3a,0xc3,0xe3,0x26,0xbd,0x8d,0xee,0x5d,0xf0,0xba,0xb6,0x65,0xff,0x77,0xc0,0x99,0xd1,0xca,0xdc,0xf5,0x4b,0x50,0x50,0x0a,0x9e,0x13,0x33,0x76,0x86,0x9b,0x39,0x79,0x78,0x73,0x5c,0x2f,0x69,0xa9,0x9e,0x0b,0xeb,0x11,0x1e,0x12,0xaa,0xc1,0x09,0x83,0x0f,0xca,0xcb,0x95,0x10,0xde,0x85,0xe3,0x75,0x62,0x4a,0xc2,0x4c},{0x68,0x78,0x6c,0xce,0x2f,0x72,0x80,0xfe,0x83,0x88,0x63,0x37,0xa7,0xa1,0x5a,0x0b,0x84,0x8a,0xda,0x28,0x84,0xf1,0x6a,0x63,0x24,0x1c,0x72,0xda,0x84,0xee,0x1d,0xe0,0x77,0xf0,0xf6,0xce,0x7e,0x79,0x0a,0x55,0x03,0x01,0x13,0x0f,0xf7,0x6b,0x45,0xe7,0xcb,0xfd,0xb0,0x37,0x93,0x4b,0x40,0x69,0xe0,0x77,0x67,0x72,0x65,0xee,0x35,0x08,0x00,0xc0,0x07,0x10,0xd8,0x6e,0x55,0x83,0x5a,0xbc,0xfa,0x67,0x80,0x8f,0xfa,0x21,0x3e,0x56,0x53,0x5b,0xbc,0x9d,0xff,0x16,0xd9,0x57,0xcf,0x2b,0x78,0x06,0x5a,0x89},{0xdf,0x32,0x1a,0x01,0x84,0xe5,0xb8,0x2c,0x70,0x6c,0xeb,0xd1,0xf0,0xb4,0x9b,0x32,0xc8,0xd0,0x81,0xc4,0xea,0xb2,0x7c,0x32,0x1a,0x02,0x61,0xf2,0xd9,0x4d,0xe5,0x85,0xad,0xfc,0xc6,0x70,0xee,0x85,0x77,0x07,0x9b,0x5d,0x5f,0x88,0xef,0xb6,0xd8,0xdf,0x2b,0xa2,0x4d,0x90,0x11,0x2d,0x38,0x3f,0xa8,0x84,0xf0,0x76,0xdd,0x31,0xd0,0x09,0x00,0xc0,0x07,0x10,0xd8,0x6e,0x55,0x83,0x5a,0xbc,0xfa,0x67,0x80,0x8f,0xfa,0x21,0x3e,0x56,0x53,0x5b,0xbc,0x9d,0xff,0x16,0xd9,0x57,0xcf,0x2b,0x78,0x06,0x5a,0x89}}, - {{0x25,0x87,0x1e,0x6f,0xe8,0xd0,0xde,0x1d,0xd5,0xf2,0xd3,0x5b,0xff,0x9e,0x67,0x99,0x60,0xb4,0x0e,0xb7,0x98,0x1b,0x2a,0x3a,0x9c,0xec,0xc1,0xe1,0x2e,0x2b,0xc0,0x3e,0x3c,0xfb,0x64,0x91,0x72,0xc6,0x7e,0x57,0x47,0x00,0x97,0xbf,0x8e,0x0e,0xbf,0xad,0xd9,0x28,0x86,0x7c,0xfd,0x41,0x91,0xae,0x2d,0xee,0xc0,0xb2,0x32,0x7d,0x99,0x7d},{0x63,0xc1,0xf9,0x61,0x9c,0x9e,0x1a,0xd7,0xca,0xa3,0x71,0xd6,0x34,0x3d,0xa7,0x08,0x36,0x0c,0xec,0x37,0x35,0x94,0x1a,0x45,0xa9,0xfa,0xf2,0xb5,0x25,0x92,0xbf,0xd1,0x1e,0xca,0xdd,0x5a,0x23,0xad,0x9e,0x45,0xc3,0x66,0xcb,0x8f,0xda,0xa3,0xd1,0xe6,0x27,0x38,0x11,0x54,0x67,0x31,0x03,0x64,0x35,0xe0,0x68,0x0b,0x93,0xee,0x81,0x17},{0x8b,0x01,0xe9,0x99,0x54,0x54,0x73,0x15,0x0b,0xac,0x38,0x7b,0xe9,0xe3,0x17,0x4f,0x02,0x3e,0xe3,0x8e,0xda,0x41,0xa0,0x9d,0x10,0xe0,0xda,0x11,0xfe,0xec,0x2f,0x42,0xe7,0xc8,0xb3,0xde,0x2f,0x7b,0xfd,0xdf,0x7c,0x34,0x3b,0x5e,0xac,0x22,0x8c,0x99,0x3d,0xa1,0xa9,0xd9,0x81,0xb6,0x51,0xc8,0xaf,0x3e,0x75,0xed,0x45,0xcf,0xf7,0xb9},{0xaf,0xe9,0x9c,0x16,0x4a,0x8f,0x3b,0x0f,0xef,0x71,0x2f,0xaa,0x8d,0x7d,0xce,0xed,0xea,0x31,0x93,0xaf,0x2c,0x75,0xc6,0xfa,0xda,0x3e,0xa6,0xea,0x2a,0x3e,0x7b,0x72,0xb6,0xf8,0xd7,0x9a,0x88,0xcb,0x0b,0x81,0x97,0x24,0x29,0x3b,0x11,0x23,0x69,0xc2,0xff,0x98,0x39,0x25,0x99,0xae,0xe1,0x07,0x3e,0x97,0xde,0x10,0x21,0x23,0x7a,0x2d},{0xbe,0x2f,0xb9,0x4c,0x41,0x5a,0x9a,0xf6,0xfb,0xf8,0x26,0x9d,0x81,0x7f,0x39,0x91,0xaf,0x5b,0xf1,0xd7,0x93,0x0a,0xdf,0x18,0x19,0x4a,0x80,0x74,0x14,0x98,0x2b,0xf2,0x3b,0x25,0xc5,0xe8,0xfc,0x07,0x3f,0x5d,0xa1,0x39,0x27,0x4e,0x1c,0xd2,0x7a,0xfe,0x3e,0x7b,0x03,0x35,0x15,0x9e,0x35,0x2b,0xd0,0xbe,0x67,0x48,0x42,0xdd,0xa4,0xdd},{0xbd,0xcd,0xd7,0xbf,0xb1,0x0a,0xdb,0x9f,0x85,0x42,0xba,0xf4,0xc8,0xff,0xb0,0xe1,0x9a,0x18,0x6d,0x1a,0xe0,0x37,0xc1,0xa2,0xe1,0x1c,0x38,0x55,0x14,0xbf,0x64,0x67,0x84,0x47,0xb6,0x0a,0xf6,0x93,0xf1,0x10,0xab,0x09,0xf0,0x60,0x84,0xe2,0x4e,0x4b,0x5e,0xa2,0xd2,0xd1,0x19,0x22,0xd7,0xc4,0x85,0x13,0x23,0xa3,0x6a,0xb6,0x75,0x0f,0x43,0xe6,0xde,0x7b,0x67,0x2a,0x73,0x77,0x9e,0xb4,0x94,0x6c,0xc3,0x9a,0x67,0x51,0xcf,0xe9,0x47,0x46,0x0e,0x3a,0x12,0x7d,0x7c,0x66,0x73,0x6c,0xd5,0x4a,0x21,0x4d},{0x89,0x7e,0xd0,0xbf,0x2e,0x9f,0x0c,0xff,0x6e,0x56,0x25,0x9b,0x79,0x99,0x52,0x27,0xc2,0x3a,0xaa,0xf0,0x47,0x6d,0xed,0x05,0xa1,0xeb,0x9c,0x92,0x28,0x7f,0x1b,0xc8,0x1c,0x57,0x76,0xab,0x05,0xe3,0xd3,0xb7,0xa3,0xf5,0xac,0xa8,0x21,0x33,0x7c,0xb7,0xe7,0xc2,0xd0,0x25,0x6f,0xdf,0x34,0xd1,0xb0,0x34,0x41,0x46,0x30,0x9c,0x76,0x07,0x43,0xe6,0xde,0x7b,0x67,0x2a,0x73,0x77,0x9e,0xb4,0x94,0x6c,0xc3,0x9a,0x67,0x51,0xcf,0xe9,0x47,0x46,0x0e,0x3a,0x12,0x7d,0x7c,0x66,0x73,0x6c,0xd5,0x4a,0x21,0x4d}} -}; - -////////////////////////////////////////////////////////////////////////////// - -static unsigned char fuzzbuf[1048576]; - -static int testCrypto() -{ - unsigned char buf1[16384]; - unsigned char buf2[sizeof(buf1)],buf3[sizeof(buf1)]; - - for(int i=0;i<3;++i) { - Utils::getSecureRandom(buf1,64); - std::cout << "[crypto] getSecureRandom: " << Utils::hex(buf1,64) << std::endl; - } - - std::cout << "[crypto] Testing Salsa20... "; std::cout.flush(); - for(unsigned int i=0;i<4;++i) { - for(unsigned int k=0;kp2 should equal p1<>p2 - if (memcmp(buf1,buf2,64)) { - std::cout << "FAIL (1)" << std::endl; - return -1; - } - // p2<>p1 should not equal p3<>p1 - if (!memcmp(buf2,buf3,64)) { - std::cout << "FAIL (2)" << std::endl; - return -1; - } - } - std::cout << "PASS" << std::endl; - - std::cout << "[crypto] Benchmarking C25519 ECC key agreement... "; std::cout.flush(); - C25519::Pair bp[8]; - for(int k=0;k<8;++k) - bp[k] = C25519::generate(); - const uint64_t st = OSUtils::now(); - for(unsigned int k=0;k<50;++k) { - C25519::agree(bp[~k & 7],bp[k & 7].pub,buf1,64); - } - const uint64_t et = OSUtils::now(); - std::cout << ((double)(et - st) / 50.0) << "ms per agreement." << std::endl; - - std::cout << "[crypto] Testing Ed25519 ECC signatures... "; std::cout.flush(); - C25519::Pair didntSign = C25519::generate(); - for(unsigned int i=0;i<10;++i) { - C25519::Pair p1 = C25519::generate(); - for(unsigned int k=0;k buf; - - std::cout << "[identity] Validate known-good identity... "; std::cout.flush(); - if (!id.fromString(KNOWN_GOOD_IDENTITY)) { - std::cout << "FAIL (1)" << std::endl; - return -1; - } - const uint64_t vst = OSUtils::now(); - for(int k=0;k<10;++k) { - if (!id.locallyValidate()) { - std::cout << "FAIL (2)" << std::endl; - return -1; - } - } - const uint64_t vet = OSUtils::now(); - std::cout << "PASS (" << ((double)(vet - vst) / 10.0) << "ms per validation)" << std::endl; - - std::cout << "[identity] Validate known-bad identity... "; std::cout.flush(); - if (!id.fromString(KNOWN_BAD_IDENTITY)) { - std::cout << "FAIL (1)" << std::endl; - return -1; - } - if (id.locallyValidate()) { - std::cout << "FAIL (2)" << std::endl; - return -1; - } - std::cout << "PASS (i.e. it failed)" << std::endl; - - for(unsigned int k=0;k<4;++k) { - std::cout << "[identity] Generate identity... "; std::cout.flush(); - uint64_t genstart = OSUtils::now(); - id.generate(); - uint64_t genend = OSUtils::now(); - std::cout << "(took " << (genend - genstart) << "ms): " << id.toString(true) << std::endl; - std::cout << "[identity] Locally validate identity: "; - if (id.locallyValidate()) { - std::cout << "PASS" << std::endl; - } else { - std::cout << "FAIL" << std::endl; - return -1; - } - } - - { - Identity id2; - buf.clear(); - id.serialize(buf,true); - id2.deserialize(buf); - std::cout << "[identity] Serialize and deserialize (w/private): "; - if ((id == id2)&&(id2.locallyValidate())) { - std::cout << "PASS" << std::endl; - } else { - std::cout << "FAIL" << std::endl; - return -1; - } - } - - { - Identity id2; - buf.clear(); - id.serialize(buf,false); - id2.deserialize(buf); - std::cout << "[identity] Serialize and deserialize (no private): "; - if ((id == id2)&&(id2.locallyValidate())) { - std::cout << "PASS" << std::endl; - } else { - std::cout << "FAIL" << std::endl; - return -1; - } - } - - { - Identity id2; - id2.fromString(id.toString(true).c_str()); - std::cout << "[identity] Serialize and deserialize (ASCII w/private): "; - if ((id == id2)&&(id2.locallyValidate())) { - std::cout << "PASS" << std::endl; - } else { - std::cout << "FAIL" << std::endl; - return -1; - } - } - - { - Identity id2; - id2.fromString(id.toString(false).c_str()); - std::cout << "[identity] Serialize and deserialize (ASCII no private): "; - if ((id == id2)&&(id2.locallyValidate())) { - std::cout << "PASS" << std::endl; - } else { - std::cout << "FAIL" << std::endl; - return -1; - } - } - - return 0; -} - -static int testCertificate() -{ - Identity authority; - std::cout << "[certificate] Generating identity to act as authority... "; std::cout.flush(); - authority.generate(); - std::cout << authority.address().toString() << std::endl; - - Identity idA,idB; - std::cout << "[certificate] Generating identities A and B... "; std::cout.flush(); - idA.generate(); - idB.generate(); - std::cout << idA.address().toString() << ", " << idB.address().toString() << std::endl; - - std::cout << "[certificate] Generating certificates A and B..."; - CertificateOfMembership cA(10000,100,1,idA.address()); - CertificateOfMembership cB(10099,100,1,idB.address()); - std::cout << std::endl; - - std::cout << "[certificate] Signing certificates A and B with authority..."; - cA.sign(authority); - cB.sign(authority); - std::cout << std::endl; - - //std::cout << "[certificate] A: " << cA.toString() << std::endl; - //std::cout << "[certificate] B: " << cB.toString() << std::endl; - - std::cout << "[certificate] A agrees with B and B with A... "; - if (cA.agreesWith(cB)) - std::cout << "yes, "; - else { - std::cout << "FAIL" << std::endl; - return -1; - } - if (cB.agreesWith(cA)) - std::cout << "yes." << std::endl; - else { - std::cout << "FAIL" << std::endl; - return -1; - } - - std::cout << "[certificate] Generating two certificates that should not agree..."; - cA = CertificateOfMembership(10000,100,1,idA.address()); - cB = CertificateOfMembership(10101,100,1,idB.address()); - std::cout << std::endl; - - std::cout << "[certificate] A agrees with B and B with A... "; - if (!cA.agreesWith(cB)) - std::cout << "no, "; - else { - std::cout << "FAIL" << std::endl; - return -1; - } - if (!cB.agreesWith(cA)) - std::cout << "no." << std::endl; - else { - std::cout << "FAIL" << std::endl; - return -1; - } - - return 0; -} - -static int testPacket() -{ - unsigned char salsaKey[32]; - Packet a,b; - - a.burn(); - b.burn(); - - for(unsigned int i=0;i<32;++i) - salsaKey[i] = (unsigned char)rand(); - - std::cout << "[packet] Testing Packet encoder/decoder... "; - - a.reset(Address(),Address(),Packet::VERB_HELLO); - for(int i=0;i<32;++i) - a.append("supercalifragilisticexpealidocious",(unsigned int)strlen("supercalifragilisticexpealidocious")); - - b = a; - if (a != b) { - std::cout << "FAIL (assign)" << std::endl; - return -1; - } - - a.compress(); - unsigned int complen = a.size(); - a.uncompress(); - - std::cout << "(compressed: " << complen << ", decompressed: " << a.size() << ") "; - if (a != b) { - std::cout << "FAIL (compresssion)" << std::endl; - return -1; - } - - a.armor(salsaKey,true,0); - if (!a.dearmor(salsaKey)) { - std::cout << "FAIL (encrypt-decrypt/verify)" << std::endl; - return -1; - } - - std::cout << "PASS" << std::endl; - return 0; -} - -static void _testExcept(int &depth) -{ - if (depth >= 16) { - throw std::runtime_error("LOL!"); - } else { - ++depth; - _testExcept(depth); - } -} - -static int testOther() -{ - std::cout << "[other] Testing C++ exceptions... "; std::cout.flush(); - int depth = 0; - try { - _testExcept(depth); - } catch (std::runtime_error &e) { - if (depth == 16) { - std::cout << "OK" << std::endl; - } else { - std::cout << "ERROR (depth not 16)" << std::endl; - return -1; - } - } catch ( ... ) { - std::cout << "ERROR (exception not std::runtime_error)" << std::endl; - return -1; - } - - std::cout << "[other] Testing Hashtable... "; std::cout.flush(); - { - Hashtable ht; - std::map ref; // assume std::map works correctly :) - for(int x=0;x<2;++x) { - for(int i=0;i<77777;++i) { - uint64_t k = rand(); - while ((k == 0)||(ref.count(k) > 0)) - ++k; - std::string v("!"); - for(int j=0;j<(int)(k % 64);++j) - v.push_back("0123456789"[rand() % 10]); - ref[k] = v; - ht.set(0xffffffffffffffffULL,v); - std::string &vref = ht[k]; - vref = v; - ht.erase(0xffffffffffffffffULL); - } - if (ht.size() != ref.size()) { - std::cout << "FAILED! (size mismatch, original)" << std::endl; - return -1; - } - { - Hashtable::Iterator i(ht); - uint64_t *k = (uint64_t *)0; - std::string *v = (std::string *)0; - while(i.next(k,v)) { - if (ref.find(*k)->second != *v) { - std::cout << "FAILED! (data mismatch!)" << std::endl; - return -1; - } - } - } - for(std::map::const_iterator i(ref.begin());i!=ref.end();++i) { - if (ht[i->first] != i->second) { - std::cout << "FAILED! (data mismatch!)" << std::endl; - return -1; - } - } - - Hashtable ht2; - ht2 = ht; - Hashtable ht3(ht2); - if (ht2.size() != ref.size()) { - std::cout << "FAILED! (size mismatch, assigned)" << std::endl; - return -1; - } - if (ht3.size() != ref.size()) { - std::cout << "FAILED! (size mismatch, copied)" << std::endl; - return -1; - } - - for(std::map::iterator i(ref.begin());i!=ref.end();++i) { - std::string *v = ht.get(i->first); - if (!v) { - std::cout << "FAILED! (key " << i->first << " not found, original)" << std::endl; - return -1; - } - if (*v != i->second) { - std::cout << "FAILED! (key " << i->first << " not equal, original)" << std::endl; - return -1; - } - v = ht2.get(i->first); - if (!v) { - std::cout << "FAILED! (key " << i->first << " not found, assigned)" << std::endl; - return -1; - } - if (*v != i->second) { - std::cout << "FAILED! (key " << i->first << " not equal, assigned)" << std::endl; - return -1; - } - v = ht3.get(i->first); - if (!v) { - std::cout << "FAILED! (key " << i->first << " not found, copied)" << std::endl; - return -1; - } - if (*v != i->second) { - std::cout << "FAILED! (key " << i->first << " not equal, copied)" << std::endl; - return -1; - } - } - { - uint64_t *k; - std::string *v; - Hashtable::Iterator i(ht); - unsigned long ic = 0; - while (i.next(k,v)) { - if (ref[*k] != *v) { - std::cout << "FAILED! (iterate)" << std::endl; - return -1; - } - ++ic; - } - if (ic != ht.size()) { - std::cout << "FAILED! (iterate coverage)" << std::endl; - return -1; - } - } - for(std::map::iterator i(ref.begin());i!=ref.end();) { - if (!ht.get(i->first)) { - std::cout << "FAILED! (erase, check if exists)" << std::endl; - return -1; - } - ht.erase(i->first); - if (ht.get(i->first)) { - std::cout << "FAILED! (erase, check if erased)" << std::endl; - return -1; - } - ref.erase(i++); - if (ht.size() != ref.size()) { - std::cout << "FAILED! (erase, size)" << std::endl; - return -1; - } - } - if (!ht.empty()) { - std::cout << "FAILED! (erase, empty)" << std::endl; - return -1; - } - for(int i=0;i<10000;++i) { - uint64_t k = rand(); - while ((k == 0)||(ref.count(k) > 0)) - ++k; - std::string v; - for(int j=0;j<(int)(k % 64);++j) - v.push_back("0123456789"[rand() % 10]); - ht.set(k,v); - ref[k] = v; - } - if (ht.size() != ref.size()) { - std::cout << "FAILED! (second populate)" << std::endl; - return -1; - } - ht.clear(); - ref.clear(); - if (ht.size() != ref.size()) { - std::cout << "FAILED! (clear)" << std::endl; - return -1; - } - for(int i=0;i<10000;++i) { - uint64_t k = rand(); - while ((k == 0)||(ref.count(k) > 0)) - ++k; - std::string v; - for(int j=0;j<(int)(k % 64);++j) - v.push_back("0123456789"[rand() % 10]); - ht.set(k,v); - ref[k] = v; - } - { - Hashtable::Iterator i(ht); - uint64_t *k; - std::string *v; - while (i.next(k,v)) - ht.erase(*k); - } - ref.clear(); - if (ht.size() != ref.size()) { - std::cout << "FAILED! (clear by iterate, " << ht.size() << ")" << std::endl; - return -1; - } - } - } - std::cout << "PASS" << std::endl; - - std::cout << "[other] Testing hex encode/decode... "; std::cout.flush(); - for(unsigned int k=0;k<1000;++k) { - unsigned int flen = (rand() % 8194) + 1; - for(unsigned int i=0;i test; - char key[32][16]; - char value[32][128]; - for(unsigned int q=0;q<32;++q) { - Utils::snprintf(key[q],16,"%.8lx",(unsigned long)rand()); - int r = rand() % 128; - for(int x=0;x= 0) { - if (strcmp(value[r],tmp)) { - std::cout << "FAILED (invalid value)!" << std::endl; - return -1; - } - } else { - std::cout << "FAILED (can't find key '" << key[r] << "')!" << std::endl; - return -1; - } - } - for(unsigned int q=0;q<31;++q) { - char tmp[128]; - test.erase(key[q]); - if (test.get(key[q],tmp,sizeof(tmp)) >= 0) { - std::cout << "FAILED (key should have been erased)!" << std::endl; - return -1; - } - if (test.get(key[q+1],tmp,sizeof(tmp)) < 0) { - std::cout << "FAILED (key should NOT have been erased)!" << std::endl; - return -1; - } - } - } - int foo = 0; - volatile int *volatile bar = &foo; // force compiler not to optimize out test.get() below - for(int k=0;k<200;++k) { - int r = rand() % 8194; - unsigned char tmp[8194]; - for(int q=0;q test((const char *)tmp); - for(unsigned int q=0;q<100;++q) { - char tmp[128]; - for(unsigned int x=0;x<128;++x) - tmp[x] = (char)(rand() & 0xff); - tmp[127] = (char)0; - char value[8194]; - *bar += test.get(tmp,value,sizeof(value)); - } - } - std::cout << "PASS (junk value to prevent optimization-out of test: " << foo << ")" << std::endl; - - /* - std::cout << "[other] Testing controller/JSONDB..."; std::cout.flush(); - { - std::map db1data; - JSONDB db1("jsondb-test"); - for(unsigned int i=0;i<256;++i) { - std::string n; - for(unsigned int j=0,k=rand() % 4;j<=k;++j) { - if (j > 0) n.push_back('/'); - char foo[24]; - Utils::snprintf(foo,sizeof(foo),"%lx",rand()); - n.append(foo); - } - db1data[n] = {{"i",i}}; - db1.put(n,db1data[n]); - } - for(std::map::iterator i(db1data.begin());i!=db1data.end();++i) { - i->second["foo"] = "bar"; - db1.put(i->first,i->second); - } - JSONDB db2("jsondb-test"); - if (db1 != db2) { - std::cout << " FAILED (db1!=db2 #1)" << std::endl; - return -1; - } - for(std::map::iterator i(db1data.begin());i!=db1data.end();++i) { - db1.erase(i->first); - } - db2.reload(); - if (db1 != db2) { - std::cout << " FAILED (db1!=db2 #2)" << std::endl; - return -1; - } - } - std::cout << " PASS" << std::endl; - */ - - return 0; -} - -#define ZT_TEST_PHY_NUM_UDP_PACKETS 10000 -#define ZT_TEST_PHY_UDP_PACKET_SIZE 1000 -#define ZT_TEST_PHY_NUM_VALID_TCP_CONNECTS 10 -#define ZT_TEST_PHY_NUM_INVALID_TCP_CONNECTS 2 -#define ZT_TEST_PHY_TCP_MESSAGE_SIZE 1000000 -#define ZT_TEST_PHY_TIMEOUT_MS 20000 -static unsigned long phyTestUdpPacketCount = 0; -static unsigned long phyTestTcpByteCount = 0; -static unsigned long phyTestTcpConnectSuccessCount = 0; -static unsigned long phyTestTcpConnectFailCount = 0; -static unsigned long phyTestTcpAcceptCount = 0; -struct TestPhyHandlers; -static Phy *testPhyInstance = (Phy *)0; -struct TestPhyHandlers -{ - inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) - { - ++phyTestUdpPacketCount; - } - - inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) - { - if (success) { - ++phyTestTcpConnectSuccessCount; - } else { - ++phyTestTcpConnectFailCount; - } - } - - inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) - { - ++phyTestTcpAcceptCount; - *uptrN = new std::string(ZT_TEST_PHY_TCP_MESSAGE_SIZE,(char)0xff); - testPhyInstance->setNotifyWritable(sockN,true); - } - - inline void phyOnTcpClose(PhySocket *sock,void **uptr) - { - delete (std::string *)*uptr; // delete testMessage if any - } - - inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) - { - phyTestTcpByteCount += len; - } - - inline void phyOnTcpWritable(PhySocket *sock,void **uptr) - { - std::string *testMessage = (std::string *)*uptr; - if ((testMessage)&&(testMessage->length() > 0)) { - long sent = testPhyInstance->streamSend(sock,(const void *)testMessage->data(),(unsigned long)testMessage->length(),true); - if (sent > 0) - testMessage->erase(0,sent); - } - if ((!testMessage)||(!testMessage->length())) { - testPhyInstance->close(sock,true); - } - } - -#ifdef __UNIX_LIKE__ - inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {} - inline void phyOnUnixClose(PhySocket *sock,void **uptr) {} - inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} - inline void phyOnUnixWritable(PhySocket *sock,void **uptr,bool b) {} -#endif // __UNIX_LIKE__ - - inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} -}; -static int testPhy() -{ - char udpTestPayload[ZT_TEST_PHY_UDP_PACKET_SIZE]; - memset(udpTestPayload,0xff,sizeof(udpTestPayload)); - - struct sockaddr_in bindaddr; - memset(&bindaddr,0,sizeof(bindaddr)); - bindaddr.sin_family = AF_INET; - bindaddr.sin_port = Utils::hton((uint16_t)60002); - bindaddr.sin_addr.s_addr = Utils::hton((uint32_t)0x7f000001); - struct sockaddr_in invalidAddr; - memset(&bindaddr,0,sizeof(bindaddr)); - bindaddr.sin_family = AF_INET; - bindaddr.sin_port = Utils::hton((uint16_t)60004); - bindaddr.sin_addr.s_addr = Utils::hton((uint32_t)0x7f000001); - - std::cout << "[phy] Creating phy endpoint..." << std::endl; - TestPhyHandlers testPhyHandlers; - testPhyInstance = new Phy(&testPhyHandlers,false,true); - - std::cout << "[phy] Binding UDP listen socket to 127.0.0.1/60002... "; - PhySocket *udpListenSock = testPhyInstance->udpBind((const struct sockaddr *)&bindaddr); - if (!udpListenSock) { - std::cout << "FAILED." << std::endl; - return -1; - } - std::cout << "OK" << std::endl; - - std::cout << "[phy] Binding TCP listen socket to 127.0.0.1/60002... "; - PhySocket *tcpListenSock = testPhyInstance->tcpListen((const struct sockaddr *)&bindaddr); - if (!tcpListenSock) { - std::cout << "FAILED." << std::endl; - return -1; - } - std::cout << "OK" << std::endl; - - unsigned long phyTestUdpPacketsSent = 0; - unsigned long phyTestTcpValidConnectionsAttempted = 0; - unsigned long phyTestTcpInvalidConnectionsAttempted = 0; - - std::cout << "[phy] Testing UDP send/receive... "; std::cout.flush(); - uint64_t timeoutAt = OSUtils::now() + ZT_TEST_PHY_TIMEOUT_MS; - while ((OSUtils::now() < timeoutAt)&&(phyTestUdpPacketCount < ZT_TEST_PHY_NUM_UDP_PACKETS)) { - if (phyTestUdpPacketsSent < ZT_TEST_PHY_NUM_UDP_PACKETS) { - if (!testPhyInstance->udpSend(udpListenSock,(const struct sockaddr *)&bindaddr,udpTestPayload,sizeof(udpTestPayload))) { - std::cout << "FAILED." << std::endl; - return -1; - } else ++phyTestUdpPacketsSent; - } - testPhyInstance->poll(100); - } - std::cout << "got " << phyTestUdpPacketCount << " packets, OK" << std::endl; - - std::cout << "[phy] Testing TCP... "; std::cout.flush(); - timeoutAt = OSUtils::now() + ZT_TEST_PHY_TIMEOUT_MS; - while ((OSUtils::now() < timeoutAt)&&(phyTestTcpByteCount < (ZT_TEST_PHY_NUM_VALID_TCP_CONNECTS * ZT_TEST_PHY_TCP_MESSAGE_SIZE))) { - if (phyTestTcpValidConnectionsAttempted < ZT_TEST_PHY_NUM_VALID_TCP_CONNECTS) { - ++phyTestTcpValidConnectionsAttempted; - bool connected = false; - if (!testPhyInstance->tcpConnect((const struct sockaddr *)&bindaddr,connected,(void *)0,true)) - ++phyTestTcpConnectFailCount; - } - if (phyTestTcpInvalidConnectionsAttempted < ZT_TEST_PHY_NUM_INVALID_TCP_CONNECTS) { - ++phyTestTcpInvalidConnectionsAttempted; - bool connected = false; - if (!testPhyInstance->tcpConnect((const struct sockaddr *)&invalidAddr,connected,(void *)0,true)) - ++phyTestTcpConnectFailCount; - } - testPhyInstance->poll(100); - } - if (phyTestTcpByteCount < (ZT_TEST_PHY_NUM_VALID_TCP_CONNECTS * ZT_TEST_PHY_TCP_MESSAGE_SIZE)) { - std::cout << "got " << phyTestTcpConnectSuccessCount << " connect successes, " << phyTestTcpConnectFailCount << " failures, and " << phyTestTcpByteCount << " bytes, FAILED." << std::endl; - return -1; - } else { - std::cout << "got " << phyTestTcpConnectSuccessCount << " connect successes, " << phyTestTcpConnectFailCount << " failures, and " << phyTestTcpByteCount << " bytes, OK" << std::endl; - } - - return 0; -} - -/* -static int testHttp() -{ - std::map requestHeaders,responseHeaders; - std::string responseBody; - - InetAddress downloadZerotierDotCom; - std::vector rr(OSUtils::resolve("download.zerotier.com")); - if (rr.empty()) { - std::cout << "[http] Resolve of download.zerotier.com failed, skipping." << std::endl; - return 0; - } else { - for(std::vector::iterator r(rr.begin());r!=rr.end();++r) { - std::cout << "[http] download.zerotier.com: " << r->toString() << std::endl; - if (r->isV4()) - downloadZerotierDotCom = *r; - } - } - downloadZerotierDotCom.setPort(80); - - std::cout << "[http] GET http://download.zerotier.com/dev/1k @" << downloadZerotierDotCom.toString() << " ... "; std::cout.flush(); - requestHeaders["Host"] = "download.zerotier.com"; - unsigned int sc = Http::GET(1024 * 1024 * 16,60000,reinterpret_cast(&downloadZerotierDotCom),"/dev/1k",requestHeaders,responseHeaders,responseBody); - std::cout << sc << " " << responseBody.length() << " bytes "; - if (sc == 0) - std::cout << "ERROR: " << responseBody << std::endl; - else std::cout << "DONE" << std::endl; - - std::cout << "[http] GET http://download.zerotier.com/dev/4m @" << downloadZerotierDotCom.toString() << " ... "; std::cout.flush(); - requestHeaders["Host"] = "download.zerotier.com"; - sc = Http::GET(1024 * 1024 * 16,60000,reinterpret_cast(&downloadZerotierDotCom),"/dev/4m",requestHeaders,responseHeaders,responseBody); - std::cout << sc << " " << responseBody.length() << " bytes "; - if (sc == 0) - std::cout << "ERROR: " << responseBody << std::endl; - else std::cout << "DONE" << std::endl; - - downloadZerotierDotCom = InetAddress("1.0.0.1/1234"); - std::cout << "[http] GET @" << downloadZerotierDotCom.toString() << " ... "; std::cout.flush(); - sc = Http::GET(1024 * 1024 * 16,2500,reinterpret_cast(&downloadZerotierDotCom),"/dev/4m",requestHeaders,responseHeaders,responseBody); - std::cout << sc << " (should be 0, time out)" << std::endl; - - return 0; -} -*/ - -#ifdef __WINDOWS__ -int _tmain(int argc, _TCHAR* argv[]) -#else -int main(int argc,char **argv) -#endif -{ - int r = 0; - -#ifdef __WINDOWS__ - WSADATA wsaData; - WSAStartup(MAKEWORD(2,2),&wsaData); -#endif - - // Code to generate the C25519 test vectors -- did this once and then - // put these up top so that we can ensure that every platform produces - // the same result. - /* - for(int k=0;k<32;++k) { - C25519::Pair p1 = C25519::generate(); - C25519::Pair p2 = C25519::generate(); - unsigned char agg[64]; - C25519::agree(p1,p2.pub,agg,64); - C25519::Signature sig1 = C25519::sign(p1,agg,64); - C25519::Signature sig2 = C25519::sign(p2,agg,64); - printf("{{"); - for(int i=0;i<64;++i) - printf("%s0x%.2x",((i > 0) ? "," : ""),(unsigned int)p1.pub.data[i]); - printf("},{"); - for(int i=0;i<64;++i) - printf("%s0x%.2x",((i > 0) ? "," : ""),(unsigned int)p1.priv.data[i]); - printf("},{"); - for(int i=0;i<64;++i) - printf("%s0x%.2x",((i > 0) ? "," : ""),(unsigned int)p2.pub.data[i]); - printf("},{"); - for(int i=0;i<64;++i) - printf("%s0x%.2x",((i > 0) ? "," : ""),(unsigned int)p2.priv.data[i]); - printf("},{"); - for(int i=0;i<64;++i) - printf("%s0x%.2x",((i > 0) ? "," : ""),(unsigned int)agg[i]); - printf("},{"); - for(int i=0;i<96;++i) - printf("%s0x%.2x",((i > 0) ? "," : ""),(unsigned int)sig1.data[i]); - printf("},{"); - for(int i=0;i<96;++i) - printf("%s0x%.2x",((i > 0) ? "," : ""),(unsigned int)sig2.data[i]); - printf("}}\n"); - } - exit(0); - */ - - std::cout << "[info] sizeof(void *) == " << sizeof(void *) << std::endl; - std::cout << "[info] sizeof(NetworkConfig) == " << sizeof(ZeroTier::NetworkConfig) << std::endl; - - srand((unsigned int)time(0)); - - ///* - r |= testOther(); - r |= testCrypto(); - r |= testPacket(); - r |= testIdentity(); - r |= testCertificate(); - r |= testPhy(); - //r |= testHttp(); - //*/ - - if (r) - std::cout << std::endl << "SOMETHING FAILED!" << std::endl; - - /* -#ifdef ZT_USE_MINIUPNPC - std::cout << std::endl; - std::cout << "[portmapper] Starting port mapper and waiting forever... use CTRL+C to exit. (enable ZT_PORTMAPPER_TRACE in PortMapper.cpp for output)" << std::endl; - PortMapper mapper(12345,"ZeroTier/__selftest"); - Thread::sleep(0xffffffff); -#endif - */ - - return r; -} diff --git a/zto/service/ClusterDefinition.hpp b/zto/service/ClusterDefinition.hpp deleted file mode 100644 index dda1a8c..0000000 --- a/zto/service/ClusterDefinition.hpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_CLUSTERDEFINITION_HPP -#define ZT_CLUSTERDEFINITION_HPP - -#ifdef ZT_ENABLE_CLUSTER - -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/NonCopyable.hpp" -#include "../osdep/OSUtils.hpp" - -#include "ClusterGeoIpService.hpp" - -namespace ZeroTier { - -/** - * Parser for cluster definition file - */ -class ClusterDefinition : NonCopyable -{ -public: - struct MemberDefinition - { - MemberDefinition() : id(0),x(0),y(0),z(0) { name[0] = (char)0; } - - unsigned int id; - int x,y,z; - char name[256]; - InetAddress clusterEndpoint; - std::vector zeroTierEndpoints; - }; - - /** - * Load and initialize cluster definition and GeoIP data if any - * - * @param myAddress My ZeroTier address - * @param pathToClusterFile Path to cluster definition file - * @throws std::runtime_error Invalid cluster definition or unable to load data - */ - ClusterDefinition(uint64_t myAddress,const char *pathToClusterFile) - { - std::string cf; - if (!OSUtils::readFile(pathToClusterFile,cf)) - return; - - char myAddressStr[64]; - Utils::snprintf(myAddressStr,sizeof(myAddressStr),"%.10llx",myAddress); - - std::vector lines(OSUtils::split(cf.c_str(),"\r\n","","")); - for(std::vector::iterator l(lines.begin());l!=lines.end();++l) { - std::vector fields(OSUtils::split(l->c_str()," \t","","")); - if ((fields.size() < 5)||(fields[0][0] == '#')||(fields[0] != myAddressStr)) - continue; - - //
geo - if (fields[1] == "geo") { - if ((fields.size() >= 7)&&(OSUtils::fileExists(fields[2].c_str()))) { - int ipStartColumn = Utils::strToInt(fields[3].c_str()); - int ipEndColumn = Utils::strToInt(fields[4].c_str()); - int latitudeColumn = Utils::strToInt(fields[5].c_str()); - int longitudeColumn = Utils::strToInt(fields[6].c_str()); - if (_geo.load(fields[2].c_str(),ipStartColumn,ipEndColumn,latitudeColumn,longitudeColumn) <= 0) - throw std::runtime_error(std::string("failed to load geo-ip data from ")+fields[2]); - } - continue; - } - - //
- int id = Utils::strToUInt(fields[1].c_str()); - if ((id < 0)||(id > ZT_CLUSTER_MAX_MEMBERS)) - throw std::runtime_error(std::string("invalid cluster member ID: ")+fields[1]); - MemberDefinition &md = _md[id]; - - md.id = (unsigned int)id; - if (fields.size() >= 6) { - std::vector xyz(OSUtils::split(fields[5].c_str(),",","","")); - md.x = (xyz.size() > 0) ? Utils::strToInt(xyz[0].c_str()) : 0; - md.y = (xyz.size() > 1) ? Utils::strToInt(xyz[1].c_str()) : 0; - md.z = (xyz.size() > 2) ? Utils::strToInt(xyz[2].c_str()) : 0; - } - Utils::scopy(md.name,sizeof(md.name),fields[2].c_str()); - md.clusterEndpoint.fromString(fields[3]); - if (!md.clusterEndpoint) - continue; - std::vector zips(OSUtils::split(fields[4].c_str(),",","","")); - for(std::vector::iterator zip(zips.begin());zip!=zips.end();++zip) { - InetAddress i; - i.fromString(*zip); - if (i) - md.zeroTierEndpoints.push_back(i); - } - - _ids.push_back((unsigned int)id); - } - - std::sort(_ids.begin(),_ids.end()); - } - - /** - * @return All member definitions in this cluster by ID (ID is array index) - */ - inline const MemberDefinition &operator[](unsigned int id) const throw() { return _md[id]; } - - /** - * @return Number of members in this cluster - */ - inline unsigned int size() const throw() { return (unsigned int)_ids.size(); } - - /** - * @return IDs of members in this cluster sorted by ID - */ - inline const std::vector &ids() const throw() { return _ids; } - - /** - * @return GeoIP service for this cluster - */ - inline ClusterGeoIpService &geo() throw() { return _geo; } - - /** - * @return A vector (new copy) containing all cluster members - */ - inline std::vector members() const - { - std::vector m; - for(std::vector::const_iterator i(_ids.begin());i!=_ids.end();++i) - m.push_back(_md[*i]); - return m; - } - -private: - MemberDefinition _md[ZT_CLUSTER_MAX_MEMBERS]; - std::vector _ids; - ClusterGeoIpService _geo; -}; - -} // namespace ZeroTier - -#endif // ZT_ENABLE_CLUSTER - -#endif diff --git a/zto/service/ClusterGeoIpService.cpp b/zto/service/ClusterGeoIpService.cpp deleted file mode 100644 index 89015c5..0000000 --- a/zto/service/ClusterGeoIpService.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifdef ZT_ENABLE_CLUSTER - -#include - -#include - -#include "ClusterGeoIpService.hpp" - -#include "../node/Utils.hpp" -#include "../osdep/OSUtils.hpp" - -#define ZT_CLUSTERGEOIPSERVICE_FILE_MODIFICATION_CHECK_EVERY 10000 - -namespace ZeroTier { - -ClusterGeoIpService::ClusterGeoIpService() : - _pathToCsv(), - _ipStartColumn(-1), - _ipEndColumn(-1), - _latitudeColumn(-1), - _longitudeColumn(-1), - _lastFileCheckTime(0), - _csvModificationTime(0), - _csvFileSize(0) -{ -} - -ClusterGeoIpService::~ClusterGeoIpService() -{ -} - -bool ClusterGeoIpService::locate(const InetAddress &ip,int &x,int &y,int &z) -{ - Mutex::Lock _l(_lock); - - if ((_pathToCsv.length() > 0)&&((OSUtils::now() - _lastFileCheckTime) > ZT_CLUSTERGEOIPSERVICE_FILE_MODIFICATION_CHECK_EVERY)) { - _lastFileCheckTime = OSUtils::now(); - if ((_csvFileSize != OSUtils::getFileSize(_pathToCsv.c_str()))||(_csvModificationTime != OSUtils::getLastModified(_pathToCsv.c_str()))) - _load(_pathToCsv.c_str(),_ipStartColumn,_ipEndColumn,_latitudeColumn,_longitudeColumn); - } - - /* We search by looking up the upper bound of the sorted vXdb vectors - * and then iterating down for a matching IP range. We stop when we hit - * the beginning or an entry whose start and end are before the IP we - * are searching. */ - - if ((ip.ss_family == AF_INET)&&(_v4db.size() > 0)) { - _V4E key; - key.start = Utils::ntoh((uint32_t)(reinterpret_cast(&ip)->sin_addr.s_addr)); - std::vector<_V4E>::const_iterator i(std::upper_bound(_v4db.begin(),_v4db.end(),key)); - while (i != _v4db.begin()) { - --i; - if ((key.start >= i->start)&&(key.start <= i->end)) { - x = i->x; - y = i->y; - z = i->z; - //printf("%s : %f,%f %d,%d,%d\n",ip.toIpString().c_str(),i->lat,i->lon,x,y,z); - return true; - } else if ((key.start > i->start)&&(key.start > i->end)) - break; - } - } else if ((ip.ss_family == AF_INET6)&&(_v6db.size() > 0)) { - _V6E key; - memcpy(key.start,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); - std::vector<_V6E>::const_iterator i(std::upper_bound(_v6db.begin(),_v6db.end(),key)); - while (i != _v6db.begin()) { - --i; - const int s_vs_s = memcmp(key.start,i->start,16); - const int s_vs_e = memcmp(key.start,i->end,16); - if ((s_vs_s >= 0)&&(s_vs_e <= 0)) { - x = i->x; - y = i->y; - z = i->z; - //printf("%s : %f,%f %d,%d,%d\n",ip.toIpString().c_str(),i->lat,i->lon,x,y,z); - return true; - } else if ((s_vs_s > 0)&&(s_vs_e > 0)) - break; - } - } - - return false; -} - -void ClusterGeoIpService::_parseLine(const char *line,std::vector<_V4E> &v4db,std::vector<_V6E> &v6db,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn) -{ - std::vector ls(OSUtils::split(line,",\t","\\","\"'")); - if ( ((ipStartColumn >= 0)&&(ipStartColumn < (int)ls.size()))&& - ((ipEndColumn >= 0)&&(ipEndColumn < (int)ls.size()))&& - ((latitudeColumn >= 0)&&(latitudeColumn < (int)ls.size()))&& - ((longitudeColumn >= 0)&&(longitudeColumn < (int)ls.size())) ) { - InetAddress ipStart(ls[ipStartColumn].c_str(),0); - InetAddress ipEnd(ls[ipEndColumn].c_str(),0); - const double lat = strtod(ls[latitudeColumn].c_str(),(char **)0); - const double lon = strtod(ls[longitudeColumn].c_str(),(char **)0); - - if ((ipStart.ss_family == ipEnd.ss_family)&&(ipStart)&&(ipEnd)&&(std::isfinite(lat))&&(std::isfinite(lon))) { - const double latRadians = lat * 0.01745329251994; // PI / 180 - const double lonRadians = lon * 0.01745329251994; // PI / 180 - const double cosLat = cos(latRadians); - const int x = (int)round((-6371.0) * cosLat * cos(lonRadians)); // 6371 == Earth's approximate radius in kilometers - const int y = (int)round(6371.0 * sin(latRadians)); - const int z = (int)round(6371.0 * cosLat * sin(lonRadians)); - - if (ipStart.ss_family == AF_INET) { - v4db.push_back(_V4E()); - v4db.back().start = Utils::ntoh((uint32_t)(reinterpret_cast(&ipStart)->sin_addr.s_addr)); - v4db.back().end = Utils::ntoh((uint32_t)(reinterpret_cast(&ipEnd)->sin_addr.s_addr)); - v4db.back().lat = (float)lat; - v4db.back().lon = (float)lon; - v4db.back().x = x; - v4db.back().y = y; - v4db.back().z = z; - //printf("%s - %s : %d,%d,%d\n",ipStart.toIpString().c_str(),ipEnd.toIpString().c_str(),x,y,z); - } else if (ipStart.ss_family == AF_INET6) { - v6db.push_back(_V6E()); - memcpy(v6db.back().start,reinterpret_cast(&ipStart)->sin6_addr.s6_addr,16); - memcpy(v6db.back().end,reinterpret_cast(&ipEnd)->sin6_addr.s6_addr,16); - v6db.back().lat = (float)lat; - v6db.back().lon = (float)lon; - v6db.back().x = x; - v6db.back().y = y; - v6db.back().z = z; - //printf("%s - %s : %d,%d,%d\n",ipStart.toIpString().c_str(),ipEnd.toIpString().c_str(),x,y,z); - } - } - } -} - -long ClusterGeoIpService::_load(const char *pathToCsv,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn) -{ - // assumes _lock is locked - - FILE *f = fopen(pathToCsv,"rb"); - if (!f) - return -1; - - std::vector<_V4E> v4db; - std::vector<_V6E> v6db; - v4db.reserve(16777216); - v6db.reserve(16777216); - - char buf[4096]; - char linebuf[1024]; - unsigned int lineptr = 0; - for(;;) { - int n = (int)fread(buf,1,sizeof(buf),f); - if (n <= 0) - break; - for(int i=0;i 0)||(v6db.size() > 0)) { - std::sort(v4db.begin(),v4db.end()); - std::sort(v6db.begin(),v6db.end()); - - _pathToCsv = pathToCsv; - _ipStartColumn = ipStartColumn; - _ipEndColumn = ipEndColumn; - _latitudeColumn = latitudeColumn; - _longitudeColumn = longitudeColumn; - - _lastFileCheckTime = OSUtils::now(); - _csvModificationTime = OSUtils::getLastModified(pathToCsv); - _csvFileSize = OSUtils::getFileSize(pathToCsv); - - _v4db.swap(v4db); - _v6db.swap(v6db); - - return (long)(_v4db.size() + _v6db.size()); - } else { - return 0; - } -} - -} // namespace ZeroTier - -#endif // ZT_ENABLE_CLUSTER - -/* -int main(int argc,char **argv) -{ - char buf[1024]; - - ZeroTier::ClusterGeoIpService gip; - printf("loading...\n"); - gip.load("/Users/api/Code/ZeroTier/Infrastructure/root-servers/zerotier-one/cluster-geoip.csv",0,1,5,6); - printf("... done!\n"); fflush(stdout); - - while (gets(buf)) { // unsafe, testing only - ZeroTier::InetAddress addr(buf,0); - printf("looking up: %s\n",addr.toString().c_str()); fflush(stdout); - int x = 0,y = 0,z = 0; - if (gip.locate(addr,x,y,z)) { - //printf("%s: %d,%d,%d\n",addr.toString().c_str(),x,y,z); fflush(stdout); - } else { - printf("%s: not found!\n",addr.toString().c_str()); fflush(stdout); - } - } - - return 0; -} -*/ diff --git a/zto/service/ClusterGeoIpService.hpp b/zto/service/ClusterGeoIpService.hpp deleted file mode 100644 index ff2fcdb..0000000 --- a/zto/service/ClusterGeoIpService.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_CLUSTERGEOIPSERVICE_HPP -#define ZT_CLUSTERGEOIPSERVICE_HPP - -#ifdef ZT_ENABLE_CLUSTER - -#include -#include -#include -#include - -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Mutex.hpp" -#include "../node/NonCopyable.hpp" -#include "../node/InetAddress.hpp" - -namespace ZeroTier { - -/** - * Loads a GeoIP CSV into memory for fast lookup, reloading as needed - * - * This was designed around the CSV from https://db-ip.com but can be used - * with any similar GeoIP CSV database that is presented in the form of an - * IP range and lat/long coordinates. - * - * It loads the whole database into memory, which can be kind of large. If - * the CSV file changes, the changes are loaded automatically. - */ -class ClusterGeoIpService : NonCopyable -{ -public: - ClusterGeoIpService(); - ~ClusterGeoIpService(); - - /** - * Load or reload CSV file - * - * CSV column indexes start at zero. CSVs can be quoted with single or - * double quotes. Whitespace before or after commas is ignored. Backslash - * may be used for escaping whitespace as well. - * - * @param pathToCsv Path to (uncompressed) CSV file - * @param ipStartColumn Column with IP range start - * @param ipEndColumn Column with IP range end (inclusive) - * @param latitudeColumn Column with latitude - * @param longitudeColumn Column with longitude - * @return Number of valid records loaded or -1 on error (invalid file, not found, etc.) - */ - inline long load(const char *pathToCsv,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn) - { - Mutex::Lock _l(_lock); - return _load(pathToCsv,ipStartColumn,ipEndColumn,latitudeColumn,longitudeColumn); - } - - /** - * Attempt to locate an IP - * - * This returns true if x, y, and z are set. If the return value is false - * the values of x, y, and z are undefined. - * - * @param ip IPv4 or IPv6 address - * @param x Reference to variable to receive X - * @param y Reference to variable to receive Y - * @param z Reference to variable to receive Z - * @return True if coordinates were set - */ - bool locate(const InetAddress &ip,int &x,int &y,int &z); - - /** - * @return True if IP database/service is available for queries (otherwise locate() will always be false) - */ - inline bool available() const - { - Mutex::Lock _l(_lock); - return ((_v4db.size() + _v6db.size()) > 0); - } - -private: - struct _V4E - { - uint32_t start; - uint32_t end; - float lat,lon; - int16_t x,y,z; - - inline bool operator<(const _V4E &e) const { return (start < e.start); } - }; - - struct _V6E - { - uint8_t start[16]; - uint8_t end[16]; - float lat,lon; - int16_t x,y,z; - - inline bool operator<(const _V6E &e) const { return (memcmp(start,e.start,16) < 0); } - }; - - static void _parseLine(const char *line,std::vector<_V4E> &v4db,std::vector<_V6E> &v6db,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn); - long _load(const char *pathToCsv,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn); - - std::string _pathToCsv; - int _ipStartColumn; - int _ipEndColumn; - int _latitudeColumn; - int _longitudeColumn; - - uint64_t _lastFileCheckTime; - uint64_t _csvModificationTime; - int64_t _csvFileSize; - - std::vector<_V4E> _v4db; - std::vector<_V6E> _v6db; - - Mutex _lock; -}; - -} // namespace ZeroTier - -#endif // ZT_ENABLE_CLUSTER - -#endif diff --git a/zto/service/OneService.cpp b/zto/service/OneService.cpp deleted file mode 100644 index e228c8e..0000000 --- a/zto/service/OneService.cpp +++ /dev/null @@ -1,2597 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "../version.h" -#include "../include/ZeroTierOne.h" - -#include "../node/Constants.hpp" -#include "../node/Mutex.hpp" -#include "../node/Node.hpp" -#include "../node/Utils.hpp" -#include "../node/InetAddress.hpp" -#include "../node/MAC.hpp" -#include "../node/Identity.hpp" -#include "../node/World.hpp" - -#include "../osdep/Phy.hpp" -#include "../osdep/Thread.hpp" -#include "../osdep/OSUtils.hpp" -#include "../osdep/Http.hpp" -#include "../osdep/PortMapper.hpp" -#include "../osdep/Binder.hpp" -#include "../osdep/ManagedRoute.hpp" - -#include "OneService.hpp" -#include "ClusterGeoIpService.hpp" -#include "ClusterDefinition.hpp" -#include "SoftwareUpdater.hpp" - -#ifdef __WINDOWS__ -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#include -#endif - -#ifdef ZT_USE_SYSTEM_HTTP_PARSER -#include -#else -#include "../ext/http-parser/http_parser.h" -#endif - -#include "../ext/json/json.hpp" - -using json = nlohmann::json; - -/** - * Uncomment to enable UDP breakage switch - * - * If this is defined, the presence of a file called /tmp/ZT_BREAK_UDP - * will cause direct UDP TX/RX to stop working. This can be used to - * test TCP tunneling fallback and other robustness features. Deleting - * this file will cause it to start working again. - */ -//#define ZT_BREAK_UDP - -#include "../controller/EmbeddedNetworkController.hpp" - -// Include the right tap device driver for this platform -- add new platforms here -#ifdef ZT_SDK - -// In network containers builds, use the virtual netcon endpoint instead of a tun/tap port driver -#include "../src/tap.hpp" -namespace ZeroTier { typedef NetconEthernetTap EthernetTap; } - -#else // not ZT_SDK so pick a tap driver - -#ifdef __APPLE__ -#include "../osdep/OSXEthernetTap.hpp" -namespace ZeroTier { typedef OSXEthernetTap EthernetTap; } -#endif // __APPLE__ -#ifdef __LINUX__ -#include "../osdep/LinuxEthernetTap.hpp" -namespace ZeroTier { typedef LinuxEthernetTap EthernetTap; } -#endif // __LINUX__ -#ifdef __WINDOWS__ -#include "../osdep/WindowsEthernetTap.hpp" -namespace ZeroTier { typedef WindowsEthernetTap EthernetTap; } -#endif // __WINDOWS__ -#ifdef __FreeBSD__ -#include "../osdep/BSDEthernetTap.hpp" -namespace ZeroTier { typedef BSDEthernetTap EthernetTap; } -#endif // __FreeBSD__ -#ifdef __OpenBSD__ -#include "../osdep/BSDEthernetTap.hpp" -namespace ZeroTier { typedef BSDEthernetTap EthernetTap; } -#endif // __OpenBSD__ - -#endif // ZT_SERVICE_NETCON - -// Sanity limits for HTTP -#define ZT_MAX_HTTP_MESSAGE_SIZE (1024 * 1024 * 64) -#define ZT_MAX_HTTP_CONNECTIONS 64 - -// Interface metric for ZeroTier taps -- this ensures that if we are on WiFi and also -// bridged via ZeroTier to the same LAN traffic will (if the OS is sane) prefer WiFi. -#define ZT_IF_METRIC 5000 - -// How often to check for new multicast subscriptions on a tap device -#define ZT_TAP_CHECK_MULTICAST_INTERVAL 5000 - -// Path under ZT1 home for controller database if controller is enabled -#define ZT_CONTROLLER_DB_PATH "controller.d" - -// TCP fallback relay (run by ZeroTier, Inc. -- this will eventually go away) -#define ZT_TCP_FALLBACK_RELAY "204.80.128.1/443" - -// Frequency at which we re-resolve the TCP fallback relay -#define ZT_TCP_FALLBACK_RERESOLVE_DELAY 86400000 - -// Attempt to engage TCP fallback after this many ms of no reply to packets sent to global-scope IPs -#define ZT_TCP_FALLBACK_AFTER 60000 - -// How often to check for local interface addresses -#define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000 - -// Clean files from iddb.d that are older than this (60 days) -#define ZT_IDDB_CLEANUP_AGE 5184000000ULL - -namespace ZeroTier { - -namespace { - -static std::string _trimString(const std::string &s) -{ - unsigned long end = (unsigned long)s.length(); - while (end) { - char c = s[end - 1]; - if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t')) - --end; - else break; - } - unsigned long start = 0; - while (start < end) { - char c = s[start]; - if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t')) - ++start; - else break; - } - return s.substr(start,end - start); -} - -static void _networkToJson(nlohmann::json &nj,const ZT_VirtualNetworkConfig *nc,const std::string &portDeviceName,const OneService::NetworkSettings &localSettings) -{ - char tmp[256]; - - const char *nstatus = "",*ntype = ""; - switch(nc->status) { - case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION: nstatus = "REQUESTING_CONFIGURATION"; break; - case ZT_NETWORK_STATUS_OK: nstatus = "OK"; break; - case ZT_NETWORK_STATUS_ACCESS_DENIED: nstatus = "ACCESS_DENIED"; break; - case ZT_NETWORK_STATUS_NOT_FOUND: nstatus = "NOT_FOUND"; break; - case ZT_NETWORK_STATUS_PORT_ERROR: nstatus = "PORT_ERROR"; break; - case ZT_NETWORK_STATUS_CLIENT_TOO_OLD: nstatus = "CLIENT_TOO_OLD"; break; - } - switch(nc->type) { - case ZT_NETWORK_TYPE_PRIVATE: ntype = "PRIVATE"; break; - case ZT_NETWORK_TYPE_PUBLIC: ntype = "PUBLIC"; break; - } - - Utils::snprintf(tmp,sizeof(tmp),"%.16llx",nc->nwid); - nj["id"] = tmp; - nj["nwid"] = tmp; - Utils::snprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)((nc->mac >> 40) & 0xff),(unsigned int)((nc->mac >> 32) & 0xff),(unsigned int)((nc->mac >> 24) & 0xff),(unsigned int)((nc->mac >> 16) & 0xff),(unsigned int)((nc->mac >> 8) & 0xff),(unsigned int)(nc->mac & 0xff)); - nj["mac"] = tmp; - nj["name"] = nc->name; - nj["status"] = nstatus; - nj["type"] = ntype; - nj["mtu"] = nc->mtu; - nj["dhcp"] = (bool)(nc->dhcp != 0); - nj["bridge"] = (bool)(nc->bridge != 0); - nj["broadcastEnabled"] = (bool)(nc->broadcastEnabled != 0); - nj["portError"] = nc->portError; - nj["netconfRevision"] = nc->netconfRevision; - nj["portDeviceName"] = portDeviceName; - nj["allowManaged"] = localSettings.allowManaged; - nj["allowGlobal"] = localSettings.allowGlobal; - nj["allowDefault"] = localSettings.allowDefault; - - nlohmann::json aa = nlohmann::json::array(); - for(unsigned int i=0;iassignedAddressCount;++i) { - aa.push_back(reinterpret_cast(&(nc->assignedAddresses[i]))->toString()); - } - nj["assignedAddresses"] = aa; - - nlohmann::json ra = nlohmann::json::array(); - for(unsigned int i=0;irouteCount;++i) { - nlohmann::json rj; - rj["target"] = reinterpret_cast(&(nc->routes[i].target))->toString(); - if (nc->routes[i].via.ss_family == nc->routes[i].target.ss_family) - rj["via"] = reinterpret_cast(&(nc->routes[i].via))->toIpString(); - else rj["via"] = nlohmann::json(); - rj["flags"] = (int)nc->routes[i].flags; - rj["metric"] = (int)nc->routes[i].metric; - ra.push_back(rj); - } - nj["routes"] = ra; -} - -static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer) -{ - char tmp[256]; - - const char *prole = ""; - switch(peer->role) { - case ZT_PEER_ROLE_LEAF: prole = "LEAF"; break; - case ZT_PEER_ROLE_MOON: prole = "MOON"; break; - case ZT_PEER_ROLE_PLANET: prole = "PLANET"; break; - } - - Utils::snprintf(tmp,sizeof(tmp),"%.10llx",peer->address); - pj["address"] = tmp; - pj["versionMajor"] = peer->versionMajor; - pj["versionMinor"] = peer->versionMinor; - pj["versionRev"] = peer->versionRev; - Utils::snprintf(tmp,sizeof(tmp),"%d.%d.%d",peer->versionMajor,peer->versionMinor,peer->versionRev); - pj["version"] = tmp; - pj["latency"] = peer->latency; - pj["role"] = prole; - - nlohmann::json pa = nlohmann::json::array(); - for(unsigned int i=0;ipathCount;++i) { - nlohmann::json j; - j["address"] = reinterpret_cast(&(peer->paths[i].address))->toString(); - j["lastSend"] = peer->paths[i].lastSend; - j["lastReceive"] = peer->paths[i].lastReceive; - j["trustedPathId"] = peer->paths[i].trustedPathId; - j["linkQuality"] = (double)peer->paths[i].linkQuality / (double)ZT_PATH_LINK_QUALITY_MAX; - j["active"] = (bool)(peer->paths[i].expired == 0); - j["expired"] = (bool)(peer->paths[i].expired != 0); - j["preferred"] = (bool)(peer->paths[i].preferred != 0); - pa.push_back(j); - } - pj["paths"] = pa; -} - -static void _moonToJson(nlohmann::json &mj,const World &world) -{ - char tmp[64]; - Utils::snprintf(tmp,sizeof(tmp),"%.16llx",world.id()); - mj["id"] = tmp; - mj["timestamp"] = world.timestamp(); - mj["signature"] = Utils::hex(world.signature().data,(unsigned int)world.signature().size()); - mj["updatesMustBeSignedBy"] = Utils::hex(world.updatesMustBeSignedBy().data,(unsigned int)world.updatesMustBeSignedBy().size()); - nlohmann::json ra = nlohmann::json::array(); - for(std::vector::const_iterator r(world.roots().begin());r!=world.roots().end();++r) { - nlohmann::json rj; - rj["identity"] = r->identity.toString(false); - nlohmann::json eps = nlohmann::json::array(); - for(std::vector::const_iterator a(r->stableEndpoints.begin());a!=r->stableEndpoints.end();++a) - eps.push_back(a->toString()); - rj["stableEndpoints"] = eps; - ra.push_back(rj); - } - mj["roots"] = ra; - mj["waiting"] = false; -} - -class OneServiceImpl; - -static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf); -static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData); -static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize); -static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,const void *data,unsigned long len,int secure); -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); -static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); -static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); - -#ifdef ZT_ENABLE_CLUSTER -static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len); -static int SclusterGeoIpFunction(void *uptr,const struct sockaddr_storage *addr,int *x,int *y,int *z); -#endif - -static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); - -static int ShttpOnMessageBegin(http_parser *parser); -static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length); -#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) -static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length); -#else -static int ShttpOnStatus(http_parser *parser); -#endif -static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnHeadersComplete(http_parser *parser); -static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnMessageComplete(http_parser *parser); - -#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1) -static const struct http_parser_settings HTTP_PARSER_SETTINGS = { - ShttpOnMessageBegin, - ShttpOnUrl, - ShttpOnStatus, - ShttpOnHeaderField, - ShttpOnValue, - ShttpOnHeadersComplete, - ShttpOnBody, - ShttpOnMessageComplete -}; -#else -static const struct http_parser_settings HTTP_PARSER_SETTINGS = { - ShttpOnMessageBegin, - ShttpOnUrl, - ShttpOnHeaderField, - ShttpOnValue, - ShttpOnHeadersComplete, - ShttpOnBody, - ShttpOnMessageComplete -}; -#endif - -struct TcpConnection -{ - enum { - TCP_HTTP_INCOMING, - TCP_HTTP_OUTGOING, // not currently used - TCP_TUNNEL_OUTGOING // fale-SSL outgoing tunnel -- HTTP-related fields are not used - } type; - - bool shouldKeepAlive; - OneServiceImpl *parent; - PhySocket *sock; - InetAddress from; - http_parser parser; - unsigned long messageSize; - uint64_t lastActivity; - - std::string currentHeaderField; - std::string currentHeaderValue; - - std::string url; - std::string status; - std::map< std::string,std::string > headers; - std::string body; - - std::string writeBuf; - Mutex writeBuf_m; -}; - -// Used to pseudo-randomize local source port picking -static volatile unsigned int _udpPortPickerCounter = 0; - -class OneServiceImpl : public OneService -{ -public: - // begin member variables -------------------------------------------------- - - const std::string _homePath; - std::string _authToken; - EmbeddedNetworkController *_controller; - Phy _phy; - Node *_node; - SoftwareUpdater *_updater; - bool _updateAutoApply; - unsigned int _primaryPort; - - // Local configuration and memo-ized static path definitions - json _localConfig; - Hashtable< uint64_t,std::vector > _v4Hints; - Hashtable< uint64_t,std::vector > _v6Hints; - Hashtable< uint64_t,std::vector > _v4Blacklists; - Hashtable< uint64_t,std::vector > _v6Blacklists; - std::vector< InetAddress > _globalV4Blacklist; - std::vector< InetAddress > _globalV6Blacklist; - std::vector< InetAddress > _allowManagementFrom; - std::vector< std::string > _interfacePrefixBlacklist; - Mutex _localConfig_m; - - /* - * To attempt to handle NAT/gateway craziness we use three local UDP ports: - * - * [0] is the normal/default port, usually 9993 - * [1] is a port dervied from our ZeroTier address - * [2] is a port computed from the normal/default for use with uPnP/NAT-PMP mappings - * - * [2] exists because on some gateways trying to do regular NAT-t interferes - * destructively with uPnP port mapping behavior in very weird buggy ways. - * It's only used if uPnP/NAT-PMP is enabled in this build. - */ - Binder _bindings[3]; - unsigned int _ports[3]; - uint16_t _portsBE[3]; // ports in big-endian network byte order as in sockaddr - - // Sockets for JSON API -- bound only to V4 and V6 localhost - PhySocket *_v4TcpControlSocket; - PhySocket *_v6TcpControlSocket; - - // Time we last received a packet from a global address - uint64_t _lastDirectReceiveFromGlobal; -#ifdef ZT_TCP_FALLBACK_RELAY - uint64_t _lastSendToGlobalV4; -#endif - - // Last potential sleep/wake event - uint64_t _lastRestart; - - // Deadline for the next background task service function - volatile uint64_t _nextBackgroundTaskDeadline; - - // Configured networks - struct NetworkState - { - NetworkState() : - tap((EthernetTap *)0) - { - // Real defaults are in network 'up' code in network event handler - settings.allowManaged = true; - settings.allowGlobal = false; - settings.allowDefault = false; - } - - EthernetTap *tap; - ZT_VirtualNetworkConfig config; // memcpy() of raw config from core - std::vector managedIps; - std::list< SharedPtr > managedRoutes; - NetworkSettings settings; - }; - std::map _nets; - Mutex _nets_m; - - // Active TCP/IP connections - std::set< TcpConnection * > _tcpConnections; // no mutex for this since it's done in the main loop thread only - TcpConnection *_tcpFallbackTunnel; - - // Termination status information - ReasonForTermination _termReason; - std::string _fatalErrorMessage; - Mutex _termReason_m; - - // uPnP/NAT-PMP port mapper if enabled - bool _portMappingEnabled; // local.conf settings -#ifdef ZT_USE_MINIUPNPC - PortMapper *_portMapper; -#endif - - // Cluster management instance if enabled -#ifdef ZT_ENABLE_CLUSTER - PhySocket *_clusterMessageSocket; - ClusterDefinition *_clusterDefinition; - unsigned int _clusterMemberId; -#endif - - // Set to false to force service to stop - volatile bool _run; - Mutex _run_m; - - // end member variables ---------------------------------------------------- - - OneServiceImpl(const char *hp,unsigned int port) : - _homePath((hp) ? hp : ".") - ,_controller((EmbeddedNetworkController *)0) - ,_phy(this,false,true) - ,_node((Node *)0) - ,_updater((SoftwareUpdater *)0) - ,_updateAutoApply(false) - ,_primaryPort(port) - ,_v4TcpControlSocket((PhySocket *)0) - ,_v6TcpControlSocket((PhySocket *)0) - ,_lastDirectReceiveFromGlobal(0) -#ifdef ZT_TCP_FALLBACK_RELAY - ,_lastSendToGlobalV4(0) -#endif - ,_lastRestart(0) - ,_nextBackgroundTaskDeadline(0) - ,_tcpFallbackTunnel((TcpConnection *)0) - ,_termReason(ONE_STILL_RUNNING) - ,_portMappingEnabled(true) -#ifdef ZT_USE_MINIUPNPC - ,_portMapper((PortMapper *)0) -#endif -#ifdef ZT_ENABLE_CLUSTER - ,_clusterMessageSocket((PhySocket *)0) - ,_clusterDefinition((ClusterDefinition *)0) - ,_clusterMemberId(0) -#endif - ,_run(true) - { - _ports[0] = 0; - _ports[1] = 0; - _ports[2] = 0; - } - - virtual ~OneServiceImpl() - { - for(int i=0;i<3;++i) - _bindings[i].closeAll(_phy); - - _phy.close(_v4TcpControlSocket); - _phy.close(_v6TcpControlSocket); - -#ifdef ZT_ENABLE_CLUSTER - _phy.close(_clusterMessageSocket); -#endif - -#ifdef ZT_USE_MINIUPNPC - delete _portMapper; -#endif - delete _controller; -#ifdef ZT_ENABLE_CLUSTER - delete _clusterDefinition; -#endif - } - - virtual ReasonForTermination run() - { - try { - { - const std::string authTokenPath(_homePath + ZT_PATH_SEPARATOR_S "authtoken.secret"); - if (!OSUtils::readFile(authTokenPath.c_str(),_authToken)) { - unsigned char foo[24]; - Utils::getSecureRandom(foo,sizeof(foo)); - _authToken = ""; - for(unsigned int i=0;i 0) ) { - trustedPathIds[trustedPathCount] = trustedPathId; - trustedPathNetworks[trustedPathCount] = trustedPathNetwork; - ++trustedPathCount; - } - } - fclose(trustpaths); - } - - // Read local config file - Mutex::Lock _l2(_localConfig_m); - std::string lcbuf; - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(),lcbuf)) { - try { - _localConfig = OSUtils::jsonParse(lcbuf); - if (!_localConfig.is_object()) { - fprintf(stderr,"WARNING: unable to parse local.conf (root element is not a JSON object)" ZT_EOL_S); - } - } catch ( ... ) { - fprintf(stderr,"WARNING: unable to parse local.conf (invalid JSON)" ZT_EOL_S); - } - } - - // Get any trusted paths in local.conf (we'll parse the rest of physical[] elsewhere) - json &physical = _localConfig["physical"]; - if (physical.is_object()) { - for(json::iterator phy(physical.begin());phy!=physical.end();++phy) { - InetAddress net(OSUtils::jsonString(phy.key(),"")); - if (net) { - if (phy.value().is_object()) { - uint64_t tpid; - if ((tpid = OSUtils::jsonInt(phy.value()["trustedPathId"],0ULL)) != 0ULL) { - if ( ((net.ss_family == AF_INET)||(net.ss_family == AF_INET6)) && (trustedPathCount < ZT_MAX_TRUSTED_PATHS) && (net.ipScope() != InetAddress::IP_SCOPE_GLOBAL) && (net.netmaskBits() > 0) ) { - trustedPathIds[trustedPathCount] = tpid; - trustedPathNetworks[trustedPathCount] = net; - ++trustedPathCount; - } - } - } - } - } - } - - // Set trusted paths if there are any - if (trustedPathCount) - _node->setTrustedPaths(reinterpret_cast(trustedPathNetworks),trustedPathIds,trustedPathCount); - } - applyLocalConfig(); - - // Bind TCP control socket - const int portTrials = (_primaryPort == 0) ? 256 : 1; // if port is 0, pick random - for(int k=0;k 0) ? 0 : 0x7f000001)); // right now we just listen for TCP @127.0.0.1 - in4.sin_port = Utils::hton((uint16_t)_primaryPort); - _v4TcpControlSocket = _phy.tcpListen((const struct sockaddr *)&in4,this); - - struct sockaddr_in6 in6; - memset((void *)&in6,0,sizeof(in6)); - in6.sin6_family = AF_INET6; - in6.sin6_port = in4.sin_port; - if (_allowManagementFrom.size() == 0) - in6.sin6_addr.s6_addr[15] = 1; // IPv6 localhost == ::1 - _v6TcpControlSocket = _phy.tcpListen((const struct sockaddr *)&in6,this); - - // We must bind one of IPv4 or IPv6 -- support either failing to support hosts that - // have only IPv4 or only IPv6 stacks. - if ((_v4TcpControlSocket)||(_v6TcpControlSocket)) { - _ports[0] = _primaryPort; - break; - } else { - if (_v4TcpControlSocket) - _phy.close(_v4TcpControlSocket,false); - if (_v6TcpControlSocket) - _phy.close(_v6TcpControlSocket,false); - _primaryPort = 0; - } - } else { - _primaryPort = 0; - } - } - if (_ports[0] == 0) { - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = "cannot bind to local control interface port"; - return _termReason; - } - - // Write file containing primary port to be read by CLIs, etc. - char portstr[64]; - Utils::snprintf(portstr,sizeof(portstr),"%u",_ports[0]); - OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S "zerotier-one.port").c_str(),std::string(portstr)); - - // Attempt to bind to a secondary port chosen from our ZeroTier address. - // This exists because there are buggy NATs out there that fail if more - // than one device behind the same NAT tries to use the same internal - // private address port number. - _ports[1] = 20000 + ((unsigned int)_node->address() % 45500); - for(int i=0;;++i) { - if (i > 1000) { - _ports[1] = 0; - break; - } else if (++_ports[1] >= 65536) { - _ports[1] = 20000; - } - if (_trialBind(_ports[1])) - break; - } - -#ifdef ZT_USE_MINIUPNPC - if (_portMappingEnabled) { - // If we're running uPnP/NAT-PMP, bind a *third* port for that. We can't - // use the other two ports for that because some NATs do really funky - // stuff with ports that are explicitly mapped that breaks things. - if (_ports[1]) { - _ports[2] = _ports[1]; - for(int i=0;;++i) { - if (i > 1000) { - _ports[2] = 0; - break; - } else if (++_ports[2] >= 65536) { - _ports[2] = 20000; - } - if (_trialBind(_ports[2])) - break; - } - if (_ports[2]) { - char uniqueName[64]; - Utils::snprintf(uniqueName,sizeof(uniqueName),"ZeroTier/%.10llx@%u",_node->address(),_ports[2]); - _portMapper = new PortMapper(_ports[2],uniqueName); - } - } - } -#endif - - // Populate ports in big-endian format for quick compare - for(int i=0;i<3;++i) - _portsBE[i] = Utils::hton((uint16_t)_ports[i]); - - _controller = new EmbeddedNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S ZT_CONTROLLER_DB_PATH).c_str()); - _node->setNetconfMaster((void *)_controller); - -#ifdef ZT_ENABLE_CLUSTER - if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S "cluster").c_str())) { - _clusterDefinition = new ClusterDefinition(_node->address(),(_homePath + ZT_PATH_SEPARATOR_S "cluster").c_str()); - if (_clusterDefinition->size() > 0) { - std::vector members(_clusterDefinition->members()); - for(std::vector::iterator m(members.begin());m!=members.end();++m) { - PhySocket *cs = _phy.udpBind(reinterpret_cast(&(m->clusterEndpoint))); - if (cs) { - if (_clusterMessageSocket) { - _phy.close(_clusterMessageSocket,false); - _phy.close(cs,false); - - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = "cluster: can't determine my cluster member ID: able to bind more than one cluster message socket IP/port!"; - return _termReason; - } - _clusterMessageSocket = cs; - _clusterMemberId = m->id; - } - } - - if (!_clusterMessageSocket) { - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = "cluster: can't determine my cluster member ID: unable to bind to any cluster message socket IP/port."; - return _termReason; - } - - const ClusterDefinition::MemberDefinition &me = (*_clusterDefinition)[_clusterMemberId]; - InetAddress endpoints[255]; - unsigned int numEndpoints = 0; - for(std::vector::const_iterator i(me.zeroTierEndpoints.begin());i!=me.zeroTierEndpoints.end();++i) - endpoints[numEndpoints++] = *i; - - if (_node->clusterInit(_clusterMemberId,reinterpret_cast(endpoints),numEndpoints,me.x,me.y,me.z,&SclusterSendFunction,this,_clusterDefinition->geo().available() ? &SclusterGeoIpFunction : 0,this) == ZT_RESULT_OK) { - std::vector members(_clusterDefinition->members()); - for(std::vector::iterator m(members.begin());m!=members.end();++m) { - if (m->id != _clusterMemberId) - _node->clusterAddMember(m->id); - } - } - } else { - delete _clusterDefinition; - _clusterDefinition = (ClusterDefinition *)0; - } - } -#endif - - { // Load existing networks - std::vector networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "networks.d").c_str())); - for(std::vector::iterator f(networksDotD.begin());f!=networksDotD.end();++f) { - std::size_t dot = f->find_last_of('.'); - if ((dot == 16)&&(f->substr(16) == ".conf")) - _node->join(Utils::hexStrToU64(f->substr(0,dot).c_str()),(void *)0,(void *)0); - } - } - { // Load existing moons - std::vector moonsDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "moons.d").c_str())); - for(std::vector::iterator f(moonsDotD.begin());f!=moonsDotD.end();++f) { - std::size_t dot = f->find_last_of('.'); - if ((dot == 16)&&(f->substr(16) == ".moon")) - _node->orbit((void *)0,Utils::hexStrToU64(f->substr(0,dot).c_str()),0); - } - } - - _nextBackgroundTaskDeadline = 0; - uint64_t clockShouldBe = OSUtils::now(); - _lastRestart = clockShouldBe; - uint64_t lastTapMulticastGroupCheck = 0; - uint64_t lastBindRefresh = 0; - uint64_t lastUpdateCheck = clockShouldBe; - uint64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle - uint64_t lastCleanedIddb = 0; - for(;;) { - _run_m.lock(); - if (!_run) { - _run_m.unlock(); - _termReason_m.lock(); - _termReason = ONE_NORMAL_TERMINATION; - _termReason_m.unlock(); - break; - } else { - _run_m.unlock(); - } - - const uint64_t now = OSUtils::now(); - - // Clean iddb.d on start and every 24 hours - if ((now - lastCleanedIddb) > 86400000) { - lastCleanedIddb = now; - OSUtils::cleanDirectory((_homePath + ZT_PATH_SEPARATOR_S "iddb.d").c_str(),now - ZT_IDDB_CLEANUP_AGE); - } - - // Attempt to detect sleep/wake events by detecting delay overruns - bool restarted = false; - if ((now > clockShouldBe)&&((now - clockShouldBe) > 10000)) { - _lastRestart = now; - restarted = true; - } - - // Check for updates (if enabled) - if ((_updater)&&((now - lastUpdateCheck) > 10000)) { - lastUpdateCheck = now; - if (_updater->check(now) && _updateAutoApply) - _updater->apply(); - } - - // Refresh bindings in case device's interfaces have changed, and also sync routes to update any shadow routes (e.g. shadow default) - if (((now - lastBindRefresh) >= ZT_BINDER_REFRESH_PERIOD)||(restarted)) { - lastBindRefresh = now; - for(int i=0;i<3;++i) { - if (_ports[i]) { - _bindings[i].refresh(_phy,_ports[i],*this); - } - } - { - Mutex::Lock _l(_nets_m); - for(std::map::iterator n(_nets.begin());n!=_nets.end();++n) { - if (n->second.tap) - syncManagedStuff(n->second,false,true); - } - } - } - - uint64_t dl = _nextBackgroundTaskDeadline; - if (dl <= now) { - _node->processBackgroundTasks((void *)0,now,&_nextBackgroundTaskDeadline); - dl = _nextBackgroundTaskDeadline; - } - - if ((_tcpFallbackTunnel)&&((now - _lastDirectReceiveFromGlobal) < (ZT_TCP_FALLBACK_AFTER / 2))) - _phy.close(_tcpFallbackTunnel->sock); - - if ((now - lastTapMulticastGroupCheck) >= ZT_TAP_CHECK_MULTICAST_INTERVAL) { - lastTapMulticastGroupCheck = now; - Mutex::Lock _l(_nets_m); - for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { - if (n->second.tap) { - std::vector added,removed; - n->second.tap->scanMulticastGroups(added,removed); - for(std::vector::iterator m(added.begin());m!=added.end();++m) - _node->multicastSubscribe((void *)0,n->first,m->mac().toInt(),m->adi()); - for(std::vector::iterator m(removed.begin());m!=removed.end();++m) - _node->multicastUnsubscribe(n->first,m->mac().toInt(),m->adi()); - } - } - } - - if ((now - lastLocalInterfaceAddressCheck) >= ZT_LOCAL_INTERFACE_CHECK_INTERVAL) { - lastLocalInterfaceAddressCheck = now; - - _node->clearLocalInterfaceAddresses(); - -#ifdef ZT_USE_MINIUPNPC - if (_portMapper) { - std::vector mappedAddresses(_portMapper->get()); - for(std::vector::const_iterator ext(mappedAddresses.begin());ext!=mappedAddresses.end();++ext) - _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext))); - } -#endif - - std::vector boundAddrs(_bindings[0].allBoundLocalInterfaceAddresses()); - for(std::vector::const_iterator i(boundAddrs.begin());i!=boundAddrs.end();++i) - _node->addLocalInterfaceAddress(reinterpret_cast(&(*i))); - } - - const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 100; - clockShouldBe = now + (uint64_t)delay; - _phy.poll(delay); - } - } catch (std::exception &exc) { - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = exc.what(); - } catch ( ... ) { - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = "unexpected exception in main thread"; - } - - try { - while (!_tcpConnections.empty()) - _phy.close((*_tcpConnections.begin())->sock); - } catch ( ... ) {} - - { - Mutex::Lock _l(_nets_m); - for(std::map::iterator n(_nets.begin());n!=_nets.end();++n) - delete n->second.tap; - _nets.clear(); - } - - delete _updater; - _updater = (SoftwareUpdater *)0; - delete _node; - _node = (Node *)0; - - return _termReason; - } - - virtual ReasonForTermination reasonForTermination() const - { - Mutex::Lock _l(_termReason_m); - return _termReason; - } - - virtual std::string fatalErrorMessage() const - { - Mutex::Lock _l(_termReason_m); - return _fatalErrorMessage; - } - - virtual std::string portDeviceName(uint64_t nwid) const - { - Mutex::Lock _l(_nets_m); - std::map::const_iterator n(_nets.find(nwid)); - if ((n != _nets.end())&&(n->second.tap)) - return n->second.tap->deviceName(); - else return std::string(); - } - - virtual void terminate() - { - _run_m.lock(); - _run = false; - _run_m.unlock(); - _phy.whack(); - } - -#ifdef ZT_SDK - virtual void leave(const char *hp) - { - _node->leave(Utils::hexStrToU64(hp),NULL, NULL); - } - - virtual void join(const char *hp) - { - _node->join(Utils::hexStrToU64(hp),NULL, NULL); - } - - virtual std::string givenHomePath() - { - return _homePath; - } - - virtual EthernetTap * getTap(uint64_t nwid) - { - Mutex::Lock _l(_nets_m); - std::map::const_iterator n(_nets.find(nwid)); - if (n == _nets.end()) - return NULL; - return n->second.tap; - } - - virtual Node * getNode() - { - return _node; - } -#endif // ZT_SDK - - virtual bool getNetworkSettings(const uint64_t nwid,NetworkSettings &settings) const - { - Mutex::Lock _l(_nets_m); - std::map::const_iterator n(_nets.find(nwid)); - if (n == _nets.end()) - return false; - memcpy(&settings,&(n->second.settings),sizeof(NetworkSettings)); - return true; - } - - virtual bool setNetworkSettings(const uint64_t nwid,const NetworkSettings &settings) - { - Mutex::Lock _l(_nets_m); - - std::map::iterator n(_nets.find(nwid)); - if (n == _nets.end()) - return false; - memcpy(&(n->second.settings),&settings,sizeof(NetworkSettings)); - - char nlcpath[256]; - Utils::snprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid); - FILE *out = fopen(nlcpath,"w"); - if (out) { - fprintf(out,"allowManaged=%d\n",(int)n->second.settings.allowManaged); - fprintf(out,"allowGlobal=%d\n",(int)n->second.settings.allowGlobal); - fprintf(out,"allowDefault=%d\n",(int)n->second.settings.allowDefault); - fclose(out); - } - - if (n->second.tap) - syncManagedStuff(n->second,true,true); - - return true; - } - - // Internal implementation methods ----------------------------------------- - - inline unsigned int handleControlPlaneHttpRequest( - const InetAddress &fromAddress, - unsigned int httpMethod, - const std::string &path, - const std::map &headers, - const std::string &body, - std::string &responseBody, - std::string &responseContentType) - { - char tmp[256]; - unsigned int scode = 404; - json res; - std::vector ps(OSUtils::split(path.c_str(),"/","","")); - std::map urlArgs; - - /* Note: this is kind of restricted in what it'll take. It does not support - * URL encoding, and /'s in URL args will screw it up. But the only URL args - * it really uses in ?jsonp=funcionName, and otherwise it just takes simple - * paths to simply-named resources. */ - if (ps.size() > 0) { - std::size_t qpos = ps[ps.size() - 1].find('?'); - if (qpos != std::string::npos) { - std::string args(ps[ps.size() - 1].substr(qpos + 1)); - ps[ps.size() - 1] = ps[ps.size() - 1].substr(0,qpos); - std::vector asplit(OSUtils::split(args.c_str(),"&","","")); - for(std::vector::iterator a(asplit.begin());a!=asplit.end();++a) { - std::size_t eqpos = a->find('='); - if (eqpos == std::string::npos) - urlArgs[*a] = ""; - else urlArgs[a->substr(0,eqpos)] = a->substr(eqpos + 1); - } - } - } - - bool isAuth = false; - { - std::map::const_iterator ah(headers.find("x-zt1-auth")); - if ((ah != headers.end())&&(_authToken == ah->second)) { - isAuth = true; - } else { - ah = urlArgs.find("auth"); - if ((ah != urlArgs.end())&&(_authToken == ah->second)) - isAuth = true; - } - } - -#ifdef __SYNOLOGY__ - // Authenticate via Synology's built-in cgi script - if (!isAuth) { - /* - fprintf(stderr, "path = %s\n", path.c_str()); - fprintf(stderr, "headers.size=%d\n", headers.size()); - std::map::const_iterator it(headers.begin()); - while(it != headers.end()) { - fprintf(stderr,"header[%s] = %s\n", (it->first).c_str(), (it->second).c_str()); - it++; - } - */ - // parse out url args - int synotoken_pos = path.find("SynoToken"); - int argpos = path.find("?"); - if(synotoken_pos != std::string::npos && argpos != std::string::npos) { - std::string cookie = path.substr(argpos+1, synotoken_pos-(argpos+1)); - std::string synotoken = path.substr(synotoken_pos); - std::string cookie_val = cookie.substr(cookie.find("=")+1); - std::string synotoken_val = synotoken.substr(synotoken.find("=")+1); - // Set necessary env for auth script - std::map::const_iterator ah2(headers.find("x-forwarded-for")); - setenv("HTTP_COOKIE", cookie_val.c_str(), true); - setenv("HTTP_X_SYNO_TOKEN", synotoken_val.c_str(), true); - setenv("REMOTE_ADDR", ah2->second.c_str(),true); - //fprintf(stderr, "HTTP_COOKIE: %s\n",std::getenv ("HTTP_COOKIE")); - //fprintf(stderr, "HTTP_X_SYNO_TOKEN: %s\n",std::getenv ("HTTP_X_SYNO_TOKEN")); - //fprintf(stderr, "REMOTE_ADDR: %s\n",std::getenv ("REMOTE_ADDR")); - // check synology web auth - char user[256], buf[1024]; - FILE *fp = NULL; - bzero(user, 256); - fp = popen("/usr/syno/synoman/webman/modules/authenticate.cgi", "r"); - if(!fp) - isAuth = false; - else { - bzero(buf, sizeof(buf)); - fread(buf, 1024, 1, fp); - if(strlen(buf) > 0) { - snprintf(user, 256, "%s", buf); - isAuth = true; - } - } - pclose(fp); - } - } -#endif - - if (httpMethod == HTTP_GET) { - if (isAuth) { - if (ps[0] == "status") { - ZT_NodeStatus status; - _node->status(&status); - - Utils::snprintf(tmp,sizeof(tmp),"%.10llx",status.address); - res["address"] = tmp; - res["publicIdentity"] = status.publicIdentity; - res["online"] = (bool)(status.online != 0); - res["tcpFallbackActive"] = (_tcpFallbackTunnel != (TcpConnection *)0); - res["versionMajor"] = ZEROTIER_ONE_VERSION_MAJOR; - res["versionMinor"] = ZEROTIER_ONE_VERSION_MINOR; - res["versionRev"] = ZEROTIER_ONE_VERSION_REVISION; - res["versionBuild"] = ZEROTIER_ONE_VERSION_BUILD; - Utils::snprintf(tmp,sizeof(tmp),"%d.%d.%d",ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION); - res["version"] = tmp; - res["clock"] = OSUtils::now(); - - { - Mutex::Lock _l(_localConfig_m); - res["config"] = _localConfig; - } - json &settings = res["config"]["settings"]; - settings["primaryPort"] = OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff; -#ifdef ZT_USE_MINIUPNPC - settings["portMappingEnabled"] = OSUtils::jsonBool(settings["portMappingEnabled"],true); -#else - settings["portMappingEnabled"] = false; // not supported in build -#endif - /* - settings["softwareUpdate"] = OSUtils::jsonString(settings["softwareUpdate"],ZT_SOFTWARE_UPDATE_DEFAULT); - settings["softwareUpdateChannel"] = OSUtils::jsonString(settings["softwareUpdateChannel"],ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL); - */ - const World planet(_node->planet()); - res["planetWorldId"] = planet.id(); - res["planetWorldTimestamp"] = planet.timestamp(); - -#ifdef ZT_ENABLE_CLUSTER - json cj; - ZT_ClusterStatus cs; - _node->clusterStatus(&cs); - if (cs.clusterSize >= 1) { - json cja = json::array(); - for(unsigned int i=0;i moons(_node->moons()); - if (ps.size() == 1) { - // Return [array] of all moons - - res = json::array(); - for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { - json mj; - _moonToJson(mj,*m); - res.push_back(mj); - } - - scode = 200; - } else { - // Return a single moon by ID - - const uint64_t id = Utils::hexStrToU64(ps[1].c_str()); - for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { - if (m->id() == id) { - _moonToJson(res,*m); - scode = 200; - break; - } - } - - } - } else if (ps[0] == "network") { - ZT_VirtualNetworkList *nws = _node->networks(); - if (nws) { - if (ps.size() == 1) { - // Return [array] of all networks - - res = nlohmann::json::array(); - for(unsigned long i=0;inetworkCount;++i) { - OneService::NetworkSettings localSettings; - getNetworkSettings(nws->networks[i].nwid,localSettings); - nlohmann::json nj; - _networkToJson(nj,&(nws->networks[i]),portDeviceName(nws->networks[i].nwid),localSettings); - res.push_back(nj); - } - - scode = 200; - } else if (ps.size() == 2) { - // Return a single network by ID or 404 if not found - - const uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); - for(unsigned long i=0;inetworkCount;++i) { - if (nws->networks[i].nwid == wantnw) { - OneService::NetworkSettings localSettings; - getNetworkSettings(nws->networks[i].nwid,localSettings); - _networkToJson(res,&(nws->networks[i]),portDeviceName(nws->networks[i].nwid),localSettings); - scode = 200; - break; - } - } - - } else scode = 404; - _node->freeQueryResult((void *)nws); - } else scode = 500; - } else if (ps[0] == "peer") { - ZT_PeerList *pl = _node->peers(); - if (pl) { - if (ps.size() == 1) { - // Return [array] of all peers - - res = nlohmann::json::array(); - for(unsigned long i=0;ipeerCount;++i) { - nlohmann::json pj; - _peerToJson(pj,&(pl->peers[i])); - res.push_back(pj); - } - - scode = 200; - } else if (ps.size() == 2) { - // Return a single peer by ID or 404 if not found - - uint64_t wantp = Utils::hexStrToU64(ps[1].c_str()); - for(unsigned long i=0;ipeerCount;++i) { - if (pl->peers[i].address == wantp) { - _peerToJson(res,&(pl->peers[i])); - scode = 200; - break; - } - } - - } else scode = 404; - _node->freeQueryResult((void *)pl); - } else scode = 500; - } else { - if (_controller) { - scode = _controller->handleControlPlaneHttpGET(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType); - } else scode = 404; - } - - } else scode = 401; // isAuth == false - } else if ((httpMethod == HTTP_POST)||(httpMethod == HTTP_PUT)) { - if (isAuth) { - - if (ps[0] == "moon") { - if (ps.size() == 2) { - - uint64_t seed = 0; - try { - json j(OSUtils::jsonParse(body)); - if (j.is_object()) { - seed = Utils::hexStrToU64(OSUtils::jsonString(j["seed"],"0").c_str()); - } - } catch ( ... ) { - // discard invalid JSON - } - - std::vector moons(_node->moons()); - const uint64_t id = Utils::hexStrToU64(ps[1].c_str()); - for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { - if (m->id() == id) { - _moonToJson(res,*m); - scode = 200; - break; - } - } - - if ((scode != 200)&&(seed != 0)) { - char tmp[64]; - Utils::snprintf(tmp,sizeof(tmp),"%.16llx",id); - res["id"] = tmp; - res["roots"] = json::array(); - res["timestamp"] = 0; - res["signature"] = json(); - res["updatesMustBeSignedBy"] = json(); - res["waiting"] = true; - _node->orbit((void *)0,id,seed); - scode = 200; - } - - } else scode = 404; - } else if (ps[0] == "network") { - if (ps.size() == 2) { - - uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); - _node->join(wantnw,(void *)0,(void *)0); // does nothing if we are a member - ZT_VirtualNetworkList *nws = _node->networks(); - if (nws) { - for(unsigned long i=0;inetworkCount;++i) { - if (nws->networks[i].nwid == wantnw) { - OneService::NetworkSettings localSettings; - getNetworkSettings(nws->networks[i].nwid,localSettings); - - try { - json j(OSUtils::jsonParse(body)); - if (j.is_object()) { - json &allowManaged = j["allowManaged"]; - if (allowManaged.is_boolean()) localSettings.allowManaged = (bool)allowManaged; - json &allowGlobal = j["allowGlobal"]; - if (allowGlobal.is_boolean()) localSettings.allowGlobal = (bool)allowGlobal; - json &allowDefault = j["allowDefault"]; - if (allowDefault.is_boolean()) localSettings.allowDefault = (bool)allowDefault; - } - } catch ( ... ) { - // discard invalid JSON - } - - setNetworkSettings(nws->networks[i].nwid,localSettings); - _networkToJson(res,&(nws->networks[i]),portDeviceName(nws->networks[i].nwid),localSettings); - - scode = 200; - break; - } - } - _node->freeQueryResult((void *)nws); - } else scode = 500; - - } else scode = 404; - } else { - if (_controller) - scode = _controller->handleControlPlaneHttpPOST(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType); - else scode = 404; - } - - } else scode = 401; // isAuth == false - } else if (httpMethod == HTTP_DELETE) { - if (isAuth) { - - if (ps[0] == "moon") { - if (ps.size() == 2) { - _node->deorbit((void *)0,Utils::hexStrToU64(ps[1].c_str())); - res["result"] = true; - scode = 200; - } // else 404 - } else if (ps[0] == "network") { - ZT_VirtualNetworkList *nws = _node->networks(); - if (nws) { - if (ps.size() == 2) { - uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); - for(unsigned long i=0;inetworkCount;++i) { - if (nws->networks[i].nwid == wantnw) { - _node->leave(wantnw,(void **)0,(void *)0); - res["result"] = true; - scode = 200; - break; - } - } - } // else 404 - _node->freeQueryResult((void *)nws); - } else scode = 500; - } else { - if (_controller) - scode = _controller->handleControlPlaneHttpDELETE(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType); - else scode = 404; - } - - } else scode = 401; // isAuth = false - } else { - scode = 400; - } - - if (responseBody.length() == 0) { - if ((res.is_object())||(res.is_array())) - responseBody = OSUtils::jsonDump(res); - else responseBody = "{}"; - responseContentType = "application/json"; - } - - // Wrap result in jsonp function call if the user included a jsonp= url argument. - // Also double-check isAuth since forbidding this without auth feels safer. - std::map::const_iterator jsonp(urlArgs.find("jsonp")); - if ((isAuth)&&(jsonp != urlArgs.end())&&(responseContentType == "application/json")) { - if (responseBody.length() > 0) - responseBody = jsonp->second + "(" + responseBody + ");"; - else responseBody = jsonp->second + "(null);"; - responseContentType = "application/javascript"; - } - - return scode; - } - - // Must be called after _localConfig is read or modified - void applyLocalConfig() - { - Mutex::Lock _l(_localConfig_m); - json lc(_localConfig); - - _v4Hints.clear(); - _v6Hints.clear(); - _v4Blacklists.clear(); - _v6Blacklists.clear(); - json &virt = lc["virtual"]; - if (virt.is_object()) { - for(json::iterator v(virt.begin());v!=virt.end();++v) { - const std::string nstr = v.key(); - if ((nstr.length() == ZT_ADDRESS_LENGTH_HEX)&&(v.value().is_object())) { - const Address ztaddr(Utils::hexStrToU64(nstr.c_str())); - if (ztaddr) { - const uint64_t ztaddr2 = ztaddr.toInt(); - std::vector &v4h = _v4Hints[ztaddr2]; - std::vector &v6h = _v6Hints[ztaddr2]; - std::vector &v4b = _v4Blacklists[ztaddr2]; - std::vector &v6b = _v6Blacklists[ztaddr2]; - - json &tryAddrs = v.value()["try"]; - if (tryAddrs.is_array()) { - for(unsigned long i=0;i 0)) { - if (phy.value().is_object()) { - if (OSUtils::jsonBool(phy.value()["blacklist"],false)) { - if (net.ss_family == AF_INET) - _globalV4Blacklist.push_back(net); - else if (net.ss_family == AF_INET6) - _globalV6Blacklist.push_back(net); - } - } - } - } - } - - _allowManagementFrom.clear(); - _interfacePrefixBlacklist.clear(); - - json &settings = lc["settings"]; - - _primaryPort = (unsigned int)OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff; - _portMappingEnabled = OSUtils::jsonBool(settings["portMappingEnabled"],true); -/* - const std::string up(OSUtils::jsonString(settings["softwareUpdate"],ZT_SOFTWARE_UPDATE_DEFAULT)); - const bool udist = OSUtils::jsonBool(settings["softwareUpdateDist"],false); - if (((up == "apply")||(up == "download"))||(udist)) { - if (!_updater) - _updater = new SoftwareUpdater(*_node,_homePath); - _updateAutoApply = (up == "apply"); - _updater->setUpdateDistribution(udist); - _updater->setChannel(OSUtils::jsonString(settings["softwareUpdateChannel"],ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL)); - } else { - delete _updater; - _updater = (SoftwareUpdater *)0; - _updateAutoApply = false; - } -*/ - json &ignoreIfs = settings["interfacePrefixBlacklist"]; - if (ignoreIfs.is_array()) { - for(unsigned long i=0;i 0) - _interfacePrefixBlacklist.push_back(tmp); - } - } - - json &amf = settings["allowManagementFrom"]; - if (amf.is_array()) { - for(unsigned long i=0;i 0) { - bool allowed = false; - for (InetAddress addr : n.settings.allowManagedWhitelist) { - if (addr.containsAddress(target) && addr.netmaskBits() <= target.netmaskBits()) { - allowed = true; - break; - } - } - if (!allowed) return false; - } - - if (target.isDefaultRoute()) - return n.settings.allowDefault; - switch(target.ipScope()) { - case InetAddress::IP_SCOPE_NONE: - case InetAddress::IP_SCOPE_MULTICAST: - case InetAddress::IP_SCOPE_LOOPBACK: - case InetAddress::IP_SCOPE_LINK_LOCAL: - return false; - case InetAddress::IP_SCOPE_GLOBAL: - return n.settings.allowGlobal; - default: - return true; - } - } - - // Match only an IP from a vector of IPs -- used in syncManagedStuff() - bool matchIpOnly(const std::vector &ips,const InetAddress &ip) const - { - for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { - if (i->ipsEqual(ip)) - return true; - } - return false; - } - - // Apply or update managed IPs for a configured network (be sure n.tap exists) - void syncManagedStuff(NetworkState &n,bool syncIps,bool syncRoutes) - { - // assumes _nets_m is locked - if (syncIps) { - std::vector newManagedIps; - newManagedIps.reserve(n.config.assignedAddressCount); - for(unsigned int i=0;i(&(n.config.assignedAddresses[i])); - if (checkIfManagedIsAllowed(n,*ii)) - newManagedIps.push_back(*ii); - } - std::sort(newManagedIps.begin(),newManagedIps.end()); - newManagedIps.erase(std::unique(newManagedIps.begin(),newManagedIps.end()),newManagedIps.end()); - - for(std::vector::iterator ip(n.managedIps.begin());ip!=n.managedIps.end();++ip) { - if (std::find(newManagedIps.begin(),newManagedIps.end(),*ip) == newManagedIps.end()) { - if (!n.tap->removeIp(*ip)) - fprintf(stderr,"ERROR: unable to remove ip address %s" ZT_EOL_S, ip->toString().c_str()); - } - } -#ifdef __SYNOLOGY__ - if (!n.tap->addIpSyn(newManagedIps)) - fprintf(stderr,"ERROR: unable to add ip addresses to ifcfg" ZT_EOL_S); -#else - for(std::vector::iterator ip(newManagedIps.begin());ip!=newManagedIps.end();++ip) { - if (std::find(n.managedIps.begin(),n.managedIps.end(),*ip) == n.managedIps.end()) { - if (!n.tap->addIp(*ip)) - fprintf(stderr,"ERROR: unable to add ip address %s" ZT_EOL_S, ip->toString().c_str()); - } - } -#endif - n.managedIps.swap(newManagedIps); - } - - if (syncRoutes) { - char tapdev[64]; -#ifdef __WINDOWS__ - Utils::snprintf(tapdev,sizeof(tapdev),"%.16llx",(unsigned long long)n.tap->luid().Value); -#else - Utils::scopy(tapdev,sizeof(tapdev),n.tap->deviceName().c_str()); -#endif - - std::vector myIps(n.tap->ips()); - - // Nuke applied routes that are no longer in n.config.routes[] and/or are not allowed - for(std::list< SharedPtr >::iterator mr(n.managedRoutes.begin());mr!=n.managedRoutes.end();) { - bool haveRoute = false; - if ( (checkIfManagedIsAllowed(n,(*mr)->target())) && (((*mr)->via().ss_family != (*mr)->target().ss_family)||(!matchIpOnly(myIps,(*mr)->via()))) ) { - for(unsigned int i=0;i(&(n.config.routes[i].target)); - const InetAddress *const via = reinterpret_cast(&(n.config.routes[i].via)); - if ( ((*mr)->target() == *target) && ( ((via->ss_family == target->ss_family)&&((*mr)->via().ipsEqual(*via))) || (tapdev == (*mr)->device()) ) ) { - haveRoute = true; - break; - } - } - } - if (haveRoute) { - ++mr; - } else { - n.managedRoutes.erase(mr++); - } - } - - // Apply routes in n.config.routes[] that we haven't applied yet, and sync those we have in case shadow routes need to change - for(unsigned int i=0;i(&(n.config.routes[i].target)); - const InetAddress *const via = reinterpret_cast(&(n.config.routes[i].via)); - - if ( (!checkIfManagedIsAllowed(n,*target)) || ((via->ss_family == target->ss_family)&&(matchIpOnly(myIps,*via))) ) - continue; - - bool haveRoute = false; - - // Ignore routes implied by local managed IPs since adding the IP adds the route - for(std::vector::iterator ip(n.managedIps.begin());ip!=n.managedIps.end();++ip) { - if ((target->netmaskBits() == ip->netmaskBits())&&(target->containsAddress(*ip))) { - haveRoute = true; - break; - } - } - if (haveRoute) - continue; - - // If we've already applied this route, just sync it and continue - for(std::list< SharedPtr >::iterator mr(n.managedRoutes.begin());mr!=n.managedRoutes.end();++mr) { - if ( ((*mr)->target() == *target) && ( ((via->ss_family == target->ss_family)&&((*mr)->via().ipsEqual(*via))) || (tapdev == (*mr)->device()) ) ) { - haveRoute = true; - (*mr)->sync(); - break; - } - } - if (haveRoute) - continue; - - // Add and apply new routes - n.managedRoutes.push_back(SharedPtr(new ManagedRoute(*target,*via,tapdev))); - if (!n.managedRoutes.back()->sync()) - n.managedRoutes.pop_back(); - } - } - } - - // ========================================================================= - // Handlers for Node and Phy<> callbacks - // ========================================================================= - - inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) - { -#ifdef ZT_ENABLE_CLUSTER - if (sock == _clusterMessageSocket) { - _lastDirectReceiveFromGlobal = OSUtils::now(); - _node->clusterHandleIncomingMessage(data,len); - return; - } -#endif - -#ifdef ZT_BREAK_UDP - if (OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) - return; -#endif - - if ((len >= 16)&&(reinterpret_cast(from)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) - _lastDirectReceiveFromGlobal = OSUtils::now(); - - const ZT_ResultCode rc = _node->processWirePacket( - (void *)0, - OSUtils::now(), - reinterpret_cast(localAddr), - (const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big - data, - len, - &_nextBackgroundTaskDeadline); - if (ZT_ResultCode_isFatal(rc)) { - char tmp[256]; - Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = tmp; - this->terminate(); - } - } - - inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) - { - if (!success) - return; - - // Outgoing TCP connections are always TCP fallback tunnel connections. - - TcpConnection *tc = new TcpConnection(); - _tcpConnections.insert(tc); - - tc->type = TcpConnection::TCP_TUNNEL_OUTGOING; - tc->shouldKeepAlive = true; - tc->parent = this; - tc->sock = sock; - // from and parser are not used - tc->messageSize = 0; // unused - tc->lastActivity = OSUtils::now(); - // HTTP stuff is not used - tc->writeBuf = ""; - *uptr = (void *)tc; - - // Send "hello" message - tc->writeBuf.push_back((char)0x17); - tc->writeBuf.push_back((char)0x03); - tc->writeBuf.push_back((char)0x03); // fake TLS 1.2 header - tc->writeBuf.push_back((char)0x00); - tc->writeBuf.push_back((char)0x04); // mlen == 4 - tc->writeBuf.push_back((char)ZEROTIER_ONE_VERSION_MAJOR); - tc->writeBuf.push_back((char)ZEROTIER_ONE_VERSION_MINOR); - tc->writeBuf.push_back((char)((ZEROTIER_ONE_VERSION_REVISION >> 8) & 0xff)); - tc->writeBuf.push_back((char)(ZEROTIER_ONE_VERSION_REVISION & 0xff)); - _phy.setNotifyWritable(sock,true); - - _tcpFallbackTunnel = tc; - } - - inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) - { - if (!from) { - _phy.close(sockN,false); - return; - } else { - TcpConnection *tc = new TcpConnection(); - _tcpConnections.insert(tc); - tc->type = TcpConnection::TCP_HTTP_INCOMING; - tc->shouldKeepAlive = true; - tc->parent = this; - tc->sock = sockN; - tc->from = from; - http_parser_init(&(tc->parser),HTTP_REQUEST); - tc->parser.data = (void *)tc; - tc->messageSize = 0; - tc->lastActivity = OSUtils::now(); - tc->currentHeaderField = ""; - tc->currentHeaderValue = ""; - tc->url = ""; - tc->status = ""; - tc->headers.clear(); - tc->body = ""; - tc->writeBuf = ""; - *uptrN = (void *)tc; - } - } - - inline void phyOnTcpClose(PhySocket *sock,void **uptr) - { - TcpConnection *tc = (TcpConnection *)*uptr; - if (tc) { - if (tc == _tcpFallbackTunnel) - _tcpFallbackTunnel = (TcpConnection *)0; - _tcpConnections.erase(tc); - delete tc; - } - } - - inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) - { - TcpConnection *tc = reinterpret_cast(*uptr); - switch(tc->type) { - - case TcpConnection::TCP_HTTP_INCOMING: - case TcpConnection::TCP_HTTP_OUTGOING: - http_parser_execute(&(tc->parser),&HTTP_PARSER_SETTINGS,(const char *)data,len); - if ((tc->parser.upgrade)||(tc->parser.http_errno != HPE_OK)) { - _phy.close(sock); - return; - } - break; - - case TcpConnection::TCP_TUNNEL_OUTGOING: - tc->body.append((const char *)data,len); - while (tc->body.length() >= 5) { - const char *data = tc->body.data(); - const unsigned long mlen = ( ((((unsigned long)data[3]) & 0xff) << 8) | (((unsigned long)data[4]) & 0xff) ); - if (tc->body.length() >= (mlen + 5)) { - InetAddress from; - - unsigned long plen = mlen; // payload length, modified if there's an IP header - data += 5; // skip forward past pseudo-TLS junk and mlen - if (plen == 4) { - // Hello message, which isn't sent by proxy and would be ignored by client - } else if (plen) { - // Messages should contain IPv4 or IPv6 source IP address data - switch(data[0]) { - case 4: // IPv4 - if (plen >= 7) { - from.set((const void *)(data + 1),4,((((unsigned int)data[5]) & 0xff) << 8) | (((unsigned int)data[6]) & 0xff)); - data += 7; // type + 4 byte IP + 2 byte port - plen -= 7; - } else { - _phy.close(sock); - return; - } - break; - case 6: // IPv6 - if (plen >= 19) { - from.set((const void *)(data + 1),16,((((unsigned int)data[17]) & 0xff) << 8) | (((unsigned int)data[18]) & 0xff)); - data += 19; // type + 16 byte IP + 2 byte port - plen -= 19; - } else { - _phy.close(sock); - return; - } - break; - case 0: // none/omitted - ++data; - --plen; - break; - default: // invalid address type - _phy.close(sock); - return; - } - - if (from) { - InetAddress fakeTcpLocalInterfaceAddress((uint32_t)0xffffffff,0xffff); - const ZT_ResultCode rc = _node->processWirePacket( - (void *)0, - OSUtils::now(), - reinterpret_cast(&fakeTcpLocalInterfaceAddress), - reinterpret_cast(&from), - data, - plen, - &_nextBackgroundTaskDeadline); - if (ZT_ResultCode_isFatal(rc)) { - char tmp[256]; - Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = tmp; - this->terminate(); - _phy.close(sock); - return; - } - } - } - - if (tc->body.length() > (mlen + 5)) - tc->body = tc->body.substr(mlen + 5); - else tc->body = ""; - } else break; - } - break; - - } - } - - inline void phyOnTcpWritable(PhySocket *sock,void **uptr, bool stack_invoked) - { - TcpConnection *tc = reinterpret_cast(*uptr); - Mutex::Lock _l(tc->writeBuf_m); - if (tc->writeBuf.length() > 0) { - long sent = (long)_phy.streamSend(sock,tc->writeBuf.data(),(unsigned long)tc->writeBuf.length(),true); - if (sent > 0) { - tc->lastActivity = OSUtils::now(); - if ((unsigned long)sent >= (unsigned long)tc->writeBuf.length()) { - tc->writeBuf = ""; - _phy.setNotifyWritable(sock,false); - if (!tc->shouldKeepAlive) - _phy.close(sock); // will call close handler to delete from _tcpConnections - } else { - tc->writeBuf = tc->writeBuf.substr(sent); - } - } - } else { - _phy.setNotifyWritable(sock,false); - } - } - - inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} - inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {} - inline void phyOnUnixClose(PhySocket *sock,void **uptr) {} - inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} - inline void phyOnUnixWritable(PhySocket *sock,void **uptr,bool lwip_invoked) {} - - inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwc) - { - Mutex::Lock _l(_nets_m); - NetworkState &n = _nets[nwid]; - - switch(op) { - - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP: - if (!n.tap) { - try { - char friendlyName[128]; - Utils::snprintf(friendlyName,sizeof(friendlyName),"ZeroTier One [%.16llx]",nwid); - - n.tap = new EthernetTap( - _homePath.c_str(), - MAC(nwc->mac), - nwc->mtu, - (unsigned int)ZT_IF_METRIC, - nwid, - friendlyName, - StapFrameHandler, - (void *)this); - *nuptr = (void *)&n; - - char nlcpath[256]; - Utils::snprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid); - std::string nlcbuf; - if (OSUtils::readFile(nlcpath,nlcbuf)) { - Dictionary<4096> nc; - nc.load(nlcbuf.c_str()); - Buffer<1024> allowManaged; - if (nc.get("allowManaged", allowManaged) && allowManaged.size() != 0) { - std::string addresses (allowManaged.begin(), allowManaged.size()); - if (allowManaged.size() <= 5) { // untidy parsing for backward compatibility - if (allowManaged[0] == '1' || allowManaged[0] == 't' || allowManaged[0] == 'T') { - n.settings.allowManaged = true; - } else { - n.settings.allowManaged = false; - } - } else { - // this should be a list of IP addresses - n.settings.allowManaged = true; - size_t pos = 0; - while (true) { - size_t nextPos = addresses.find(',', pos); - std::string address = addresses.substr(pos, (nextPos == std::string::npos ? addresses.size() : nextPos) - pos); - n.settings.allowManagedWhitelist.push_back(InetAddress(address)); - if (nextPos == std::string::npos) break; - pos = nextPos + 1; - } - } - } else { - n.settings.allowManaged = true; - } - n.settings.allowGlobal = nc.getB("allowGlobal", false); - n.settings.allowDefault = nc.getB("allowDefault", false); - } - } catch (std::exception &exc) { -#ifdef __WINDOWS__ - FILE *tapFailLog = fopen((_homePath + ZT_PATH_SEPARATOR_S"port_error_log.txt").c_str(),"a"); - if (tapFailLog) { - fprintf(tapFailLog,"%.16llx: %s" ZT_EOL_S,(unsigned long long)nwid,exc.what()); - fclose(tapFailLog); - } -#else - fprintf(stderr,"ERROR: unable to configure virtual network port: %s" ZT_EOL_S,exc.what()); -#endif - _nets.erase(nwid); - return -999; - } catch ( ... ) { - return -999; // tap init failed - } - } - // After setting up tap, fall through to CONFIG_UPDATE since we also want to do this... - - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE: - memcpy(&(n.config),nwc,sizeof(ZT_VirtualNetworkConfig)); - if (n.tap) { // sanity check -#ifdef __WINDOWS__ - // wait for up to 5 seconds for the WindowsEthernetTap to actually be initialized - // - // without WindowsEthernetTap::isInitialized() returning true, the won't actually - // be online yet and setting managed routes on it will fail. - const int MAX_SLEEP_COUNT = 500; - for (int i = 0; !n.tap->isInitialized() && i < MAX_SLEEP_COUNT; i++) { - Sleep(10); - } -#endif - syncManagedStuff(n,true,true); - } else { - _nets.erase(nwid); - return -999; // tap init failed - } - break; - - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN: - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY: - if (n.tap) { // sanity check -#ifdef __WINDOWS__ - std::string winInstanceId(n.tap->instanceId()); -#endif - *nuptr = (void *)0; - delete n.tap; - _nets.erase(nwid); -#ifdef __WINDOWS__ - if ((op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY)&&(winInstanceId.length() > 0)) - WindowsEthernetTap::deletePersistentTapDevice(winInstanceId.c_str()); -#endif - if (op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY) { - char nlcpath[256]; - Utils::snprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid); - OSUtils::rm(nlcpath); - } - } else { - _nets.erase(nwid); - } - break; - - } - return 0; - } - - inline void nodeEventCallback(enum ZT_Event event,const void *metaData) - { - switch(event) { - case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION: { - Mutex::Lock _l(_termReason_m); - _termReason = ONE_IDENTITY_COLLISION; - _fatalErrorMessage = "identity/address collision"; - this->terminate(); - } break; - - case ZT_EVENT_TRACE: { - if (metaData) { - ::fprintf(stderr,"%s" ZT_EOL_S,(const char *)metaData); - ::fflush(stderr); - } - } break; - - case ZT_EVENT_USER_MESSAGE: { - const ZT_UserMessage *um = reinterpret_cast(metaData); - if ((um->typeId == ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE)&&(_updater)) { - _updater->handleSoftwareUpdateUserMessage(um->origin,um->data,um->length); - } - } break; - - default: - break; - } - } - - inline long nodeDataStoreGetFunction(const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize) - { - std::string p(_dataStorePrepPath(name)); - if (!p.length()) - return -2; - - FILE *f = fopen(p.c_str(),"rb"); - if (!f) - return -1; - if (fseek(f,0,SEEK_END) != 0) { - fclose(f); - return -2; - } - long ts = ftell(f); - if (ts < 0) { - fclose(f); - return -2; - } - *totalSize = (unsigned long)ts; - if (fseek(f,(long)readIndex,SEEK_SET) != 0) { - fclose(f); - return -2; - } - long n = (long)fread(buf,1,bufSize,f); - fclose(f); - return n; - } - - inline int nodeDataStorePutFunction(const char *name,const void *data,unsigned long len,int secure) - { - std::string p(_dataStorePrepPath(name)); - if (!p.length()) - return -2; - - if (!data) { - OSUtils::rm(p.c_str()); - return 0; - } - - FILE *f = fopen(p.c_str(),"wb"); - if (!f) - return -1; - if (fwrite(data,len,1,f) == 1) { - fclose(f); - if (secure) - OSUtils::lockDownFile(p.c_str(),false); - return 0; - } else { - fclose(f); - OSUtils::rm(p.c_str()); - return -1; - } - } - - inline int nodeWirePacketSendFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) - { - unsigned int fromBindingNo = 0; - - if (addr->ss_family == AF_INET) { - if (reinterpret_cast(localAddr)->sin_port == 0) { - // If sender is sending from wildcard (null address), choose the secondary backup - // port 1/4 of the time. (but only for IPv4) - fromBindingNo = (++_udpPortPickerCounter & 0x4) >> 2; - if (!_ports[fromBindingNo]) - fromBindingNo = 0; - } else { - const uint16_t lp = reinterpret_cast(localAddr)->sin_port; - if (lp == _portsBE[1]) - fromBindingNo = 1; - else if (lp == _portsBE[2]) - fromBindingNo = 2; - } - -#ifdef ZT_TCP_FALLBACK_RELAY - // TCP fallback tunnel support, currently IPv4 only - if ((len >= 16)&&(reinterpret_cast(addr)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { - // Engage TCP tunnel fallback if we haven't received anything valid from a global - // IP address in ZT_TCP_FALLBACK_AFTER milliseconds. If we do start getting - // valid direct traffic we'll stop using it and close the socket after a while. - const uint64_t now = OSUtils::now(); - if (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER)&&((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER)) { - if (_tcpFallbackTunnel) { - Mutex::Lock _l(_tcpFallbackTunnel->writeBuf_m); - if (!_tcpFallbackTunnel->writeBuf.length()) - _phy.setNotifyWritable(_tcpFallbackTunnel->sock,true); - unsigned long mlen = len + 7; - _tcpFallbackTunnel->writeBuf.push_back((char)0x17); - _tcpFallbackTunnel->writeBuf.push_back((char)0x03); - _tcpFallbackTunnel->writeBuf.push_back((char)0x03); // fake TLS 1.2 header - _tcpFallbackTunnel->writeBuf.push_back((char)((mlen >> 8) & 0xff)); - _tcpFallbackTunnel->writeBuf.push_back((char)(mlen & 0xff)); - _tcpFallbackTunnel->writeBuf.push_back((char)4); // IPv4 - _tcpFallbackTunnel->writeBuf.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_addr.s_addr))),4); - _tcpFallbackTunnel->writeBuf.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_port))),2); - _tcpFallbackTunnel->writeBuf.append((const char *)data,len); - } else if (((now - _lastSendToGlobalV4) < ZT_TCP_FALLBACK_AFTER)&&((now - _lastSendToGlobalV4) > (ZT_PING_CHECK_INVERVAL / 2))) { - bool connected = false; - const InetAddress addr(ZT_TCP_FALLBACK_RELAY); - _phy.tcpConnect(reinterpret_cast(&addr),connected); - } - } - _lastSendToGlobalV4 = now; - } -#endif // ZT_TCP_FALLBACK_RELAY - } else if (addr->ss_family == AF_INET6) { - if (reinterpret_cast(localAddr)->sin6_port != 0) { - const uint16_t lp = reinterpret_cast(localAddr)->sin6_port; - if (lp == _portsBE[1]) - fromBindingNo = 1; - else if (lp == _portsBE[2]) - fromBindingNo = 2; - } - } else { - return -1; - } - -#ifdef ZT_BREAK_UDP - if (OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) - return 0; // silently break UDP -#endif - - return (_bindings[fromBindingNo].udpSend(_phy,*(reinterpret_cast(localAddr)),*(reinterpret_cast(addr)),data,len,ttl)) ? 0 : -1; - } - - inline void nodeVirtualNetworkFrameFunction(uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) - { - NetworkState *n = reinterpret_cast(*nuptr); - if ((!n)||(!n->tap)) - return; - n->tap->put(MAC(sourceMac),MAC(destMac),etherType,data,len); - } - - inline int nodePathCheckFunction(uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) - { - // Make sure we're not trying to do ZeroTier-over-ZeroTier - { - Mutex::Lock _l(_nets_m); - for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { - if (n->second.tap) { - std::vector ips(n->second.tap->ips()); - for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { - if (i->containsAddress(*(reinterpret_cast(remoteAddr)))) { - return 0; - } - } - } - } - } - - /* Note: I do not think we need to scan for overlap with managed routes - * because of the "route forking" and interface binding that we do. This - * ensures (we hope) that ZeroTier traffic will still take the physical - * path even if its managed routes override this for other traffic. Will - * revisit if we see recursion problems. */ - - // Check blacklists - const Hashtable< uint64_t,std::vector > *blh = (const Hashtable< uint64_t,std::vector > *)0; - const std::vector *gbl = (const std::vector *)0; - if (remoteAddr->ss_family == AF_INET) { - blh = &_v4Blacklists; - gbl = &_globalV4Blacklist; - } else if (remoteAddr->ss_family == AF_INET6) { - blh = &_v6Blacklists; - gbl = &_globalV6Blacklist; - } - if (blh) { - Mutex::Lock _l(_localConfig_m); - const std::vector *l = blh->get(ztaddr); - if (l) { - for(std::vector::const_iterator a(l->begin());a!=l->end();++a) { - if (a->containsAddress(*reinterpret_cast(remoteAddr))) - return 0; - } - } - for(std::vector::const_iterator a(gbl->begin());a!=gbl->end();++a) { - if (a->containsAddress(*reinterpret_cast(remoteAddr))) - return 0; - } - } - - return 1; - } - - inline int nodePathLookupFunction(uint64_t ztaddr,int family,struct sockaddr_storage *result) - { - const Hashtable< uint64_t,std::vector > *lh = (const Hashtable< uint64_t,std::vector > *)0; - if (family < 0) - lh = (_node->prng() & 1) ? &_v4Hints : &_v6Hints; - else if (family == AF_INET) - lh = &_v4Hints; - else if (family == AF_INET6) - lh = &_v6Hints; - else return 0; - const std::vector *l = lh->get(ztaddr); - if ((l)&&(l->size() > 0)) { - memcpy(result,&((*l)[(unsigned long)_node->prng() % l->size()]),sizeof(struct sockaddr_storage)); - return 1; - } else return 0; - } - - inline void tapFrameHandler(uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) - { - _node->processVirtualNetworkFrame((void *)0,OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline); - } - - inline void onHttpRequestToServer(TcpConnection *tc) - { - char tmpn[256]; - std::string data; - std::string contentType("text/plain"); // default if not changed in handleRequest() - unsigned int scode = 404; - - bool allow; - { - Mutex::Lock _l(_localConfig_m); - if (_allowManagementFrom.size() == 0) { - allow = (tc->from.ipScope() == InetAddress::IP_SCOPE_LOOPBACK); - } else { - allow = false; - for(std::vector::const_iterator i(_allowManagementFrom.begin());i!=_allowManagementFrom.end();++i) { - if (i->containsAddress(tc->from)) { - allow = true; - break; - } - } - } - } - - if (allow) { - try { - scode = handleControlPlaneHttpRequest(tc->from,tc->parser.method,tc->url,tc->headers,tc->body,data,contentType); - } catch (std::exception &exc) { - fprintf(stderr,"WARNING: unexpected exception processing control HTTP request: %s" ZT_EOL_S,exc.what()); - scode = 500; - } catch ( ... ) { - fprintf(stderr,"WARNING: unexpected exception processing control HTTP request: unknown exceptino" ZT_EOL_S); - scode = 500; - } - } else { - scode = 401; - } - - const char *scodestr; - switch(scode) { - case 200: scodestr = "OK"; break; - case 400: scodestr = "Bad Request"; break; - case 401: scodestr = "Unauthorized"; break; - case 403: scodestr = "Forbidden"; break; - case 404: scodestr = "Not Found"; break; - case 500: scodestr = "Internal Server Error"; break; - case 501: scodestr = "Not Implemented"; break; - case 503: scodestr = "Service Unavailable"; break; - default: scodestr = "Error"; break; - } - - Utils::snprintf(tmpn,sizeof(tmpn),"HTTP/1.1 %.3u %s\r\nCache-Control: no-cache\r\nPragma: no-cache\r\n",scode,scodestr); - { - Mutex::Lock _l(tc->writeBuf_m); - tc->writeBuf.assign(tmpn); - tc->writeBuf.append("Content-Type: "); - tc->writeBuf.append(contentType); - Utils::snprintf(tmpn,sizeof(tmpn),"\r\nContent-Length: %lu\r\n",(unsigned long)data.length()); - tc->writeBuf.append(tmpn); - if (!tc->shouldKeepAlive) - tc->writeBuf.append("Connection: close\r\n"); - tc->writeBuf.append("\r\n"); - if (tc->parser.method != HTTP_HEAD) - tc->writeBuf.append(data); - } - - _phy.setNotifyWritable(tc->sock,true); - } - - inline void onHttpResponseFromClient(TcpConnection *tc) - { - if (!tc->shouldKeepAlive) - _phy.close(tc->sock); // will call close handler, which deletes from _tcpConnections - } - - bool shouldBindInterface(const char *ifname,const InetAddress &ifaddr) - { -#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) - if ((ifname[0] == 'l')&&(ifname[1] == 'o')) return false; // loopback - if ((ifname[0] == 'z')&&(ifname[1] == 't')) return false; // sanity check: zt# - if ((ifname[0] == 't')&&(ifname[1] == 'u')&&(ifname[2] == 'n')) return false; // tun# is probably an OpenVPN tunnel or similar - if ((ifname[0] == 't')&&(ifname[1] == 'a')&&(ifname[2] == 'p')) return false; // tap# is probably an OpenVPN tunnel or similar -#endif - -#ifdef __APPLE__ - if ((ifname[0] == 'l')&&(ifname[1] == 'o')) return false; // loopback - if ((ifname[0] == 'z')&&(ifname[1] == 't')) return false; // sanity check: zt# - if ((ifname[0] == 't')&&(ifname[1] == 'u')&&(ifname[2] == 'n')) return false; // tun# is probably an OpenVPN tunnel or similar - if ((ifname[0] == 't')&&(ifname[1] == 'a')&&(ifname[2] == 'p')) return false; // tap# is probably an OpenVPN tunnel or similar - if ((ifname[0] == 'u')&&(ifname[1] == 't')&&(ifname[2] == 'u')&&(ifname[3] == 'n')) return false; // ... as is utun# -#endif - - { - Mutex::Lock _l(_localConfig_m); - for(std::vector::const_iterator p(_interfacePrefixBlacklist.begin());p!=_interfacePrefixBlacklist.end();++p) { - if (!strncmp(p->c_str(),ifname,p->length())) - return false; - } - } - - { - Mutex::Lock _l(_nets_m); - for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { - if (n->second.tap) { - std::vector ips(n->second.tap->ips()); - for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { - if (i->ipsEqual(ifaddr)) - return false; - } - } - } - } - - return true; - } - - std::string _dataStorePrepPath(const char *name) const - { - std::string p(_homePath); - p.push_back(ZT_PATH_SEPARATOR); - char lastc = (char)0; - for(const char *n=name;(*n);++n) { - if ((*n == '.')&&(lastc == '.')) - return std::string(); // don't allow ../../ stuff as a precaution - if (*n == '/') { - OSUtils::mkdir(p.c_str()); - p.push_back(ZT_PATH_SEPARATOR); - } else p.push_back(*n); - lastc = *n; - } - return p; - } - - bool _trialBind(unsigned int port) - { - struct sockaddr_in in4; - struct sockaddr_in6 in6; - PhySocket *tb; - - memset(&in4,0,sizeof(in4)); - in4.sin_family = AF_INET; - in4.sin_port = Utils::hton((uint16_t)port); - tb = _phy.udpBind(reinterpret_cast(&in4),(void *)0,0); - if (tb) { - _phy.close(tb,false); - tb = _phy.tcpListen(reinterpret_cast(&in4),(void *)0); - if (tb) { - _phy.close(tb,false); - return true; - } - } - - memset(&in6,0,sizeof(in6)); - in6.sin6_family = AF_INET6; - in6.sin6_port = Utils::hton((uint16_t)port); - tb = _phy.udpBind(reinterpret_cast(&in6),(void *)0,0); - if (tb) { - _phy.close(tb,false); - tb = _phy.tcpListen(reinterpret_cast(&in6),(void *)0); - if (tb) { - _phy.close(tb,false); - return true; - } - } - - return false; - } -}; - -static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf) -{ return reinterpret_cast(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); } -static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData) -{ reinterpret_cast(uptr)->nodeEventCallback(event,metaData); } -static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize) -{ return reinterpret_cast(uptr)->nodeDataStoreGetFunction(name,buf,bufSize,readIndex,totalSize); } -static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,const void *data,unsigned long len,int secure) -{ return reinterpret_cast(uptr)->nodeDataStorePutFunction(name,data,len,secure); } -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) -{ return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); } -static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) -{ reinterpret_cast(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) -{ return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localAddr,remoteAddr); } -static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) -{ return reinterpret_cast(uptr)->nodePathLookupFunction(ztaddr,family,result); } - -#ifdef ZT_ENABLE_CLUSTER -static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len) -{ - OneServiceImpl *const impl = reinterpret_cast(uptr); - const ClusterDefinition::MemberDefinition &md = (*(impl->_clusterDefinition))[toMemberId]; - if (md.clusterEndpoint) - impl->_phy.udpSend(impl->_clusterMessageSocket,reinterpret_cast(&(md.clusterEndpoint)),data,len); -} -static int SclusterGeoIpFunction(void *uptr,const struct sockaddr_storage *addr,int *x,int *y,int *z) -{ - OneServiceImpl *const impl = reinterpret_cast(uptr); - return (int)(impl->_clusterDefinition->geo().locate(*(reinterpret_cast(addr)),*x,*y,*z)); -} -#endif - -static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) -{ reinterpret_cast(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); } - -static int ShttpOnMessageBegin(http_parser *parser) -{ - TcpConnection *tc = reinterpret_cast(parser->data); - tc->currentHeaderField = ""; - tc->currentHeaderValue = ""; - tc->messageSize = 0; - tc->url = ""; - tc->status = ""; - tc->headers.clear(); - tc->body = ""; - return 0; -} -static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) -{ - TcpConnection *tc = reinterpret_cast(parser->data); - tc->messageSize += (unsigned long)length; - if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) - return -1; - tc->url.append(ptr,length); - return 0; -} -#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) -static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) -#else -static int ShttpOnStatus(http_parser *parser) -#endif -{ - /* - TcpConnection *tc = reinterpret_cast(parser->data); - tc->messageSize += (unsigned long)length; - if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) - return -1; - tc->status.append(ptr,length); - */ - return 0; -} -static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) -{ - TcpConnection *tc = reinterpret_cast(parser->data); - tc->messageSize += (unsigned long)length; - if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) - return -1; - if ((tc->currentHeaderField.length())&&(tc->currentHeaderValue.length())) { - tc->headers[tc->currentHeaderField] = tc->currentHeaderValue; - tc->currentHeaderField = ""; - tc->currentHeaderValue = ""; - } - for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i])); - return 0; -} -static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) -{ - TcpConnection *tc = reinterpret_cast(parser->data); - tc->messageSize += (unsigned long)length; - if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) - return -1; - tc->currentHeaderValue.append(ptr,length); - return 0; -} -static int ShttpOnHeadersComplete(http_parser *parser) -{ - TcpConnection *tc = reinterpret_cast(parser->data); - if ((tc->currentHeaderField.length())&&(tc->currentHeaderValue.length())) - tc->headers[tc->currentHeaderField] = tc->currentHeaderValue; - return 0; -} -static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) -{ - TcpConnection *tc = reinterpret_cast(parser->data); - tc->messageSize += (unsigned long)length; - if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) - return -1; - tc->body.append(ptr,length); - return 0; -} -static int ShttpOnMessageComplete(http_parser *parser) -{ - TcpConnection *tc = reinterpret_cast(parser->data); - tc->shouldKeepAlive = (http_should_keep_alive(parser) != 0); - tc->lastActivity = OSUtils::now(); - if (tc->type == TcpConnection::TCP_HTTP_INCOMING) { - tc->parent->onHttpRequestToServer(tc); - } else { - tc->parent->onHttpResponseFromClient(tc); - } - return 0; -} - -} // anonymous namespace - -std::string OneService::platformDefaultHomePath() -{ - return OSUtils::platformDefaultHomePath(); -} - -OneService *OneService::newInstance(const char *hp,unsigned int port) { return new OneServiceImpl(hp,port); } -OneService::~OneService() {} - -} // namespace ZeroTier diff --git a/zto/service/OneService.hpp b/zto/service/OneService.hpp deleted file mode 100644 index 3ab5b1b..0000000 --- a/zto/service/OneService.hpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_ONESERVICE_HPP -#define ZT_ONESERVICE_HPP - -#include -#include - -#include "../node/InetAddress.hpp" -#include "../node/Node.hpp" - -// Include the right tap device driver for this platform -- add new platforms here -#ifdef ZT_SDK - // In network containers builds, use the virtual netcon endpoint instead of a tun/tap port driver - #include "../src/tap.hpp" - namespace ZeroTier { typedef NetconEthernetTap EthernetTap; } -#endif // not ZT_SDK so pick a tap driver - -namespace ZeroTier { - - -/** - * Local service for ZeroTier One as system VPN/NFV provider - */ -class OneService -{ -public: - /** - * Returned by node main if/when it terminates - */ - enum ReasonForTermination - { - /** - * Instance is still running - */ - ONE_STILL_RUNNING = 0, - - /** - * Normal shutdown - */ - ONE_NORMAL_TERMINATION = 1, - - /** - * A serious unrecoverable error has occurred - */ - ONE_UNRECOVERABLE_ERROR = 2, - - /** - * Your identity has collided with another - */ - ONE_IDENTITY_COLLISION = 3 - }; - - /** - * Local settings for each network - */ - struct NetworkSettings - { - /** - * Allow this network to configure IP addresses and routes? - */ - bool allowManaged; - - /** - * Whitelist of addresses that can be configured by this network. - * If empty and allowManaged is true, allow all private/pseudoprivate addresses. - */ - std::vector allowManagedWhitelist; - - /** - * Allow configuration of IPs and routes within global (Internet) IP space? - */ - bool allowGlobal; - - /** - * Allow overriding of system default routes for "full tunnel" operation? - */ - bool allowDefault; - }; - - /** - * @return Platform default home path or empty string if this platform doesn't have one - */ - static std::string platformDefaultHomePath(); - - /** - * Create a new instance of the service - * - * Once created, you must call the run() method to actually start - * processing. - * - * The port is saved to a file in the home path called zerotier-one.port, - * which is used by the CLI and can be used to see which port was chosen if - * 0 (random port) is picked. - * - * @param hp Home path - * @param port TCP and UDP port for packets and HTTP control (if 0, pick random port) - */ - static OneService *newInstance(const char *hp,unsigned int port); - - virtual ~OneService(); - - /** - * Execute the service main I/O loop until terminated - * - * The terminate() method may be called from a signal handler or another - * thread to terminate execution. Otherwise this will not return unless - * another condition terminates execution such as a fatal error. - */ - virtual ReasonForTermination run() = 0; - - /** - * @return Reason for terminating or ONE_STILL_RUNNING if running - */ - virtual ReasonForTermination reasonForTermination() const = 0; - - /** - * @return Fatal error message or empty string if none - */ - virtual std::string fatalErrorMessage() const = 0; - - /** - * @return System device name corresponding with a given ZeroTier network ID or empty string if not opened yet or network ID not found - */ - virtual std::string portDeviceName(uint64_t nwid) const = 0; - - /** - * Terminate background service (can be called from other threads) - */ - virtual void terminate() = 0; - -#ifdef ZT_SDK - /** - * Leaves a network - */ - virtual void leave(const char *hp) = 0; - - /** - * Joins a network - */ - virtual void join(const char *hp) = 0; - - /** - * Returns the homePath given by the client application - * - Used for SDK mode - */ - virtual std::string givenHomePath() = 0; - - /* - * - */ - virtual EthernetTap * getTap(uint64_t nwid) = 0; - - /* - * - */ - virtual Node * getNode() = 0; -#endif - - /** - * Get local settings for a network - * - * @param nwid Network ID - * @param settings Buffer to fill with local network settings - * @return True if network was found and settings is filled - */ - virtual bool getNetworkSettings(const uint64_t nwid,NetworkSettings &settings) const = 0; - - /** - * Set local settings for a network - * - * @param nwid Network ID - * @param settings New network local settings - * @return True if network was found and setting modified - */ - virtual bool setNetworkSettings(const uint64_t nwid,const NetworkSettings &settings) = 0; - - /** - * @return True if service is still running - */ - inline bool isRunning() const { return (this->reasonForTermination() == ONE_STILL_RUNNING); } - -protected: - OneService() {} - -private: - OneService(const OneService &one) {} - inline OneService &operator=(const OneService &one) { return *this; } -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/service/README.md b/zto/service/README.md deleted file mode 100644 index f5223f2..0000000 --- a/zto/service/README.md +++ /dev/null @@ -1,181 +0,0 @@ -ZeroTier One Network Virtualization Service -====== - -This is the actual implementation of ZeroTier One, a service providing connectivity to ZeroTier virtual networks for desktops, laptops, servers, VMs, etc. (Mobile versions for iOS and Android have their own implementations in native Java and Objective C that leverage only the ZeroTier core engine.) - -### Local Configuration File - -A file called `local.conf` in the ZeroTier home folder contains configuration options that apply to the local node. It can be used to set up trusted paths, blacklist physical paths, set up physical path hints for certain nodes, and define trusted upstream devices (federated roots). In a large deployment it can be deployed using a tool like Puppet, Chef, SaltStack, etc. to set a uniform configuration across systems. It's a JSON format file that can also be edited and rewritten by ZeroTier One itself, so ensure that proper JSON formatting is used. - -Settings available in `local.conf` (this is not valid JSON, and JSON does not allow comments): - -```javascript -{ - "physical": { /* Settings that apply to physical L2/L3 network paths. */ - "NETWORK/bits": { /* Network e.g. 10.0.0.0/24 or fd00::/32 */ - "blacklist": true|false, /* If true, blacklist this path for all ZeroTier traffic */ - "trustedPathId": 0|!0 /* If present and nonzero, define this as a trusted path (see below) */ - } /* ,... additional networks */ - }, - "virtual": { /* Settings applied to ZeroTier virtual network devices (VL1) */ - "##########": { /* 10-digit ZeroTier address */ - "try": [ "IP/port"/*,...*/ ], /* Hints on where to reach this peer if no upstreams/roots are online */ - "blacklist": [ "NETWORK/bits"/*,...*/ ] /* Blacklist a physical path for only this peer. */ - } - }, - "settings": { /* Other global settings */ - "primaryPort": 0-65535, /* If set, override default port of 9993 and any command line port */ - "portMappingEnabled": true|false, /* If true (the default), try to use uPnP or NAT-PMP to map ports */ - "softwareUpdate": "apply"|"download"|"disable", /* Automatically apply updates, just download, or disable built-in software updates */ - "softwareUpdateChannel": "release"|"beta", /* Software update channel */ - "softwareUpdateDist": true|false, /* If true, distribute software updates (only really useful to ZeroTier, Inc. itself, default is false) */ - "interfacePrefixBlacklist": [ "XXX",... ], /* Array of interface name prefixes (e.g. eth for eth#) to blacklist for ZT traffic */ - "allowManagementFrom": "NETWORK/bits"|null /* If non-NULL, allow JSON/HTTP management from this IP network. Default is 127.0.0.1 only. */ - } -} -``` - - * **trustedPathId**: A trusted path is a physical network over which encryption and authentication are not required. This provides a performance boost but sacrifices all ZeroTier's security features when communicating over this path. Only use this if you know what you are doing and really need the performance! To set up a trusted path, all devices using it *MUST* have the *same trusted path ID* for the same network. Trusted path IDs are arbitrary positive non-zero integers. For example a group of devices on a LAN with IPs in 10.0.0.0/24 could use it as a fast trusted path if they all had the same trusted path ID of "25" defined for that network. - * **relayPolicy**: Under what circumstances should this device relay traffic for other devices? The default is TRUSTED, meaning that we'll only relay for devices we know to be members of a network we have joined. NEVER is the default on mobile devices (iOS/Android) and tells us to never relay traffic. ALWAYS is usually only set for upstreams and roots, allowing them to act as promiscuous relays for anyone who desires it. - -An example `local.conf`: - -```javascript -{ - "physical": { - "10.0.0.0/24": { - "blacklist": true - }, - "10.10.10.0/24": { - "trustedPathId": 101010024 - }, - }, - "virtual": { - "feedbeef12": { - "role": "UPSTREAM", - "try": [ "10.10.20.1/9993" ], - "blacklist": [ "192.168.0.0/24" ] - } - }, - "settings": { - "softwareUpdate": "apply", - "softwraeUpdateChannel": "release" - } -} -``` - -### Network Virtualization Service API - -The JSON API supports GET, POST/PUT, and DELETE. PUT is treated as a synonym for POST. Other methods including HEAD are not supported. - -Values POSTed to the JSON API are *extremely* type sensitive. Things *must* be of the indicated type, otherwise they will be ignored or will generate an error. Anything quoted is a string so booleans and integers must lack quotes. Booleans must be *true* or *false* and nothing else. Integers cannot contain decimal points or they are floats (and vice versa). If something seems to be getting ignored or set to a strange value, or if you receive errors, check the type of all JSON fields you are submitting against the types listed below. Unrecognized fields in JSON objects are also ignored. - -API requests must be authenticated via an authentication token. ZeroTier One saves this token in the *authtoken.secret* file in its working directory. This token may be supplied via the *auth* URL parameter (e.g. '?auth=...') or via the *X-ZT1-Auth* HTTP request header. Static UI pages are the only thing the server will allow without authentication. - -A *jsonp* URL argument may be supplied to request JSONP encapsulation. A JSONP response is sent as a script with its JSON response payload wrapped in a call to the function name supplied as the argument to *jsonp*. - -#### /status - - * Purpose: Get running node status and addressing info - * Methods: GET - * Returns: { object } - -| Field | Type | Description | Writable | -| --------------------- | ------------- | ------------------------------------------------- | -------- | -| address | string | 10-digit hex ZeroTier address of this node | no | -| publicIdentity | string | This node's ZeroTier identity.public | no | -| worldId | integer | ZeroTier world ID (never changes except for test) | no | -| worldTimestamp | integer | Timestamp of most recent world definition | no | -| online | boolean | If true at least one upstream peer is reachable | no | -| tcpFallbackActive | boolean | If true we are using slow TCP fallback | no | -| relayPolicy | string | Relay policy: ALWAYS, TRUSTED, or NEVER | no | -| versionMajor | integer | Software major version | no | -| versionMinor | integer | Software minor version | no | -| versionRev | integer | Software revision | no | -| version | string | major.minor.revision | no | -| clock | integer | Current system clock at node (ms since epoch) | no | - -#### /network - - * Purpose: Get all network memberships - * Methods: GET - * Returns: [ {object}, ... ] - -Getting /network returns an array of all networks that this node has joined. See below for network object format. - -#### /network/\ - - * Purpose: Get, join, or leave a network - * Methods: GET, POST, DELETE - * Returns: { object } - -To join a network, POST to it. Since networks have no mandatory writable parameters, POST data is optional and may be omitted. Example: POST to /network/8056c2e21c000001 to join the public "Earth" network. To leave a network, DELETE it e.g. DELETE /network/8056c2e21c000001. - -Most network settings are not writable, as they are defined by the network controller. - -| Field | Type | Description | Writable | -| --------------------- | ------------- | ------------------------------------------------- | -------- | -| id | string | 16-digit hex network ID | no | -| nwid | string | 16-digit hex network ID (legacy field) | no | -| mac | string | MAC address of network device for this network | no | -| name | string | Short name of this network (from controller) | no | -| status | string | Network status (OK, ACCESS_DENIED, etc.) | no | -| type | string | Network type (PUBLIC or PRIVATE) | no | -| mtu | integer | Ethernet MTU | no | -| dhcp | boolean | If true, DHCP should be used to get IP info | no | -| bridge | boolean | If true, this device can bridge others | no | -| broadcastEnabled | boolean | If true ff:ff:ff:ff:ff:ff broadcasts work | no | -| portError | integer | Error code returned by underlying tap driver | no | -| netconfRevision | integer | Network configuration revision ID | no | -| assignedAddresses | [string] | Array of ZeroTier-assigned IP addresses (/bits) | no | -| routes | [object] | Array of ZeroTier-assigned routes (see below) | no | -| portDeviceName | string | Name of virtual network device (if any) | no | -| allowManaged | boolean | Allow IP and route management | yes | -| allowGlobal | boolean | Allow IPs and routes that overlap with global IPs | yes | -| allowDefault | boolean | Allow overriding of system default route | yes | - -Route objects: - -| Field | Type | Description | Writable | -| --------------------- | ------------- | ------------------------------------------------- | -------- | -| target | string | Target network / netmask bits | no | -| via | string | Gateway IP address (next hop) or null for LAN | no | -| flags | integer | Flags, currently always 0 | no | -| metric | integer | Route metric (not currently used) | no | - -#### /peer - - * Purpose: Get all peers - * Methods: GET - * Returns: [ {object}, ... ] - -Getting /peer returns an array of peer objects for all current peers. See below for peer object format. - -#### /peer/\ - - * Purpose: Get or set information about a peer - * Methods: GET, POST - * Returns: { object } - -| Field | Type | Description | Writable | -| --------------------- | ------------- | ------------------------------------------------- | -------- | -| address | string | 10-digit hex ZeroTier address of peer | no | -| versionMajor | integer | Major version of remote (if known) | no | -| versionMinor | integer | Minor version of remote (if known) | no | -| versionRev | integer | Software revision of remote (if known) | no | -| version | string | major.minor.revision | no | -| latency | integer | Latency in milliseconds if known | no | -| role | string | LEAF, UPSTREAM, or ROOT | no | -| paths | [object] | Currently active physical paths (see below) | no | - -Path objects: - -| Field | Type | Description | Writable | -| --------------------- | ------------- | ------------------------------------------------- | -------- | -| address | string | Physical socket address e.g. IP/port | no | -| lastSend | integer | Time of last send through this path | no | -| lastReceive | integer | Time of last receive through this path | no | -| active | boolean | Is this path in use? | no | -| expired | boolean | Is this path expired? | no | -| preferred | boolean | Is this a current preferred path? | no | -| trustedPathId | integer | If nonzero this is a trusted path (unencrypted) | no | diff --git a/zto/service/SoftwareUpdater.cpp b/zto/service/SoftwareUpdater.cpp deleted file mode 100644 index 7ec377c..0000000 --- a/zto/service/SoftwareUpdater.cpp +++ /dev/null @@ -1,406 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../version.h" - -#ifdef __WINDOWS__ -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#include -#endif - -#include "SoftwareUpdater.hpp" - -#include "../node/Utils.hpp" -#include "../node/SHA512.hpp" -#include "../node/Buffer.hpp" -#include "../node/Node.hpp" - -#include "../osdep/OSUtils.hpp" - -namespace ZeroTier { - -SoftwareUpdater::SoftwareUpdater(Node &node,const std::string &homePath) : - _node(node), - _lastCheckTime(0), - _homePath(homePath), - _channel(ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL), - _distLog((FILE *)0), - _latestValid(false), - _downloadLength(0) -{ - OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); -} - -SoftwareUpdater::~SoftwareUpdater() -{ - if (_distLog) - fclose(_distLog); -} - -void SoftwareUpdater::setUpdateDistribution(bool distribute) -{ - _dist.clear(); - if (distribute) { - _distLog = fopen((_homePath + ZT_PATH_SEPARATOR_S "update-dist.log").c_str(),"a"); - - const std::string udd(_homePath + ZT_PATH_SEPARATOR_S "update-dist.d"); - const std::vector ud(OSUtils::listDirectory(udd.c_str())); - for(std::vector::const_iterator u(ud.begin());u!=ud.end();++u) { - // Each update has a companion .json file describing it. Other files are ignored. - if ((u->length() > 5)&&(u->substr(u->length() - 5,5) == ".json")) { - - std::string buf; - if (OSUtils::readFile((udd + ZT_PATH_SEPARATOR_S + *u).c_str(),buf)) { - try { - _D d; - d.meta = OSUtils::jsonParse(buf); // throws on invalid JSON - - // If update meta is called e.g. foo.exe.json, then foo.exe is the update itself - const std::string binPath(udd + ZT_PATH_SEPARATOR_S + u->substr(0,u->length() - 5)); - const std::string metaHash(OSUtils::jsonBinFromHex(d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH])); - if ((metaHash.length() == ZT_SHA512_DIGEST_LEN)&&(OSUtils::readFile(binPath.c_str(),d.bin))) { - uint8_t sha512[ZT_SHA512_DIGEST_LEN]; - SHA512::hash(sha512,d.bin.data(),(unsigned int)d.bin.length()); - if (!memcmp(sha512,metaHash.data(),ZT_SHA512_DIGEST_LEN)) { // double check that hash in JSON is correct - d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE] = d.bin.length(); // override with correct value -- setting this in meta json is optional - _dist[Array(sha512)] = d; - if (_distLog) { - fprintf(_distLog,".......... INIT: DISTRIBUTING %s (%u bytes)" ZT_EOL_S,binPath.c_str(),(unsigned int)d.bin.length()); - fflush(_distLog); - } - } - } - } catch ( ... ) {} // ignore bad meta JSON, etc. - } - - } - } - } else { - if (_distLog) { - fclose(_distLog); - _distLog = (FILE *)0; - } - } -} - -void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void *data,unsigned int len) -{ - if (!len) return; - const MessageVerb v = (MessageVerb)reinterpret_cast(data)[0]; - try { - switch(v) { - - case VERB_GET_LATEST: - case VERB_LATEST: { - nlohmann::json req = OSUtils::jsonParse(std::string(reinterpret_cast(data) + 1,len - 1)); // throws on invalid JSON - if (req.is_object()) { - const unsigned int rvMaj = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR],0); - const unsigned int rvMin = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR],0); - const unsigned int rvRev = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION],0); - const unsigned int rvBld = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD],0); - const unsigned int rvPlatform = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_PLATFORM],0); - const unsigned int rvArch = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE],0); - const unsigned int rvVendor = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VENDOR],0); - const std::string rvChannel(OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_CHANNEL],"")); - - if (v == VERB_GET_LATEST) { - - if (_dist.size() > 0) { - const nlohmann::json *latest = (const nlohmann::json *)0; - const std::string expectedSigner = OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY],""); - unsigned int bestVMaj = rvMaj; - unsigned int bestVMin = rvMin; - unsigned int bestVRev = rvRev; - unsigned int bestVBld = rvBld; - for(std::map< Array,_D >::const_iterator d(_dist.begin());d!=_dist.end();++d) { - // The arch field in update description .json files can be an array for e.g. multi-arch update files - const nlohmann::json &dvArch2 = d->second.meta[ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE]; - std::vector dvArch; - if (dvArch2.is_array()) { - for(unsigned long i=0;isecond.meta[ZT_SOFTWARE_UPDATE_JSON_PLATFORM],0) == rvPlatform)&& - (std::find(dvArch.begin(),dvArch.end(),rvArch) != dvArch.end())&& - (OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VENDOR],0) == rvVendor)&& - (OSUtils::jsonString(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_CHANNEL],"") == rvChannel)&& - (OSUtils::jsonString(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY],"") == expectedSigner)) { - const unsigned int dvMaj = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR],0); - const unsigned int dvMin = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR],0); - const unsigned int dvRev = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION],0); - const unsigned int dvBld = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD],0); - if (Utils::compareVersion(dvMaj,dvMin,dvRev,dvBld,bestVMaj,bestVMin,bestVRev,bestVBld) > 0) { - latest = &(d->second.meta); - bestVMaj = dvMaj; - bestVMin = dvMin; - bestVRev = dvRev; - bestVBld = dvBld; - } - } - } - if (latest) { - std::string lj; - lj.push_back((char)VERB_LATEST); - lj.append(OSUtils::jsonDump(*latest)); - _node.sendUserMessage((void *)0,origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,lj.data(),(unsigned int)lj.length()); - if (_distLog) { - fprintf(_distLog,"%.10llx GET_LATEST %u.%u.%u_%u platform %u arch %u vendor %u channel %s -> LATEST %u.%u.%u_%u" ZT_EOL_S,(unsigned long long)origin,rvMaj,rvMin,rvRev,rvBld,rvPlatform,rvArch,rvVendor,rvChannel.c_str(),bestVMaj,bestVMin,bestVRev,bestVBld); - fflush(_distLog); - } - } - } // else no reply, since we have nothing to distribute - - } else { // VERB_LATEST - - if ((origin == ZT_SOFTWARE_UPDATE_SERVICE)&& - (Utils::compareVersion(rvMaj,rvMin,rvRev,rvBld,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION,ZEROTIER_ONE_VERSION_BUILD) > 0)&& - (OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY],"") == ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY)) { - const unsigned long len = (unsigned long)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE],0); - const std::string hash = OSUtils::jsonBinFromHex(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH]); - if ((len <= ZT_SOFTWARE_UPDATE_MAX_SIZE)&&(hash.length() >= 16)) { - if (_latestMeta != req) { - _latestMeta = req; - _latestValid = false; - OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); - _download = std::string(); - memcpy(_downloadHashPrefix.data,hash.data(),16); - _downloadLength = len; - } - - if ((_downloadLength > 0)&&(_download.length() < _downloadLength)) { - Buffer<128> gd; - gd.append((uint8_t)VERB_GET_DATA); - gd.append(_downloadHashPrefix.data,16); - gd.append((uint32_t)_download.length()); - _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); - } - } - } - } - - } - } break; - - case VERB_GET_DATA: - if ((len >= 21)&&(_dist.size() > 0)) { - unsigned long idx = (unsigned long)*(reinterpret_cast(data) + 17) << 24; - idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; - idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; - idx |= (unsigned long)*(reinterpret_cast(data) + 20); - //printf("<< GET_DATA @%u from %.10llx for %s\n",(unsigned int)idx,origin,Utils::hex(reinterpret_cast(data) + 1,16).c_str()); - std::map< Array,_D >::iterator d(_dist.find(Array(reinterpret_cast(data) + 1))); - if ((d != _dist.end())&&(idx < (unsigned long)d->second.bin.length())) { - Buffer buf; - buf.append((uint8_t)VERB_DATA); - buf.append(reinterpret_cast(data) + 1,16); - buf.append((uint32_t)idx); - buf.append(d->second.bin.data() + idx,std::min((unsigned long)ZT_SOFTWARE_UPDATE_CHUNK_SIZE,(unsigned long)(d->second.bin.length() - idx))); - _node.sendUserMessage((void *)0,origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,buf.data(),buf.size()); - //printf(">> DATA @%u\n",(unsigned int)idx); - } - } - break; - - case VERB_DATA: - if ((len >= 21)&&(_downloadLength > 0)&&(!memcmp(_downloadHashPrefix.data,reinterpret_cast(data) + 1,16))) { - unsigned long idx = (unsigned long)*(reinterpret_cast(data) + 17) << 24; - idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; - idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; - idx |= (unsigned long)*(reinterpret_cast(data) + 20); - //printf("<< DATA @%u / %u bytes (we now have %u bytes)\n",(unsigned int)idx,(unsigned int)(len - 21),(unsigned int)_download.length()); - if (idx == (unsigned long)_download.length()) { - _download.append(reinterpret_cast(data) + 21,len - 21); - if (_download.length() < _downloadLength) { - Buffer<128> gd; - gd.append((uint8_t)VERB_GET_DATA); - gd.append(_downloadHashPrefix.data,16); - gd.append((uint32_t)_download.length()); - _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); - } - } - } - break; - - default: - if (_distLog) { - fprintf(_distLog,"%.10llx WARNING: bad update message verb==%u length==%u (unrecognized verb)" ZT_EOL_S,(unsigned long long)origin,(unsigned int)v,len); - fflush(_distLog); - } - break; - } - } catch ( ... ) { - if (_distLog) { - fprintf(_distLog,"%.10llx WARNING: bad update message verb==%u length==%u (unexpected exception, likely invalid JSON)" ZT_EOL_S,(unsigned long long)origin,(unsigned int)v,len); - fflush(_distLog); - } - } -} - -bool SoftwareUpdater::check(const uint64_t now) -{ - if ((now - _lastCheckTime) >= ZT_SOFTWARE_UPDATE_CHECK_PERIOD) { - _lastCheckTime = now; - char tmp[512]; - const unsigned int len = Utils::snprintf(tmp,sizeof(tmp), - "%c{\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY "\":\"%s\"," - "\"" ZT_SOFTWARE_UPDATE_JSON_PLATFORM "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_VENDOR "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_CHANNEL "\":\"%s\"}", - (char)VERB_GET_LATEST, - ZEROTIER_ONE_VERSION_MAJOR, - ZEROTIER_ONE_VERSION_MINOR, - ZEROTIER_ONE_VERSION_REVISION, - ZEROTIER_ONE_VERSION_BUILD, - ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY, - ZT_BUILD_PLATFORM, - ZT_BUILD_ARCHITECTURE, - (int)ZT_VENDOR_ZEROTIER, - _channel.c_str()); - _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,tmp,len); - //printf(">> GET_LATEST\n"); - } - - if (_latestValid) - return true; - - if (_downloadLength > 0) { - if (_download.length() >= _downloadLength) { - // This is the very important security validation part that makes sure - // this software update doesn't have cooties. - - const std::string binPath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME); - try { - // (1) Check the hash itself to make sure the image is basically okay - uint8_t sha512[ZT_SHA512_DIGEST_LEN]; - SHA512::hash(sha512,_download.data(),(unsigned int)_download.length()); - if (Utils::hex(sha512,ZT_SHA512_DIGEST_LEN) == OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"")) { - // (2) Check signature by signing authority - const std::string sig(OSUtils::jsonBinFromHex(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE])); - if (Identity(ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY).verify(_download.data(),(unsigned int)_download.length(),sig.data(),(unsigned int)sig.length())) { - // (3) Try to save file, and if so we are good. - OSUtils::rm(binPath.c_str()); - if (OSUtils::writeFile(binPath.c_str(),_download)) { - OSUtils::lockDownFile(binPath.c_str(),false); - _latestValid = true; - //printf("VALID UPDATE\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); - _download = std::string(); - _downloadLength = 0; - return true; - } - } - } - } catch ( ... ) {} // any exception equals verification failure - - // If we get here, checks failed. - //printf("INVALID UPDATE (!!!)\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); - OSUtils::rm(binPath.c_str()); - _latestMeta = nlohmann::json(); - _latestValid = false; - _download = std::string(); - _downloadLength = 0; - } else { - Buffer<128> gd; - gd.append((uint8_t)VERB_GET_DATA); - gd.append(_downloadHashPrefix.data,16); - gd.append((uint32_t)_download.length()); - _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); - } - } - - return false; -} - -void SoftwareUpdater::apply() -{ - std::string updatePath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME); - if ((_latestMeta.is_object())&&(_latestValid)&&(OSUtils::fileExists(updatePath.c_str(),false))) { -#ifdef __WINDOWS__ - std::string cmdArgs(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS],"")); - if (cmdArgs.length() > 0) { - updatePath.push_back(' '); - updatePath.append(cmdArgs); - } - STARTUPINFOA si; - PROCESS_INFORMATION pi; - memset(&si,0,sizeof(si)); - memset(&pi,0,sizeof(pi)); - CreateProcessA(NULL,const_cast(updatePath.c_str()),NULL,NULL,FALSE,CREATE_NO_WINDOW|CREATE_NEW_PROCESS_GROUP,NULL,NULL,&si,&pi); - // Windows doesn't exit here -- updater will stop the service during update, etc. -- but we do want to stop multiple runs from happening - _latestMeta = nlohmann::json(); - _latestValid = false; -#else - char *argv[256]; - unsigned long ac = 0; - argv[ac++] = const_cast(updatePath.c_str()); - const std::vector argsSplit(OSUtils::split(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS],"").c_str()," ","\\","\"")); - for(std::vector::const_iterator a(argsSplit.begin());a!=argsSplit.end();++a) { - argv[ac] = const_cast(a->c_str()); - if (++ac == 255) break; - } - argv[ac] = (char *)0; - chmod(updatePath.c_str(),0700); - - // Close all open file descriptors except stdout/stderr/etc. - int minMyFd = STDIN_FILENO; - if (STDOUT_FILENO > minMyFd) minMyFd = STDOUT_FILENO; - if (STDERR_FILENO > minMyFd) minMyFd = STDERR_FILENO; - ++minMyFd; -#ifdef _SC_OPEN_MAX - int maxMyFd = (int)sysconf(_SC_OPEN_MAX); - if (maxMyFd <= minMyFd) - maxMyFd = 65536; -#else - int maxMyFd = 65536; -#endif - while (minMyFd < maxMyFd) - close(minMyFd++); - - execv(updatePath.c_str(),argv); - fprintf(stderr,"FATAL: unable to execute software update binary at %s\n",updatePath.c_str()); - exit(1); -#endif - } -} - -} // namespace ZeroTier diff --git a/zto/service/SoftwareUpdater.hpp b/zto/service/SoftwareUpdater.hpp deleted file mode 100644 index 4bb0ef5..0000000 --- a/zto/service/SoftwareUpdater.hpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ZT_SOFTWAREUPDATER_HPP -#define ZT_SOFTWAREUPDATER_HPP - -#include -#include - -#include -#include -#include - -#include "../include/ZeroTierOne.h" - -#include "../node/Identity.hpp" -#include "../node/Array.hpp" -#include "../node/Packet.hpp" - -#include "../ext/json/json.hpp" - -/** - * VERB_USER_MESSAGE type ID for software update messages - */ -#define ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE 100 - -/** - * ZeroTier address of node that provides software updates - */ -#define ZT_SOFTWARE_UPDATE_SERVICE 0xb1d366e81fULL - -/** - * ZeroTier identity that must be used to sign software updates - * - * df24360f3e - update-signing-key-0010 generated Fri Jan 13th, 2017 at 4:05pm PST - */ -#define ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY "df24360f3e:0:06072642959c8dfb68312904d74d90197c8a7692697caa1b3fd769eca714f4370fab462fcee6ebcb5fffb63bc5af81f28a2514b2cd68daabb42f7352c06f21db" - -/** - * Chunk size for in-band downloads (can be changed, designed to always fit in one UDP packet easily) - */ -#define ZT_SOFTWARE_UPDATE_CHUNK_SIZE (ZT_PROTO_MAX_PACKET_LENGTH - 128) - -/** - * Sanity limit for the size of an update binary image - */ -#define ZT_SOFTWARE_UPDATE_MAX_SIZE (1024 * 1024 * 256) - -/** - * How often (ms) do we check? - */ -#define ZT_SOFTWARE_UPDATE_CHECK_PERIOD (60 * 10 * 1000) - -/** - * Default update channel - */ -#define ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL "release" - -/** - * Filename for latest update's binary image - */ -#define ZT_SOFTWARE_UPDATE_BIN_FILENAME "latest-update.exe" - -#define ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR "vMajor" -#define ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR "vMinor" -#define ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION "vRev" -#define ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD "vBuild" -#define ZT_SOFTWARE_UPDATE_JSON_PLATFORM "platform" -#define ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE "arch" -#define ZT_SOFTWARE_UPDATE_JSON_VENDOR "vendor" -#define ZT_SOFTWARE_UPDATE_JSON_CHANNEL "channel" -#define ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY "expectedSigner" -#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY "signer" -#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE "signature" -#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH "hash" -#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE "size" -#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS "execArgs" -#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_URL "url" - -namespace ZeroTier { - -class Node; - -/** - * This class handles retrieving and executing updates, or serving them - */ -class SoftwareUpdater -{ -public: - /** - * Each message begins with an 8-bit message verb - */ - enum MessageVerb - { - /** - * Payload: JSON containing current system platform, version, etc. - */ - VERB_GET_LATEST = 1, - - /** - * Payload: JSON describing latest update for this target. (No response is sent if there is none.) - */ - VERB_LATEST = 2, - - /** - * Payload: - * <[16] first 128 bits of hash of data object> - * <[4] 32-bit index of chunk to get> - */ - VERB_GET_DATA = 3, - - /** - * Payload: - * <[16] first 128 bits of hash of data object> - * <[4] 32-bit index of chunk> - * <[...] chunk data> - */ - VERB_DATA = 4 - }; - - SoftwareUpdater(Node &node,const std::string &homePath); - ~SoftwareUpdater(); - - /** - * Set whether or not we will distribute updates - * - * @param distribute If true, scan update-dist.d now and distribute updates found there -- if false, clear and stop distributing - */ - void setUpdateDistribution(bool distribute); - - /** - * Handle a software update user message - * - * @param origin ZeroTier address of message origin - * @param data Message payload - * @param len Length of message - */ - void handleSoftwareUpdateUserMessage(uint64_t origin,const void *data,unsigned int len); - - /** - * Check for updates and do other update-related housekeeping - * - * It should be called about every 10 seconds. - * - * @return True if we've downloaded and verified an update - */ - bool check(const uint64_t now); - - /** - * @return Meta-data for downloaded update or NULL if none - */ - inline const nlohmann::json &pending() const { return _latestMeta; } - - /** - * Apply any ready update now - * - * Depending on the platform this function may never return and may forcibly - * exit the process. It does nothing if no update is ready. - */ - void apply(); - - /** - * Set software update channel - * - * @param channel 'release', 'beta', etc. - */ - inline void setChannel(const std::string &channel) { _channel = channel; } - -private: - Node &_node; - uint64_t _lastCheckTime; - std::string _homePath; - std::string _channel; - FILE *_distLog; - - // Offered software updates if we are an update host (we have update-dist.d and update hosting is enabled) - struct _D - { - nlohmann::json meta; - std::string bin; - }; - std::map< Array,_D > _dist; // key is first 16 bytes of hash - - nlohmann::json _latestMeta; - bool _latestValid; - - std::string _download; - Array _downloadHashPrefix; - unsigned long _downloadLength; -}; - -} // namespace ZeroTier - -#endif diff --git a/zto/tcp-proxy/Makefile b/zto/tcp-proxy/Makefile deleted file mode 100644 index af4e71e..0000000 --- a/zto/tcp-proxy/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -CXX=$(shell which clang++ g++ c++ 2>/dev/null | head -n 1) - -all: - $(CXX) -O3 -fno-rtti -o tcp-proxy tcp-proxy.cpp - -clean: - rm -f *.o tcp-proxy *.dSYM diff --git a/zto/tcp-proxy/README.md b/zto/tcp-proxy/README.md deleted file mode 100644 index 6f347d6..0000000 --- a/zto/tcp-proxy/README.md +++ /dev/null @@ -1,4 +0,0 @@ -TCP Proxy Server -====== - -This is the TCP proxy server we run for TCP tunneling from peers behind fascist NATs. Regular users won't have much use for this. diff --git a/zto/tcp-proxy/tcp-proxy.cpp b/zto/tcp-proxy/tcp-proxy.cpp deleted file mode 100644 index a7906aa..0000000 --- a/zto/tcp-proxy/tcp-proxy.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -// HACK! Will eventually use epoll() or something in Phy<> instead of select(). -// Also be sure to change ulimit -n and fs.file-max in /etc/sysctl.conf on relays. -#if defined(__linux__) || defined(__LINUX__) || defined(__LINUX) || defined(LINUX) -#include -#include -#undef __FD_SETSIZE -#define __FD_SETSIZE 1048576 -#undef FD_SETSIZE -#define FD_SETSIZE 1048576 -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "../osdep/Phy.hpp" - -#define ZT_TCP_PROXY_CONNECTION_TIMEOUT_SECONDS 300 -#define ZT_TCP_PROXY_TCP_PORT 443 - -using namespace ZeroTier; - -/* - * ZeroTier TCP Proxy Server - * - * This implements a simple packet encapsulation that is designed to look like - * a TLS connection. It's not a TLS connection, but it sends TLS format record - * headers. It could be extended in the future to implement a fake TLS - * handshake. - * - * At the moment, each packet is just made to look like TLS application data: - * <[1] TLS content type> - currently 0x17 for "application data" - * <[1] TLS major version> - currently 0x03 for TLS 1.2 - * <[1] TLS minor version> - currently 0x03 for TLS 1.2 - * <[2] payload length> - 16-bit length of payload in bytes - * <[...] payload> - Message payload - * - * TCP is inherently inefficient for encapsulating Ethernet, since TCP and TCP - * like protocols over TCP lead to double-ACKs. So this transport is only used - * to enable access when UDP or other datagram protocols are not available. - * - * Clients send a greeting, which is a four-byte message that contains: - * <[1] ZeroTier major version> - * <[1] minor version> - * <[2] revision> - * - * If a client has sent a greeting, it uses the new version of this protocol - * in which every encapsulated ZT packet is prepended by an IP address where - * it should be forwarded (or where it came from for replies). This causes - * this proxy to act as a remote UDP socket similar to a socks proxy, which - * will allow us to move this function off the rootservers and onto dedicated - * proxy nodes. - * - * Older ZT clients that do not send this message get their packets relayed - * to/from 127.0.0.1:9993, which will allow them to talk to and relay via - * the ZT node on the same machine as the proxy. We'll only support this for - * as long as such nodes appear to be in the wild. - */ - -struct TcpProxyService; -struct TcpProxyService -{ - Phy *phy; - int udpPortCounter; - struct Client - { - char tcpReadBuf[131072]; - char tcpWriteBuf[131072]; - unsigned long tcpWritePtr; - unsigned long tcpReadPtr; - PhySocket *tcp; - PhySocket *udp; - time_t lastActivity; - bool newVersion; - }; - std::map< PhySocket *,Client > clients; - - PhySocket *getUnusedUdp(void *uptr) - { - for(int i=0;i<65535;++i) { - ++udpPortCounter; - if (udpPortCounter > 0xfffe) - udpPortCounter = 1024; - struct sockaddr_in laddr; - memset(&laddr,0,sizeof(struct sockaddr_in)); - laddr.sin_family = AF_INET; - laddr.sin_port = htons((uint16_t)udpPortCounter); - PhySocket *udp = phy->udpBind(reinterpret_cast(&laddr),uptr); - if (udp) - return udp; - } - return (PhySocket *)0; - } - - void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) - { - if (!*uptr) - return; - if ((from->sa_family == AF_INET)&&(len >= 16)&&(len < 2048)) { - Client &c = *((Client *)*uptr); - c.lastActivity = time((time_t *)0); - - unsigned long mlen = len; - if (c.newVersion) - mlen += 7; // new clients get IP info - - if ((c.tcpWritePtr + 5 + mlen) <= sizeof(c.tcpWriteBuf)) { - if (!c.tcpWritePtr) - phy->setNotifyWritable(c.tcp,true); - - c.tcpWriteBuf[c.tcpWritePtr++] = 0x17; // look like TLS data - c.tcpWriteBuf[c.tcpWritePtr++] = 0x03; // look like TLS 1.2 - c.tcpWriteBuf[c.tcpWritePtr++] = 0x03; // look like TLS 1.2 - - c.tcpWriteBuf[c.tcpWritePtr++] = (char)((mlen >> 8) & 0xff); - c.tcpWriteBuf[c.tcpWritePtr++] = (char)(mlen & 0xff); - - if (c.newVersion) { - c.tcpWriteBuf[c.tcpWritePtr++] = (char)4; // IPv4 - *((uint32_t *)(c.tcpWriteBuf + c.tcpWritePtr)) = ((const struct sockaddr_in *)from)->sin_addr.s_addr; - c.tcpWritePtr += 4; - *((uint16_t *)(c.tcpWriteBuf + c.tcpWritePtr)) = ((const struct sockaddr_in *)from)->sin_port; - c.tcpWritePtr += 2; - } - - for(unsigned long i=0;i %.16llx\n",inet_ntoa(reinterpret_cast(from)->sin_addr),(int)ntohs(reinterpret_cast(from)->sin_port),(unsigned long long)&c); - } - } - - void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) - { - // unused, we don't initiate outbound connections - } - - void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) - { - Client &c = clients[sockN]; - PhySocket *udp = getUnusedUdp((void *)&c); - if (!udp) { - phy->close(sockN); - clients.erase(sockN); - //printf("** TCP rejected, no more UDP ports to assign\n"); - return; - } - c.tcpWritePtr = 0; - c.tcpReadPtr = 0; - c.tcp = sockN; - c.udp = udp; - c.lastActivity = time((time_t *)0); - c.newVersion = false; - *uptrN = (void *)&c; - //printf("<< TCP from %s -> %.16llx\n",inet_ntoa(reinterpret_cast(from)->sin_addr),(unsigned long long)&c); - } - - void phyOnTcpClose(PhySocket *sock,void **uptr) - { - if (!*uptr) - return; - Client &c = *((Client *)*uptr); - phy->close(c.udp); - clients.erase(sock); - //printf("** TCP %.16llx closed\n",(unsigned long long)*uptr); - } - - void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) - { - Client &c = *((Client *)*uptr); - c.lastActivity = time((time_t *)0); - - for(unsigned long i=0;i= sizeof(c.tcpReadBuf)) { - phy->close(sock); - return; - } - c.tcpReadBuf[c.tcpReadPtr++] = ((const char *)data)[i]; - - if (c.tcpReadPtr >= 5) { - unsigned long mlen = ( ((((unsigned long)c.tcpReadBuf[3]) & 0xff) << 8) | (((unsigned long)c.tcpReadBuf[4]) & 0xff) ); - if (c.tcpReadPtr >= (mlen + 5)) { - if (mlen == 4) { - // Right now just sending this means the client is 'new enough' for the IP header - c.newVersion = true; - //printf("<< TCP %.16llx HELLO\n",(unsigned long long)*uptr); - } else if (mlen >= 7) { - char *payload = c.tcpReadBuf + 5; - unsigned long payloadLen = mlen; - - struct sockaddr_in dest; - memset(&dest,0,sizeof(dest)); - if (c.newVersion) { - if (*payload == (char)4) { - // New clients tell us where their packets go. - ++payload; - dest.sin_family = AF_INET; - dest.sin_addr.s_addr = *((uint32_t *)payload); - payload += 4; - dest.sin_port = *((uint16_t *)payload); // will be in network byte order already - payload += 2; - payloadLen -= 7; - } - } else { - // For old clients we will just proxy everything to a local ZT instance. The - // fact that this will come from 127.0.0.1 will in turn prevent that instance - // from doing unite() with us. It'll just forward. There will not be many of - // these. - dest.sin_family = AF_INET; - dest.sin_addr.s_addr = htonl(0x7f000001); // 127.0.0.1 - dest.sin_port = htons(9993); - } - - // Note: we do not relay to privileged ports... just an abuse prevention rule. - if ((ntohs(dest.sin_port) > 1024)&&(payloadLen >= 16)) { - phy->udpSend(c.udp,(const struct sockaddr *)&dest,payload,payloadLen); - //printf(">> TCP %.16llx to %s:%d\n",(unsigned long long)*uptr,inet_ntoa(dest.sin_addr),(int)ntohs(dest.sin_port)); - } - } - - memmove(c.tcpReadBuf,c.tcpReadBuf + (mlen + 5),c.tcpReadPtr -= (mlen + 5)); - } - } - } - } - - void phyOnTcpWritable(PhySocket *sock,void **uptr) - { - Client &c = *((Client *)*uptr); - if (c.tcpWritePtr) { - long n = phy->streamSend(sock,c.tcpWriteBuf,c.tcpWritePtr); - if (n > 0) { - memmove(c.tcpWriteBuf,c.tcpWriteBuf + n,c.tcpWritePtr -= (unsigned long)n); - if (!c.tcpWritePtr) - phy->setNotifyWritable(sock,false); - } - } else phy->setNotifyWritable(sock,false); - } - - void doHousekeeping() - { - std::vector toClose; - time_t now = time((time_t *)0); - for(std::map< PhySocket *,Client >::iterator c(clients.begin());c!=clients.end();++c) { - if ((now - c->second.lastActivity) >= ZT_TCP_PROXY_CONNECTION_TIMEOUT_SECONDS) { - toClose.push_back(c->first); - toClose.push_back(c->second.udp); - } - } - for(std::vector::iterator s(toClose.begin());s!=toClose.end();++s) - phy->close(*s); - } -}; - -int main(int argc,char **argv) -{ - signal(SIGPIPE,SIG_IGN); - signal(SIGHUP,SIG_IGN); - srand(time((time_t *)0)); - - TcpProxyService svc; - Phy phy(&svc,false,true); - svc.phy = &phy; - svc.udpPortCounter = 1023; - - { - struct sockaddr_in laddr; - memset(&laddr,0,sizeof(laddr)); - laddr.sin_family = AF_INET; - laddr.sin_port = htons(ZT_TCP_PROXY_TCP_PORT); - if (!phy.tcpListen((const struct sockaddr *)&laddr)) { - fprintf(stderr,"%s: fatal error: unable to bind TCP port %d\n",argv[0],ZT_TCP_PROXY_TCP_PORT); - return 1; - } - } - - time_t lastDidHousekeeping = time((time_t *)0); - for(;;) { - phy.poll(120000); - time_t now = time((time_t *)0); - if ((now - lastDidHousekeeping) > 120) { - lastDidHousekeeping = now; - svc.doHousekeeping(); - } - } - - return 0; -} diff --git a/zto/version.h b/zto/version.h deleted file mode 100644 index 3d71f6d..0000000 --- a/zto/version.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _ZT_VERSION_H -#define _ZT_VERSION_H - -/** - * Major version - */ -#define ZEROTIER_ONE_VERSION_MAJOR 1 - -/** - * Minor version - */ -#define ZEROTIER_ONE_VERSION_MINOR 2 - -/** - * Revision - */ -#define ZEROTIER_ONE_VERSION_REVISION 3 - -/** - * Build version - * - * This starts at 0 for each major.minor.rev tuple and can be incremented - * to force a minor update without an actual version number change. It's - * not part of the actual release version number. - */ -#define ZEROTIER_ONE_VERSION_BUILD 0 - -#ifndef ZT_BUILD_ARCHITECTURE -#define ZT_BUILD_ARCHITECTURE 0 -#endif -#ifndef ZT_BUILD_PLATFORM -#define ZT_BUILD_PLATFORM 0 -#endif - -#endif diff --git a/zto/windows/README.md b/zto/windows/README.md deleted file mode 100644 index 9f3f48b..0000000 --- a/zto/windows/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This folder contains the Windows driver code, Windows-specific service code, and the Microsoft Visual Studio projects and "solution" for doing Windows builds. - -This code may also build with MinGW but this hasn't been tested. diff --git a/zto/windows/TapDriver6/TapDriver6.vcxproj b/zto/windows/TapDriver6/TapDriver6.vcxproj deleted file mode 100644 index cf6b150..0000000 --- a/zto/windows/TapDriver6/TapDriver6.vcxproj +++ /dev/null @@ -1,396 +0,0 @@ - - - - - Win8 Debug - Win32 - - - Win8 Release - Win32 - - - Win7 Debug - Win32 - - - Win7 Release - Win32 - - - Vista Debug - Win32 - - - Vista Release - Win32 - - - Win8 Debug - x64 - - - Win8 Release - x64 - - - Win7 Debug - x64 - - - Win7 Release - x64 - - - Vista Debug - x64 - - - Vista Release - x64 - - - - {43BA7584-D4DB-4F7C-90FC-E2B18A68A213} - {1bc93793-694f-48fe-9372-81e2b05556fd} - v4.5 - 11.0 - Win8 Debug - Win32 - - - TapDriver6 - $(VCTargetsPath11) - - - Driver - KMDF - - - - Windows8 - true - WindowsKernelModeDriver10.0 - - - Windows8 - false - WindowsKernelModeDriver10.0 - - - Windows7 - true - WindowsKernelModeDriver10.0 - - - Windows7 - false - WindowsKernelModeDriver10.0 - - - Vista - true - WindowsKernelModeDriver8.0 - - - Vista - false - 1 - 7 - WindowsKernelModeDriver8.0 - - - Windows8 - true - WindowsKernelModeDriver10.0 - - - Windows8 - false - WindowsKernelModeDriver10.0 - - - Windows7 - true - WindowsKernelModeDriver10.0 - - - Windows7 - false - WindowsKernelModeDriver10.0 - - - Vista - true - WindowsKernelModeDriver8.0 - - - Vista - false - 1 - 7 - WindowsKernelModeDriver8.0 - - - - - - - - - - zttap300 - - - DbgengKernelDebugger - - - zttap300 - - - zttap300 - - - zttap300 - - - zttap300 - - - zttap300 - - - zttap300 - - - zttap300 - - - zttap300 - - - zttap300 - - - zttap300 - - - zttap300 - - - - false - trace.h - false - false - false - false - false - false - false - false - false - false - false - false - false - Level1 - Level1 - Level1 - Level1 - Level1 - Level1 - Level1 - Level1 - Level1 - Level1 - Level1 - Level1 - Default - Default - Default - Default - Default - Default - Default - Default - Default - Default - Default - Default - - - C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies) - - - C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies) - - - C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies) - - - $(DDK_LIB_PATH)ndis.lib;$(DDK_LIB_PATH)ntstrsafe.lib;$(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDependencies) - - - $(DDK_LIB_PATH)ndis.lib;$(DDK_LIB_PATH)ntstrsafe.lib;$(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDependencies) - - - C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies) - - - C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies) - - - C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies) - - - C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies) - - - $(DDK_LIB_PATH)ndis.lib;$(DDK_LIB_PATH)ntstrsafe.lib;$(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDependencies) - - - $(DDK_LIB_PATH)ndis.lib;$(DDK_LIB_PATH)ntstrsafe.lib;$(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDependencies) - - - C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies) - - - 3.00.00.0 - false - false - - - 3.00.00.0 - false - false - - - 3.00.00.0 - false - false - - - 3.00.00.0 - true - true - - - zttap300.cat - - - - - false - false - - - - 3.00.00.0 - false - false - - - 3.00.00.0 - false - false - - - 3.00.00.0 - false - false - - - 3.00.00.0 - false - false - - - 3.00.00.0 - true - true - - - zttap300.cat - -v "3.00.00.0" %(AdditionalOptions) - - - 3.00.00.0 - true - true - -v "3.00.00.0" %(AdditionalOptions) - - - 3.00.00.0 - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3.00.00.0 - false - 3.00.00.0 - false - 3.00.00.0 - false - 3.00.00.0 - false - 3.00.00.0 - false - 3.00.00.0 - false - 3.00.00.0 - false - 3.00.00.0 - false - 3.00.00.0 - false - 3.00.00.0 - false - 3.00.00.0 - false - false - 3.00.00.0 - - - - - - \ No newline at end of file diff --git a/zto/windows/TapDriver6/TapDriver6.vcxproj.filters b/zto/windows/TapDriver6/TapDriver6.vcxproj.filters deleted file mode 100644 index 14cbbde..0000000 --- a/zto/windows/TapDriver6/TapDriver6.vcxproj.filters +++ /dev/null @@ -1,110 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {8E41214B-6785-4CFE-B992-037D68949A14} - inf;inv;inx;mof;mc; - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - - - - Driver Files - - - \ No newline at end of file diff --git a/zto/windows/TapDriver6/adapter.c b/zto/windows/TapDriver6/adapter.c deleted file mode 100644 index 7ce4b31..0000000 --- a/zto/windows/TapDriver6/adapter.c +++ /dev/null @@ -1,1716 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// -// Include files. -// - -#include "tap.h" - -NDIS_OID TAPSupportedOids[] = -{ - OID_GEN_HARDWARE_STATUS, - OID_GEN_TRANSMIT_BUFFER_SPACE, - OID_GEN_RECEIVE_BUFFER_SPACE, - OID_GEN_TRANSMIT_BLOCK_SIZE, - OID_GEN_RECEIVE_BLOCK_SIZE, - OID_GEN_VENDOR_ID, - OID_GEN_VENDOR_DESCRIPTION, - OID_GEN_VENDOR_DRIVER_VERSION, - OID_GEN_CURRENT_PACKET_FILTER, - OID_GEN_CURRENT_LOOKAHEAD, - OID_GEN_DRIVER_VERSION, - OID_GEN_MAXIMUM_TOTAL_SIZE, - OID_GEN_XMIT_OK, - OID_GEN_RCV_OK, - OID_GEN_STATISTICS, -#ifdef IMPLEMENT_OPTIONAL_OIDS - OID_GEN_TRANSMIT_QUEUE_LENGTH, // Optional -#endif // IMPLEMENT_OPTIONAL_OIDS - OID_GEN_LINK_PARAMETERS, - OID_GEN_INTERRUPT_MODERATION, - OID_GEN_MEDIA_SUPPORTED, - OID_GEN_MEDIA_IN_USE, - OID_GEN_MAXIMUM_SEND_PACKETS, - OID_GEN_XMIT_ERROR, - OID_GEN_RCV_ERROR, - OID_GEN_RCV_NO_BUFFER, - OID_802_3_PERMANENT_ADDRESS, - OID_802_3_CURRENT_ADDRESS, - OID_802_3_MULTICAST_LIST, - OID_802_3_MAXIMUM_LIST_SIZE, - OID_802_3_RCV_ERROR_ALIGNMENT, - OID_802_3_XMIT_ONE_COLLISION, - OID_802_3_XMIT_MORE_COLLISIONS, -#ifdef IMPLEMENT_OPTIONAL_OIDS - OID_802_3_XMIT_DEFERRED, // Optional - OID_802_3_XMIT_MAX_COLLISIONS, // Optional - OID_802_3_RCV_OVERRUN, // Optional - OID_802_3_XMIT_UNDERRUN, // Optional - OID_802_3_XMIT_HEARTBEAT_FAILURE, // Optional - OID_802_3_XMIT_TIMES_CRS_LOST, // Optional - OID_802_3_XMIT_LATE_COLLISIONS, // Optional - OID_PNP_CAPABILITIES, // Optional -#endif // IMPLEMENT_OPTIONAL_OIDS -}; - -//====================================================================== -// TAP NDIS 6 Miniport Callbacks -//====================================================================== - -// Returns with reference count initialized to one. -PTAP_ADAPTER_CONTEXT -tapAdapterContextAllocate( - __in NDIS_HANDLE MiniportAdapterHandle -) -{ - PTAP_ADAPTER_CONTEXT adapter = NULL; - - adapter = (PTAP_ADAPTER_CONTEXT )NdisAllocateMemoryWithTagPriority( - GlobalData.NdisDriverHandle, - sizeof(TAP_ADAPTER_CONTEXT), - TAP_ADAPTER_TAG, - NormalPoolPriority - ); - - if(adapter) - { - NET_BUFFER_LIST_POOL_PARAMETERS nblPoolParameters = {0}; - - NdisZeroMemory(adapter,sizeof(TAP_ADAPTER_CONTEXT)); - - adapter->MiniportAdapterHandle = MiniportAdapterHandle; - - // Initialize cancel-safe IRP queue - tapIrpCsqInitialize(&adapter->PendingReadIrpQueue); - - // Initialize TAP send packet queue. - tapPacketQueueInitialize(&adapter->SendPacketQueue); - - // Allocate the adapter lock. - NdisAllocateSpinLock(&adapter->AdapterLock); - - // NBL pool for making TAP receive indications. - NdisZeroMemory(&nblPoolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS)); - - // Initialize event used to determine when all receive NBLs have been returned. - NdisInitializeEvent(&adapter->ReceiveNblInFlightCountZeroEvent); - - nblPoolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; - nblPoolParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1; - nblPoolParameters.Header.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1; - nblPoolParameters.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT; - nblPoolParameters.ContextSize = 0; - //nblPoolParameters.ContextSize = sizeof(RX_NETBUFLIST_RSVD); - nblPoolParameters.fAllocateNetBuffer = TRUE; - nblPoolParameters.PoolTag = TAP_RX_NBL_TAG; - -#pragma warning( suppress : 28197 ) - adapter->ReceiveNblPool = NdisAllocateNetBufferListPool( - adapter->MiniportAdapterHandle, - &nblPoolParameters); - - if (adapter->ReceiveNblPool == NULL) - { - DEBUGP (("[TAP] Couldn't allocate adapter receive NBL pool\n")); - NdisFreeMemory(adapter,0,0); - } - - // Add initial reference. Normally removed in AdapterHalt. - adapter->RefCount = 1; - - // Safe for multiple removes. - NdisInitializeListHead(&adapter->AdapterListLink); - - // - // The miniport adapter is initially powered up - // - adapter->CurrentPowerState = NdisDeviceStateD0; - } - - return adapter; -} - -VOID -tapReadPermanentAddress( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in NDIS_HANDLE ConfigurationHandle, - __out MACADDR PermanentAddress - ) -{ - NDIS_STATUS status; - NDIS_CONFIGURATION_PARAMETER *configParameter; - NDIS_STRING macKey = NDIS_STRING_CONST("MAC"); - ANSI_STRING macString; - BOOLEAN macFromRegistry = FALSE; - - // Read MAC parameter from registry. - NdisReadConfiguration( - &status, - &configParameter, - ConfigurationHandle, - &macKey, - NdisParameterString - ); - - if (status == NDIS_STATUS_SUCCESS) - { - if( (configParameter->ParameterType == NdisParameterString) - && (configParameter->ParameterData.StringData.Length >= 12) - ) - { - if (RtlUnicodeStringToAnsiString( - &macString, - &configParameter->ParameterData.StringData, - TRUE) == STATUS_SUCCESS - ) - { - macFromRegistry = ParseMAC (PermanentAddress, macString.Buffer); - RtlFreeAnsiString (&macString); - } - } - } - - if(!macFromRegistry) - { - // - // There is no (valid) address stashed in the registry parameter. - // - // Make up a dummy mac address based on the ANSI representation of the - // NetCfgInstanceId GUID. - // - GenerateRandomMac(PermanentAddress, MINIPORT_INSTANCE_ID(Adapter)); - } -} - -NDIS_STATUS -tapReadConfiguration( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - NDIS_STATUS status = NDIS_STATUS_SUCCESS; - NDIS_CONFIGURATION_OBJECT configObject; - NDIS_HANDLE configHandle; - - DEBUGP (("[TAP] --> tapReadConfiguration\n")); - - // - // Setup defaults in case configuration cannot be opened. - // - Adapter->MtuSize = ETHERNET_MTU; - Adapter->MediaStateAlwaysConnected = FALSE; - Adapter->LogicalMediaState = FALSE; - Adapter->AllowNonAdmin = FALSE; - // - // Open the registry for this adapter to read advanced - // configuration parameters stored by the INF file. - // - NdisZeroMemory(&configObject, sizeof(configObject)); - - {C_ASSERT(sizeof(configObject) >= NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1);} - configObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT; - configObject.Header.Size = NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1; - configObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1; - - configObject.NdisHandle = Adapter->MiniportAdapterHandle; - configObject.Flags = 0; - - status = NdisOpenConfigurationEx( - &configObject, - &configHandle - ); - - // Read on the opened configuration handle. - if(status == NDIS_STATUS_SUCCESS) - { - NDIS_CONFIGURATION_PARAMETER *configParameter; - NDIS_STRING mkey = NDIS_STRING_CONST("NetCfgInstanceId"); - - // - // Read NetCfgInstanceId from the registry. - // ------------------------------------ - // NetCfgInstanceId is required to create device and associated - // symbolic link for the adapter device. - // - // NetCfgInstanceId is a GUID string provided by NDIS that identifies - // the adapter instance. An example is: - // - // NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0} - // - // Other names are derived from NetCfgInstanceId. For example, MiniportName: - // - // MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0} - // - NdisReadConfiguration ( - &status, - &configParameter, - configHandle, - &mkey, - NdisParameterString - ); - - if (status == NDIS_STATUS_SUCCESS) - { - if (configParameter->ParameterType == NdisParameterString) - { - DEBUGP (("[TAP] NdisReadConfiguration (NetCfgInstanceId=%wZ)\n", - &configParameter->ParameterData.StringData )); - - // Save NetCfgInstanceId as UNICODE_STRING. - Adapter->NetCfgInstanceId.Length = Adapter->NetCfgInstanceId.MaximumLength - = configParameter->ParameterData.StringData.Length; - - Adapter->NetCfgInstanceId.Buffer = Adapter->NetCfgInstanceIdBuffer; - - NdisMoveMemory( - Adapter->NetCfgInstanceId.Buffer, - configParameter->ParameterData.StringData.Buffer, - Adapter->NetCfgInstanceId.Length - ); - - // Save NetCfgInstanceId as ANSI_STRING as well. - if (RtlUnicodeStringToAnsiString ( - &Adapter->NetCfgInstanceIdAnsi, - &configParameter->ParameterData.StringData, - TRUE) != STATUS_SUCCESS - ) - { - DEBUGP (("[TAP] NetCfgInstanceId ANSI name conversion failed\n")); - status = NDIS_STATUS_RESOURCES; - } - } - else - { - DEBUGP (("[TAP] NetCfgInstanceId has invalid type\n")); - status = NDIS_STATUS_INVALID_DATA; - } - } - else - { - DEBUGP (("[TAP] NetCfgInstanceId failed\n")); - status = NDIS_STATUS_INVALID_DATA; - } - - if (status == NDIS_STATUS_SUCCESS) - { - NDIS_STATUS localStatus; // Use default if these fail. - NDIS_CONFIGURATION_PARAMETER *configParameter; - NDIS_STRING mtuKey = NDIS_STRING_CONST("MTU"); - NDIS_STRING mediaStatusKey = NDIS_STRING_CONST("MediaStatus"); -#if ENABLE_NONADMIN - NDIS_STRING allowNonAdminKey = NDIS_STRING_CONST("AllowNonAdmin"); -#endif - - // Read MTU from the registry. - NdisReadConfiguration ( - &localStatus, - &configParameter, - configHandle, - &mtuKey, - NdisParameterInteger - ); - - if (localStatus == NDIS_STATUS_SUCCESS) - { - if (configParameter->ParameterType == NdisParameterInteger) - { - int mtu = configParameter->ParameterData.IntegerData; - - if(mtu == 0) - { - mtu = ETHERNET_MTU; - } - - // Sanity check - if (mtu < MINIMUM_MTU) - { - mtu = MINIMUM_MTU; - } - else if (mtu > MAXIMUM_MTU) - { - mtu = MAXIMUM_MTU; - } - - Adapter->MtuSize = mtu; - } - } - - DEBUGP (("[%s] Using MTU %d\n", - MINIPORT_INSTANCE_ID (Adapter), - Adapter->MtuSize - )); - - // Read MediaStatus setting from registry. - NdisReadConfiguration ( - &localStatus, - &configParameter, - configHandle, - &mediaStatusKey, - NdisParameterInteger - ); - - if (localStatus == NDIS_STATUS_SUCCESS) - { - if (configParameter->ParameterType == NdisParameterInteger) - { - if(configParameter->ParameterData.IntegerData == 0) - { - // Connect state is appplication controlled. - DEBUGP(("[%s] Initial MediaConnectState: Application Controlled\n", - MINIPORT_INSTANCE_ID (Adapter))); - - Adapter->MediaStateAlwaysConnected = FALSE; - Adapter->LogicalMediaState = FALSE; - } - else - { - // Connect state is always connected. - DEBUGP(("[%s] Initial MediaConnectState: Always Connected\n", - MINIPORT_INSTANCE_ID (Adapter))); - - Adapter->MediaStateAlwaysConnected = TRUE; - Adapter->LogicalMediaState = TRUE; - } - } - } - - // Read MAC PermanentAddress setting from registry. - tapReadPermanentAddress( - Adapter, - configHandle, - Adapter->PermanentAddress - ); - - DEBUGP (("[%s] Using MAC PermanentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", - MINIPORT_INSTANCE_ID (Adapter), - Adapter->PermanentAddress[0], - Adapter->PermanentAddress[1], - Adapter->PermanentAddress[2], - Adapter->PermanentAddress[3], - Adapter->PermanentAddress[4], - Adapter->PermanentAddress[5]) - ); - - // Now seed the current MAC address with the permanent address. - ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentAddress, Adapter->PermanentAddress); - - DEBUGP (("[%s] Using MAC CurrentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", - MINIPORT_INSTANCE_ID (Adapter), - Adapter->CurrentAddress[0], - Adapter->CurrentAddress[1], - Adapter->CurrentAddress[2], - Adapter->CurrentAddress[3], - Adapter->CurrentAddress[4], - Adapter->CurrentAddress[5]) - ); - - // Read optional AllowNonAdmin setting from registry. -#if ENABLE_NONADMIN - NdisReadConfiguration ( - &localStatus, - &configParameter, - configHandle, - &allowNonAdminKey, - NdisParameterInteger - ); - - if (localStatus == NDIS_STATUS_SUCCESS) - { - if (configParameter->ParameterType == NdisParameterInteger) - { - Adapter->AllowNonAdmin = TRUE; - } - } -#endif - } - - // Close the configuration handle. - NdisCloseConfiguration(configHandle); - } - else - { - DEBUGP (("[TAP] Couldn't open adapter registry\n")); - } - - DEBUGP (("[TAP] <-- tapReadConfiguration; status = %8.8X\n",status)); - - return status; -} - -VOID -tapAdapterContextAddToGlobalList( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - LOCK_STATE lockState; - PLIST_ENTRY listEntry = &Adapter->AdapterListLink; - - // Acquire global adapter list lock. - NdisAcquireReadWriteLock( - &GlobalData.Lock, - TRUE, // Acquire for write - &lockState - ); - - // Adapter context should NOT be in any list. - ASSERT( (listEntry->Flink == listEntry) && (listEntry->Blink == listEntry ) ); - - // Add reference to persist until after removal. - tapAdapterContextReference(Adapter); - - // Add the adapter context to the global list. - InsertTailList(&GlobalData.AdapterList,&Adapter->AdapterListLink); - - // Release global adapter list lock. - NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState); -} - -VOID -tapAdapterContextRemoveFromGlobalList( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - LOCK_STATE lockState; - - // Acquire global adapter list lock. - NdisAcquireReadWriteLock( - &GlobalData.Lock, - TRUE, // Acquire for write - &lockState - ); - - // Remove the adapter context from the global list. - RemoveEntryList(&Adapter->AdapterListLink); - - // Safe for multiple removes. - NdisInitializeListHead(&Adapter->AdapterListLink); - - // Remove reference added in tapAdapterContextAddToGlobalList. - tapAdapterContextDereference(Adapter); - - // Release global adapter list lock. - NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState); -} - -// Returns with added reference on adapter context. -PTAP_ADAPTER_CONTEXT -tapAdapterContextFromDeviceObject( - __in PDEVICE_OBJECT DeviceObject - ) -{ - LOCK_STATE lockState; - - // Acquire global adapter list lock. - NdisAcquireReadWriteLock( - &GlobalData.Lock, - FALSE, // Acquire for read - &lockState - ); - - if (!IsListEmpty(&GlobalData.AdapterList)) - { - PLIST_ENTRY entry = GlobalData.AdapterList.Flink; - PTAP_ADAPTER_CONTEXT adapter; - - while (entry != &GlobalData.AdapterList) - { - adapter = CONTAINING_RECORD(entry, TAP_ADAPTER_CONTEXT, AdapterListLink); - - // Match on DeviceObject - if(adapter->DeviceObject == DeviceObject ) - { - // Add reference to adapter context. - tapAdapterContextReference(adapter); - - // Release global adapter list lock. - NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState); - - return adapter; - } - - // Move to next entry - entry = entry->Flink; - } - } - - // Release global adapter list lock. - NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState); - - return (PTAP_ADAPTER_CONTEXT )NULL; -} - -NDIS_STATUS -AdapterSetOptions( - __in NDIS_HANDLE NdisDriverHandle, - __in NDIS_HANDLE DriverContext - ) -/*++ -Routine Description: - - The MiniportSetOptions function registers optional handlers. For each - optional handler that should be registered, this function makes a call - to NdisSetOptionalHandlers. - - MiniportSetOptions runs at IRQL = PASSIVE_LEVEL. - -Arguments: - - DriverContext The context handle - -Return Value: - - NDIS_STATUS_xxx code - ---*/ -{ - NDIS_STATUS status; - - DEBUGP (("[TAP] --> AdapterSetOptions\n")); - - // - // Set any optional handlers by filling out the appropriate struct and - // calling NdisSetOptionalHandlers here. - // - - status = NDIS_STATUS_SUCCESS; - - DEBUGP (("[TAP] <-- AdapterSetOptions; status = %8.8X\n",status)); - - return status; -} - -NDIS_STATUS -AdapterCreate( - __in NDIS_HANDLE MiniportAdapterHandle, - __in NDIS_HANDLE MiniportDriverContext, - __in PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters - ) -{ - PTAP_ADAPTER_CONTEXT adapter = NULL; - NDIS_STATUS status; - - UNREFERENCED_PARAMETER(MiniportDriverContext); - UNREFERENCED_PARAMETER(MiniportInitParameters); - - DEBUGP (("[TAP] --> AdapterCreate\n")); - - do - { - NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES regAttributes = {0}; - NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES genAttributes = {0}; - NDIS_PNP_CAPABILITIES pnpCapabilities = {0}; - - // - // Allocate adapter context structure and initialize all the - // memory resources for sending and receiving packets. - // - // Returns with reference count initialized to one. - // - adapter = tapAdapterContextAllocate(MiniportAdapterHandle); - - if(adapter == NULL) - { - DEBUGP (("[TAP] Couldn't allocate adapter memory\n")); - status = NDIS_STATUS_RESOURCES; - break; - } - - // Enter the Initializing state. - DEBUGP (("[TAP] Miniport State: Initializing\n")); - - tapAdapterAcquireLock(adapter,FALSE); - adapter->Locked.AdapterState = MiniportInitializingState; - tapAdapterReleaseLock(adapter,FALSE); - - // - // First read adapter configuration from registry. - // ----------------------------------------------- - // Subsequent device registration will fail if NetCfgInstanceId - // has not been successfully read. - // - status = tapReadConfiguration(adapter); - - // - // Set the registration attributes. - // - {C_ASSERT(sizeof(regAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1);} - regAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES; - regAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; - regAttributes.Header.Revision = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; - - regAttributes.MiniportAdapterContext = adapter; - regAttributes.AttributeFlags = TAP_ADAPTER_ATTRIBUTES_FLAGS; - - regAttributes.CheckForHangTimeInSeconds = TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS; - regAttributes.InterfaceType = TAP_INTERFACE_TYPE; - - //NDIS_DECLARE_MINIPORT_ADAPTER_CONTEXT(TAP_ADAPTER_CONTEXT); - status = NdisMSetMiniportAttributes( - MiniportAdapterHandle, - (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)®Attributes - ); - - if (status != NDIS_STATUS_SUCCESS) - { - DEBUGP (("[TAP] NdisSetOptionalHandlers failed; Status 0x%08x\n",status)); - break; - } - - // - // Next, set the general attributes. - // - {C_ASSERT(sizeof(genAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1);} - genAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES; - genAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; - genAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; - - // - // Specify the medium type that the NIC can support but not - // necessarily the medium type that the NIC currently uses. - // - genAttributes.MediaType = TAP_MEDIUM_TYPE; - - // - // Specifiy medium type that the NIC currently uses. - // - genAttributes.PhysicalMediumType = TAP_PHYSICAL_MEDIUM; - - // - // Specifiy the maximum network frame size, in bytes, that the NIC - // supports excluding the header. - // - genAttributes.MtuSize = TAP_FRAME_MAX_DATA_SIZE; - genAttributes.MaxXmitLinkSpeed = TAP_XMIT_SPEED; - genAttributes.XmitLinkSpeed = TAP_XMIT_SPEED; - genAttributes.MaxRcvLinkSpeed = TAP_RECV_SPEED; - genAttributes.RcvLinkSpeed = TAP_RECV_SPEED; - - if(adapter->MediaStateAlwaysConnected) - { - DEBUGP(("[%s] Initial MediaConnectState: Connected\n", - MINIPORT_INSTANCE_ID (adapter))); - - genAttributes.MediaConnectState = MediaConnectStateConnected; - } - else - { - DEBUGP(("[%s] Initial MediaConnectState: Disconnected\n", - MINIPORT_INSTANCE_ID (adapter))); - - genAttributes.MediaConnectState = MediaConnectStateDisconnected; - } - - genAttributes.MediaDuplexState = MediaDuplexStateFull; - - // - // The maximum number of bytes the NIC can provide as lookahead data. - // If that value is different from the size of the lookahead buffer - // supported by bound protocols, NDIS will call MiniportOidRequest to - // set the size of the lookahead buffer provided by the miniport driver - // to the minimum of the miniport driver and protocol(s) values. If the - // driver always indicates up full packets with - // NdisMIndicateReceiveNetBufferLists, it should set this value to the - // maximum total frame size, which excludes the header. - // - // Upper-layer drivers examine lookahead data to determine whether a - // packet that is associated with the lookahead data is intended for - // one or more of their clients. If the underlying driver supports - // multipacket receive indications, bound protocols are given full net - // packets on every indication. Consequently, this value is identical - // to that returned for OID_GEN_RECEIVE_BLOCK_SIZE. - // - genAttributes.LookaheadSize = TAP_MAX_LOOKAHEAD; - genAttributes.MacOptions = TAP_MAC_OPTIONS; - genAttributes.SupportedPacketFilters = TAP_SUPPORTED_FILTERS; - - // - // The maximum number of multicast addresses the NIC driver can manage. - // This list is global for all protocols bound to (or above) the NIC. - // Consequently, a protocol can receive NDIS_STATUS_MULTICAST_FULL from - // the NIC driver when attempting to set the multicast address list, - // even if the number of elements in the given list is less than the - // number originally returned for this query. - // - genAttributes.MaxMulticastListSize = TAP_MAX_MCAST_LIST; - genAttributes.MacAddressLength = MACADDR_SIZE; - - // - // Return the MAC address of the NIC burnt in the hardware. - // - ETH_COPY_NETWORK_ADDRESS(genAttributes.PermanentMacAddress, adapter->PermanentAddress); - - // - // Return the MAC address the NIC is currently programmed to use. Note - // that this address could be different from the permananent address as - // the user can override using registry. Read NdisReadNetworkAddress - // doc for more info. - // - ETH_COPY_NETWORK_ADDRESS(genAttributes.CurrentMacAddress, adapter->CurrentAddress); - - genAttributes.RecvScaleCapabilities = NULL; - genAttributes.AccessType = TAP_ACCESS_TYPE; - genAttributes.DirectionType = TAP_DIRECTION_TYPE; - genAttributes.ConnectionType = TAP_CONNECTION_TYPE; - genAttributes.IfType = TAP_IFTYPE; - genAttributes.IfConnectorPresent = TAP_HAS_PHYSICAL_CONNECTOR; - genAttributes.SupportedStatistics = TAP_SUPPORTED_STATISTICS; - genAttributes.SupportedPauseFunctions = NdisPauseFunctionsUnsupported; // IEEE 802.3 pause frames - genAttributes.DataBackFillSize = 0; - genAttributes.ContextBackFillSize = 0; - - // - // The SupportedOidList is an array of OIDs for objects that the - // underlying driver or its NIC supports. Objects include general, - // media-specific, and implementation-specific objects. NDIS forwards a - // subset of the returned list to protocols that make this query. That - // is, NDIS filters any supported statistics OIDs out of the list - // because protocols never make statistics queries. - // - genAttributes.SupportedOidList = TAPSupportedOids; - genAttributes.SupportedOidListLength = sizeof(TAPSupportedOids); - genAttributes.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED; - - // - // Set power management capabilities - // - NdisZeroMemory(&pnpCapabilities, sizeof(pnpCapabilities)); - pnpCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; - pnpCapabilities.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified; - genAttributes.PowerManagementCapabilities = &pnpCapabilities; - - status = NdisMSetMiniportAttributes( - MiniportAdapterHandle, - (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&genAttributes - ); - - if (status != NDIS_STATUS_SUCCESS) - { - DEBUGP (("[TAP] NdisMSetMiniportAttributes failed; Status 0x%08x\n",status)); - break; - } - - // - // Create the Win32 device I/O interface. - // - status = CreateTapDevice(adapter); - - if (status == NDIS_STATUS_SUCCESS) - { - // Add this adapter to the global adapter list. - tapAdapterContextAddToGlobalList(adapter); - } - else - { - DEBUGP (("[TAP] CreateTapDevice failed; Status 0x%08x\n",status)); - break; - } - } while(FALSE); - - if(status == NDIS_STATUS_SUCCESS) - { - // Enter the Paused state if initialization is complete. - DEBUGP (("[TAP] Miniport State: Paused\n")); - - tapAdapterAcquireLock(adapter,FALSE); - adapter->Locked.AdapterState = MiniportPausedState; - tapAdapterReleaseLock(adapter,FALSE); - } - else - { - if(adapter != NULL) - { - DEBUGP (("[TAP] Miniport State: Halted\n")); - - // - // Remove reference when adapter context was allocated - // --------------------------------------------------- - // This should result in freeing adapter context memory - // and assiciated resources. - // - tapAdapterContextDereference(adapter); - adapter = NULL; - } - } - - DEBUGP (("[TAP] <-- AdapterCreate; status = %8.8X\n",status)); - - return status; -} - -VOID -AdapterHalt( - __in NDIS_HANDLE MiniportAdapterContext, - __in NDIS_HALT_ACTION HaltAction - ) -/*++ - -Routine Description: - - Halt handler is called when NDIS receives IRP_MN_STOP_DEVICE, - IRP_MN_SUPRISE_REMOVE or IRP_MN_REMOVE_DEVICE requests from the PNP - manager. Here, the driver should free all the resources acquired in - MiniportInitialize and stop access to the hardware. NDIS will not submit - any further request once this handler is invoked. - - 1) Free and unmap all I/O resources. - 2) Disable interrupt and deregister interrupt handler. - 3) Deregister shutdown handler regsitered by - NdisMRegisterAdapterShutdownHandler . - 4) Cancel all queued up timer callbacks. - 5) Finally wait indefinitely for all the outstanding receive - packets indicated to the protocol to return. - - MiniportHalt runs at IRQL = PASSIVE_LEVEL. - - -Arguments: - - MiniportAdapterContext Pointer to the Adapter - HaltAction The reason for halting the adapter - -Return Value: - - None. - ---*/ -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - - UNREFERENCED_PARAMETER(HaltAction); - - DEBUGP (("[TAP] --> AdapterHalt\n")); - - // Enter the Halted state. - DEBUGP (("[TAP] Miniport State: Halted\n")); - - tapAdapterAcquireLock(adapter,FALSE); - adapter->Locked.AdapterState = MiniportHaltedState; - tapAdapterReleaseLock(adapter,FALSE); - - // Remove this adapter from the global adapter list. - tapAdapterContextRemoveFromGlobalList(adapter); - - // BUGBUG!!! Call AdapterShutdownEx to do some of the work of stopping. - - // TODO!!! More... - - // - // Destroy the TAP Win32 device. - // - DestroyTapDevice(adapter); - - // - // Remove initial reference added in AdapterCreate. - // ------------------------------------------------ - // This should result in freeing adapter context memory - // and resources allocated in AdapterCreate. - // - tapAdapterContextDereference(adapter); - adapter = NULL; - - DEBUGP (("[TAP] <-- AdapterHalt\n")); -} - -VOID -tapWaitForReceiveNblInFlightCountZeroEvent( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - LONG nblCount; - - // - // Wait until higher-level protocol has returned all NBLs - // to the driver. - // - - // Add one NBL "bias" to insure allow event to be reset safely. - nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount); - ASSERT(nblCount > 0 ); - NdisResetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent); - - // - // Now remove the bias and wait for the ReceiveNblInFlightCountZeroEvent - // if the count returned is not zero. - // - nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount); - ASSERT(nblCount >= 0); - - if(nblCount) - { - LARGE_INTEGER startTime, currentTime; - - NdisGetSystemUpTimeEx(&startTime); - - for (;;) - { - BOOLEAN waitResult = NdisWaitEvent( - &Adapter->ReceiveNblInFlightCountZeroEvent, - TAP_WAIT_POLL_LOOP_TIMEOUT - ); - - NdisGetSystemUpTimeEx(¤tTime); - - if (waitResult) - { - break; - } - - DEBUGP (("[%s] Waiting for %d in-flight receive NBLs to be returned.\n", - MINIPORT_INSTANCE_ID (Adapter), - Adapter->ReceiveNblInFlightCount - )); - } - - DEBUGP (("[%s] Waited %d ms for all in-flight NBLs to be returned.\n", - MINIPORT_INSTANCE_ID (Adapter), - (currentTime.LowPart - startTime.LowPart) - )); - } -} - -NDIS_STATUS -AdapterPause( - __in NDIS_HANDLE MiniportAdapterContext, - __in PNDIS_MINIPORT_PAUSE_PARAMETERS PauseParameters - ) -/*++ - -Routine Description: - - When a miniport receives a pause request, it enters into a Pausing state. - The miniport should not indicate up any more network data. Any pending - send requests must be completed, and new requests must be rejected with - NDIS_STATUS_PAUSED. - - Once all sends have been completed and all recieve NBLs have returned to - the miniport, the miniport enters the Paused state. - - While paused, the miniport can still service interrupts from the hardware - (to, for example, continue to indicate NDIS_STATUS_MEDIA_CONNECT - notifications). - - The miniport must continue to be able to handle status indications and OID - requests. MiniportPause is different from MiniportHalt because, in - general, the MiniportPause operation won't release any resources. - MiniportPause must not attempt to acquire any resources where allocation - can fail, since MiniportPause itself must not fail. - - - MiniportPause runs at IRQL = PASSIVE_LEVEL. - -Arguments: - - MiniportAdapterContext Pointer to the Adapter - MiniportPauseParameters Additional information about the pause operation - -Return Value: - - If the miniport is able to immediately enter the Paused state, it should - return NDIS_STATUS_SUCCESS. - - If the miniport must wait for send completions or pending receive NBLs, it - should return NDIS_STATUS_PENDING now, and call NDISMPauseComplete when the - miniport has entered the Paused state. - - No other return value is permitted. The pause operation must not fail. - ---*/ -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - NDIS_STATUS status; - - UNREFERENCED_PARAMETER(PauseParameters); - - DEBUGP (("[TAP] --> AdapterPause\n")); - - // Enter the Pausing state. - DEBUGP (("[TAP] Miniport State: Pausing\n")); - - tapAdapterAcquireLock(adapter,FALSE); - adapter->Locked.AdapterState = MiniportPausingState; - tapAdapterReleaseLock(adapter,FALSE); - - // - // Stop the flow of network data through the receive path - // ------------------------------------------------------ - // In the Pausing and Paused state tapAdapterSendAndReceiveReady - // will prevent new calls to NdisMIndicateReceiveNetBufferLists - // to indicate additional receive NBLs to the host. - // - // However, there may be some in-flight NBLs owned by the driver - // that have been indicated to the host but have not yet been - // returned. - // - // Wait here for all in-flight receive indications to be returned. - // - tapWaitForReceiveNblInFlightCountZeroEvent(adapter); - - // - // Stop the flow of network data through the send path - // --------------------------------------------------- - // The initial implementation of the NDIS 6 send path follows the - // NDIS 5 pattern. Under this approach every send packet is copied - // into a driver-owned TAP_PACKET structure and the NBL owned by - // higher-level protocol is immediatly completed. - // - // With this deep-copy approach the driver never claims ownership - // of any send NBL. - // - // A future implementation may queue send NBLs and thereby eliminate - // the need for the unnecessary allocation and deep copy of each packet. - // - // So, nothing to do here for the send path for now... - - status = NDIS_STATUS_SUCCESS; - - // Enter the Paused state. - DEBUGP (("[TAP] Miniport State: Paused\n")); - - tapAdapterAcquireLock(adapter,FALSE); - adapter->Locked.AdapterState = MiniportPausedState; - tapAdapterReleaseLock(adapter,FALSE); - - DEBUGP (("[TAP] <-- AdapterPause; status = %8.8X\n",status)); - - return status; -} - -NDIS_STATUS -AdapterRestart( - __in NDIS_HANDLE MiniportAdapterContext, - __in PNDIS_MINIPORT_RESTART_PARAMETERS RestartParameters - ) -/*++ - -Routine Description: - - When a miniport receives a restart request, it enters into a Restarting - state. The miniport may begin indicating received data (e.g., using - NdisMIndicateReceiveNetBufferLists), handling status indications, and - processing OID requests in the Restarting state. However, no sends will be - requested while the miniport is in the Restarting state. - - Once the miniport is ready to send data, it has entered the Running state. - The miniport informs NDIS that it is in the Running state by returning - NDIS_STATUS_SUCCESS from this MiniportRestart function; or if this function - has already returned NDIS_STATUS_PENDING, by calling NdisMRestartComplete. - - - MiniportRestart runs at IRQL = PASSIVE_LEVEL. - -Arguments: - - MiniportAdapterContext Pointer to the Adapter - RestartParameters Additional information about the restart operation - -Return Value: - - If the miniport is able to immediately enter the Running state, it should - return NDIS_STATUS_SUCCESS. - - If the miniport is still in the Restarting state, it should return - NDIS_STATUS_PENDING now, and call NdisMRestartComplete when the miniport - has entered the Running state. - - Other NDIS_STATUS codes indicate errors. If an error is encountered, the - miniport must return to the Paused state (i.e., stop indicating receives). - ---*/ -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - NDIS_STATUS status; - - UNREFERENCED_PARAMETER(RestartParameters); - - DEBUGP (("[TAP] --> AdapterRestart\n")); - - // Enter the Restarting state. - DEBUGP (("[TAP] Miniport State: Restarting\n")); - - tapAdapterAcquireLock(adapter,FALSE); - adapter->Locked.AdapterState = MiniportRestartingState; - tapAdapterReleaseLock(adapter,FALSE); - - status = NDIS_STATUS_SUCCESS; - - if(status == NDIS_STATUS_SUCCESS) - { - // Enter the Running state. - DEBUGP (("[TAP] Miniport State: Running\n")); - - tapAdapterAcquireLock(adapter,FALSE); - adapter->Locked.AdapterState = MiniportRunning; - tapAdapterReleaseLock(adapter,FALSE); - } - else - { - // Enter the Paused state if restart failed. - DEBUGP (("[TAP] Miniport State: Paused\n")); - - tapAdapterAcquireLock(adapter,FALSE); - adapter->Locked.AdapterState = MiniportPausedState; - tapAdapterReleaseLock(adapter,FALSE); - } - - DEBUGP (("[TAP] <-- AdapterRestart; status = %8.8X\n",status)); - - return status; -} - -BOOLEAN -tapAdapterReadAndWriteReady( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -/*++ - -Routine Description: - - This routine determines whether the adapter device interface can - accept read and write operations. - -Arguments: - - Adapter Pointer to our adapter context - -Return Value: - - Returns TRUE if the adapter state allows it to queue IRPs passed to - the device read and write callbacks. ---*/ -{ - if(!Adapter->TapDeviceCreated) - { - // TAP device not created or is being destroyed. - return FALSE; - } - - if(Adapter->TapFileObject == NULL) - { - // TAP application file object not open. - return FALSE; - } - - if(!Adapter->TapFileIsOpen) - { - // TAP application file object may be closing. - return FALSE; - } - - if(!Adapter->LogicalMediaState) - { - // Don't handle read/write if media not connected. - return FALSE; - } - - if(Adapter->CurrentPowerState != NdisDeviceStateD0) - { - // Don't handle read/write if device is not fully powered. - return FALSE; - } - - return TRUE; -} - -NDIS_STATUS -tapAdapterSendAndReceiveReady( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -/*++ - -Routine Description: - - This routine determines whether the adapter NDIS send and receive - paths are ready. - - This routine examines various adapter state variables and returns - a value that indicates whether the adapter NDIS interfaces can - accept send packets or indicate receive packets. - - In normal operation the adapter may temporarily enter and then exit - a not-ready condition. In particular, the adapter becomes not-ready - when in the Pausing/Paused states, but may become ready again when - Restarted. - - Runs at IRQL <= DISPATCH_LEVEL - -Arguments: - - Adapter Pointer to our adapter context - -Return Value: - - Returns NDIS_STATUS_SUCCESS if the adapter state allows it to - accept send packets and indicate receive packets. - - Otherwise it returns a NDIS_STATUS value other than NDIS_STATUS_SUCCESS. - These status values can be used directly as the completion status for - packets that must be completed immediatly in the send path. ---*/ -{ - NDIS_STATUS status = NDIS_STATUS_SUCCESS; - - // - // Check various state variables to insure adapter is ready. - // - tapAdapterAcquireLock(Adapter,FALSE); - - if(!Adapter->LogicalMediaState) - { - status = NDIS_STATUS_MEDIA_DISCONNECTED; - } - else if(Adapter->CurrentPowerState != NdisDeviceStateD0) - { - status = NDIS_STATUS_LOW_POWER_STATE; - } - else if(Adapter->ResetInProgress) - { - status = NDIS_STATUS_RESET_IN_PROGRESS; - } - else - { - switch(Adapter->Locked.AdapterState) - { - case MiniportPausingState: - case MiniportPausedState: - status = NDIS_STATUS_PAUSED; - break; - - case MiniportHaltedState: - status = NDIS_STATUS_INVALID_STATE; - break; - - default: - status = NDIS_STATUS_SUCCESS; - break; - } - } - - tapAdapterReleaseLock(Adapter,FALSE); - - return status; -} - -BOOLEAN -AdapterCheckForHangEx( - __in NDIS_HANDLE MiniportAdapterContext - ) -/*++ - -Routine Description: - - The MiniportCheckForHangEx handler is called to report the state of the - NIC, or to monitor the responsiveness of an underlying device driver. - This is an optional function. If this handler is not specified, NDIS - judges the driver unresponsive when the driver holds - MiniportQueryInformation or MiniportSetInformation requests for a - time-out interval (deafult 4 sec), and then calls the driver's - MiniportReset function. A NIC driver's MiniportInitialize function can - extend NDIS's time-out interval by calling NdisMSetAttributesEx to - avoid unnecessary resets. - - MiniportCheckForHangEx runs at IRQL <= DISPATCH_LEVEL. - -Arguments: - - MiniportAdapterContext Pointer to our adapter - -Return Value: - - TRUE NDIS calls the driver's MiniportReset function. - FALSE Everything is fine - ---*/ -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - - //DEBUGP (("[TAP] --> AdapterCheckForHangEx\n")); - - //DEBUGP (("[TAP] <-- AdapterCheckForHangEx; status = FALSE\n")); - - return FALSE; // Everything is fine -} - -NDIS_STATUS -AdapterReset( - __in NDIS_HANDLE MiniportAdapterContext, - __out PBOOLEAN AddressingReset - ) -/*++ - -Routine Description: - - MiniportResetEx is a required to issue a hardware reset to the NIC - and/or to reset the driver's software state. - - 1) The miniport driver can optionally complete any pending - OID requests. NDIS will submit no further OID requests - to the miniport driver for the NIC being reset until - the reset operation has finished. After the reset, - NDIS will resubmit to the miniport driver any OID requests - that were pending but not completed by the miniport driver - before the reset. - - 2) A deserialized miniport driver must complete any pending send - operations. NDIS will not requeue pending send packets for - a deserialized driver since NDIS does not maintain the send - queue for such a driver. - - 3) If MiniportReset returns NDIS_STATUS_PENDING, the driver must - complete the original request subsequently with a call to - NdisMResetComplete. - - MiniportReset runs at IRQL <= DISPATCH_LEVEL. - -Arguments: - -AddressingReset - If multicast or functional addressing information - or the lookahead size, is changed by a reset, - MiniportReset must set the variable at AddressingReset - to TRUE before it returns control. This causes NDIS to - call the MiniportSetInformation function to restore - the information. - -MiniportAdapterContext - Pointer to our adapter - -Return Value: - - NDIS_STATUS - ---*/ -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - NDIS_STATUS status; - - UNREFERENCED_PARAMETER(MiniportAdapterContext); - UNREFERENCED_PARAMETER(AddressingReset); - - DEBUGP (("[TAP] --> AdapterReset\n")); - - // Indicate that adapter reset is in progress. - adapter->ResetInProgress = TRUE; - - // See note above... - *AddressingReset = FALSE; - - // BUGBUG!!! TODO!!! Lots of work here... - - // Indicate that adapter reset has completed. - adapter->ResetInProgress = FALSE; - - status = NDIS_STATUS_SUCCESS; - - DEBUGP (("[TAP] <-- AdapterReset; status = %8.8X\n",status)); - - return status; -} - -VOID -AdapterDevicePnpEventNotify( - __in NDIS_HANDLE MiniportAdapterContext, - __in PNET_DEVICE_PNP_EVENT NetDevicePnPEvent - ) -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - - DEBUGP (("[TAP] --> AdapterDevicePnpEventNotify\n")); - -/* - switch (NetDevicePnPEvent->DevicePnPEvent) - { - case NdisDevicePnPEventSurpriseRemoved: - // - // Called when NDIS receives IRP_MN_SUPRISE_REMOVAL. - // NDIS calls MiniportHalt function after this call returns. - // - MP_SET_FLAG(Adapter, fMP_ADAPTER_SURPRISE_REMOVED); - DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventSurpriseRemoved\n", Adapter); - break; - - case NdisDevicePnPEventPowerProfileChanged: - // - // After initializing a miniport driver and after miniport driver - // receives an OID_PNP_SET_POWER notification that specifies - // a device power state of NdisDeviceStateD0 (the powered-on state), - // NDIS calls the miniport's MiniportPnPEventNotify function with - // PnPEvent set to NdisDevicePnPEventPowerProfileChanged. - // - DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventPowerProfileChanged\n", Adapter); - - if (NetDevicePnPEvent->InformationBufferLength == sizeof(ULONG)) - { - ULONG NdisPowerProfile = *((PULONG)NetDevicePnPEvent->InformationBuffer); - - if (NdisPowerProfile == NdisPowerProfileBattery) - { - DEBUGP(MP_INFO, "[%p] The host system is running on battery power\n", Adapter); - } - if (NdisPowerProfile == NdisPowerProfileAcOnLine) - { - DEBUGP(MP_INFO, "[%p] The host system is running on AC power\n", Adapter); - } - } - break; - - default: - DEBUGP(MP_ERROR, "[%p] MPDevicePnpEventNotify: unknown PnP event 0x%x\n", Adapter, NetDevicePnPEvent->DevicePnPEvent); - } -*/ - DEBUGP (("[TAP] <-- AdapterDevicePnpEventNotify\n")); -} - -VOID -AdapterShutdownEx( - __in NDIS_HANDLE MiniportAdapterContext, - __in NDIS_SHUTDOWN_ACTION ShutdownAction - ) -/*++ - -Routine Description: - - The MiniportShutdownEx handler restores hardware to its initial state when - the system is shut down, whether by the user or because an unrecoverable - system error occurred. This is to ensure that the NIC is in a known - state and ready to be reinitialized when the machine is rebooted after - a system shutdown occurs for any reason, including a crash dump. - - Here just disable the interrupt and stop the DMA engine. Do not free - memory resources or wait for any packet transfers to complete. Do not call - into NDIS at this time. - - This can be called at aribitrary IRQL, including in the context of a - bugcheck. - -Arguments: - - MiniportAdapterContext Pointer to our adapter - ShutdownAction The reason why NDIS called the shutdown function - -Return Value: - - None. - ---*/ -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - - UNREFERENCED_PARAMETER(ShutdownAction); - UNREFERENCED_PARAMETER(MiniportAdapterContext); - - DEBUGP (("[TAP] --> AdapterShutdownEx\n")); - - // Enter the Shutdown state. - DEBUGP (("[TAP] Miniport State: Shutdown\n")); - - tapAdapterAcquireLock(adapter,FALSE); - adapter->Locked.AdapterState = MiniportShutdownState; - tapAdapterReleaseLock(adapter,FALSE); - - // - // BUGBUG!!! FlushIrpQueues??? - // - - DEBUGP (("[TAP] <-- AdapterShutdownEx\n")); -} - - -// Free adapter context memory and associated resources. -VOID -tapAdapterContextFree( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - PLIST_ENTRY listEntry = &Adapter->AdapterListLink; - - DEBUGP (("[TAP] --> tapAdapterContextFree\n")); - - // Adapter context should already be removed. - ASSERT( (listEntry->Flink == listEntry) && (listEntry->Blink == listEntry ) ); - - // Insure that adapter context has been removed from global adapter list. - RemoveEntryList(&Adapter->AdapterListLink); - - // Free the adapter lock. - NdisFreeSpinLock(&Adapter->AdapterLock); - - // Free the ANSI NetCfgInstanceId buffer. - if(Adapter->NetCfgInstanceIdAnsi.Buffer != NULL) - { - RtlFreeAnsiString(&Adapter->NetCfgInstanceIdAnsi); - } - - Adapter->NetCfgInstanceIdAnsi.Buffer = NULL; - - // Free the receive NBL pool. - if(Adapter->ReceiveNblPool != NULL ) - { - NdisFreeNetBufferListPool(Adapter->ReceiveNblPool); - } - - Adapter->ReceiveNblPool = NULL; - - NdisFreeMemory(Adapter,0,0); - - DEBUGP (("[TAP] <-- tapAdapterContextFree\n")); -} -ULONG -tapGetNetBufferFrameType( - __in PNET_BUFFER NetBuffer - ) -/*++ - -Routine Description: - - Reads the network frame's destination address to determine the type - (broadcast, multicast, etc) - - Runs at IRQL <= DISPATCH_LEVEL. - -Arguments: - - NetBuffer The NB to examine - -Return Value: - - NDIS_PACKET_TYPE_BROADCAST - NDIS_PACKET_TYPE_MULTICAST - NDIS_PACKET_TYPE_DIRECTED - ---*/ -{ - PETH_HEADER ethernetHeader; - - ethernetHeader = (PETH_HEADER )NdisGetDataBuffer( - NetBuffer, - sizeof(ETH_HEADER), - NULL, - 1, - 0 - ); - - ASSERT(ethernetHeader); - - if (ETH_IS_BROADCAST(ethernetHeader->dest)) - { - return NDIS_PACKET_TYPE_BROADCAST; - } - else if(ETH_IS_MULTICAST(ethernetHeader->dest)) - { - return NDIS_PACKET_TYPE_MULTICAST; - } - else - { - return NDIS_PACKET_TYPE_DIRECTED; - } - -} - -ULONG -tapGetNetBufferCountsFromNetBufferList( - __in PNET_BUFFER_LIST NetBufferList, - __inout_opt PULONG TotalByteCount // Of all linked NBs - ) -/*++ - -Routine Description: - - Returns the number of net buffers linked to the net buffer list. - - Optionally retuens the total byte count of all net buffers linked - to the net buffer list - - Runs at IRQL <= DISPATCH_LEVEL. - -Arguments: - - NetBufferList The NBL to examine - -Return Value: - - The number of net buffers linked to the net buffer list. - ---*/ -{ - ULONG netBufferCount = 0; - PNET_BUFFER currentNb; - - if(TotalByteCount) - { - *TotalByteCount = 0; - } - - currentNb = NET_BUFFER_LIST_FIRST_NB(NetBufferList); - - while(currentNb) - { - ++netBufferCount; - - if(TotalByteCount) - { - *TotalByteCount += NET_BUFFER_DATA_LENGTH(currentNb); - } - - // Move to next NB - currentNb = NET_BUFFER_NEXT_NB(currentNb); - } - - return netBufferCount; -} - -VOID -tapAdapterAcquireLock( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in BOOLEAN DispatchLevel - ) -{ - ASSERT(!DispatchLevel || (DISPATCH_LEVEL == KeGetCurrentIrql())); - - if (DispatchLevel) - { - NdisDprAcquireSpinLock(&Adapter->AdapterLock); - } - else - { - NdisAcquireSpinLock(&Adapter->AdapterLock); - } -} - -VOID -tapAdapterReleaseLock( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in BOOLEAN DispatchLevel - ) -{ - ASSERT(!DispatchLevel || (DISPATCH_LEVEL == KeGetCurrentIrql())); - - if (DispatchLevel) - { - NdisDprReleaseSpinLock(&Adapter->AdapterLock); - } - else - { - NdisReleaseSpinLock(&Adapter->AdapterLock); - } -} - - diff --git a/zto/windows/TapDriver6/adapter.h b/zto/windows/TapDriver6/adapter.h deleted file mode 100644 index 0ebaaea..0000000 --- a/zto/windows/TapDriver6/adapter.h +++ /dev/null @@ -1,352 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __TAP_ADAPTER_CONTEXT_H_ -#define __TAP_ADAPTER_CONTEXT_H_ - -#include "tap.h" - -// Memory allocation tags. -#define TAP_ADAPTER_TAG ((ULONG)'ApaT') // "TapA -#define TAP_RX_NBL_TAG ((ULONG)'RpaT') // "TapR -#define TAP_RX_INJECT_BUFFER_TAG ((ULONG)'IpaT') // "TapI - -#define TAP_MAX_NDIS_NAME_LENGTH 64 // 38 character GUID string plus extra.. - -// TAP receive indication NBL flag definitions. -#define TAP_RX_NBL_FLAGS NBL_FLAGS_MINIPORT_RESERVED -#define TAP_RX_NBL_FLAGS_CLEAR_ALL(_NBL) ((_NBL)->Flags &= ~TAP_RX_NBL_FLAGS) -#define TAP_RX_NBL_FLAG_SET(_NBL, _F) ((_NBL)->Flags |= ((_F) & TAP_RX_NBL_FLAGS)) -#define TAP_RX_NBL_FLAG_CLEAR(_NBL, _F) ((_NBL)->Flags &= ~((_F) & TAP_RX_NBL_FLAGS)) -#define TAP_RX_NBL_FLAG_TEST(_NBL, _F) (((_NBL)->Flags & ((_F) & TAP_RX_NBL_FLAGS)) != 0) - -#define TAP_RX_NBL_FLAGS_IS_P2P 0x00001000 -#define TAP_RX_NBL_FLAGS_IS_INJECTED 0x00002000 - -// MSDN Ref: http://msdn.microsoft.com/en-us/library/windows/hardware/ff560490(v=vs.85).aspx -typedef -enum _TAP_MINIPORT_ADAPTER_STATE -{ - // The Halted state is the initial state of all adapters. When an - // adapter is in the Halted state, NDIS can call the driver's - // MiniportInitializeEx function to initialize the adapter. - MiniportHaltedState, - - // In the Shutdown state, a system shutdown and restart must occur - // before the system can use the adapter again. - MiniportShutdownState, - - // In the Initializing state, a miniport driver completes any - //operations that are required to initialize an adapter. - MiniportInitializingState, - - // Entering the Paused state... - MiniportPausingState, - - // In the Paused state, the adapter does not indicate received - // network data or accept send requests. - MiniportPausedState, - - // In the Running state, a miniport driver performs send and - // receive processing for an adapter. - MiniportRunning, - - // In the Restarting state, a miniport driver completes any - // operations that are required to restart send and receive - // operations for an adapter. - MiniportRestartingState -} TAP_MINIPORT_ADAPTER_STATE, *PTAP_MINIPORT_ADAPTER_STATE; - -// -// Each adapter managed by this driver has a TapAdapter struct. -// ------------------------------------------------------------ -// Since there is a one-to-one relationship between adapter instances -// and device instances this structure is the device extension as well. -// -typedef struct _TAP_ADAPTER_CONTEXT -{ - LIST_ENTRY AdapterListLink; - - volatile LONG RefCount; - - NDIS_HANDLE MiniportAdapterHandle; - - NDIS_SPIN_LOCK AdapterLock; // Lock for protection of state and outstanding sends and recvs - - // - // All fields that are protected by the AdapterLock are included - // in the Locked structure to remind us to take the Lock - // before accessing them :) - // - struct - { - TAP_MINIPORT_ADAPTER_STATE AdapterState; - } Locked; - - BOOLEAN ResetInProgress; - - // - // NetCfgInstanceId as UNICODE_STRING - // ---------------------------------- - // This a GUID string provided by NDIS that identifies the adapter instance. - // An example is: - // - // NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0} - // - // Other names are derived from NetCfgInstanceId. For example, MiniportName: - // - // MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0} - // - NDIS_STRING NetCfgInstanceId; - WCHAR NetCfgInstanceIdBuffer[TAP_MAX_NDIS_NAME_LENGTH]; - -# define MINIPORT_INSTANCE_ID(a) ((a)->NetCfgInstanceIdAnsi.Buffer) - ANSI_STRING NetCfgInstanceIdAnsi; // Used occasionally - - ULONG MtuSize; // 1500 byte (typical) - - // TRUE if adapter should always be "connected" even when device node - // is not open by a userspace process. - // - // FALSE if connection state is application controlled. - BOOLEAN MediaStateAlwaysConnected; - - // TRUE if device is "connected". - BOOLEAN LogicalMediaState; - - NDIS_DEVICE_POWER_STATE CurrentPowerState; - - BOOLEAN AllowNonAdmin; - - MACADDR PermanentAddress; // From registry, if available - MACADDR CurrentAddress; - - // Device registration parameters from NdisRegisterDeviceEx. - NDIS_STRING DeviceName; - WCHAR DeviceNameBuffer[TAP_MAX_NDIS_NAME_LENGTH]; - - NDIS_STRING LinkName; - WCHAR LinkNameBuffer[TAP_MAX_NDIS_NAME_LENGTH]; - - NDIS_HANDLE DeviceHandle; - PDEVICE_OBJECT DeviceObject; - BOOLEAN TapDeviceCreated; // WAS: m_TapIsRunning - - PFILE_OBJECT TapFileObject; // Exclusive access - BOOLEAN TapFileIsOpen; // WAS: m_TapOpens - LONG TapFileOpenCount; // WAS: m_NumTapOpens - - // Cancel-Safe read IRP queue. - TAP_IRP_CSQ PendingReadIrpQueue; - - // Queue containing TAP packets representing host send NBs. These are - // waiting to be read by user-mode application. - TAP_PACKET_QUEUE SendPacketQueue; - - // NBL pool for making TAP receive indications. - NDIS_HANDLE ReceiveNblPool; - - volatile LONG ReceiveNblInFlightCount; -#define TAP_WAIT_POLL_LOOP_TIMEOUT 3000 // 3 seconds - NDIS_EVENT ReceiveNblInFlightCountZeroEvent; - - /* - // Info for point-to-point mode - BOOLEAN m_tun; - IPADDR m_localIP; - IPADDR m_remoteNetwork; - IPADDR m_remoteNetmask; - ETH_HEADER m_TapToUser; - ETH_HEADER m_UserToTap; - ETH_HEADER m_UserToTap_IPv6; // same as UserToTap but proto=ipv6 - */ - - // Info for DHCP server masquerade - /* - BOOLEAN m_dhcp_enabled; - IPADDR m_dhcp_addr; - ULONG m_dhcp_netmask; - IPADDR m_dhcp_server_ip; - BOOLEAN m_dhcp_server_arp; - MACADDR m_dhcp_server_mac; - ULONG m_dhcp_lease_time; - UCHAR m_dhcp_user_supplied_options_buffer[DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE]; - ULONG m_dhcp_user_supplied_options_buffer_len; - BOOLEAN m_dhcp_received_discover; - ULONG m_dhcp_bad_requests; - */ - - // Multicast list. Fixed size. - ULONG ulMCListSize; - UCHAR MCList[TAP_MAX_MCAST_LIST][MACADDR_SIZE]; - - ULONG PacketFilter; - ULONG ulLookahead; - - // - // Statistics - // ------------------------------------------------------------------------- - // - - // Packet counts - ULONG64 FramesRxDirected; - ULONG64 FramesRxMulticast; - ULONG64 FramesRxBroadcast; - ULONG64 FramesTxDirected; - ULONG64 FramesTxMulticast; - ULONG64 FramesTxBroadcast; - - // Byte counts - ULONG64 BytesRxDirected; - ULONG64 BytesRxMulticast; - ULONG64 BytesRxBroadcast; - ULONG64 BytesTxDirected; - ULONG64 BytesTxMulticast; - ULONG64 BytesTxBroadcast; - - // Count of transmit errors - ULONG TxAbortExcessCollisions; - ULONG TxLateCollisions; - ULONG TxDmaUnderrun; - ULONG TxLostCRS; - ULONG TxOKButDeferred; - ULONG OneRetry; - ULONG MoreThanOneRetry; - ULONG TotalRetries; - ULONG TransmitFailuresOther; - - // Count of receive errors - ULONG RxCrcErrors; - ULONG RxAlignmentErrors; - ULONG RxResourceErrors; - ULONG RxDmaOverrunErrors; - ULONG RxCdtFrames; - ULONG RxRuntErrors; - -#if PACKET_TRUNCATION_CHECK - LONG m_RxTrunc, m_TxTrunc; -#endif - - BOOLEAN m_InterfaceIsRunning; - LONG m_Rx, m_RxErr; - NDIS_MEDIUM m_Medium; - - // Help to tear down the adapter by keeping - // some state information on allocated - // resources. - BOOLEAN m_CalledAdapterFreeResources; - BOOLEAN m_RegisteredAdapterShutdownHandler; - -} TAP_ADAPTER_CONTEXT, *PTAP_ADAPTER_CONTEXT; - -FORCEINLINE -LONG -tapAdapterContextReference( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - LONG refCount = NdisInterlockedIncrement(&Adapter->RefCount); - - ASSERT(refCount>1); // Cannot dereference a zombie. - - return refCount; -} - -VOID -tapAdapterContextFree( - __in PTAP_ADAPTER_CONTEXT Adapter - ); - -FORCEINLINE -LONG -tapAdapterContextDereference( - IN PTAP_ADAPTER_CONTEXT Adapter - ) -{ - LONG refCount = NdisInterlockedDecrement(&Adapter->RefCount); - ASSERT(refCount >= 0); - if (!refCount) - { - tapAdapterContextFree(Adapter); - } - - return refCount; -} - -VOID -tapAdapterAcquireLock( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in BOOLEAN DispatchLevel - ); - -VOID -tapAdapterReleaseLock( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in BOOLEAN DispatchLevel - ); - -// Returns with added reference on adapter context. -PTAP_ADAPTER_CONTEXT -tapAdapterContextFromDeviceObject( - __in PDEVICE_OBJECT DeviceObject - ); - -BOOLEAN -tapAdapterReadAndWriteReady( - __in PTAP_ADAPTER_CONTEXT Adapter - ); - -NDIS_STATUS -tapAdapterSendAndReceiveReady( - __in PTAP_ADAPTER_CONTEXT Adapter - ); - -ULONG -tapGetNetBufferFrameType( - __in PNET_BUFFER NetBuffer - ); - -ULONG -tapGetNetBufferCountsFromNetBufferList( - __in PNET_BUFFER_LIST NetBufferList, - __inout_opt PULONG TotalByteCount // Of all linked NBs - ); - -// Prototypes for standard NDIS miniport entry points -MINIPORT_SET_OPTIONS AdapterSetOptions; -MINIPORT_INITIALIZE AdapterCreate; -MINIPORT_HALT AdapterHalt; -MINIPORT_UNLOAD TapDriverUnload; -MINIPORT_PAUSE AdapterPause; -MINIPORT_RESTART AdapterRestart; -MINIPORT_OID_REQUEST AdapterOidRequest; -MINIPORT_SEND_NET_BUFFER_LISTS AdapterSendNetBufferLists; -MINIPORT_RETURN_NET_BUFFER_LISTS AdapterReturnNetBufferLists; -MINIPORT_CANCEL_SEND AdapterCancelSend; -MINIPORT_CHECK_FOR_HANG AdapterCheckForHangEx; -MINIPORT_RESET AdapterReset; -MINIPORT_DEVICE_PNP_EVENT_NOTIFY AdapterDevicePnpEventNotify; -MINIPORT_SHUTDOWN AdapterShutdownEx; -MINIPORT_CANCEL_OID_REQUEST AdapterCancelOidRequest; - -#endif // __TAP_ADAPTER_CONTEXT_H_ \ No newline at end of file diff --git a/zto/windows/TapDriver6/config.h b/zto/windows/TapDriver6/config.h deleted file mode 100644 index 4d36c5a..0000000 --- a/zto/windows/TapDriver6/config.h +++ /dev/null @@ -1,9 +0,0 @@ -#define PRODUCT_NAME "ZeroTier One Virtual Port" -#define PRODUCT_VERSION "3.0.0" -#define PRODUCT_VERSION_RESOURCE 3,0,0,1 -#define PRODUCT_TAP_WIN_COMPONENT_ID "zttap300" -#define PRODUCT_TAP_WIN_MAJOR 3 -#define PRODUCT_TAP_WIN_MINOR 0 -#define PRODUCT_TAP_WIN_PROVIDER "ZeroTier Networks" -#define PRODUCT_TAP_WIN_DEVICE_DESCRIPTION PRODUCT_NAME -#define PRODUCT_TAP_WIN_RELDATE "04/25/2015" diff --git a/zto/windows/TapDriver6/constants.h b/zto/windows/TapDriver6/constants.h deleted file mode 100644 index 91a876f..0000000 --- a/zto/windows/TapDriver6/constants.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -//==================================================================== -// Product and Version public settings -//==================================================================== - -#define PRODUCT_STRING PRODUCT_TAP_DEVICE_DESCRIPTION - - -// -// Update the driver version number every time you release a new driver -// The high word is the major version. The low word is the minor version. -// Also make sure that VER_FILEVERSION specified in the .RC file also -// matches with the driver version because NDISTESTER checks for that. -// -#ifndef TAP_DRIVER_MAJOR_VERSION - -#define TAP_DRIVER_MAJOR_VERSION 0x04 -#define TAP_DRIVER_MINOR_VERSION 0x02 - -#endif - -#define TAP_DRIVER_VENDOR_VERSION ((TAP_DRIVER_MAJOR_VERSION << 16) | TAP_DRIVER_MINOR_VERSION) - -// -// Define the NDIS miniport interface version that this driver targets. -// -#if defined(NDIS60_MINIPORT) -# define TAP_NDIS_MAJOR_VERSION 6 -# define TAP_NDIS_MINOR_VERSION 0 -#elif defined(NDIS61_MINIPORT) -# define TAP_NDIS_MAJOR_VERSION 6 -# define TAP_NDIS_MINOR_VERSION 1 -#elif defined(NDIS620_MINIPORT) -# define TAP_NDIS_MAJOR_VERSION 6 -# define TAP_NDIS_MINOR_VERSION 20 -#elif defined(NDIS630_MINIPORT) -# define TAP_NDIS_MAJOR_VERSION 6 -# define TAP_NDIS_MINOR_VERSION 30 -#else -#define TAP_NDIS_MAJOR_VERSION 5 -#define TAP_NDIS_MINOR_VERSION 0 -#endif - -//=========================================================== -// Driver constants -//=========================================================== - -#define ETHERNET_HEADER_SIZE (sizeof (ETH_HEADER)) -//#define ETHERNET_MTU 1500 -#define ETHERNET_MTU 2800 -#define ETHERNET_PACKET_SIZE (ETHERNET_MTU + ETHERNET_HEADER_SIZE) -#define DEFAULT_PACKET_LOOKAHEAD (ETHERNET_PACKET_SIZE) -#define VLAN_TAG_SIZE 4 - -//=========================================================== -// Medium properties -//=========================================================== - -#define TAP_FRAME_HEADER_SIZE ETHERNET_HEADER_SIZE -#define TAP_FRAME_MAX_DATA_SIZE ETHERNET_MTU -#define TAP_MAX_FRAME_SIZE (TAP_FRAME_HEADER_SIZE + TAP_FRAME_MAX_DATA_SIZE) -#define TAP_MIN_FRAME_SIZE 60 - -#define TAP_MEDIUM_TYPE NdisMedium802_3 - -//=========================================================== -// Physical adapter properties -//=========================================================== - -// The bus that connects the adapter to the PC. -// (Example: PCI adapters should use NdisInterfacePci). -#define TAP_INTERFACE_TYPE NdisInterfaceInternal - -#define TAP_VENDOR_DESC PRODUCT_TAP_WIN_DEVICE_DESCRIPTION - -// Highest byte is the NIC byte plus three vendor bytes. This is normally -// obtained from the NIC. -#define TAP_VENDOR_ID 0x00FFFFFF - -// If you have physical hardware on 802.3, use NdisPhysicalMedium802_3. -#define TAP_PHYSICAL_MEDIUM NdisPhysicalMediumUnspecified - -// Claim to be 100mbps duplex -#define MEGABITS_PER_SECOND 1000000ULL -#define TAP_XMIT_SPEED (100ULL*MEGABITS_PER_SECOND) -#define TAP_RECV_SPEED (100ULL*MEGABITS_PER_SECOND) - -// Max number of multicast addresses supported in hardware -#define TAP_MAX_MCAST_LIST 128 - -#define TAP_MAX_LOOKAHEAD TAP_FRAME_MAX_DATA_SIZE -#define TAP_BUFFER_SIZE TAP_MAX_FRAME_SIZE - -// Set this value to TRUE if there is a physical adapter. -#define TAP_HAS_PHYSICAL_CONNECTOR FALSE -#define TAP_ACCESS_TYPE NET_IF_ACCESS_BROADCAST -#define TAP_DIRECTION_TYPE NET_IF_DIRECTION_SENDRECEIVE -#define TAP_CONNECTION_TYPE NET_IF_CONNECTION_DEDICATED - -// This value must match the *IfType in the driver .inf file -#define TAP_IFTYPE IF_TYPE_ETHERNET_CSMACD - -// -// This is a virtual device, so it can tolerate surprise removal and -// suspend. Ensure the correct flags are set for your hardware. -// -#define TAP_ADAPTER_ATTRIBUTES_FLAGS (\ - NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK | NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM) - -#define TAP_SUPPORTED_FILTERS ( \ - NDIS_PACKET_TYPE_DIRECTED | \ - NDIS_PACKET_TYPE_MULTICAST | \ - NDIS_PACKET_TYPE_BROADCAST | \ - NDIS_PACKET_TYPE_ALL_LOCAL | \ - NDIS_PACKET_TYPE_PROMISCUOUS | \ - NDIS_PACKET_TYPE_ALL_MULTICAST) - -//#define TAP_MAX_MCAST_LIST 128 // Max length of multicast address list - -// -// Specify a bitmask that defines optional properties of the NIC. -// This miniport indicates receive with NdisMIndicateReceiveNetBufferLists -// function. Such a driver should set this NDIS_MAC_OPTION_TRANSFERS_NOT_PEND -// flag. -// -// NDIS_MAC_OPTION_NO_LOOPBACK tells NDIS that NIC has no internal -// loopback support so NDIS will manage loopbacks on behalf of -// this driver. -// -// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA tells the protocol that -// our receive buffer is not on a device-specific card. If -// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA is not set, multi-buffer -// indications are copied to a single flat buffer. -// - -#define TAP_MAC_OPTIONS (\ - NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \ - NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | \ - NDIS_MAC_OPTION_NO_LOOPBACK) - -#define TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS 4 - - -// NDIS 6.x miniports must support all counters in OID_GEN_STATISTICS. -#define TAP_SUPPORTED_STATISTICS (\ - NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV | \ - NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV | \ - NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV | \ - NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV | \ - NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS | \ - NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR | \ - NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT | \ - NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT | \ - NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT | \ - NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT | \ - NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR | \ - NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS | \ - NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | \ - NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV | \ - NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | \ - NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT | \ - NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | \ - NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT) - - -#define MINIMUM_MTU 576 // USE TCP Minimum MTU -#define MAXIMUM_MTU 65536 // IP maximum MTU - -#define PACKET_QUEUE_SIZE 64 // tap -> userspace queue size -#define IRP_QUEUE_SIZE 16 // max number of simultaneous i/o operations from userspace -#define INJECT_QUEUE_SIZE 16 // DHCP/ARP -> tap injection queue - -#define TAP_LITTLE_ENDIAN // affects ntohs, htonl, etc. functions diff --git a/zto/windows/TapDriver6/device.c b/zto/windows/TapDriver6/device.c deleted file mode 100644 index 7367143..0000000 --- a/zto/windows/TapDriver6/device.c +++ /dev/null @@ -1,1209 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// -// Include files. -// - -#include "tap.h" -#include // for SDDLs - -//====================================================================== -// TAP Win32 Device I/O Callbacks -//====================================================================== - -#ifdef ALLOC_PRAGMA -#pragma alloc_text( PAGE, TapDeviceCreate) -#pragma alloc_text( PAGE, TapDeviceControl) -#pragma alloc_text( PAGE, TapDeviceCleanup) -#pragma alloc_text( PAGE, TapDeviceClose) -#endif // ALLOC_PRAGMA - -//=================================================================== -// Go back to default TAP mode from Point-To-Point mode. -// Also reset (i.e. disable) DHCP Masq mode. -//=================================================================== -VOID tapResetAdapterState( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - /* - // Point-To-Point - Adapter->m_tun = FALSE; - Adapter->m_localIP = 0; - Adapter->m_remoteNetwork = 0; - Adapter->m_remoteNetmask = 0; - NdisZeroMemory (&Adapter->m_TapToUser, sizeof (Adapter->m_TapToUser)); - NdisZeroMemory (&Adapter->m_UserToTap, sizeof (Adapter->m_UserToTap)); - NdisZeroMemory (&Adapter->m_UserToTap_IPv6, sizeof (Adapter->m_UserToTap_IPv6)); - */ - - // DHCP Masq - /* - Adapter->m_dhcp_enabled = FALSE; - Adapter->m_dhcp_server_arp = FALSE; - Adapter->m_dhcp_user_supplied_options_buffer_len = 0; - Adapter->m_dhcp_addr = 0; - Adapter->m_dhcp_netmask = 0; - Adapter->m_dhcp_server_ip = 0; - Adapter->m_dhcp_lease_time = 0; - Adapter->m_dhcp_received_discover = FALSE; - Adapter->m_dhcp_bad_requests = 0; - NdisZeroMemory (Adapter->m_dhcp_server_mac, MACADDR_SIZE); - */ -} - -// IRP_MJ_CREATE -NTSTATUS -TapDeviceCreate( - PDEVICE_OBJECT DeviceObject, - PIRP Irp - ) -/*++ - -Routine Description: - - This routine is called by the I/O system when the device is opened. - - No action is performed other than completing the request successfully. - -Arguments: - - DeviceObject - a pointer to the object that represents the device - that I/O is to be done on. - - Irp - a pointer to the I/O Request Packet for this request. - -Return Value: - - NT status code - ---*/ -{ - NDIS_STATUS status; - PIO_STACK_LOCATION irpSp;// Pointer to current stack location - PTAP_ADAPTER_CONTEXT adapter = NULL; - PFILE_OBJECT originalFileObject; - - PAGED_CODE(); - - DEBUGP (("[TAP] --> TapDeviceCreate\n")); - - irpSp = IoGetCurrentIrpStackLocation(Irp); - - // - // Invalidate file context - // - irpSp->FileObject->FsContext = NULL; - irpSp->FileObject->FsContext2 = NULL; - - // - // Find adapter context for this device. - // ------------------------------------- - // Returns with added reference on adapter context. - // - adapter = tapAdapterContextFromDeviceObject(DeviceObject); - - // Insure that adapter exists. - ASSERT(adapter); - - if(adapter == NULL ) - { - DEBUGP (("[TAP] release [%d.%d] open request; adapter not found\n", - TAP_DRIVER_MAJOR_VERSION, - TAP_DRIVER_MINOR_VERSION - )); - - Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; - Irp->IoStatus.Information = 0; - - IoCompleteRequest( Irp, IO_NO_INCREMENT ); - - return STATUS_DEVICE_DOES_NOT_EXIST; - } - - DEBUGP(("[%s] [TAP] release [%d.%d] open request (TapFileIsOpen=%d)\n", - MINIPORT_INSTANCE_ID(adapter), - TAP_DRIVER_MAJOR_VERSION, - TAP_DRIVER_MINOR_VERSION, - adapter->TapFileIsOpen - )); - - // Enforce exclusive access - originalFileObject = InterlockedCompareExchangePointer( - &adapter->TapFileObject, - irpSp->FileObject, - NULL - ); - - if(originalFileObject == NULL) - { - irpSp->FileObject->FsContext = adapter; // Quick reference - - status = STATUS_SUCCESS; - } - else - { - status = STATUS_UNSUCCESSFUL; - } - - // Release the lock. - //tapAdapterReleaseLock(adapter,FALSE); - - if(status == STATUS_SUCCESS) - { - // Reset adapter state on successful open. - tapResetAdapterState(adapter); - - adapter->TapFileIsOpen = 1; // Legacy... - - // NOTE!!! Reference added by tapAdapterContextFromDeviceObject - // will be removed when file is closed. - } - else - { - DEBUGP (("[%s] TAP is presently unavailable (TapFileIsOpen=%d)\n", - MINIPORT_INSTANCE_ID(adapter), adapter->TapFileIsOpen - )); - - NOTE_ERROR(); - - // Remove reference added by tapAdapterContextFromDeviceObject. - tapAdapterContextDereference(adapter); - } - - // Complete the IRP. - Irp->IoStatus.Status = status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest( Irp, IO_NO_INCREMENT ); - - DEBUGP (("[TAP] <-- TapDeviceCreate; status = %8.8X\n",status)); - - return status; -} - -//=================================================== -// Tell Windows whether the TAP device should be -// considered "connected" or "disconnected". -// -// Allows application control of media connect state. -//=================================================== -VOID -tapSetMediaConnectStatus( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in BOOLEAN LogicalMediaState - ) -{ - NDIS_STATUS_INDICATION statusIndication; - NDIS_LINK_STATE linkState; - - NdisZeroMemory(&statusIndication, sizeof(NDIS_STATUS_INDICATION)); - NdisZeroMemory(&linkState, sizeof(NDIS_LINK_STATE)); - - // - // Fill in object headers - // - statusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION; - statusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1; - statusIndication.Header.Size = sizeof(NDIS_STATUS_INDICATION); - - linkState.Header.Revision = NDIS_LINK_STATE_REVISION_1; - linkState.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; - linkState.Header.Size = sizeof(NDIS_LINK_STATE); - - // - // Link state buffer - // - if(Adapter->LogicalMediaState == TRUE) - { - linkState.MediaConnectState = MediaConnectStateConnected; - } - - linkState.MediaDuplexState = MediaDuplexStateFull; - linkState.RcvLinkSpeed = TAP_RECV_SPEED; - linkState.XmitLinkSpeed = TAP_XMIT_SPEED; - - // - // Fill in the status buffer - // - statusIndication.StatusCode = NDIS_STATUS_LINK_STATE; - statusIndication.SourceHandle = Adapter->MiniportAdapterHandle; - statusIndication.DestinationHandle = NULL; - statusIndication.RequestId = 0; - - statusIndication.StatusBuffer = &linkState; - statusIndication.StatusBufferSize = sizeof(NDIS_LINK_STATE); - - // Fill in new media connect state. - if ( (Adapter->LogicalMediaState != LogicalMediaState) && !Adapter->MediaStateAlwaysConnected) - { - Adapter->LogicalMediaState = LogicalMediaState; - - if (LogicalMediaState == TRUE) - { - linkState.MediaConnectState = MediaConnectStateConnected; - - DEBUGP (("[TAP] Set MediaConnectState: Connected.\n")); - } - else - { - linkState.MediaConnectState = MediaConnectStateDisconnected; - - DEBUGP (("[TAP] Set MediaConnectState: Disconnected.\n")); - } - } - - // Make the status indication. - if(Adapter->Locked.AdapterState != MiniportHaltedState) - { - NdisMIndicateStatusEx(Adapter->MiniportAdapterHandle, &statusIndication); - } -} - -/* -//====================================================== -// If DHCP mode is used together with tun -// mode, consider the fact that the P2P remote subnet -// might enclose the DHCP masq server address. -//====================================================== -VOID -CheckIfDhcpAndTunMode ( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - if (Adapter->m_tun && Adapter->m_dhcp_enabled) - { - if ((Adapter->m_dhcp_server_ip & Adapter->m_remoteNetmask) == Adapter->m_remoteNetwork) - { - ETH_COPY_NETWORK_ADDRESS (Adapter->m_dhcp_server_mac, Adapter->m_TapToUser.dest); - Adapter->m_dhcp_server_arp = FALSE; - } - } -} -*/ - -// IRP_MJ_DEVICE_CONTROL callback. -NTSTATUS -TapDeviceControl( - PDEVICE_OBJECT DeviceObject, - PIRP Irp - ) - -/*++ - -Routine Description: - - This routine is called by the I/O system to perform a device I/O - control function. - -Arguments: - - DeviceObject - a pointer to the object that represents the device - that I/O is to be done on. - - Irp - a pointer to the I/O Request Packet for this request. - -Return Value: - - NT status code - ---*/ - -{ - NTSTATUS ntStatus = STATUS_SUCCESS; // Assume success - PIO_STACK_LOCATION irpSp; // Pointer to current stack location - PTAP_ADAPTER_CONTEXT adapter = NULL; - ULONG inBufLength; // Input buffer length - ULONG outBufLength; // Output buffer length - PCHAR inBuf, outBuf; // pointer to Input and output buffer - PMDL mdl = NULL; - PCHAR buffer = NULL; - - PAGED_CODE(); - - irpSp = IoGetCurrentIrpStackLocation( Irp ); - - // - // Fetch adapter context for this device. - // -------------------------------------- - // Adapter pointer was stashed in FsContext when handle was opened. - // - adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; - - ASSERT(adapter); - - inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength; - outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; - - if (!inBufLength || !outBufLength) - { - ntStatus = STATUS_INVALID_PARAMETER; - goto End; - } - - // - // Determine which I/O control code was specified. - // - switch ( irpSp->Parameters.DeviceIoControl.IoControlCode ) - { - case TAP_WIN_IOCTL_GET_MAC: - { - if (outBufLength >= MACADDR_SIZE ) - { - ETH_COPY_NETWORK_ADDRESS( - Irp->AssociatedIrp.SystemBuffer, - adapter->CurrentAddress - ); - - Irp->IoStatus.Information = MACADDR_SIZE; - } - else - { - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; - } - } - break; - - case TAP_WIN_IOCTL_GET_VERSION: - { - const ULONG size = sizeof (ULONG) * 3; - - if (outBufLength >= size) - { - ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0] - = TAP_DRIVER_MAJOR_VERSION; - - ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[1] - = TAP_DRIVER_MINOR_VERSION; - - ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[2] -#if DBG - = 1; -#else - = 0; -#endif - Irp->IoStatus.Information = size; - } - else - { - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; - } - } - break; - - case TAP_WIN_IOCTL_GET_MTU: - { - const ULONG size = sizeof (ULONG) * 1; - - if (outBufLength >= size) - { - ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0] - = adapter->MtuSize; - - Irp->IoStatus.Information = size; - } - else - { - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; - } - } - break; - - // Allow ZeroTier One to get multicast memberships at the L2 level in a - // protocol-neutral manner. - case TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS: - { - if (outBufLength < TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE) { - /* output buffer too small */ - NOTE_ERROR (); - Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; - } else { - char *out = (char *)Irp->AssociatedIrp.SystemBuffer; - char *end = out + TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE; - unsigned long i,j; - for(i=0;iulMCListSize;++i) { - if (i >= TAP_MAX_MCAST_LIST) - break; - for(j=0;j<6;++j) - *(out++) = adapter->MCList[i][j]; - if (out >= end) - break; - } - while (out < end) - *(out++) = (char)0; - Irp->IoStatus.Information = TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE; - Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS; - } - break; - } - - -#if 0 - case TAP_WIN_IOCTL_CONFIG_TUN: - { - if(inBufLength >= sizeof(IPADDR)*3) - { - MACADDR dest; - - adapter->m_tun = FALSE; - - GenerateRelatedMAC (dest, adapter->CurrentAddress, 1); - - adapter->m_localIP = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0]; - adapter->m_remoteNetwork = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1]; - adapter->m_remoteNetmask = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[2]; - - // Sanity check on network/netmask - if ((adapter->m_remoteNetwork & adapter->m_remoteNetmask) != adapter->m_remoteNetwork) - { - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; - break; - } - - ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.src, adapter->CurrentAddress); - ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.dest, dest); - ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.src, dest); - ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.dest, adapter->CurrentAddress); - - adapter->m_TapToUser.proto = adapter->m_UserToTap.proto = htons (NDIS_ETH_TYPE_IPV4); - adapter->m_UserToTap_IPv6 = adapter->m_UserToTap; - adapter->m_UserToTap_IPv6.proto = htons(NDIS_ETH_TYPE_IPV6); - - adapter->m_tun = TRUE; - - CheckIfDhcpAndTunMode (adapter); - - Irp->IoStatus.Information = 1; // Simple boolean value - - DEBUGP (("[TAP] Set TUN mode.\n")); - } - else - { - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; - } - } - break; - - case TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT: - { - if(inBufLength >= sizeof(IPADDR)*2) - { - MACADDR dest; - - adapter->m_tun = FALSE; - - GenerateRelatedMAC (dest, adapter->CurrentAddress, 1); - - adapter->m_localIP = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0]; - adapter->m_remoteNetwork = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1]; - adapter->m_remoteNetmask = ~0; - - ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.src, adapter->CurrentAddress); - ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.dest, dest); - ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.src, dest); - ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.dest, adapter->CurrentAddress); - - adapter->m_TapToUser.proto = adapter->m_UserToTap.proto = htons (NDIS_ETH_TYPE_IPV4); - adapter->m_UserToTap_IPv6 = adapter->m_UserToTap; - adapter->m_UserToTap_IPv6.proto = htons(NDIS_ETH_TYPE_IPV6); - - adapter->m_tun = TRUE; - - CheckIfDhcpAndTunMode (adapter); - - Irp->IoStatus.Information = 1; // Simple boolean value - - DEBUGP (("[TAP] Set P2P mode.\n")); - } - else - { - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; - } - } - break; -#endif - -#if 0 - case TAP_WIN_IOCTL_CONFIG_DHCP_MASQ: - { - if(inBufLength >= sizeof(IPADDR)*4) - { - adapter->m_dhcp_enabled = FALSE; - adapter->m_dhcp_server_arp = FALSE; - adapter->m_dhcp_user_supplied_options_buffer_len = 0; - - // Adapter IP addr / netmask - adapter->m_dhcp_addr = - ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0]; - adapter->m_dhcp_netmask = - ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1]; - - // IP addr of DHCP masq server - adapter->m_dhcp_server_ip = - ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[2]; - - // Lease time in seconds - adapter->m_dhcp_lease_time = - ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[3]; - - GenerateRelatedMAC( - adapter->m_dhcp_server_mac, - adapter->CurrentAddress, - 2 - ); - - adapter->m_dhcp_enabled = TRUE; - adapter->m_dhcp_server_arp = TRUE; - - CheckIfDhcpAndTunMode (adapter); - - Irp->IoStatus.Information = 1; // Simple boolean value - - DEBUGP (("[TAP] Configured DHCP MASQ.\n")); - } - else - { - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; - } - } - break; - - case TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT: - { - if (inBufLength <= DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE - && adapter->m_dhcp_enabled) - { - adapter->m_dhcp_user_supplied_options_buffer_len = 0; - - NdisMoveMemory( - adapter->m_dhcp_user_supplied_options_buffer, - Irp->AssociatedIrp.SystemBuffer, - inBufLength - ); - - adapter->m_dhcp_user_supplied_options_buffer_len = - inBufLength; - - Irp->IoStatus.Information = 1; // Simple boolean value - - DEBUGP (("[TAP] Set DHCP OPT.\n")); - } - else - { - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; - } - } - break; -#endif - -#if 0 - case TAP_WIN_IOCTL_GET_INFO: - { - char state[16]; - - // Fetch adapter (miniport) state. - if (tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS) - state[0] = 'A'; - else - state[0] = 'a'; - - if (tapAdapterReadAndWriteReady(adapter)) - state[1] = 'T'; - else - state[1] = 't'; - - state[2] = '0' + adapter->CurrentPowerState; - - if (adapter->MediaStateAlwaysConnected) - state[3] = 'C'; - else - state[3] = 'c'; - - state[4] = '\0'; - - // BUGBUG!!! What follows, and is not yet implemented, is a real mess. - // BUGBUG!!! Tied closely to the NDIS 5 implementation. Need to map - // as much as possible to the NDIS 6 implementation. - Irp->IoStatus.Status = ntStatus = RtlStringCchPrintfExA ( - ((LPTSTR) (Irp->AssociatedIrp.SystemBuffer)), - outBufLength, - NULL, - NULL, - STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS, -#if PACKET_TRUNCATION_CHECK - "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d,%d] Rx=[%d,%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]", -#else - "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]", -#endif - state, - g_LastErrorFilename, - g_LastErrorLineNumber, - (int)adapter->TapFileOpenCount, - (int)(adapter->FramesTxDirected + adapter->FramesTxMulticast + adapter->FramesTxBroadcast), - (int)adapter->TransmitFailuresOther, -#if PACKET_TRUNCATION_CHECK - (int)adapter->m_TxTrunc, -#endif - (int)adapter->m_Rx, - (int)adapter->m_RxErr, -#if PACKET_TRUNCATION_CHECK - (int)adapter->m_RxTrunc, -#endif - (int)adapter->PendingReadIrpQueue.Count, - (int)adapter->PendingReadIrpQueue.MaxCount, - (int)IRP_QUEUE_SIZE, // Ignored in NDIS 6 driver... - - (int)adapter->SendPacketQueue.Count, - (int)adapter->SendPacketQueue.MaxCount, - (int)PACKET_QUEUE_SIZE, - - (int)0, // adapter->InjectPacketQueue.Count - Unused - (int)0, // adapter->InjectPacketQueue.MaxCount - Unused - (int)INJECT_QUEUE_SIZE - ); - - Irp->IoStatus.Information = outBufLength; - - // BUGBUG!!! Fail because this is not completely implemented. - ntStatus = STATUS_INVALID_DEVICE_REQUEST; - } -#endif - -#if DBG - case TAP_WIN_IOCTL_GET_LOG_LINE: - { - if (GetDebugLine( (LPTSTR)Irp->AssociatedIrp.SystemBuffer,outBufLength)) - { - Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS; - } - else - { - Irp->IoStatus.Status = ntStatus = STATUS_UNSUCCESSFUL; - } - - Irp->IoStatus.Information = outBufLength; - - break; - } -#endif - - case TAP_WIN_IOCTL_SET_MEDIA_STATUS: - { - if(inBufLength >= sizeof(ULONG)) - { - ULONG parm = ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0]; - tapSetMediaConnectStatus (adapter, (BOOLEAN) parm); - Irp->IoStatus.Information = 1; - } - else - { - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; - } - } - break; - - default: - - // - // The specified I/O control code is unrecognized by this driver. - // - ntStatus = STATUS_INVALID_DEVICE_REQUEST; - break; - } - -End: - - // - // Finish the I/O operation by simply completing the packet and returning - // the same status as in the packet itself. - // - Irp->IoStatus.Status = ntStatus; - - IoCompleteRequest( Irp, IO_NO_INCREMENT ); - - return ntStatus; -} - -// Flush the pending read IRP queue. -VOID -tapFlushIrpQueues( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - - DEBUGP (("[TAP] tapFlushIrpQueues: Flushing %d pending read IRPs\n", - Adapter->PendingReadIrpQueue.Count)); - - tapIrpCsqFlush(&Adapter->PendingReadIrpQueue); -} - -// IRP_MJ_CLEANUP -NTSTATUS -TapDeviceCleanup( - PDEVICE_OBJECT DeviceObject, - PIRP Irp - ) -/*++ - -Routine Description: - - Receipt of this request indicates that the last handle for a file - object that is associated with the target device object has been closed - (but, due to outstanding I/O requests, might not have been released). - - A driver that holds pending IRPs internally must implement a routine for - IRP_MJ_CLEANUP. When the routine is called, the driver should cancel all - the pending IRPs that belong to the file object identified by the IRP_MJ_CLEANUP - call. - - In other words, it should cancel all the IRPs that have the same file-object - pointer as the one supplied in the current I/O stack location of the IRP for the - IRP_MJ_CLEANUP call. Of course, IRPs belonging to other file objects should - not be canceled. Also, if an outstanding IRP is completed immediately, the - driver does not have to cancel it. - -Arguments: - - DeviceObject - a pointer to the object that represents the device - to be cleaned up. - - Irp - a pointer to the I/O Request Packet for this request. - -Return Value: - - NT status code - ---*/ - -{ - NDIS_STATUS status = NDIS_STATUS_SUCCESS; // Always succeed. - PIO_STACK_LOCATION irpSp; // Pointer to current stack location - PTAP_ADAPTER_CONTEXT adapter = NULL; - - PAGED_CODE(); - - DEBUGP (("[TAP] --> TapDeviceCleanup\n")); - - irpSp = IoGetCurrentIrpStackLocation(Irp); - - // - // Fetch adapter context for this device. - // -------------------------------------- - // Adapter pointer was stashed in FsContext when handle was opened. - // - adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; - - // Insure that adapter exists. - ASSERT(adapter); - - if(adapter == NULL ) - { - DEBUGP (("[TAP] release [%d.%d] cleanup request; adapter not found\n", - TAP_DRIVER_MAJOR_VERSION, - TAP_DRIVER_MINOR_VERSION - )); - } - - if(adapter != NULL ) - { - adapter->TapFileIsOpen = 0; // Legacy... - - // Disconnect from media. - tapSetMediaConnectStatus(adapter,FALSE); - - // Reset adapter state when cleaning up; - tapResetAdapterState(adapter); - - // BUGBUG!!! Use RemoveLock??? - - // - // Flush pending send TAP packet queue. - // - tapFlushSendPacketQueue(adapter); - - ASSERT(adapter->SendPacketQueue.Count == 0); - - // - // Flush the pending IRP queues - // - tapFlushIrpQueues(adapter); - - ASSERT(adapter->PendingReadIrpQueue.Count == 0); - } - - // Complete the IRP. - Irp->IoStatus.Status = status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest( Irp, IO_NO_INCREMENT ); - - DEBUGP (("[TAP] <-- TapDeviceCleanup; status = %8.8X\n",status)); - - return status; -} - -// IRP_MJ_CLOSE -NTSTATUS -TapDeviceClose( - PDEVICE_OBJECT DeviceObject, - PIRP Irp - ) -/*++ - -Routine Description: - - Receipt of this request indicates that the last handle of the file - object that is associated with the target device object has been closed - and released. - - All outstanding I/O requests have been completed or canceled. - -Arguments: - - DeviceObject - a pointer to the object that represents the device - to be closed. - - Irp - a pointer to the I/O Request Packet for this request. - -Return Value: - - NT status code - ---*/ - -{ - NDIS_STATUS status = NDIS_STATUS_SUCCESS; // Always succeed. - PIO_STACK_LOCATION irpSp; // Pointer to current stack location - PTAP_ADAPTER_CONTEXT adapter = NULL; - - PAGED_CODE(); - - DEBUGP (("[TAP] --> TapDeviceClose\n")); - - irpSp = IoGetCurrentIrpStackLocation(Irp); - - // - // Fetch adapter context for this device. - // -------------------------------------- - // Adapter pointer was stashed in FsContext when handle was opened. - // - adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; - - // Insure that adapter exists. - ASSERT(adapter); - - if(adapter == NULL ) - { - DEBUGP (("[TAP] release [%d.%d] close request; adapter not found\n", - TAP_DRIVER_MAJOR_VERSION, - TAP_DRIVER_MINOR_VERSION - )); - } - - if(adapter != NULL ) - { - if(adapter->TapFileObject == NULL) - { - // Should never happen!!! - ASSERT(FALSE); - } - else - { - ASSERT(irpSp->FileObject->FsContext == adapter); - - ASSERT(adapter->TapFileObject == irpSp->FileObject); - } - - adapter->TapFileObject = NULL; - irpSp->FileObject = NULL; - - // Remove reference added by when handle was opened. - tapAdapterContextDereference(adapter); - } - - // Complete the IRP. - Irp->IoStatus.Status = status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest( Irp, IO_NO_INCREMENT ); - - DEBUGP (("[TAP] <-- TapDeviceClose; status = %8.8X\n",status)); - - return status; -} - -NTSTATUS -tapConcatenateNdisStrings( - __inout PNDIS_STRING DestinationString, - __in_opt PNDIS_STRING SourceString1, - __in_opt PNDIS_STRING SourceString2, - __in_opt PNDIS_STRING SourceString3 - ) -{ - NTSTATUS status; - - ASSERT(SourceString1 && SourceString2 && SourceString3); - - status = RtlAppendUnicodeStringToString( - DestinationString, - SourceString1 - ); - - if(status == STATUS_SUCCESS) - { - status = RtlAppendUnicodeStringToString( - DestinationString, - SourceString2 - ); - - if(status == STATUS_SUCCESS) - { - status = RtlAppendUnicodeStringToString( - DestinationString, - SourceString3 - ); - } - } - - return status; -} - -NTSTATUS -tapMakeDeviceNames( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - NDIS_STATUS status; - NDIS_STRING deviceNamePrefix = NDIS_STRING_CONST("\\Device\\"); - NDIS_STRING tapNameSuffix = NDIS_STRING_CONST(".tap"); - - // Generate DeviceName from NetCfgInstanceId. - Adapter->DeviceName.Buffer = Adapter->DeviceNameBuffer; - Adapter->DeviceName.MaximumLength = sizeof(Adapter->DeviceNameBuffer); - - status = tapConcatenateNdisStrings( - &Adapter->DeviceName, - &deviceNamePrefix, - &Adapter->NetCfgInstanceId, - &tapNameSuffix - ); - - if(status == STATUS_SUCCESS) - { - NDIS_STRING linkNamePrefix = NDIS_STRING_CONST("\\DosDevices\\Global\\"); - - Adapter->LinkName.Buffer = Adapter->LinkNameBuffer; - Adapter->LinkName.MaximumLength = sizeof(Adapter->LinkNameBuffer); - - status = tapConcatenateNdisStrings( - &Adapter->LinkName, - &linkNamePrefix, - &Adapter->NetCfgInstanceId, - &tapNameSuffix - ); - } - - return status; -} - -NDIS_STATUS -CreateTapDevice( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - NDIS_STATUS status; - NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttribute; - PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1]; - - DEBUGP (("[TAP] version [%d.%d] creating tap device: %wZ\n", - TAP_DRIVER_MAJOR_VERSION, - TAP_DRIVER_MINOR_VERSION, - &Adapter->NetCfgInstanceId)); - - // Generate DeviceName and LinkName from NetCfgInstanceId. - status = tapMakeDeviceNames(Adapter); - - if (NT_SUCCESS(status)) - { - DEBUGP (("[TAP] DeviceName: %wZ\n",&Adapter->DeviceName)); - DEBUGP (("[TAP] LinkName: %wZ\n",&Adapter->LinkName)); - - // Initialize dispatch table. - NdisZeroMemory(dispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH)); - - dispatchTable[IRP_MJ_CREATE] = TapDeviceCreate; - dispatchTable[IRP_MJ_CLEANUP] = TapDeviceCleanup; - dispatchTable[IRP_MJ_CLOSE] = TapDeviceClose; - dispatchTable[IRP_MJ_READ] = TapDeviceRead; - dispatchTable[IRP_MJ_WRITE] = TapDeviceWrite; - dispatchTable[IRP_MJ_DEVICE_CONTROL] = TapDeviceControl; - - // - // Create a device object and register dispatch handlers - // - NdisZeroMemory(&deviceAttribute, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES)); - - deviceAttribute.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES; - deviceAttribute.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1; - deviceAttribute.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES); - - deviceAttribute.DeviceName = &Adapter->DeviceName; - deviceAttribute.SymbolicName = &Adapter->LinkName; - deviceAttribute.MajorFunctions = &dispatchTable[0]; - //deviceAttribute.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION); - -#if ENABLE_NONADMIN - if(Adapter->AllowNonAdmin) - { - // - // SDDL_DEVOBJ_SYS_ALL_WORLD_RWX_RES_RWX allows the kernel and system complete - // control over the device. By default the admin can access the entire device, - // but cannot change the ACL (the admin must take control of the device first) - // - // Everyone else, including "restricted" or "untrusted" code can read or write - // to the device. Traversal beneath the device is also granted (removing it - // would only effect storage devices, except if the "bypass-traversal" - // privilege was revoked). - // - deviceAttribute.DefaultSDDLString = &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX; - } -#endif - - status = NdisRegisterDeviceEx( - Adapter->MiniportAdapterHandle, - &deviceAttribute, - &Adapter->DeviceObject, - &Adapter->DeviceHandle - ); - } - - ASSERT(NT_SUCCESS(status)); - - if (NT_SUCCESS(status)) - { - // Set TAP device flags. - (Adapter->DeviceObject)->Flags &= ~DO_BUFFERED_IO; - (Adapter->DeviceObject)->Flags |= DO_DIRECT_IO;; - - //======================== - // Finalize initialization - //======================== - - Adapter->TapDeviceCreated = TRUE; - - DEBUGP (("[%wZ] successfully created TAP device [%wZ]\n", - &Adapter->NetCfgInstanceId, - &Adapter->DeviceName - )); - } - - DEBUGP (("[TAP] <-- CreateTapDevice; status = %8.8X\n",status)); - - return status; -} - -// -// DestroyTapDevice is called from AdapterHalt and NDIS miniport -// is in Halted state. Prior to entering the Halted state the -// miniport would have passed through the Pausing and Paused -// states. These miniport states have responsibility for waiting -// until NDIS network operations have completed. -// -VOID -DestroyTapDevice( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - DEBUGP (("[TAP] --> DestroyTapDevice; Adapter: %wZ\n", - &Adapter->NetCfgInstanceId)); - - // - // Let clients know we are shutting down - // - Adapter->TapDeviceCreated = FALSE; - - // - // Flush pending send TAP packet queue. - // - tapFlushSendPacketQueue(Adapter); - - ASSERT(Adapter->SendPacketQueue.Count == 0); - - // - // Flush IRP queues. Wait for pending I/O. Etc. - // -------------------------------------------- - // Exhaust IRP and packet queues. Any pending IRPs will - // be cancelled, causing user-space to get this error - // on overlapped reads: - // - // ERROR_OPERATION_ABORTED, code=995 - // - // "The I/O operation has been aborted because of either a - // thread exit or an application request." - // - // It's important that user-space close the device handle - // when this code is returned, so that when we finally - // do a NdisMDeregisterDeviceEx, the device reference count - // is 0. Otherwise the driver will not unload even if the - // the last adapter has been halted. - // - // The act of flushing the queues at this point should result in the user-mode - // application closing the adapter's device handle. Closing the handle will - // result in the TapDeviceCleanup call being made, followed by the a call to - // the TapDeviceClose callback. - // - tapFlushIrpQueues(Adapter); - - ASSERT(Adapter->PendingReadIrpQueue.Count == 0); - - // - // Deregister the Win32 device. - // ---------------------------- - // When a driver calls NdisDeregisterDeviceEx, the I/O manager deletes the - // target device object if there are no outstanding references to it. However, - // if any outstanding references remain, the I/O manager marks the device - // object as "delete pending" and deletes the device object when the references - // are finally released. - // - if(Adapter->DeviceHandle) - { - DEBUGP (("[TAP] Calling NdisDeregisterDeviceEx\n")); - NdisDeregisterDeviceEx(Adapter->DeviceHandle); - } - - Adapter->DeviceHandle = NULL; - - DEBUGP (("[TAP] <-- DestroyTapDevice\n")); -} - diff --git a/zto/windows/TapDriver6/device.h b/zto/windows/TapDriver6/device.h deleted file mode 100644 index 93dae0d..0000000 --- a/zto/windows/TapDriver6/device.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __TAP_DEVICE_H_ -#define __TAP_DEVICE_H_ - -//====================================================================== -// TAP Prototypes for standard Win32 device I/O entry points -//====================================================================== - -__drv_dispatchType(IRP_MJ_CREATE) -DRIVER_DISPATCH TapDeviceCreate; - -__drv_dispatchType(IRP_MJ_READ) -DRIVER_DISPATCH TapDeviceRead; - -__drv_dispatchType(IRP_MJ_WRITE) -DRIVER_DISPATCH TapDeviceWrite; - -__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) -DRIVER_DISPATCH TapDeviceControl; - -__drv_dispatchType(IRP_MJ_CLEANUP) -DRIVER_DISPATCH TapDeviceCleanup; - -__drv_dispatchType(IRP_MJ_CLOSE) -DRIVER_DISPATCH TapDeviceClose; - -#endif // __TAP_DEVICE_H_ \ No newline at end of file diff --git a/zto/windows/TapDriver6/endian.h b/zto/windows/TapDriver6/endian.h deleted file mode 100644 index b7d3449..0000000 --- a/zto/windows/TapDriver6/endian.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef TAP_LITTLE_ENDIAN -#define ntohs(x) RtlUshortByteSwap(x) -#define htons(x) RtlUshortByteSwap(x) -#define ntohl(x) RtlUlongByteSwap(x) -#define htonl(x) RtlUlongByteSwap(x) -#else -#define ntohs(x) ((USHORT)(x)) -#define htons(x) ((USHORT)(x)) -#define ntohl(x) ((ULONG)(x)) -#define htonl(x) ((ULONG)(x)) -#endif diff --git a/zto/windows/TapDriver6/error.c b/zto/windows/TapDriver6/error.c deleted file mode 100644 index 1fad1d3..0000000 --- a/zto/windows/TapDriver6/error.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tap.h" - -//----------------- -// DEBUGGING OUTPUT -//----------------- - -const char *g_LastErrorFilename; -int g_LastErrorLineNumber; - -#if DBG - -DebugOutput g_Debug; - -BOOLEAN -NewlineExists (const char *str, int len) -{ - while (len-- > 0) - { - const char c = *str++; - if (c == '\n') - return TRUE; - else if (c == '\0') - break; - } - return FALSE; -} - -VOID -MyDebugInit (unsigned int bufsiz) -{ - NdisZeroMemory (&g_Debug, sizeof (g_Debug)); - g_Debug.text = (char *) MemAlloc (bufsiz, FALSE); - - if (g_Debug.text) - { - g_Debug.capacity = bufsiz; - } -} - -VOID -MyDebugFree () -{ - if (g_Debug.text) - { - MemFree (g_Debug.text, g_Debug.capacity); - } - - NdisZeroMemory (&g_Debug, sizeof (g_Debug)); -} - -VOID -MyDebugPrint (const unsigned char* format, ...) -{ - if (g_Debug.text && g_Debug.capacity > 0 && CAN_WE_PRINT) - { - BOOLEAN owned; - ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned); - if (owned) - { - const int remaining = (int)g_Debug.capacity - (int)g_Debug.out; - - if (remaining > 0) - { - va_list args; - NTSTATUS status; - char *end; - -#ifdef DBG_PRINT - va_start (args, format); - vDbgPrintEx (DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, format, args); - va_end (args); -#endif - va_start (args, format); - status = RtlStringCchVPrintfExA (g_Debug.text + g_Debug.out, - remaining, - &end, - NULL, - STRSAFE_NO_TRUNCATION | STRSAFE_IGNORE_NULLS, - format, - args); - va_end (args); - va_start (args, format); - vDbgPrintEx(DPFLTR_IHVDRIVER_ID , 1, format, args); - va_end (args); - if (status == STATUS_SUCCESS) - g_Debug.out = (unsigned int) (end - g_Debug.text); - else - g_Debug.error = TRUE; - } - else - g_Debug.error = TRUE; - - RELEASE_MUTEX (&g_Debug.lock); - } - else - g_Debug.error = TRUE; - } -} - -BOOLEAN -GetDebugLine ( - __in char *buf, - __in const int len - ) -{ - static const char *truncated = "[OUTPUT TRUNCATED]\n"; - BOOLEAN ret = FALSE; - - NdisZeroMemory (buf, len); - - if (g_Debug.text && g_Debug.capacity > 0) - { - BOOLEAN owned; - ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned); - if (owned) - { - int i = 0; - - if (g_Debug.error || NewlineExists (g_Debug.text + g_Debug.in, (int)g_Debug.out - (int)g_Debug.in)) - { - while (i < (len - 1) && g_Debug.in < g_Debug.out) - { - const char c = g_Debug.text[g_Debug.in++]; - if (c == '\n') - break; - buf[i++] = c; - } - if (i < len) - buf[i] = '\0'; - } - - if (!i) - { - if (g_Debug.in == g_Debug.out) - { - g_Debug.in = g_Debug.out = 0; - if (g_Debug.error) - { - const unsigned int tlen = strlen (truncated); - if (tlen < g_Debug.capacity) - { - NdisMoveMemory (g_Debug.text, truncated, tlen+1); - g_Debug.out = tlen; - } - g_Debug.error = FALSE; - } - } - } - else - ret = TRUE; - - RELEASE_MUTEX (&g_Debug.lock); - } - } - return ret; -} - -VOID -PrMac (const MACADDR mac) -{ - DEBUGP (("%x:%x:%x:%x:%x:%x", - mac[0], mac[1], mac[2], - mac[3], mac[4], mac[5])); -} - -VOID -PrIP (IPADDR ip_addr) -{ - const unsigned char *ip = (const unsigned char *) &ip_addr; - - DEBUGP (("%d.%d.%d.%d", - ip[0], ip[1], ip[2], ip[3])); -} - -const char * -PrIPProto (int proto) -{ - switch (proto) - { - case IPPROTO_UDP: - return "UDP"; - - case IPPROTO_TCP: - return "TCP"; - - case IPPROTO_ICMP: - return "ICMP"; - - case IPPROTO_IGMP: - return "IGMP"; - - default: - return "???"; - } -} - -VOID -DumpARP (const char *prefix, const ARP_PACKET *arp) -{ - DEBUGP (("%s ARP src=", prefix)); - PrMac (arp->m_MAC_Source); - DEBUGP ((" dest=")); - PrMac (arp->m_MAC_Destination); - DEBUGP ((" OP=0x%04x", - (int)ntohs(arp->m_ARP_Operation))); - DEBUGP ((" M=0x%04x(%d)", - (int)ntohs(arp->m_MAC_AddressType), - (int)arp->m_MAC_AddressSize)); - DEBUGP ((" P=0x%04x(%d)", - (int)ntohs(arp->m_PROTO_AddressType), - (int)arp->m_PROTO_AddressSize)); - - DEBUGP ((" MacSrc=")); - PrMac (arp->m_ARP_MAC_Source); - DEBUGP ((" MacDest=")); - PrMac (arp->m_ARP_MAC_Destination); - - DEBUGP ((" IPSrc=")); - PrIP (arp->m_ARP_IP_Source); - DEBUGP ((" IPDest=")); - PrIP (arp->m_ARP_IP_Destination); - - DEBUGP (("\n")); -} - -struct ethpayload -{ - ETH_HEADER eth; - UCHAR payload[DEFAULT_PACKET_LOOKAHEAD]; -}; - -#ifdef ALLOW_PACKET_DUMP - -VOID -DumpPacket2( - __in const char *prefix, - __in const ETH_HEADER *eth, - __in const unsigned char *data, - __in unsigned int len - ) -{ - struct ethpayload *ep = (struct ethpayload *) MemAlloc (sizeof (struct ethpayload), TRUE); - if (ep) - { - if (len > DEFAULT_PACKET_LOOKAHEAD) - len = DEFAULT_PACKET_LOOKAHEAD; - ep->eth = *eth; - NdisMoveMemory (ep->payload, data, len); - DumpPacket (prefix, (unsigned char *) ep, sizeof (ETH_HEADER) + len); - MemFree (ep, sizeof (struct ethpayload)); - } -} - -VOID -DumpPacket( - __in const char *prefix, - __in const unsigned char *data, - __in unsigned int len - ) -{ - const ETH_HEADER *eth = (const ETH_HEADER *) data; - const IPHDR *ip = (const IPHDR *) (data + sizeof (ETH_HEADER)); - - if (len < sizeof (ETH_HEADER)) - { - DEBUGP (("%s TRUNCATED PACKET LEN=%d\n", prefix, len)); - return; - } - - // ARP Packet? - if (len >= sizeof (ARP_PACKET) && eth->proto == htons (ETH_P_ARP)) - { - DumpARP (prefix, (const ARP_PACKET *) data); - return; - } - - // IPv4 packet? - if (len >= (sizeof (IPHDR) + sizeof (ETH_HEADER)) - && eth->proto == htons (ETH_P_IP) - && IPH_GET_VER (ip->version_len) == 4) - { - const int hlen = IPH_GET_LEN (ip->version_len); - const int blen = len - sizeof (ETH_HEADER); - BOOLEAN did = FALSE; - - DEBUGP (("%s IPv4 %s[%d]", prefix, PrIPProto (ip->protocol), len)); - - if (!(ntohs (ip->tot_len) == blen && hlen <= blen)) - { - DEBUGP ((" XXX")); - return; - } - - // TCP packet? - if (ip->protocol == IPPROTO_TCP - && blen - hlen >= (sizeof (TCPHDR))) - { - const TCPHDR *tcp = (TCPHDR *) (data + sizeof (ETH_HEADER) + hlen); - DEBUGP ((" ")); - PrIP (ip->saddr); - DEBUGP ((":%d", ntohs (tcp->source))); - DEBUGP ((" -> ")); - PrIP (ip->daddr); - DEBUGP ((":%d", ntohs (tcp->dest))); - did = TRUE; - } - - // UDP packet? - else if ((ntohs (ip->frag_off) & IP_OFFMASK) == 0 - && ip->protocol == IPPROTO_UDP - && blen - hlen >= (sizeof (UDPHDR))) - { - const UDPHDR *udp = (UDPHDR *) (data + sizeof (ETH_HEADER) + hlen); - - // DHCP packet? - if ((udp->dest == htons (BOOTPC_PORT) || udp->dest == htons (BOOTPS_PORT)) - && blen - hlen >= (sizeof (UDPHDR) + sizeof (DHCP))) - { - const DHCP *dhcp = (DHCP *) (data - + hlen - + sizeof (ETH_HEADER) - + sizeof (UDPHDR)); - - int optlen = len - - sizeof (ETH_HEADER) - - hlen - - sizeof (UDPHDR) - - sizeof (DHCP); - - if (optlen < 0) - optlen = 0; - - DumpDHCP (eth, ip, udp, dhcp, optlen); - did = TRUE; - } - - if (!did) - { - DEBUGP ((" ")); - PrIP (ip->saddr); - DEBUGP ((":%d", ntohs (udp->source))); - DEBUGP ((" -> ")); - PrIP (ip->daddr); - DEBUGP ((":%d", ntohs (udp->dest))); - did = TRUE; - } - } - - if (!did) - { - DEBUGP ((" ipproto=%d ", ip->protocol)); - PrIP (ip->saddr); - DEBUGP ((" -> ")); - PrIP (ip->daddr); - } - - DEBUGP (("\n")); - return; - } - - { - DEBUGP (("%s ??? src=", prefix)); - PrMac (eth->src); - DEBUGP ((" dest=")); - PrMac (eth->dest); - DEBUGP ((" proto=0x%04x len=%d\n", - (int) ntohs(eth->proto), - len)); - } -} - -#endif // ALLOW_PACKET_DUMP - -#endif diff --git a/zto/windows/TapDriver6/error.h b/zto/windows/TapDriver6/error.h deleted file mode 100644 index 2ba39cc..0000000 --- a/zto/windows/TapDriver6/error.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -//----------------- -// DEBUGGING OUTPUT -//----------------- - -extern const char *g_LastErrorFilename; -extern int g_LastErrorLineNumber; - -// Debug info output -#define ALSO_DBGPRINT 1 -#define DEBUGP_AT_DISPATCH 1 - -// Uncomment line below to allow packet dumps -//#define ALLOW_PACKET_DUMP 1 - -#define NOTE_ERROR() \ -{ \ - g_LastErrorFilename = __FILE__; \ - g_LastErrorLineNumber = __LINE__; \ -} - -#if DBG - -typedef struct -{ - unsigned int in; - unsigned int out; - unsigned int capacity; - char *text; - BOOLEAN error; - MUTEX lock; -} DebugOutput; - -VOID MyDebugPrint (const unsigned char* format, ...); - -VOID PrMac (const MACADDR mac); - -VOID PrIP (IPADDR ip_addr); - -#ifdef ALLOW_PACKET_DUMP - -VOID -DumpPacket( - __in const char *prefix, - __in const unsigned char *data, - __in unsigned int len - ); - -DumpPacket2( - __in const char *prefix, - __in const ETH_HEADER *eth, - __in const unsigned char *data, - __in unsigned int len - ); - -#else -#define DUMP_PACKET(prefix, data, len) -#define DUMP_PACKET2(prefix, eth, data, len) -#endif - -#define CAN_WE_PRINT (DEBUGP_AT_DISPATCH || KeGetCurrentIrql () < DISPATCH_LEVEL) - -#if ALSO_DBGPRINT -#define DEBUGP(fmt) { MyDebugPrint fmt; if (CAN_WE_PRINT) DbgPrint fmt; } -#else -#define DEBUGP(fmt) { MyDebugPrint fmt; } -#endif - -#ifdef ALLOW_PACKET_DUMP - -#define DUMP_PACKET(prefix, data, len) \ - DumpPacket (prefix, data, len) - -#define DUMP_PACKET2(prefix, eth, data, len) \ - DumpPacket2 (prefix, eth, data, len) - -#endif - -BOOLEAN -GetDebugLine ( - __in char *buf, - __in const int len - ); - -#else - -#define DEBUGP(fmt) -#define DUMP_PACKET(prefix, data, len) -#define DUMP_PACKET2(prefix, eth, data, len) - -#endif diff --git a/zto/windows/TapDriver6/hexdump.h b/zto/windows/TapDriver6/hexdump.h deleted file mode 100644 index d6275c1..0000000 --- a/zto/windows/TapDriver6/hexdump.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef HEXDUMP_DEFINED -#define HEXDUMP_DEFINED - -#ifdef __cplusplus -extern "C" { -#endif - -//===================================================================================== -// Debug Routines -//===================================================================================== - -#ifndef NDIS_MINIPORT_DRIVER -# include -# include -# include -# include -# include - -# ifndef DEBUGP -# define DEBUGP(fmt) { DbgMessage fmt; } -# endif - - extern VOID (*DbgMessage)(char *p_Format, ...); - - VOID DisplayDebugString (char *p_Format, ...); -#endif - -//=================================================================================== -// Reporting / Debugging -//=================================================================================== -#define IfPrint(c) (c >= 32 && c < 127 ? c : '.') - -VOID HexDump (unsigned char *p_Buffer, unsigned long p_Size); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/zto/windows/TapDriver6/lock.h b/zto/windows/TapDriver6/lock.h deleted file mode 100644 index c80b164..0000000 --- a/zto/windows/TapDriver6/lock.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -typedef struct -{ - volatile long count; -} MUTEX; - -#define MUTEX_SLEEP_TIME 10000 // microseconds - -#define INIT_MUTEX(m) { (m)->count = 0; } - -#define ACQUIRE_MUTEX_BLOCKING(m) \ -{ \ - while (NdisInterlockedIncrement (&((m)->count)) != 1) \ - { \ - NdisInterlockedDecrement(&((m)->count)); \ - NdisMSleep(MUTEX_SLEEP_TIME); \ - } \ -} - -#define RELEASE_MUTEX(m) \ -{ \ - NdisInterlockedDecrement(&((m)->count)); \ -} - -#define ACQUIRE_MUTEX_NONBLOCKING(m, result) \ -{ \ - if (NdisInterlockedIncrement (&((m)->count)) != 1) \ - { \ - NdisInterlockedDecrement(&((m)->count)); \ - result = FALSE; \ - } \ - else \ - { \ - result = TRUE; \ - } \ -} - -#define ACQUIRE_MUTEX_ADAPTIVE(m, result) \ -{ \ - result = TRUE; \ - while (NdisInterlockedIncrement (&((m)->count)) != 1) \ - { \ - NdisInterlockedDecrement(&((m)->count)); \ - if (KeGetCurrentIrql () < DISPATCH_LEVEL) \ - NdisMSleep(MUTEX_SLEEP_TIME); \ - else \ - { \ - result = FALSE; \ - break; \ - } \ - } \ -} diff --git a/zto/windows/TapDriver6/macinfo.c b/zto/windows/TapDriver6/macinfo.c deleted file mode 100644 index dfd0a07..0000000 --- a/zto/windows/TapDriver6/macinfo.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "tap.h" - -int -HexStringToDecimalInt (const int p_Character) -{ - int l_Value = 0; - - if (p_Character >= 'A' && p_Character <= 'F') - l_Value = (p_Character - 'A') + 10; - else if (p_Character >= 'a' && p_Character <= 'f') - l_Value = (p_Character - 'a') + 10; - else if (p_Character >= '0' && p_Character <= '9') - l_Value = p_Character - '0'; - - return l_Value; -} - -BOOLEAN -ParseMAC (MACADDR dest, const char *src) -{ - int c; - int mac_index = 0; - BOOLEAN high_digit = FALSE; - int delim_action = 1; - - ASSERT (src); - ASSERT (dest); - - CLEAR_MAC (dest); - - while (c = *src++) - { - if (IsMacDelimiter (c)) - { - mac_index += delim_action; - high_digit = FALSE; - delim_action = 1; - } - else if (IsHexDigit (c)) - { - const int digit = HexStringToDecimalInt (c); - if (mac_index < sizeof (MACADDR)) - { - if (!high_digit) - { - dest[mac_index] = (char)(digit); - high_digit = TRUE; - delim_action = 1; - } - else - { - dest[mac_index] = (char)(dest[mac_index] * 16 + digit); - ++mac_index; - high_digit = FALSE; - delim_action = 0; - } - } - else - return FALSE; - } - else - return FALSE; - } - - return (mac_index + delim_action) >= sizeof (MACADDR); -} - -/* - * Generate a MAC using the GUID in the adapter name. - * - * The mac is constructed as 00:FF:xx:xx:xx:xx where - * the Xs are taken from the first 32 bits of the GUID in the - * adapter name. This is similar to the Linux 2.4 tap MAC - * generator, except linux uses 32 random bits for the Xs. - * - * In general, this solution is reasonable for most - * applications except for very large bridged TAP networks, - * where the probability of address collisions becomes more - * than infintesimal. - * - * Using the well-known "birthday paradox", on a 1000 node - * network the probability of collision would be - * 0.000116292153. On a 10,000 node network, the probability - * of collision would be 0.01157288998621678766. - */ - -VOID -GenerateRandomMac( - __in MACADDR mac, - __in const unsigned char *adapter_name - ) -{ - unsigned const char *cp = adapter_name; - unsigned char c; - unsigned int i = 2; - unsigned int byte = 0; - int brace = 0; - int state = 0; - - CLEAR_MAC (mac); - - mac[0] = 0x00; - mac[1] = 0xFF; - - while (c = *cp++) - { - if (i >= sizeof (MACADDR)) - break; - if (c == '{') - brace = 1; - if (IsHexDigit (c) && brace) - { - const unsigned int digit = HexStringToDecimalInt (c); - if (state) - { - byte <<= 4; - byte |= digit; - mac[i++] = (unsigned char) byte; - state = 0; - } - else - { - byte = digit; - state = 1; - } - } - } -} - -VOID -GenerateRelatedMAC( - __in MACADDR dest, - __in const MACADDR src, - __in const int delta - ) -{ - ETH_COPY_NETWORK_ADDRESS (dest, src); - dest[2] += (UCHAR) delta; -} diff --git a/zto/windows/TapDriver6/macinfo.h b/zto/windows/TapDriver6/macinfo.h deleted file mode 100644 index dd88b6f..0000000 --- a/zto/windows/TapDriver6/macinfo.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MacInfoDefined -#define MacInfoDefined - -//=================================================================================== -// Macros -//=================================================================================== -#define IsMacDelimiter(a) (a == ':' || a == '-' || a == '.') -#define IsHexDigit(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) - -#define CLEAR_MAC(dest) NdisZeroMemory ((dest), sizeof (MACADDR)) -#define MAC_EQUAL(a,b) (memcmp ((a), (b), sizeof (MACADDR)) == 0) - -BOOLEAN -ParseMAC (MACADDR dest, const char *src); - -VOID -GenerateRandomMac( - __in MACADDR mac, - __in const unsigned char *adapter_name - ); - -VOID -GenerateRelatedMAC( - __in MACADDR dest, - __in const MACADDR src, - __in const int delta - ); - -#endif diff --git a/zto/windows/TapDriver6/mem.c b/zto/windows/TapDriver6/mem.c deleted file mode 100644 index ae2e3d4..0000000 --- a/zto/windows/TapDriver6/mem.c +++ /dev/null @@ -1,401 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -//------------------ -// Memory Management -//------------------ - -#include "tap.h" - -PVOID -MemAlloc( - __in ULONG p_Size, - __in BOOLEAN zero - ) -{ - PVOID l_Return = NULL; - - if (p_Size) - { - __try - { - if (NdisAllocateMemoryWithTag (&l_Return, p_Size, 'APAT') - == NDIS_STATUS_SUCCESS) - { - if (zero) - { - NdisZeroMemory (l_Return, p_Size); - } - } - else - { - l_Return = NULL; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - l_Return = NULL; - } - } - - return l_Return; -} - -VOID -MemFree( - __in PVOID p_Addr, - __in ULONG p_Size - ) -{ - if (p_Addr && p_Size) - { - __try - { -#if DBG - NdisZeroMemory (p_Addr, p_Size); -#endif - NdisFreeMemory (p_Addr, p_Size, 0); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - } - } -} - -//====================================================================== -// TAP Packet Queue Support -//====================================================================== - -VOID -tapPacketQueueInsertTail( - __in PTAP_PACKET_QUEUE TapPacketQueue, - __in PTAP_PACKET TapPacket - ) -{ - KIRQL irql; - - KeAcquireSpinLock(&TapPacketQueue->QueueLock,&irql); - - InsertTailList(&TapPacketQueue->Queue,&TapPacket->QueueLink); - - // BUGBUG!!! Enforce PACKET_QUEUE_SIZE queue count limit??? - // For NDIS 6 there is no per-packet status, so this will need to - // be handled on per-NBL basis in AdapterSendNetBufferLists... - - // Update counts - ++TapPacketQueue->Count; - - if(TapPacketQueue->Count > TapPacketQueue->MaxCount) - { - TapPacketQueue->MaxCount = TapPacketQueue->Count; - - DEBUGP (("[TAP] tapPacketQueueInsertTail: New MAX queued packet count = %d\n", - TapPacketQueue->MaxCount)); - } - - KeReleaseSpinLock(&TapPacketQueue->QueueLock,irql); -} - -// Call with QueueLock held -PTAP_PACKET -tapPacketRemoveHeadLocked( - __in PTAP_PACKET_QUEUE TapPacketQueue - ) -{ - PTAP_PACKET tapPacket = NULL; - PLIST_ENTRY listEntry; - - listEntry = RemoveHeadList(&TapPacketQueue->Queue); - - if(listEntry != &TapPacketQueue->Queue) - { - tapPacket = CONTAINING_RECORD(listEntry, TAP_PACKET, QueueLink); - - // Update counts - --TapPacketQueue->Count; - } - - return tapPacket; -} - -PTAP_PACKET -tapPacketRemoveHead( - __in PTAP_PACKET_QUEUE TapPacketQueue - ) -{ - PTAP_PACKET tapPacket = NULL; - KIRQL irql; - - KeAcquireSpinLock(&TapPacketQueue->QueueLock,&irql); - - tapPacket = tapPacketRemoveHeadLocked(TapPacketQueue); - - KeReleaseSpinLock(&TapPacketQueue->QueueLock,irql); - - return tapPacket; -} - -VOID -tapPacketQueueInitialize( - __in PTAP_PACKET_QUEUE TapPacketQueue - ) -{ - KeInitializeSpinLock(&TapPacketQueue->QueueLock); - - NdisInitializeListHead(&TapPacketQueue->Queue); -} - -//====================================================================== -// TAP Cancel-Safe Queue Support -//====================================================================== - -VOID -tapIrpCsqInsert ( - __in struct _IO_CSQ *Csq, - __in PIRP Irp - ) -{ - PTAP_IRP_CSQ tapIrpCsq; - - tapIrpCsq = (PTAP_IRP_CSQ )Csq; - - InsertTailList( - &tapIrpCsq->Queue, - &Irp->Tail.Overlay.ListEntry - ); - - // Update counts - ++tapIrpCsq->Count; - - if(tapIrpCsq->Count > tapIrpCsq->MaxCount) - { - tapIrpCsq->MaxCount = tapIrpCsq->Count; - - DEBUGP (("[TAP] tapIrpCsqInsert: New MAX queued IRP count = %d\n", - tapIrpCsq->MaxCount)); - } -} - -VOID -tapIrpCsqRemoveIrp( - __in PIO_CSQ Csq, - __in PIRP Irp - ) -{ - PTAP_IRP_CSQ tapIrpCsq; - - tapIrpCsq = (PTAP_IRP_CSQ )Csq; - - // Update counts - --tapIrpCsq->Count; - - RemoveEntryList(&Irp->Tail.Overlay.ListEntry); -} - - -PIRP -tapIrpCsqPeekNextIrp( - __in PIO_CSQ Csq, - __in PIRP Irp, - __in PVOID PeekContext - ) -{ - PTAP_IRP_CSQ tapIrpCsq; - PIRP nextIrp = NULL; - PLIST_ENTRY nextEntry; - PLIST_ENTRY listHead; - PIO_STACK_LOCATION irpStack; - - tapIrpCsq = (PTAP_IRP_CSQ )Csq; - - listHead = &tapIrpCsq->Queue; - - // - // If the IRP is NULL, we will start peeking from the listhead, else - // we will start from that IRP onwards. This is done under the - // assumption that new IRPs are always inserted at the tail. - // - - if (Irp == NULL) - { - nextEntry = listHead->Flink; - } - else - { - nextEntry = Irp->Tail.Overlay.ListEntry.Flink; - } - - while(nextEntry != listHead) - { - nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry); - - irpStack = IoGetCurrentIrpStackLocation(nextIrp); - - // - // If context is present, continue until you find a matching one. - // Else you break out as you got next one. - // - if (PeekContext) - { - if (irpStack->FileObject == (PFILE_OBJECT) PeekContext) - { - break; - } - } - else - { - break; - } - - nextIrp = NULL; - nextEntry = nextEntry->Flink; - } - - return nextIrp; -} - -// -// tapIrpCsqAcquireQueueLock modifies the execution level of the current processor. -// -// KeAcquireSpinLock raises the execution level to Dispatch Level and stores -// the current execution level in the Irql parameter to be restored at a later -// time. KeAcqurieSpinLock also requires us to be running at no higher than -// Dispatch level when it is called. -// -// The annotations reflect these changes and requirments. -// - -__drv_raisesIRQL(DISPATCH_LEVEL) -__drv_maxIRQL(DISPATCH_LEVEL) -VOID -tapIrpCsqAcquireQueueLock( - __in PIO_CSQ Csq, - __out PKIRQL Irql - ) -{ - PTAP_IRP_CSQ tapIrpCsq; - - tapIrpCsq = (PTAP_IRP_CSQ )Csq; - - // - // Suppressing because the address below csq is valid since it's - // part of TAP_ADAPTER_CONTEXT structure. - // -#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'adapter->PendingReadCsqQueueLock'") - KeAcquireSpinLock(&tapIrpCsq->QueueLock, Irql); -} - -// -// tapIrpCsqReleaseQueueLock modifies the execution level of the current processor. -// -// KeReleaseSpinLock assumes we already hold the spin lock and are therefore -// running at Dispatch level. It will use the Irql parameter saved in a -// previous call to KeAcquireSpinLock to return the thread back to it's original -// execution level. -// -// The annotations reflect these changes and requirments. -// - -__drv_requiresIRQL(DISPATCH_LEVEL) -VOID -tapIrpCsqReleaseQueueLock( - __in PIO_CSQ Csq, - __in KIRQL Irql - ) -{ - PTAP_IRP_CSQ tapIrpCsq; - - tapIrpCsq = (PTAP_IRP_CSQ )Csq; - - // - // Suppressing because the address below csq is valid since it's - // part of TAP_ADAPTER_CONTEXT structure. - // -#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'adapter->PendingReadCsqQueueLock'") - KeReleaseSpinLock(&tapIrpCsq->QueueLock, Irql); -} - -VOID -tapIrpCsqCompleteCanceledIrp( - __in PIO_CSQ pCsq, - __in PIRP Irp - ) -{ - UNREFERENCED_PARAMETER(pCsq); - - Irp->IoStatus.Status = STATUS_CANCELLED; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); -} - -VOID -tapIrpCsqInitialize( - __in PTAP_IRP_CSQ TapIrpCsq - ) -{ - KeInitializeSpinLock(&TapIrpCsq->QueueLock); - - NdisInitializeListHead(&TapIrpCsq->Queue); - - IoCsqInitialize( - &TapIrpCsq->CsqQueue, - tapIrpCsqInsert, - tapIrpCsqRemoveIrp, - tapIrpCsqPeekNextIrp, - tapIrpCsqAcquireQueueLock, - tapIrpCsqReleaseQueueLock, - tapIrpCsqCompleteCanceledIrp - ); -} - -VOID -tapIrpCsqFlush( - __in PTAP_IRP_CSQ TapIrpCsq - ) -{ - PIRP pendingIrp; - - // - // Flush the pending read IRP queue. - // - pendingIrp = IoCsqRemoveNextIrp( - &TapIrpCsq->CsqQueue, - NULL - ); - - while(pendingIrp) - { - // Cancel the IRP - pendingIrp->IoStatus.Information = 0; - pendingIrp->IoStatus.Status = STATUS_CANCELLED; - IoCompleteRequest(pendingIrp, IO_NO_INCREMENT); - - pendingIrp = IoCsqRemoveNextIrp( - &TapIrpCsq->CsqQueue, - NULL - ); - } - - ASSERT(IsListEmpty(&TapIrpCsq->Queue)); -} diff --git a/zto/windows/TapDriver6/mem.h b/zto/windows/TapDriver6/mem.h deleted file mode 100644 index a8359e1..0000000 --- a/zto/windows/TapDriver6/mem.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -//------------------ -// Memory Management -//------------------ - -PVOID -MemAlloc( - __in ULONG p_Size, - __in BOOLEAN zero - ); - -VOID -MemFree( - __in PVOID p_Addr, - __in ULONG p_Size - ); - -//====================================================================== -// TAP Packet Queue -//====================================================================== - -typedef -struct _TAP_PACKET -{ - LIST_ENTRY QueueLink; - -# define TAP_PACKET_SIZE(data_size) (sizeof (TAP_PACKET) + (data_size)) -# define TP_TUN 0x80000000 -# define TP_SIZE_MASK (~TP_TUN) - ULONG m_SizeFlags; - - // m_Data must be the last struct member - UCHAR m_Data []; -} TAP_PACKET, *PTAP_PACKET; - -#define TAP_PACKET_TAG '6PAT' // "TAP6" - -typedef struct _TAP_PACKET_QUEUE -{ - KSPIN_LOCK QueueLock; - LIST_ENTRY Queue; - ULONG Count; // Count of currently queued items - ULONG MaxCount; -} TAP_PACKET_QUEUE, *PTAP_PACKET_QUEUE; - -VOID -tapPacketQueueInsertTail( - __in PTAP_PACKET_QUEUE TapPacketQueue, - __in PTAP_PACKET TapPacket - ); - - -// Call with QueueLock held -PTAP_PACKET -tapPacketRemoveHeadLocked( - __in PTAP_PACKET_QUEUE TapPacketQueue - ); - -PTAP_PACKET -tapPacketRemoveHead( - __in PTAP_PACKET_QUEUE TapPacketQueue - ); - -VOID -tapPacketQueueInitialize( - __in PTAP_PACKET_QUEUE TapPacketQueue - ); - -//---------------------- -// Cancel-Safe IRP Queue -//---------------------- - -typedef struct _TAP_IRP_CSQ -{ - IO_CSQ CsqQueue; - KSPIN_LOCK QueueLock; - LIST_ENTRY Queue; - ULONG Count; // Count of currently queued items - ULONG MaxCount; -} TAP_IRP_CSQ, *PTAP_IRP_CSQ; - -VOID -tapIrpCsqInitialize( - __in PTAP_IRP_CSQ TapIrpCsq - ); - -VOID -tapIrpCsqFlush( - __in PTAP_IRP_CSQ TapIrpCsq - ); diff --git a/zto/windows/TapDriver6/oidrequest.c b/zto/windows/TapDriver6/oidrequest.c deleted file mode 100644 index a6882f8..0000000 --- a/zto/windows/TapDriver6/oidrequest.c +++ /dev/null @@ -1,1028 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// -// Include files. -// - -#include "tap.h" - -#ifndef DBG - -#define DBG_PRINT_OID_NAME - -#else - -VOID -DBG_PRINT_OID_NAME( - __in NDIS_OID Oid - ) -{ - PCHAR oidName = NULL; - - switch (Oid){ - - #undef MAKECASE - #define MAKECASE(oidx) case oidx: oidName = #oidx "\n"; break; - - /* Operational OIDs */ - MAKECASE(OID_GEN_SUPPORTED_LIST) - MAKECASE(OID_GEN_HARDWARE_STATUS) - MAKECASE(OID_GEN_MEDIA_SUPPORTED) - MAKECASE(OID_GEN_MEDIA_IN_USE) - MAKECASE(OID_GEN_MAXIMUM_LOOKAHEAD) - MAKECASE(OID_GEN_MAXIMUM_FRAME_SIZE) - MAKECASE(OID_GEN_LINK_SPEED) - MAKECASE(OID_GEN_TRANSMIT_BUFFER_SPACE) - MAKECASE(OID_GEN_RECEIVE_BUFFER_SPACE) - MAKECASE(OID_GEN_TRANSMIT_BLOCK_SIZE) - MAKECASE(OID_GEN_RECEIVE_BLOCK_SIZE) - MAKECASE(OID_GEN_VENDOR_ID) - MAKECASE(OID_GEN_VENDOR_DESCRIPTION) - MAKECASE(OID_GEN_VENDOR_DRIVER_VERSION) - MAKECASE(OID_GEN_CURRENT_PACKET_FILTER) - MAKECASE(OID_GEN_CURRENT_LOOKAHEAD) - MAKECASE(OID_GEN_DRIVER_VERSION) - MAKECASE(OID_GEN_MAXIMUM_TOTAL_SIZE) - MAKECASE(OID_GEN_PROTOCOL_OPTIONS) - MAKECASE(OID_GEN_MAC_OPTIONS) - MAKECASE(OID_GEN_MEDIA_CONNECT_STATUS) - MAKECASE(OID_GEN_MAXIMUM_SEND_PACKETS) - MAKECASE(OID_GEN_SUPPORTED_GUIDS) - MAKECASE(OID_GEN_NETWORK_LAYER_ADDRESSES) - MAKECASE(OID_GEN_TRANSPORT_HEADER_OFFSET) - MAKECASE(OID_GEN_MEDIA_CAPABILITIES) - MAKECASE(OID_GEN_PHYSICAL_MEDIUM) - MAKECASE(OID_GEN_MACHINE_NAME) - MAKECASE(OID_GEN_VLAN_ID) - MAKECASE(OID_GEN_RNDIS_CONFIG_PARAMETER) - - /* Operational OIDs for NDIS 6.0 */ - MAKECASE(OID_GEN_MAX_LINK_SPEED) - MAKECASE(OID_GEN_LINK_STATE) - MAKECASE(OID_GEN_LINK_PARAMETERS) - MAKECASE(OID_GEN_MINIPORT_RESTART_ATTRIBUTES) - MAKECASE(OID_GEN_ENUMERATE_PORTS) - MAKECASE(OID_GEN_PORT_STATE) - MAKECASE(OID_GEN_PORT_AUTHENTICATION_PARAMETERS) - MAKECASE(OID_GEN_INTERRUPT_MODERATION) - MAKECASE(OID_GEN_PHYSICAL_MEDIUM_EX) - - /* Statistical OIDs */ - MAKECASE(OID_GEN_XMIT_OK) - MAKECASE(OID_GEN_RCV_OK) - MAKECASE(OID_GEN_XMIT_ERROR) - MAKECASE(OID_GEN_RCV_ERROR) - MAKECASE(OID_GEN_RCV_NO_BUFFER) - MAKECASE(OID_GEN_DIRECTED_BYTES_XMIT) - MAKECASE(OID_GEN_DIRECTED_FRAMES_XMIT) - MAKECASE(OID_GEN_MULTICAST_BYTES_XMIT) - MAKECASE(OID_GEN_MULTICAST_FRAMES_XMIT) - MAKECASE(OID_GEN_BROADCAST_BYTES_XMIT) - MAKECASE(OID_GEN_BROADCAST_FRAMES_XMIT) - MAKECASE(OID_GEN_DIRECTED_BYTES_RCV) - MAKECASE(OID_GEN_DIRECTED_FRAMES_RCV) - MAKECASE(OID_GEN_MULTICAST_BYTES_RCV) - MAKECASE(OID_GEN_MULTICAST_FRAMES_RCV) - MAKECASE(OID_GEN_BROADCAST_BYTES_RCV) - MAKECASE(OID_GEN_BROADCAST_FRAMES_RCV) - MAKECASE(OID_GEN_RCV_CRC_ERROR) - MAKECASE(OID_GEN_TRANSMIT_QUEUE_LENGTH) - - /* Statistical OIDs for NDIS 6.0 */ - MAKECASE(OID_GEN_STATISTICS) - MAKECASE(OID_GEN_BYTES_RCV) - MAKECASE(OID_GEN_BYTES_XMIT) - MAKECASE(OID_GEN_RCV_DISCARDS) - MAKECASE(OID_GEN_XMIT_DISCARDS) - - /* Misc OIDs */ - MAKECASE(OID_GEN_GET_TIME_CAPS) - MAKECASE(OID_GEN_GET_NETCARD_TIME) - MAKECASE(OID_GEN_NETCARD_LOAD) - MAKECASE(OID_GEN_DEVICE_PROFILE) - MAKECASE(OID_GEN_INIT_TIME_MS) - MAKECASE(OID_GEN_RESET_COUNTS) - MAKECASE(OID_GEN_MEDIA_SENSE_COUNTS) - - /* PnP power management operational OIDs */ - MAKECASE(OID_PNP_CAPABILITIES) - MAKECASE(OID_PNP_SET_POWER) - MAKECASE(OID_PNP_QUERY_POWER) - MAKECASE(OID_PNP_ADD_WAKE_UP_PATTERN) - MAKECASE(OID_PNP_REMOVE_WAKE_UP_PATTERN) - MAKECASE(OID_PNP_ENABLE_WAKE_UP) - MAKECASE(OID_PNP_WAKE_UP_PATTERN_LIST) - - /* PnP power management statistical OIDs */ - MAKECASE(OID_PNP_WAKE_UP_ERROR) - MAKECASE(OID_PNP_WAKE_UP_OK) - - /* Ethernet operational OIDs */ - MAKECASE(OID_802_3_PERMANENT_ADDRESS) - MAKECASE(OID_802_3_CURRENT_ADDRESS) - MAKECASE(OID_802_3_MULTICAST_LIST) - MAKECASE(OID_802_3_MAXIMUM_LIST_SIZE) - MAKECASE(OID_802_3_MAC_OPTIONS) - - /* Ethernet operational OIDs for NDIS 6.0 */ - MAKECASE(OID_802_3_ADD_MULTICAST_ADDRESS) - MAKECASE(OID_802_3_DELETE_MULTICAST_ADDRESS) - - /* Ethernet statistical OIDs */ - MAKECASE(OID_802_3_RCV_ERROR_ALIGNMENT) - MAKECASE(OID_802_3_XMIT_ONE_COLLISION) - MAKECASE(OID_802_3_XMIT_MORE_COLLISIONS) - MAKECASE(OID_802_3_XMIT_DEFERRED) - MAKECASE(OID_802_3_XMIT_MAX_COLLISIONS) - MAKECASE(OID_802_3_RCV_OVERRUN) - MAKECASE(OID_802_3_XMIT_UNDERRUN) - MAKECASE(OID_802_3_XMIT_HEARTBEAT_FAILURE) - MAKECASE(OID_802_3_XMIT_TIMES_CRS_LOST) - MAKECASE(OID_802_3_XMIT_LATE_COLLISIONS) - - /* TCP/IP OIDs */ - MAKECASE(OID_TCP_TASK_OFFLOAD) - MAKECASE(OID_TCP_TASK_IPSEC_ADD_SA) - MAKECASE(OID_TCP_TASK_IPSEC_DELETE_SA) - MAKECASE(OID_TCP_SAN_SUPPORT) - MAKECASE(OID_TCP_TASK_IPSEC_ADD_UDPESP_SA) - MAKECASE(OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA) - MAKECASE(OID_TCP4_OFFLOAD_STATS) - MAKECASE(OID_TCP6_OFFLOAD_STATS) - MAKECASE(OID_IP4_OFFLOAD_STATS) - MAKECASE(OID_IP6_OFFLOAD_STATS) - - /* TCP offload OIDs for NDIS 6 */ - MAKECASE(OID_TCP_OFFLOAD_CURRENT_CONFIG) - MAKECASE(OID_TCP_OFFLOAD_PARAMETERS) - MAKECASE(OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES) - MAKECASE(OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG) - MAKECASE(OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES) - MAKECASE(OID_OFFLOAD_ENCAPSULATION) - -#if (NDIS_SUPPORT_NDIS620) - /* VMQ OIDs for NDIS 6.20 */ - MAKECASE(OID_RECEIVE_FILTER_FREE_QUEUE) - MAKECASE(OID_RECEIVE_FILTER_CLEAR_FILTER) - MAKECASE(OID_RECEIVE_FILTER_ALLOCATE_QUEUE) - MAKECASE(OID_RECEIVE_FILTER_QUEUE_ALLOCATION_COMPLETE) - MAKECASE(OID_RECEIVE_FILTER_SET_FILTER) -#endif - -#if (NDIS_SUPPORT_NDIS630) - /* NDIS QoS OIDs for NDIS 6.30 */ - MAKECASE(OID_QOS_PARAMETERS) -#endif - } - - if (oidName) - { - DEBUGP(("OID: %s", oidName)); - } - else - { - DEBUGP(("<** Unknown OID 0x%08x **>\n", Oid)); - } -} - -#endif // DBG - -//====================================================================== -// TAP NDIS 6 OID Request Callbacks -//====================================================================== - -NDIS_STATUS -tapSetMulticastList( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in PNDIS_OID_REQUEST OidRequest - ) -{ - NDIS_STATUS status = NDIS_STATUS_SUCCESS; - - // - // Initialize. - // - OidRequest->DATA.SET_INFORMATION.BytesNeeded = MACADDR_SIZE; - OidRequest->DATA.SET_INFORMATION.BytesRead - = OidRequest->DATA.SET_INFORMATION.InformationBufferLength; - - - do - { - if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength % MACADDR_SIZE) - { - status = NDIS_STATUS_INVALID_LENGTH; - break; - } - - if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength > (TAP_MAX_MCAST_LIST * MACADDR_SIZE)) - { - status = NDIS_STATUS_MULTICAST_FULL; - OidRequest->DATA.SET_INFORMATION.BytesNeeded = TAP_MAX_MCAST_LIST * MACADDR_SIZE; - break; - } - - // BUGBUG!!! Is lock needed??? If so, use NDIS_RW_LOCK. Also apply to packet filter. - - NdisZeroMemory(Adapter->MCList, - TAP_MAX_MCAST_LIST * MACADDR_SIZE); - - NdisMoveMemory(Adapter->MCList, - OidRequest->DATA.SET_INFORMATION.InformationBuffer, - OidRequest->DATA.SET_INFORMATION.InformationBufferLength); - - Adapter->ulMCListSize = OidRequest->DATA.SET_INFORMATION.InformationBufferLength / MACADDR_SIZE; - - } while(FALSE); - return status; -} - -NDIS_STATUS -tapSetPacketFilter( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in ULONG PacketFilter - ) -{ - NDIS_STATUS status = NDIS_STATUS_SUCCESS; - - // any bits not supported? - if (PacketFilter & ~(TAP_SUPPORTED_FILTERS)) - { - DEBUGP (("[TAP] Unsupported packet filter: 0x%08x\n", PacketFilter)); - status = NDIS_STATUS_NOT_SUPPORTED; - } - else - { - // Any actual filtering changes? - if (PacketFilter != Adapter->PacketFilter) - { - // - // Change the filtering modes on hardware - // - - // Save the new packet filter value - Adapter->PacketFilter = PacketFilter; - } - } - - return status; -} - -NDIS_STATUS -AdapterSetPowerD0( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -/*++ -Routine Description: - - NIC power has been restored to the working power state (D0). - Prepare the NIC for normal operation: - - Restore hardware context (packet filters, multicast addresses, MAC address, etc.) - - Enable interrupts and the NIC's DMA engine. - -Arguments: - - Adapter - Pointer to adapter block - -Return Value: - - NDIS_STATUS - ---*/ -{ - NDIS_STATUS status = NDIS_STATUS_SUCCESS; - - DEBUGP (("[TAP] PowerState: Fully powered\n")); - - // Start data path... - - return status; -} - -NDIS_STATUS -AdapterSetPowerLow( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in NDIS_DEVICE_POWER_STATE PowerState - ) -/*++ -Routine Description: - - The NIC is about to be transitioned to a low power state. - Prepare the NIC for the sleeping state: - - Disable interrupts and the NIC's DMA engine, cancel timers. - - Save any hardware context that the NIC cannot preserve in - a sleeping state (packet filters, multicast addresses, - the current MAC address, etc.) - A miniport driver cannot access the NIC hardware after - the NIC has been set to the D3 state by the bus driver. - - Miniport drivers NDIS v6.30 and above - Do NOT wait for NDIS to return the ownership of all - NBLs from outstanding receive indications - Retain ownership of all the receive descriptors and - packet buffers previously owned by the hardware. - -Arguments: - - Adapter - Pointer to adapter block - PowerState - New power state - -Return Value: - - NDIS_STATUS - ---*/ -{ - NDIS_STATUS status = NDIS_STATUS_SUCCESS; - - DEBUGP (("[TAP] PowerState: Low-power\n")); - - // - // Miniport drivers NDIS v6.20 and below are - // paused prior the low power transition - // - - // Check for paused state... - // Verify data path stopped... - - return status; -} - -NDIS_STATUS -tapSetInformation( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in PNDIS_OID_REQUEST OidRequest - ) -/*++ - -Routine Description: - - Helper function to perform a set OID request - -Arguments: - - Adapter - - NdisSetRequest - The OID to set - -Return Value: - - NDIS_STATUS - ---*/ -{ - NDIS_STATUS status = NDIS_STATUS_SUCCESS; - - DBG_PRINT_OID_NAME(OidRequest->DATA.SET_INFORMATION.Oid); - - switch(OidRequest->DATA.SET_INFORMATION.Oid) - { - case OID_802_3_MULTICAST_LIST: - // - // Set the multicast address list on the NIC for packet reception. - // The NIC driver can set a limit on the number of multicast - // addresses bound protocol drivers can enable simultaneously. - // NDIS returns NDIS_STATUS_MULTICAST_FULL if a protocol driver - // exceeds this limit or if it specifies an invalid multicast - // address. - // - status = tapSetMulticastList(Adapter,OidRequest); - break; - - case OID_GEN_CURRENT_LOOKAHEAD: - // - // A protocol driver can set a suggested value for the number - // of bytes to be used in its binding; however, the underlying - // NIC driver is never required to limit its indications to - // the value set. - // - if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG)) - { - OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG); - status = NDIS_STATUS_INVALID_LENGTH; - break; - } - - Adapter->ulLookahead = *(PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer; - - OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(ULONG); - status = NDIS_STATUS_SUCCESS; - break; - - case OID_GEN_CURRENT_PACKET_FILTER: - // - // Program the hardware to indicate the packets - // of certain filter types. - // - if(OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG)) - { - OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG); - status = NDIS_STATUS_INVALID_LENGTH; - break; - } - - OidRequest->DATA.SET_INFORMATION.BytesRead - = OidRequest->DATA.SET_INFORMATION.InformationBufferLength; - - status = tapSetPacketFilter( - Adapter, - *((PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer) - ); - - break; - - case OID_PNP_SET_POWER: - { - // Sanity check. - if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength - < sizeof(NDIS_DEVICE_POWER_STATE) - ) - { - status = NDIS_STATUS_INVALID_LENGTH; - } - else - { - NDIS_DEVICE_POWER_STATE PowerState; - - PowerState = *(PNDIS_DEVICE_POWER_STATE UNALIGNED)OidRequest->DATA.SET_INFORMATION.InformationBuffer; - OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(NDIS_DEVICE_POWER_STATE); - - if(PowerState < NdisDeviceStateD0 || - PowerState > NdisDeviceStateD3) - { - status = NDIS_STATUS_INVALID_DATA; - } - else - { - Adapter->CurrentPowerState = PowerState; - - if (PowerState == NdisDeviceStateD0) - { - status = AdapterSetPowerD0(Adapter); - } - else - { - status = AdapterSetPowerLow(Adapter, PowerState); - } - } - } - } - break; - -#if (NDIS_SUPPORT_NDIS61) - case OID_PNP_ADD_WAKE_UP_PATTERN: - case OID_PNP_REMOVE_WAKE_UP_PATTERN: - case OID_PNP_ENABLE_WAKE_UP: -#endif - ASSERT(!"NIC does not support wake on LAN OIDs"); - default: - // - // The entry point may by used by other requests - // - status = NDIS_STATUS_NOT_SUPPORTED; - break; - } - - return status; -} - -NDIS_STATUS -tapQueryInformation( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in PNDIS_OID_REQUEST OidRequest - ) -/*++ - -Routine Description: - - Helper function to perform a query OID request - -Arguments: - - Adapter - - OidRequest - The OID request that is being queried - -Return Value: - - NDIS_STATUS - ---*/ -{ - NDIS_STATUS status = NDIS_STATUS_SUCCESS; - NDIS_MEDIUM Medium = TAP_MEDIUM_TYPE; - NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady; - UCHAR VendorDesc[] = TAP_VENDOR_DESC; - ULONG ulInfo; - USHORT usInfo; - ULONG64 ulInfo64; - - // Default to returning the ULONG value - PVOID pInfo=NULL; - ULONG ulInfoLen = sizeof(ulInfo); - - // ATTENTION!!! Ignore OIDs to noisy to print... - if((OidRequest->DATA.QUERY_INFORMATION.Oid != OID_GEN_STATISTICS) - && (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP4_OFFLOAD_STATS) - && (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP6_OFFLOAD_STATS) - ) - { - DBG_PRINT_OID_NAME(OidRequest->DATA.QUERY_INFORMATION.Oid); - } - - // Dispatch based on object identifier (OID). - switch(OidRequest->DATA.QUERY_INFORMATION.Oid) - { - case OID_GEN_HARDWARE_STATUS: - // - // Specify the current hardware status of the underlying NIC as - // one of the following NDIS_HARDWARE_STATUS-type values. - // - pInfo = (PVOID) &HardwareStatus; - ulInfoLen = sizeof(NDIS_HARDWARE_STATUS); - break; - - case OID_802_3_PERMANENT_ADDRESS: - // - // Return the MAC address of the NIC burnt in the hardware. - // - pInfo = Adapter->PermanentAddress; - ulInfoLen = MACADDR_SIZE; - break; - - case OID_802_3_CURRENT_ADDRESS: - // - // Return the MAC address the NIC is currently programmed to - // use. Note that this address could be different from the - // permananent address as the user can override using - // registry. Read NdisReadNetworkAddress doc for more info. - // - pInfo = Adapter->CurrentAddress; - ulInfoLen = MACADDR_SIZE; - break; - - case OID_GEN_MEDIA_SUPPORTED: - // - // Return an array of media that are supported by the miniport. - // This miniport only supports one medium (Ethernet), so the OID - // returns identical results to OID_GEN_MEDIA_IN_USE. - // - - __fallthrough; - - case OID_GEN_MEDIA_IN_USE: - // - // Return an array of media that are currently in use by the - // miniport. This array should be a subset of the array returned - // by OID_GEN_MEDIA_SUPPORTED. - // - pInfo = &Medium; - ulInfoLen = sizeof(Medium); - break; - - case OID_GEN_MAXIMUM_TOTAL_SIZE: - // - // Specify the maximum total packet length, in bytes, the NIC - // supports including the header. A protocol driver might use - // this returned length as a gauge to determine the maximum - // size packet that a NIC driver could forward to the - // protocol driver. The miniport driver must never indicate - // up to the bound protocol driver packets received over the - // network that are longer than the packet size specified by - // OID_GEN_MAXIMUM_TOTAL_SIZE. - // - - __fallthrough; - - case OID_GEN_TRANSMIT_BLOCK_SIZE: - // - // The OID_GEN_TRANSMIT_BLOCK_SIZE OID specifies the minimum - // number of bytes that a single net packet occupies in the - // transmit buffer space of the NIC. In our case, the transmit - // block size is identical to its maximum packet size. - __fallthrough; - - case OID_GEN_RECEIVE_BLOCK_SIZE: - // - // The OID_GEN_RECEIVE_BLOCK_SIZE OID specifies the amount of - // storage, in bytes, that a single packet occupies in the receive - // buffer space of the NIC. - // - ulInfo = (ULONG) TAP_MAX_FRAME_SIZE; - pInfo = &ulInfo; - break; - - case OID_GEN_INTERRUPT_MODERATION: - { - PNDIS_INTERRUPT_MODERATION_PARAMETERS moderationParams - = (PNDIS_INTERRUPT_MODERATION_PARAMETERS)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer; - - moderationParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; - moderationParams->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; - moderationParams->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; - moderationParams->Flags = 0; - moderationParams->InterruptModeration = NdisInterruptModerationNotSupported; - ulInfoLen = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; - } - break; - - case OID_PNP_QUERY_POWER: - // Simply succeed this. - break; - - case OID_GEN_VENDOR_ID: - // - // Specify a three-byte IEEE-registered vendor code, followed - // by a single byte that the vendor assigns to identify a - // particular NIC. The IEEE code uniquely identifies the vendor - // and is the same as the three bytes appearing at the beginning - // of the NIC hardware address. Vendors without an IEEE-registered - // code should use the value 0xFFFFFF. - // - - ulInfo = TAP_VENDOR_ID; - pInfo = &ulInfo; - break; - - case OID_GEN_VENDOR_DESCRIPTION: - // - // Specify a zero-terminated string describing the NIC vendor. - // - pInfo = VendorDesc; - ulInfoLen = sizeof(VendorDesc); - break; - - case OID_GEN_VENDOR_DRIVER_VERSION: - // - // Specify the vendor-assigned version number of the NIC driver. - // The low-order half of the return value specifies the minor - // version; the high-order half specifies the major version. - // - - ulInfo = TAP_DRIVER_VENDOR_VERSION; - pInfo = &ulInfo; - break; - - case OID_GEN_DRIVER_VERSION: - // - // Specify the NDIS version in use by the NIC driver. The high - // byte is the major version number; the low byte is the minor - // version number. - // - usInfo = (USHORT) (TAP_NDIS_MAJOR_VERSION<<8) + TAP_NDIS_MINOR_VERSION; - pInfo = (PVOID) &usInfo; - ulInfoLen = sizeof(USHORT); - break; - - case OID_802_3_MAXIMUM_LIST_SIZE: - // - // The maximum number of multicast addresses the NIC driver - // can manage. This list is global for all protocols bound - // to (or above) the NIC. Consequently, a protocol can receive - // NDIS_STATUS_MULTICAST_FULL from the NIC driver when - // attempting to set the multicast address list, even if - // the number of elements in the given list is less than - // the number originally returned for this query. - // - - ulInfo = TAP_MAX_MCAST_LIST; - pInfo = &ulInfo; - break; - - case OID_GEN_XMIT_ERROR: - ulInfo = (ULONG) - (Adapter->TxAbortExcessCollisions + - Adapter->TxDmaUnderrun + - Adapter->TxLostCRS + - Adapter->TxLateCollisions+ - Adapter->TransmitFailuresOther); - pInfo = &ulInfo; - break; - - case OID_GEN_RCV_ERROR: - ulInfo = (ULONG) - (Adapter->RxCrcErrors + - Adapter->RxAlignmentErrors + - Adapter->RxDmaOverrunErrors + - Adapter->RxRuntErrors); - pInfo = &ulInfo; - break; - - case OID_GEN_RCV_DISCARDS: - ulInfo = (ULONG)Adapter->RxResourceErrors; - pInfo = &ulInfo; - break; - - case OID_GEN_RCV_NO_BUFFER: - ulInfo = (ULONG)Adapter->RxResourceErrors; - pInfo = &ulInfo; - break; - - case OID_GEN_XMIT_OK: - ulInfo64 = Adapter->FramesTxBroadcast - + Adapter->FramesTxMulticast - + Adapter->FramesTxDirected; - pInfo = &ulInfo64; - if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) || - OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0) - { - ulInfoLen = sizeof(ULONG64); - } - else - { - ulInfoLen = sizeof(ULONG); - } - - // We should always report that only 8 bytes are required to keep ndistest happy - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64); - break; - - case OID_GEN_RCV_OK: - ulInfo64 = Adapter->FramesRxBroadcast - + Adapter->FramesRxMulticast - + Adapter->FramesRxDirected; - - pInfo = &ulInfo64; - - if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) || - OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0) - { - ulInfoLen = sizeof(ULONG64); - } - else - { - ulInfoLen = sizeof(ULONG); - } - - // We should always report that only 8 bytes are required to keep ndistest happy - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64); - break; - - case OID_802_3_RCV_ERROR_ALIGNMENT: - - ulInfo = Adapter->RxAlignmentErrors; - pInfo = &ulInfo; - break; - - case OID_802_3_XMIT_ONE_COLLISION: - - ulInfo = Adapter->OneRetry; - pInfo = &ulInfo; - break; - - case OID_802_3_XMIT_MORE_COLLISIONS: - - ulInfo = Adapter->MoreThanOneRetry; - pInfo = &ulInfo; - break; - - case OID_802_3_XMIT_DEFERRED: - - ulInfo = Adapter->TxOKButDeferred; - pInfo = &ulInfo; - break; - - case OID_802_3_XMIT_MAX_COLLISIONS: - - ulInfo = Adapter->TxAbortExcessCollisions; - pInfo = &ulInfo; - break; - - case OID_802_3_RCV_OVERRUN: - - ulInfo = Adapter->RxDmaOverrunErrors; - pInfo = &ulInfo; - break; - - case OID_802_3_XMIT_UNDERRUN: - - ulInfo = Adapter->TxDmaUnderrun; - pInfo = &ulInfo; - break; - - case OID_GEN_STATISTICS: - - if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(NDIS_STATISTICS_INFO)) - { - status = NDIS_STATUS_INVALID_LENGTH; - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(NDIS_STATISTICS_INFO); - break; - } - else - { - PNDIS_STATISTICS_INFO Statistics - = (PNDIS_STATISTICS_INFO)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer; - - {C_ASSERT(sizeof(NDIS_STATISTICS_INFO) >= NDIS_SIZEOF_STATISTICS_INFO_REVISION_1);} - Statistics->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; - Statistics->Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1; - Statistics->Header.Revision = NDIS_STATISTICS_INFO_REVISION_1; - - Statistics->SupportedStatistics = TAP_SUPPORTED_STATISTICS; - - /* Bytes in */ - Statistics->ifHCInOctets = - Adapter->BytesRxDirected + - Adapter->BytesRxMulticast + - Adapter->BytesRxBroadcast; - - Statistics->ifHCInUcastOctets = - Adapter->BytesRxDirected; - - Statistics->ifHCInMulticastOctets = - Adapter->BytesRxMulticast; - - Statistics->ifHCInBroadcastOctets = - Adapter->BytesRxBroadcast; - - /* Packets in */ - Statistics->ifHCInUcastPkts = - Adapter->FramesRxDirected; - - Statistics->ifHCInMulticastPkts = - Adapter->FramesRxMulticast; - - Statistics->ifHCInBroadcastPkts = - Adapter->FramesRxBroadcast; - - /* Errors in */ - Statistics->ifInErrors = - Adapter->RxCrcErrors + - Adapter->RxAlignmentErrors + - Adapter->RxDmaOverrunErrors + - Adapter->RxRuntErrors; - - Statistics->ifInDiscards = - Adapter->RxResourceErrors; - - - /* Bytes out */ - Statistics->ifHCOutOctets = - Adapter->BytesTxDirected + - Adapter->BytesTxMulticast + - Adapter->BytesTxBroadcast; - - Statistics->ifHCOutUcastOctets = - Adapter->BytesTxDirected; - - Statistics->ifHCOutMulticastOctets = - Adapter->BytesTxMulticast; - - Statistics->ifHCOutBroadcastOctets = - Adapter->BytesTxBroadcast; - - /* Packets out */ - Statistics->ifHCOutUcastPkts = - Adapter->FramesTxDirected; - - Statistics->ifHCOutMulticastPkts = - Adapter->FramesTxMulticast; - - Statistics->ifHCOutBroadcastPkts = - Adapter->FramesTxBroadcast; - - /* Errors out */ - Statistics->ifOutErrors = - Adapter->TxAbortExcessCollisions + - Adapter->TxDmaUnderrun + - Adapter->TxLostCRS + - Adapter->TxLateCollisions+ - Adapter->TransmitFailuresOther; - - Statistics->ifOutDiscards = 0ULL; - - ulInfoLen = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1; - } - - break; - - // TODO: Inplement these query information requests. - case OID_GEN_RECEIVE_BUFFER_SPACE: - case OID_GEN_MAXIMUM_SEND_PACKETS: - case OID_GEN_TRANSMIT_QUEUE_LENGTH: - case OID_802_3_XMIT_HEARTBEAT_FAILURE: - case OID_802_3_XMIT_TIMES_CRS_LOST: - case OID_802_3_XMIT_LATE_COLLISIONS: - - default: - // - // The entry point may by used by other requests - // - status = NDIS_STATUS_NOT_SUPPORTED; - break; - } - - if (status == NDIS_STATUS_SUCCESS) - { - ASSERT(ulInfoLen > 0); - - if (ulInfoLen <= OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength) - { - if(pInfo) - { - // Copy result into InformationBuffer - NdisMoveMemory( - OidRequest->DATA.QUERY_INFORMATION.InformationBuffer, - pInfo, - ulInfoLen - ); - } - - OidRequest->DATA.QUERY_INFORMATION.BytesWritten = ulInfoLen; - } - else - { - // too short - OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = ulInfoLen; - status = NDIS_STATUS_BUFFER_TOO_SHORT; - } - } - - return status; -} - -NDIS_STATUS -AdapterOidRequest( - __in NDIS_HANDLE MiniportAdapterContext, - __in PNDIS_OID_REQUEST OidRequest - ) -/*++ - -Routine Description: - - Entry point called by NDIS to get or set the value of a specified OID. - -Arguments: - - MiniportAdapterContext - Our adapter handle - NdisRequest - The OID request to handle - -Return Value: - - Return code from the NdisRequest below. - ---*/ -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - NDIS_STATUS status; - - // Dispatch based on request type. - switch (OidRequest->RequestType) - { - case NdisRequestSetInformation: - status = tapSetInformation(adapter,OidRequest); - break; - - case NdisRequestQueryInformation: - case NdisRequestQueryStatistics: - status = tapQueryInformation(adapter,OidRequest); - break; - - case NdisRequestMethod: // TAP doesn't need to respond to this request type. - default: - // - // The entry point may by used by other requests - // - status = NDIS_STATUS_NOT_SUPPORTED; - break; - } - - return status; -} - -VOID -AdapterCancelOidRequest( - __in NDIS_HANDLE MiniportAdapterContext, - __in PVOID RequestId - ) -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - - UNREFERENCED_PARAMETER(RequestId); - - // - // This miniport sample does not pend any OID requests, so we don't have - // to worry about cancelling them. - // -} - diff --git a/zto/windows/TapDriver6/proto.h b/zto/windows/TapDriver6/proto.h deleted file mode 100644 index cc23de6..0000000 --- a/zto/windows/TapDriver6/proto.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -//============================================================ -// MAC address, Ethernet header, and ARP -//============================================================ - -#pragma pack(1) - -#define IP_HEADER_SIZE 20 -#define IPV6_HEADER_SIZE 40 - -#define MACADDR_SIZE 6 -typedef unsigned char MACADDR[MACADDR_SIZE]; - -typedef unsigned long IPADDR; -typedef unsigned char IPV6ADDR[16]; - -//----------------- -// Ethernet address -//----------------- - -typedef struct { - MACADDR addr; -} ETH_ADDR; - -typedef struct { - ETH_ADDR list[TAP_MAX_MCAST_LIST]; -} MC_LIST; - - -// BUGBUG!!! Consider using ststem defines in netiodef.h!!! - -//---------------- -// Ethernet header -//---------------- -typedef struct -{ - MACADDR dest; /* destination eth addr */ - MACADDR src; /* source ether addr */ - USHORT proto; /* packet type ID field */ -} ETH_HEADER, *PETH_HEADER; - -//---------------- -// ARP packet -//---------------- - -typedef struct - { - MACADDR m_MAC_Destination; // Reverse these two - MACADDR m_MAC_Source; // to answer ARP requests - USHORT m_Proto; // 0x0806 - -# define MAC_ADDR_TYPE 0x0001 - USHORT m_MAC_AddressType; // 0x0001 - - USHORT m_PROTO_AddressType; // 0x0800 - UCHAR m_MAC_AddressSize; // 0x06 - UCHAR m_PROTO_AddressSize; // 0x04 - -# define ARP_REQUEST 0x0001 -# define ARP_REPLY 0x0002 - USHORT m_ARP_Operation; // 0x0001 for ARP request, 0x0002 for ARP reply - - MACADDR m_ARP_MAC_Source; - IPADDR m_ARP_IP_Source; - MACADDR m_ARP_MAC_Destination; - IPADDR m_ARP_IP_Destination; - } -ARP_PACKET, *PARP_PACKET; - -//---------- -// IP Header -//---------- - -typedef struct { -# define IPH_GET_VER(v) (((v) >> 4) & 0x0F) -# define IPH_GET_LEN(v) (((v) & 0x0F) << 2) - UCHAR version_len; - - UCHAR tos; - USHORT tot_len; - USHORT id; - -# define IP_OFFMASK 0x1fff - USHORT frag_off; - - UCHAR ttl; - -# define IPPROTO_UDP 17 /* UDP protocol */ -# define IPPROTO_TCP 6 /* TCP protocol */ -# define IPPROTO_ICMP 1 /* ICMP protocol */ -# define IPPROTO_IGMP 2 /* IGMP protocol */ - UCHAR protocol; - - USHORT check; - ULONG saddr; - ULONG daddr; - /* The options start here. */ -} IPHDR; - -//----------- -// UDP header -//----------- - -typedef struct { - USHORT source; - USHORT dest; - USHORT len; - USHORT check; -} UDPHDR; - -//-------------------------- -// TCP header, per RFC 793. -//-------------------------- - -typedef struct { - USHORT source; /* source port */ - USHORT dest; /* destination port */ - ULONG seq; /* sequence number */ - ULONG ack_seq; /* acknowledgement number */ - -# define TCPH_GET_DOFF(d) (((d) & 0xF0) >> 2) - UCHAR doff_res; - -# define TCPH_FIN_MASK (1<<0) -# define TCPH_SYN_MASK (1<<1) -# define TCPH_RST_MASK (1<<2) -# define TCPH_PSH_MASK (1<<3) -# define TCPH_ACK_MASK (1<<4) -# define TCPH_URG_MASK (1<<5) -# define TCPH_ECE_MASK (1<<6) -# define TCPH_CWR_MASK (1<<7) - UCHAR flags; - - USHORT window; - USHORT check; - USHORT urg_ptr; -} TCPHDR; - -#define TCPOPT_EOL 0 -#define TCPOPT_NOP 1 -#define TCPOPT_MAXSEG 2 -#define TCPOLEN_MAXSEG 4 - -//------------ -// IPv6 Header -//------------ - -typedef struct { - UCHAR version_prio; - UCHAR flow_lbl[3]; - USHORT payload_len; -# define IPPROTO_ICMPV6 0x3a /* ICMP protocol v6 */ - UCHAR nexthdr; - UCHAR hop_limit; - IPV6ADDR saddr; - IPV6ADDR daddr; -} IPV6HDR; - -//-------------------------------------------- -// IPCMPv6 NS/NA Packets (RFC4443 and RFC4861) -//-------------------------------------------- - -// Neighbor Solictiation - RFC 4861, 4.3 -// (this is just the ICMPv6 part of the packet) -typedef struct { - UCHAR type; -# define ICMPV6_TYPE_NS 135 // neighbour solicitation - UCHAR code; -# define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA - USHORT checksum; - ULONG reserved; - IPV6ADDR target_addr; -} ICMPV6_NS; - -// Neighbor Advertisement - RFC 4861, 4.4 + 4.6/4.6.1 -// (this is just the ICMPv6 payload) -typedef struct { - UCHAR type; -# define ICMPV6_TYPE_NA 136 // neighbour advertisement - UCHAR code; -# define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA - USHORT checksum; - UCHAR rso_bits; // Router(0), Solicited(2), Ovrrd(4) - UCHAR reserved[3]; - IPV6ADDR target_addr; -// always include "Target Link-layer Address" option (RFC 4861 4.6.1) - UCHAR opt_type; -#define ICMPV6_OPTION_TLLA 2 - UCHAR opt_length; -#define ICMPV6_LENGTH_TLLA 1 // multiplied by 8 -> 1 = 8 bytes - MACADDR target_macaddr; -} ICMPV6_NA; - -// this is the complete packet with Ethernet and IPv6 headers -typedef struct { - ETH_HEADER eth; - IPV6HDR ipv6; - ICMPV6_NA icmpv6; -} ICMPV6_NA_PKT; - -#pragma pack() diff --git a/zto/windows/TapDriver6/prototypes.h b/zto/windows/TapDriver6/prototypes.h deleted file mode 100644 index a48d35e..0000000 --- a/zto/windows/TapDriver6/prototypes.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TAP_PROTOTYPES_DEFINED -#define TAP_PROTOTYPES_DEFINED - -DRIVER_INITIALIZE DriverEntry; - -//VOID AdapterFreeResources -// ( -// TapAdapterPointer p_Adapter -// ); -// - -// -//NTSTATUS TapDeviceHook -// ( -// IN PDEVICE_OBJECT p_DeviceObject, -// IN PIRP p_IRP -// ); -// - -NDIS_STATUS -CreateTapDevice( - __in PTAP_ADAPTER_CONTEXT Adapter - ); - -VOID -DestroyTapDevice( - __in PTAP_ADAPTER_CONTEXT Adapter - ); - -// Flush the pending send TAP packet queue. -VOID -tapFlushSendPacketQueue( - __in PTAP_ADAPTER_CONTEXT Adapter - ); - -VOID -IndicateReceivePacket( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in PUCHAR packetData, - __in const unsigned int packetLength - ); - -/* -BOOLEAN -ProcessDHCP( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in const ETH_HEADER *eth, - __in const IPHDR *ip, - __in const UDPHDR *udp, - __in const DHCP *dhcp, - __in int optlen - ); -*/ - -/* -BOOLEAN -ProcessARP( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in const PARP_PACKET src, - __in const IPADDR adapter_ip, - __in const IPADDR ip_network, - __in const IPADDR ip_netmask, - __in const MACADDR mac - ); -*/ - -#endif diff --git a/zto/windows/TapDriver6/resource.h b/zto/windows/TapDriver6/resource.h deleted file mode 100644 index e736408..0000000 --- a/zto/windows/TapDriver6/resource.h +++ /dev/null @@ -1,1573 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by resource.rc -// -#define SW_HIDE 0 -#define HIDE_WINDOW 0 -#define WM_NULL 0x0000 -#define WA_INACTIVE 0 -#define HTNOWHERE 0 -#define SMTO_NORMAL 0x0000 -#define ICON_SMALL 0 -#define SIZE_RESTORED 0 -#define BN_CLICKED 0 -#define BST_UNCHECKED 0x0000 -#define HDS_HORZ 0x0000 -#define TBSTYLE_BUTTON 0x0000 -#define TBS_HORZ 0x0000 -#define TBS_BOTTOM 0x0000 -#define TBS_RIGHT 0x0000 -#define LVS_ICON 0x0000 -#define LVS_ALIGNTOP 0x0000 -#define TCS_TABS 0x0000 -#define TCS_SINGLELINE 0x0000 -#define TCS_RIGHTJUSTIFY 0x0000 -#define DTS_SHORTDATEFORMAT 0x0000 -#define PGS_VERT 0x00000000 -#define LANG_NEUTRAL 0x00 -#define SUBLANG_NEUTRAL 0x00 -#define SORT_DEFAULT 0x0 -#define SORT_JAPANESE_XJIS 0x0 -#define SORT_CHINESE_BIG5 0x0 -#define SORT_CHINESE_PRCP 0x0 -#define SORT_KOREAN_KSC 0x0 -#define SORT_HUNGARIAN_DEFAULT 0x0 -#define SORT_GEORGIAN_TRADITIONAL 0x0 -#define _USE_DECLSPECS_FOR_SAL 0 -#define _USE_ATTRIBUTES_FOR_SAL 0 -#define __drv_typeConst 0 -#define VER_DEBUG 0 -#define VER_PRERELEASE 0 -#define PRODUCT_TAP_WIN_MINOR 0 -#define WINAPI_PARTITION_DESKTOP 0x00000001 -#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 -#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID 1 -#define SW_SHOWNORMAL 1 -#define SW_NORMAL 1 -#define SHOW_OPENWINDOW 1 -#define SW_PARENTCLOSING 1 -#define VK_LBUTTON 0x01 -#define WM_CREATE 0x0001 -#define WA_ACTIVE 1 -#define PWR_OK 1 -#define PWR_SUSPENDREQUEST 1 -#define NFR_ANSI 1 -#define UIS_SET 1 -#define UISF_HIDEFOCUS 0x1 -#define XBUTTON1 0x0001 -#define WMSZ_LEFT 1 -#define HTCLIENT 1 -#define SMTO_BLOCK 0x0001 -#define MA_ACTIVATE 1 -#define ICON_BIG 1 -#define SIZE_MINIMIZED 1 -#define MK_LBUTTON 0x0001 -#define TME_HOVER 0x00000001 -#define CS_VREDRAW 0x0001 -#define CF_TEXT 1 -#define SCF_ISSECURE 0x00000001 -#define IDOK 1 -#define BN_PAINT 1 -#define BST_CHECKED 0x0001 -#define TBSTYLE_SEP 0x0001 -#define TTS_ALWAYSTIP 0x01 -#define TBS_AUTOTICKS 0x0001 -#define UDS_WRAP 0x0001 -#define PBS_SMOOTH 0x01 -#define LWS_TRANSPARENT 0x0001 -#define LVS_REPORT 0x0001 -#define TVS_HASBUTTONS 0x0001 -#define TVS_EX_NOSINGLECOLLAPSE 0x0001 -#define TCS_SCROLLOPPOSITE 0x0001 -#define ACS_CENTER 0x0001 -#define MCS_DAYSTATE 0x0001 -#define DTS_UPDOWN 0x0001 -#define PGS_HORZ 0x00000001 -#define NFS_EDIT 0x0001 -#define BCSIF_GLYPH 0x0001 -#define BCSS_NOSPLIT 0x0001 -#define LANG_ARABIC 0x01 -#define SUBLANG_DEFAULT 0x01 -#define SUBLANG_AFRIKAANS_SOUTH_AFRICA 0x01 -#define SUBLANG_ALBANIAN_ALBANIA 0x01 -#define SUBLANG_ALSATIAN_FRANCE 0x01 -#define SUBLANG_AMHARIC_ETHIOPIA 0x01 -#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 -#define SUBLANG_ARMENIAN_ARMENIA 0x01 -#define SUBLANG_ASSAMESE_INDIA 0x01 -#define SUBLANG_AZERI_LATIN 0x01 -#define SUBLANG_AZERBAIJANI_AZERBAIJAN_LATIN 0x01 -#define SUBLANG_BANGLA_INDIA 0x01 -#define SUBLANG_BASHKIR_RUSSIA 0x01 -#define SUBLANG_BASQUE_BASQUE 0x01 -#define SUBLANG_BELARUSIAN_BELARUS 0x01 -#define SUBLANG_BENGALI_INDIA 0x01 -#define SUBLANG_BRETON_FRANCE 0x01 -#define SUBLANG_BULGARIAN_BULGARIA 0x01 -#define SUBLANG_CATALAN_CATALAN 0x01 -#define SUBLANG_CENTRAL_KURDISH_IRAQ 0x01 -#define SUBLANG_CHEROKEE_CHEROKEE 0x01 -#define SUBLANG_CHINESE_TRADITIONAL 0x01 -#define SUBLANG_CORSICAN_FRANCE 0x01 -#define SUBLANG_CZECH_CZECH_REPUBLIC 0x01 -#define SUBLANG_CROATIAN_CROATIA 0x01 -#define SUBLANG_DANISH_DENMARK 0x01 -#define SUBLANG_DARI_AFGHANISTAN 0x01 -#define SUBLANG_DIVEHI_MALDIVES 0x01 -#define SUBLANG_DUTCH 0x01 -#define SUBLANG_ENGLISH_US 0x01 -#define SUBLANG_ESTONIAN_ESTONIA 0x01 -#define SUBLANG_FAEROESE_FAROE_ISLANDS 0x01 -#define SUBLANG_FILIPINO_PHILIPPINES 0x01 -#define SUBLANG_FINNISH_FINLAND 0x01 -#define SUBLANG_FRENCH 0x01 -#define SUBLANG_FRISIAN_NETHERLANDS 0x01 -#define SUBLANG_GALICIAN_GALICIAN 0x01 -#define SUBLANG_GEORGIAN_GEORGIA 0x01 -#define SUBLANG_GERMAN 0x01 -#define SUBLANG_GREEK_GREECE 0x01 -#define SUBLANG_GREENLANDIC_GREENLAND 0x01 -#define SUBLANG_GUJARATI_INDIA 0x01 -#define SUBLANG_HAUSA_NIGERIA_LATIN 0x01 -#define SUBLANG_HAWAIIAN_US 0x01 -#define SUBLANG_HEBREW_ISRAEL 0x01 -#define SUBLANG_HINDI_INDIA 0x01 -#define SUBLANG_HUNGARIAN_HUNGARY 0x01 -#define SUBLANG_ICELANDIC_ICELAND 0x01 -#define SUBLANG_IGBO_NIGERIA 0x01 -#define SUBLANG_INDONESIAN_INDONESIA 0x01 -#define SUBLANG_INUKTITUT_CANADA 0x01 -#define SUBLANG_ITALIAN 0x01 -#define SUBLANG_JAPANESE_JAPAN 0x01 -#define SUBLANG_KANNADA_INDIA 0x01 -#define SUBLANG_KAZAK_KAZAKHSTAN 0x01 -#define SUBLANG_KHMER_CAMBODIA 0x01 -#define SUBLANG_KICHE_GUATEMALA 0x01 -#define SUBLANG_KINYARWANDA_RWANDA 0x01 -#define SUBLANG_KONKANI_INDIA 0x01 -#define SUBLANG_KOREAN 0x01 -#define SUBLANG_KYRGYZ_KYRGYZSTAN 0x01 -#define SUBLANG_LAO_LAO 0x01 -#define SUBLANG_LATVIAN_LATVIA 0x01 -#define SUBLANG_LITHUANIAN 0x01 -#define SUBLANG_LUXEMBOURGISH_LUXEMBOURG 0x01 -#define SUBLANG_MACEDONIAN_MACEDONIA 0x01 -#define SUBLANG_MALAY_MALAYSIA 0x01 -#define SUBLANG_MALAYALAM_INDIA 0x01 -#define SUBLANG_MALTESE_MALTA 0x01 -#define SUBLANG_MAORI_NEW_ZEALAND 0x01 -#define SUBLANG_MAPUDUNGUN_CHILE 0x01 -#define SUBLANG_MARATHI_INDIA 0x01 -#define SUBLANG_MOHAWK_MOHAWK 0x01 -#define SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA 0x01 -#define SUBLANG_NEPALI_NEPAL 0x01 -#define SUBLANG_NORWEGIAN_BOKMAL 0x01 -#define SUBLANG_OCCITAN_FRANCE 0x01 -#define SUBLANG_ODIA_INDIA 0x01 -#define SUBLANG_ORIYA_INDIA 0x01 -#define SUBLANG_PASHTO_AFGHANISTAN 0x01 -#define SUBLANG_PERSIAN_IRAN 0x01 -#define SUBLANG_POLISH_POLAND 0x01 -#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01 -#define SUBLANG_PUNJABI_INDIA 0x01 -#define SUBLANG_QUECHUA_BOLIVIA 0x01 -#define SUBLANG_ROMANIAN_ROMANIA 0x01 -#define SUBLANG_ROMANSH_SWITZERLAND 0x01 -#define SUBLANG_RUSSIAN_RUSSIA 0x01 -#define SUBLANG_SAKHA_RUSSIA 0x01 -#define SUBLANG_SAMI_NORTHERN_NORWAY 0x01 -#define SUBLANG_SANSKRIT_INDIA 0x01 -#define SUBLANG_SCOTTISH_GAELIC 0x01 -#define SUBLANG_SERBIAN_CROATIA 0x01 -#define SUBLANG_SINDHI_INDIA 0x01 -#define SUBLANG_SINHALESE_SRI_LANKA 0x01 -#define SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA 0x01 -#define SUBLANG_SLOVAK_SLOVAKIA 0x01 -#define SUBLANG_SLOVENIAN_SLOVENIA 0x01 -#define SUBLANG_SPANISH 0x01 -#define SUBLANG_SWAHILI_KENYA 0x01 -#define SUBLANG_SWEDISH 0x01 -#define SUBLANG_SYRIAC_SYRIA 0x01 -#define SUBLANG_TAJIK_TAJIKISTAN 0x01 -#define SUBLANG_TAMIL_INDIA 0x01 -#define SUBLANG_TATAR_RUSSIA 0x01 -#define SUBLANG_TELUGU_INDIA 0x01 -#define SUBLANG_THAI_THAILAND 0x01 -#define SUBLANG_TIBETAN_PRC 0x01 -#define SUBLANG_TIGRINYA_ETHIOPIA 0x01 -#define SUBLANG_TSWANA_SOUTH_AFRICA 0x01 -#define SUBLANG_TURKISH_TURKEY 0x01 -#define SUBLANG_TURKMEN_TURKMENISTAN 0x01 -#define SUBLANG_UIGHUR_PRC 0x01 -#define SUBLANG_UKRAINIAN_UKRAINE 0x01 -#define SUBLANG_UPPER_SORBIAN_GERMANY 0x01 -#define SUBLANG_URDU_PAKISTAN 0x01 -#define SUBLANG_UZBEK_LATIN 0x01 -#define SUBLANG_VIETNAMESE_VIETNAM 0x01 -#define SUBLANG_WELSH_UNITED_KINGDOM 0x01 -#define SUBLANG_WOLOF_SENEGAL 0x01 -#define SUBLANG_XHOSA_SOUTH_AFRICA 0x01 -#define SUBLANG_YAKUT_RUSSIA 0x01 -#define SUBLANG_YI_PRC 0x01 -#define SUBLANG_YORUBA_NIGERIA 0x01 -#define SUBLANG_ZULU_SOUTH_AFRICA 0x01 -#define SORT_INVARIANT_MATH 0x1 -#define SORT_JAPANESE_UNICODE 0x1 -#define SORT_CHINESE_UNICODE 0x1 -#define SORT_KOREAN_UNICODE 0x1 -#define SORT_GERMAN_PHONE_BOOK 0x1 -#define SORT_HUNGARIAN_TECHNICAL 0x1 -#define SORT_GEORGIAN_MODERN 0x1 -#define __drv_typeCond 1 -#define VS_VERSION_INFO 1 -#define VFFF_ISSHAREDFILE 0x0001 -#define VFF_CURNEDEST 0x0001 -#define VIFF_FORCEINSTALL 0x0001 -#define WINAPI_PARTITION_APP 0x00000002 -#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 -#define SW_SHOWMINIMIZED 2 -#define SHOW_ICONWINDOW 2 -#define SW_OTHERZOOM 2 -#define VK_RBUTTON 0x02 -#define WM_DESTROY 0x0002 -#define WA_CLICKACTIVE 2 -#define PWR_SUSPENDRESUME 2 -#define NFR_UNICODE 2 -#define UIS_CLEAR 2 -#define UISF_HIDEACCEL 0x2 -#define XBUTTON2 0x0002 -#define WMSZ_RIGHT 2 -#define HTCAPTION 2 -#define SMTO_ABORTIFHUNG 0x0002 -#define MA_ACTIVATEANDEAT 2 -#define ICON_SMALL2 2 -#define SIZE_MAXIMIZED 2 -#define MK_RBUTTON 0x0002 -#define TME_LEAVE 0x00000002 -#define CS_HREDRAW 0x0002 -#define CF_BITMAP 2 -#define IDCANCEL 2 -#define BN_HILITE 2 -#define BST_INDETERMINATE 0x0002 -#define HDS_BUTTONS 0x0002 -#define TBSTYLE_CHECK 0x0002 -#define TTS_NOPREFIX 0x02 -#define TBS_VERT 0x0002 -#define UDS_SETBUDDYINT 0x0002 -#define LWS_IGNORERETURN 0x0002 -#define LVS_SMALLICON 0x0002 -#define TVS_HASLINES 0x0002 -#define TVS_EX_MULTISELECT 0x0002 -#define TCS_BOTTOM 0x0002 -#define TCS_RIGHT 0x0002 -#define ACS_TRANSPARENT 0x0002 -#define MCS_MULTISELECT 0x0002 -#define DTS_SHOWNONE 0x0002 -#define PGS_AUTOSCROLL 0x00000002 -#define NFS_STATIC 0x0002 -#define BCSIF_IMAGE 0x0002 -#define BCSS_STRETCH 0x0002 -#define LANG_BULGARIAN 0x02 -#define SUBLANG_SYS_DEFAULT 0x02 -#define SUBLANG_ARABIC_IRAQ 0x02 -#define SUBLANG_AZERI_CYRILLIC 0x02 -#define SUBLANG_AZERBAIJANI_AZERBAIJAN_CYRILLIC 0x02 -#define SUBLANG_BANGLA_BANGLADESH 0x02 -#define SUBLANG_BENGALI_BANGLADESH 0x02 -#define SUBLANG_CHINESE_SIMPLIFIED 0x02 -#define SUBLANG_DUTCH_BELGIAN 0x02 -#define SUBLANG_ENGLISH_UK 0x02 -#define SUBLANG_FRENCH_BELGIAN 0x02 -#define SUBLANG_FULAH_SENEGAL 0x02 -#define SUBLANG_GERMAN_SWISS 0x02 -#define SUBLANG_INUKTITUT_CANADA_LATIN 0x02 -#define SUBLANG_IRISH_IRELAND 0x02 -#define SUBLANG_ITALIAN_SWISS 0x02 -#define SUBLANG_KASHMIRI_SASIA 0x02 -#define SUBLANG_KASHMIRI_INDIA 0x02 -#define SUBLANG_LOWER_SORBIAN_GERMANY 0x02 -#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 -#define SUBLANG_MONGOLIAN_PRC 0x02 -#define SUBLANG_NEPALI_INDIA 0x02 -#define SUBLANG_NORWEGIAN_NYNORSK 0x02 -#define SUBLANG_PORTUGUESE 0x02 -#define SUBLANG_PULAR_SENEGAL 0x02 -#define SUBLANG_PUNJABI_PAKISTAN 0x02 -#define SUBLANG_QUECHUA_ECUADOR 0x02 -#define SUBLANG_SAMI_NORTHERN_SWEDEN 0x02 -#define SUBLANG_SERBIAN_LATIN 0x02 -#define SUBLANG_SINDHI_PAKISTAN 0x02 -#define SUBLANG_SINDHI_AFGHANISTAN 0x02 -#define SUBLANG_SPANISH_MEXICAN 0x02 -#define SUBLANG_SWEDISH_FINLAND 0x02 -#define SUBLANG_TAMAZIGHT_ALGERIA_LATIN 0x02 -#define SUBLANG_TAMIL_SRI_LANKA 0x02 -#define SUBLANG_TIGRIGNA_ERITREA 0x02 -#define SUBLANG_TIGRINYA_ERITREA 0x02 -#define SUBLANG_TSWANA_BOTSWANA 0x02 -#define SUBLANG_URDU_INDIA 0x02 -#define SUBLANG_UZBEK_CYRILLIC 0x02 -#define SUBLANG_VALENCIAN_VALENCIA 0x02 -#define SORT_CHINESE_PRC 0x2 -#define __drv_typeBitset 2 -#define VFF_FILEINUSE 0x0002 -#define VIFF_DONTDELETEOLD 0x0002 -#define VER_PRODUCTMINORVERSION 2 -#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3 -#define SW_SHOWMAXIMIZED 3 -#define SW_MAXIMIZE 3 -#define SHOW_FULLSCREEN 3 -#define SW_PARENTOPENING 3 -#define VK_CANCEL 0x03 -#define WM_MOVE 0x0003 -#define PWR_CRITICALRESUME 3 -#define NF_QUERY 3 -#define UIS_INITIALIZE 3 -#define WMSZ_TOP 3 -#define HTSYSMENU 3 -#define MA_NOACTIVATE 3 -#define SIZE_MAXSHOW 3 -#define CF_METAFILEPICT 3 -#define IDABORT 3 -#define BN_UNHILITE 3 -#define LVS_LIST 0x0003 -#define LVS_TYPEMASK 0x0003 -#define LANG_CATALAN 0x03 -#define LANG_VALENCIAN 0x03 -#define SUBLANG_CUSTOM_DEFAULT 0x03 -#define SUBLANG_ARABIC_EGYPT 0x03 -#define SUBLANG_CHINESE_HONGKONG 0x03 -#define SUBLANG_ENGLISH_AUS 0x03 -#define SUBLANG_FRENCH_CANADIAN 0x03 -#define SUBLANG_GERMAN_AUSTRIAN 0x03 -#define SUBLANG_QUECHUA_PERU 0x03 -#define SUBLANG_SAMI_NORTHERN_FINLAND 0x03 -#define SUBLANG_SERBIAN_CYRILLIC 0x03 -#define SUBLANG_SPANISH_MODERN 0x03 -#define SORT_CHINESE_BOPOMOFO 0x3 -#define __drv_typeExpr 3 -#define PRODUCT_TAP_WIN_MAJOR 3 -#define SW_SHOWNOACTIVATE 4 -#define SHOW_OPENNOACTIVATE 4 -#define SW_OTHERUNZOOM 4 -#define VK_MBUTTON 0x04 -#define NF_REQUERY 4 -#define UISF_ACTIVE 0x4 -#define WMSZ_TOPLEFT 4 -#define HTGROWBOX 4 -#define MA_NOACTIVATEANDEAT 4 -#define SIZE_MAXHIDE 4 -#define MK_SHIFT 0x0004 -#define CF_SYLK 4 -#define IDRETRY 4 -#define BN_DISABLE 4 -#define BST_PUSHED 0x0004 -#define HDS_HOTTRACK 0x0004 -#define TBSTYLE_GROUP 0x0004 -#define TBS_TOP 0x0004 -#define TBS_LEFT 0x0004 -#define UDS_ALIGNRIGHT 0x0004 -#define PBS_VERTICAL 0x04 -#define LWS_NOPREFIX 0x0004 -#define LVS_SINGLESEL 0x0004 -#define TVS_LINESATROOT 0x0004 -#define TVS_EX_DOUBLEBUFFER 0x0004 -#define TCS_MULTISELECT 0x0004 -#define ACS_AUTOPLAY 0x0004 -#define MCS_WEEKNUMBERS 0x0004 -#define DTS_LONGDATEFORMAT 0x0004 -#define PGS_DRAGNDROP 0x00000004 -#define NFS_LISTCOMBO 0x0004 -#define BCSIF_STYLE 0x0004 -#define BCSS_ALIGNLEFT 0x0004 -#define LANG_CHINESE 0x04 -#define LANG_CHINESE_SIMPLIFIED 0x04 -#define SUBLANG_CUSTOM_UNSPECIFIED 0x04 -#define SUBLANG_ARABIC_LIBYA 0x04 -#define SUBLANG_CHINESE_SINGAPORE 0x04 -#define SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN 0x04 -#define SUBLANG_ENGLISH_CAN 0x04 -#define SUBLANG_FRENCH_SWISS 0x04 -#define SUBLANG_GERMAN_LUXEMBOURG 0x04 -#define SUBLANG_SAMI_LULE_NORWAY 0x04 -#define SUBLANG_SPANISH_GUATEMALA 0x04 -#define SUBLANG_TAMAZIGHT_MOROCCO_TIFINAGH 0x04 -#define SORT_JAPANESE_RADICALSTROKE 0x4 -#define SORT_CHINESE_RADICALSTROKE 0x4 -#define VFF_BUFFTOOSMALL 0x0004 -#define SW_SHOW 5 -#define VK_XBUTTON1 0x05 -#define WM_SIZE 0x0005 -#define WMSZ_TOPRIGHT 5 -#define HTMENU 5 -#define CF_DIF 5 -#define IDIGNORE 5 -#define BN_DOUBLECLICKED 5 -#define LANG_CZECH 0x05 -#define SUBLANG_UI_CUSTOM_DEFAULT 0x05 -#define SUBLANG_ARABIC_ALGERIA 0x05 -#define SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN 0x05 -#define SUBLANG_CHINESE_MACAU 0x05 -#define SUBLANG_ENGLISH_NZ 0x05 -#define SUBLANG_FRENCH_LUXEMBOURG 0x05 -#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 -#define SUBLANG_SAMI_LULE_SWEDEN 0x05 -#define SUBLANG_SPANISH_COSTA_RICA 0x05 -#define SW_MINIMIZE 6 -#define VK_XBUTTON2 0x06 -#define WM_ACTIVATE 0x0006 -#define WMSZ_BOTTOM 6 -#define HTHSCROLL 6 -#define CF_TIFF 6 -#define IDYES 6 -#define BN_SETFOCUS 6 -#define LANG_DANISH 0x06 -#define SUBLANG_ARABIC_MOROCCO 0x06 -#define SUBLANG_ENGLISH_EIRE 0x06 -#define SUBLANG_FRENCH_MONACO 0x06 -#define SUBLANG_SAMI_SOUTHERN_NORWAY 0x06 -#define SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_LATIN 0x06 -#define SUBLANG_SPANISH_PANAMA 0x06 -#define VER_PRODUCTMAJORVERSION 6 -#define SW_SHOWMINNOACTIVE 7 -#define WM_SETFOCUS 0x0007 -#define WMSZ_BOTTOMLEFT 7 -#define HTVSCROLL 7 -#define CF_OEMTEXT 7 -#define IDNO 7 -#define BN_KILLFOCUS 7 -#define LANG_GERMAN 0x07 -#define SUBLANG_ARABIC_TUNISIA 0x07 -#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 -#define SUBLANG_SAMI_SOUTHERN_SWEDEN 0x07 -#define SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_CYRILLIC 0x07 -#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 -#define SW_SHOWNA 8 -#define VK_BACK 0x08 -#define WM_KILLFOCUS 0x0008 -#define WMSZ_BOTTOMRIGHT 8 -#define HTMINBUTTON 8 -#define SMTO_NOTIMEOUTIFNOTHUNG 0x0008 -#define MK_CONTROL 0x0008 -#define CS_DBLCLKS 0x0008 -#define CF_DIB 8 -#define IDCLOSE 8 -#define BST_FOCUS 0x0008 -#define HDS_HIDDEN 0x0008 -#define TBSTYLE_DROPDOWN 0x0008 -#define TBS_BOTH 0x0008 -#define UDS_ALIGNLEFT 0x0008 -#define PBS_MARQUEE 0x08 -#define LWS_USEVISUALSTYLE 0x0008 -#define LVS_SHOWSELALWAYS 0x0008 -#define TVS_EDITLABELS 0x0008 -#define TVS_EX_NOINDENTSTATE 0x0008 -#define TCS_FLATBUTTONS 0x0008 -#define ACS_TIMER 0x0008 -#define MCS_NOTODAYCIRCLE 0x0008 -#define NFS_BUTTON 0x0008 -#define BCSIF_SIZE 0x0008 -#define BCSS_IMAGE 0x0008 -#define LANG_GREEK 0x08 -#define SUBLANG_ARABIC_OMAN 0x08 -#define SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC 0x08 -#define SUBLANG_ENGLISH_JAMAICA 0x08 -#define SUBLANG_SAMI_SKOLT_FINLAND 0x08 -#define SUBLANG_SPANISH_VENEZUELA 0x08 -#define SW_RESTORE 9 -#define VK_TAB 0x09 -#define HTMAXBUTTON 9 -#define CF_PALETTE 9 -#define IDHELP 9 -#define DTS_TIMEFORMAT 0x0009 -#define LANG_ENGLISH 0x09 -#define SUBLANG_ARABIC_YEMEN 0x09 -#define SUBLANG_ENGLISH_CARIBBEAN 0x09 -#define SUBLANG_SAMI_INARI_FINLAND 0x09 -#define SUBLANG_SERBIAN_SERBIA_LATIN 0x09 -#define SUBLANG_SPANISH_COLOMBIA 0x09 -#define SW_SHOWDEFAULT 10 -#define WM_ENABLE 0x000A -#define HTLEFT 10 -#define CF_PENDATA 10 -#define IDTRYAGAIN 10 -#define HELP_CONTEXTMENU 0x000a -#define LANG_SPANISH 0x0a -#define SUBLANG_ARABIC_SYRIA 0x0a -#define SUBLANG_ENGLISH_BELIZE 0x0a -#define SUBLANG_SERBIAN_SERBIA_CYRILLIC 0x0a -#define SUBLANG_SPANISH_PERU 0x0a -#define SW_FORCEMINIMIZE 11 -#define SW_MAX 11 -#define WM_SETREDRAW 0x000B -#define HTRIGHT 11 -#define CF_RIFF 11 -#define IDCONTINUE 11 -#define HELP_FINDER 0x000b -#define LANG_FINNISH 0x0b -#define SUBLANG_ARABIC_JORDAN 0x0b -#define SUBLANG_ENGLISH_TRINIDAD 0x0b -#define SUBLANG_SERBIAN_MONTENEGRO_LATIN 0x0b -#define SUBLANG_SPANISH_ARGENTINA 0x0b -#define VK_CLEAR 0x0C -#define WM_SETTEXT 0x000C -#define HTTOP 12 -#define CF_WAVE 12 -#define HELP_WM_HELP 0x000c -#define DTS_SHORTDATECENTURYFORMAT 0x000C -#define LANG_FRENCH 0x0c -#define SUBLANG_ARABIC_LEBANON 0x0c -#define SUBLANG_ENGLISH_ZIMBABWE 0x0c -#define SUBLANG_SERBIAN_MONTENEGRO_CYRILLIC 0x0c -#define SUBLANG_SPANISH_ECUADOR 0x0c -#define VK_RETURN 0x0D -#define WM_GETTEXT 0x000D -#define HTTOPLEFT 13 -#define CF_UNICODETEXT 13 -#define HELP_SETPOPUP_POS 0x000d -#define LANG_HEBREW 0x0d -#define SUBLANG_ARABIC_KUWAIT 0x0d -#define SUBLANG_ENGLISH_PHILIPPINES 0x0d -#define SUBLANG_SPANISH_CHILE 0x0d -#define WM_GETTEXTLENGTH 0x000E -#define HTTOPRIGHT 14 -#define CF_ENHMETAFILE 14 -#define LANG_HUNGARIAN 0x0e -#define SUBLANG_ARABIC_UAE 0x0e -#define SUBLANG_SPANISH_URUGUAY 0x0e -#define WM_PAINT 0x000F -#define HTBOTTOM 15 -#define CF_HDROP 15 -#define LANG_ICELANDIC 0x0f -#define SUBLANG_ARABIC_BAHRAIN 0x0f -#define SUBLANG_SPANISH_PARAGUAY 0x0f -#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID 16 -#define VK_SHIFT 0x10 -#define WM_CLOSE 0x0010 -#define HTBOTTOMLEFT 16 -#define WVR_ALIGNTOP 0x0010 -#define MK_MBUTTON 0x0010 -#define TME_NONCLIENT 0x00000010 -#define CF_LOCALE 16 -#define HELP_TCARD_DATA 0x0010 -#define TBSTYLE_AUTOSIZE 0x0010 -#define TTS_NOANIMATE 0x10 -#define TBS_NOTICKS 0x0010 -#define UDS_AUTOBUDDY 0x0010 -#define PBS_SMOOTHREVERSE 0x10 -#define LWS_USECUSTOMTEXT 0x0010 -#define LVS_SORTASCENDING 0x0010 -#define TVS_DISABLEDRAGDROP 0x0010 -#define TVS_EX_RICHTOOLTIP 0x0010 -#define TCS_FORCEICONLEFT 0x0010 -#define MCS_NOTODAY 0x0010 -#define DTS_APPCANPARSE 0x0010 -#define NFS_ALL 0x0010 -#define LANG_ITALIAN 0x10 -#define SUBLANG_ARABIC_QATAR 0x10 -#define SUBLANG_ENGLISH_INDIA 0x10 -#define SUBLANG_SPANISH_BOLIVIA 0x10 -#define VK_CONTROL 0x11 -#define WM_QUERYENDSESSION 0x0011 -#define HTBOTTOMRIGHT 17 -#define CF_DIBV5 17 -#define HELP_TCARD_OTHER_CALLER 0x0011 -#define LANG_JAPANESE 0x11 -#define SUBLANG_ENGLISH_MALAYSIA 0x11 -#define SUBLANG_SPANISH_EL_SALVADOR 0x11 -#define VK_MENU 0x12 -#define WM_QUIT 0x0012 -#define HTBORDER 18 -#define CF_MAX 18 -#define LANG_KOREAN 0x12 -#define SUBLANG_ENGLISH_SINGAPORE 0x12 -#define SUBLANG_SPANISH_HONDURAS 0x12 -#define VK_PAUSE 0x13 -#define WM_QUERYOPEN 0x0013 -#define HTOBJECT 19 -#define LANG_DUTCH 0x13 -#define SUBLANG_SPANISH_NICARAGUA 0x13 -#define VK_CAPITAL 0x14 -#define WM_ERASEBKGND 0x0014 -#define HTCLOSE 20 -#define LANG_NORWEGIAN 0x14 -#define SUBLANG_SPANISH_PUERTO_RICO 0x14 -#define _SAL_VERSION 20 -#define VK_KANA 0x15 -#define VK_HANGEUL 0x15 -#define VK_HANGUL 0x15 -#define WM_SYSCOLORCHANGE 0x0015 -#define HTHELP 21 -#define LANG_POLISH 0x15 -#define SUBLANG_SPANISH_US 0x15 -#define WM_ENDSESSION 0x0016 -#define LANG_PORTUGUESE 0x16 -#define VK_JUNJA 0x17 -#define LANG_ROMANSH 0x17 -#define RT_MANIFEST 24 -#define VK_FINAL 0x18 -#define WM_SHOWWINDOW 0x0018 -#define LANG_ROMANIAN 0x18 -#define VK_HANJA 0x19 -#define VK_KANJI 0x19 -#define LANG_RUSSIAN 0x19 -#define WM_WININICHANGE 0x001A -#define LANG_BOSNIAN 0x1a -#define LANG_CROATIAN 0x1a -#define LANG_SERBIAN 0x1a -#define VK_ESCAPE 0x1B -#define WM_DEVMODECHANGE 0x001B -#define LANG_SLOVAK 0x1b -#define VK_CONVERT 0x1C -#define WM_ACTIVATEAPP 0x001C -#define LANG_ALBANIAN 0x1c -#define VK_NONCONVERT 0x1D -#define WM_FONTCHANGE 0x001D -#define LANG_SWEDISH 0x1d -#define VK_ACCEPT 0x1E -#define WM_TIMECHANGE 0x001E -#define LANG_THAI 0x1e -#define VK_MODECHANGE 0x1F -#define WM_CANCELMODE 0x001F -#define LANG_TURKISH 0x1f -#define VK_SPACE 0x20 -#define WM_SETCURSOR 0x0020 -#define SMTO_ERRORONEXIT 0x0020 -#define WVR_ALIGNLEFT 0x0020 -#define MK_XBUTTON1 0x0020 -#define CS_OWNDC 0x0020 -#define TBSTYLE_NOPREFIX 0x0020 -#define TTS_NOFADE 0x20 -#define TBS_ENABLESELRANGE 0x0020 -#define UDS_ARROWKEYS 0x0020 -#define LWS_RIGHT 0x0020 -#define LVS_SORTDESCENDING 0x0020 -#define TVS_SHOWSELALWAYS 0x0020 -#define TVS_EX_AUTOHSCROLL 0x0020 -#define TCS_FORCELABELLEFT 0x0020 -#define DTS_RIGHTALIGN 0x0020 -#define NFS_USEFONTASSOC 0x0020 -#define LANG_URDU 0x20 -#define VK_PRIOR 0x21 -#define WM_MOUSEACTIVATE 0x0021 -#define LANG_INDONESIAN 0x21 -#define VK_NEXT 0x22 -#define WM_CHILDACTIVATE 0x0022 -#define LANG_UKRAINIAN 0x22 -#define VK_END 0x23 -#define WM_QUEUESYNC 0x0023 -#define LANG_BELARUSIAN 0x23 -#define VK_HOME 0x24 -#define WM_GETMINMAXINFO 0x0024 -#define LANG_SLOVENIAN 0x24 -#define VK_LEFT 0x25 -#define LANG_ESTONIAN 0x25 -#define VK_UP 0x26 -#define WM_PAINTICON 0x0026 -#define LANG_LATVIAN 0x26 -#define VK_RIGHT 0x27 -#define WM_ICONERASEBKGND 0x0027 -#define LANG_LITHUANIAN 0x27 -#define VK_DOWN 0x28 -#define WM_NEXTDLGCTL 0x0028 -#define LANG_TAJIK 0x28 -#define VK_SELECT 0x29 -#define LANG_FARSI 0x29 -#define LANG_PERSIAN 0x29 -#define VK_PRINT 0x2A -#define WM_SPOOLERSTATUS 0x002A -#define LANG_VIETNAMESE 0x2a -#define VK_EXECUTE 0x2B -#define WM_DRAWITEM 0x002B -#define LANG_ARMENIAN 0x2b -#define VK_SNAPSHOT 0x2C -#define WM_MEASUREITEM 0x002C -#define LANG_AZERI 0x2c -#define LANG_AZERBAIJANI 0x2c -#define VK_INSERT 0x2D -#define WM_DELETEITEM 0x002D -#define LANG_BASQUE 0x2d -#define VK_DELETE 0x2E -#define WM_VKEYTOITEM 0x002E -#define LANG_LOWER_SORBIAN 0x2e -#define LANG_UPPER_SORBIAN 0x2e -#define VK_HELP 0x2F -#define WM_CHARTOITEM 0x002F -#define LANG_MACEDONIAN 0x2f -#define WM_SETFONT 0x0030 -#define WM_GETFONT 0x0031 -#define WM_SETHOTKEY 0x0032 -#define LANG_TSWANA 0x32 -#define WM_GETHOTKEY 0x0033 -#define LANG_XHOSA 0x34 -#define LANG_ZULU 0x35 -#define LANG_AFRIKAANS 0x36 -#define WM_QUERYDRAGICON 0x0037 -#define LANG_GEORGIAN 0x37 -#define LANG_FAEROESE 0x38 -#define WM_COMPAREITEM 0x0039 -#define LANG_HINDI 0x39 -#define LANG_MALTESE 0x3a -#define LANG_SAMI 0x3b -#define LANG_IRISH 0x3c -#define WM_GETOBJECT 0x003D -#define LANG_MALAY 0x3e -#define LANG_KAZAK 0x3f -#define WVR_ALIGNBOTTOM 0x0040 -#define MK_XBUTTON2 0x0040 -#define CS_CLASSDC 0x0040 -#define HDS_DRAGDROP 0x0040 -#define BTNS_SHOWTEXT 0x0040 -#define TTS_BALLOON 0x40 -#define TBS_FIXEDLENGTH 0x0040 -#define UDS_HORZ 0x0040 -#define LVS_SHAREIMAGELISTS 0x0040 -#define TVS_RTLREADING 0x0040 -#define TVS_EX_FADEINOUTEXPANDOS 0x0040 -#define TCS_HOTTRACK 0x0040 -#define MCS_NOTRAILINGDATES 0x0040 -#define LANG_KYRGYZ 0x40 -#define WM_COMPACTING 0x0041 -#define LANG_SWAHILI 0x41 -#define LANG_TURKMEN 0x42 -#define LANG_UZBEK 0x43 -#define WM_COMMNOTIFY 0x0044 -#define LANG_TATAR 0x44 -#define LANG_BANGLA 0x45 -#define LANG_BENGALI 0x45 -#define WM_WINDOWPOSCHANGING 0x0046 -#define LANG_PUNJABI 0x46 -#define WM_WINDOWPOSCHANGED 0x0047 -#define LANG_GUJARATI 0x47 -#define WM_POWER 0x0048 -#define LANG_ODIA 0x48 -#define LANG_ORIYA 0x48 -#define LANG_TAMIL 0x49 -#define WM_COPYDATA 0x004A -#define LANG_TELUGU 0x4a -#define WM_CANCELJOURNAL 0x004B -#define LANG_KANNADA 0x4b -#define LANG_MALAYALAM 0x4c -#define LANG_ASSAMESE 0x4d -#define WM_NOTIFY 0x004E -#define LANG_MARATHI 0x4e -#define LANG_SANSKRIT 0x4f -#define WM_INPUTLANGCHANGEREQUEST 0x0050 -#define LANG_MONGOLIAN 0x50 -#define WM_INPUTLANGCHANGE 0x0051 -#define LANG_TIBETAN 0x51 -#define WM_TCARD 0x0052 -#define LANG_WELSH 0x52 -#define WM_HELP 0x0053 -#define LANG_KHMER 0x53 -#define WM_USERCHANGED 0x0054 -#define LANG_LAO 0x54 -#define WM_NOTIFYFORMAT 0x0055 -#define LANG_GALICIAN 0x56 -#define LANG_KONKANI 0x57 -#define LANG_MANIPURI 0x58 -#define LANG_SINDHI 0x59 -#define LANG_SYRIAC 0x5a -#define VK_LWIN 0x5B -#define LANG_SINHALESE 0x5b -#define VK_RWIN 0x5C -#define LANG_CHEROKEE 0x5c -#define VK_APPS 0x5D -#define LANG_INUKTITUT 0x5d -#define LANG_AMHARIC 0x5e -#define VK_SLEEP 0x5F -#define LANG_TAMAZIGHT 0x5f -#define VK_NUMPAD0 0x60 -#define LANG_KASHMIRI 0x60 -#define VK_NUMPAD1 0x61 -#define LANG_NEPALI 0x61 -#define VK_NUMPAD2 0x62 -#define LANG_FRISIAN 0x62 -#define VK_NUMPAD3 0x63 -#define LANG_PASHTO 0x63 -#define VK_NUMPAD4 0x64 -#define LANG_FILIPINO 0x64 -#define VS_USER_DEFINED 100 -#define VK_NUMPAD5 0x65 -#define LANG_DIVEHI 0x65 -#define VK_NUMPAD6 0x66 -#define VK_NUMPAD7 0x67 -#define LANG_FULAH 0x67 -#define LANG_PULAR 0x67 -#define VK_NUMPAD8 0x68 -#define LANG_HAUSA 0x68 -#define VK_NUMPAD9 0x69 -#define VK_MULTIPLY 0x6A -#define LANG_YORUBA 0x6a -#define VK_ADD 0x6B -#define LANG_QUECHUA 0x6b -#define VK_SEPARATOR 0x6C -#define LANG_SOTHO 0x6c -#define VK_SUBTRACT 0x6D -#define LANG_BASHKIR 0x6d -#define VK_DECIMAL 0x6E -#define LANG_LUXEMBOURGISH 0x6e -#define VK_DIVIDE 0x6F -#define LANG_GREENLANDIC 0x6f -#define VK_F1 0x70 -#define LANG_IGBO 0x70 -#define VK_F2 0x71 -#define VK_F3 0x72 -#define VK_F4 0x73 -#define LANG_TIGRIGNA 0x73 -#define LANG_TIGRINYA 0x73 -#define VK_F5 0x74 -#define VK_F6 0x75 -#define LANG_HAWAIIAN 0x75 -#define VK_F7 0x76 -#define VK_F8 0x77 -#define VK_F9 0x78 -#define WHEEL_DELTA 120 -#define LANG_YI 0x78 -#define VK_F10 0x79 -#define VK_F11 0x7A -#define LANG_MAPUDUNGUN 0x7a -#define VK_F12 0x7B -#define WM_CONTEXTMENU 0x007B -#define VK_F13 0x7C -#define WM_STYLECHANGING 0x007C -#define LANG_MOHAWK 0x7c -#define VK_F14 0x7D -#define WM_STYLECHANGED 0x007D -#define VK_F15 0x7E -#define WM_DISPLAYCHANGE 0x007E -#define LANG_BRETON 0x7e -#define VK_F16 0x7F -#define WM_GETICON 0x007F -#define LANG_INVARIANT 0x7f -#define VK_F17 0x80 -#define WM_SETICON 0x0080 -#define WVR_ALIGNRIGHT 0x0080 -#define CS_PARENTDC 0x0080 -#define CF_OWNERDISPLAY 0x0080 -#define HDS_FULLDRAG 0x0080 -#define BTNS_WHOLEDROPDOWN 0x0080 -#define TTS_CLOSE 0x80 -#define TBS_NOTHUMB 0x0080 -#define UDS_NOTHOUSANDS 0x0080 -#define LVS_NOLABELWRAP 0x0080 -#define TVS_NOTOOLTIPS 0x0080 -#define TVS_EX_PARTIALCHECKBOXES 0x0080 -#define TCS_VERTICAL 0x0080 -#define MCS_SHORTDAYSOFWEEK 0x0080 -#define LANG_UIGHUR 0x80 -#define VK_F18 0x81 -#define WM_NCCREATE 0x0081 -#define CF_DSPTEXT 0x0081 -#define LANG_MAORI 0x81 -#define VK_F19 0x82 -#define WM_NCDESTROY 0x0082 -#define CF_DSPBITMAP 0x0082 -#define LANG_OCCITAN 0x82 -#define VK_F20 0x83 -#define WM_NCCALCSIZE 0x0083 -#define CF_DSPMETAFILEPICT 0x0083 -#define LANG_CORSICAN 0x83 -#define VK_F21 0x84 -#define WM_NCHITTEST 0x0084 -#define LANG_ALSATIAN 0x84 -#define VK_F22 0x85 -#define WM_NCPAINT 0x0085 -#define LANG_SAKHA 0x85 -#define LANG_YAKUT 0x85 -#define VK_F23 0x86 -#define WM_NCACTIVATE 0x0086 -#define LANG_KICHE 0x86 -#define VK_F24 0x87 -#define WM_GETDLGCODE 0x0087 -#define LANG_KINYARWANDA 0x87 -#define WM_SYNCPAINT 0x0088 -#define LANG_WOLOF 0x88 -#define LANG_DARI 0x8c -#define CF_DSPENHMETAFILE 0x008E -#define VK_NUMLOCK 0x90 -#define VK_SCROLL 0x91 -#define LANG_SCOTTISH_GAELIC 0x91 -#define VK_OEM_NEC_EQUAL 0x92 -#define VK_OEM_FJ_JISHO 0x92 -#define LANG_CENTRAL_KURDISH 0x92 -#define VK_OEM_FJ_MASSHOU 0x93 -#define VK_OEM_FJ_TOUROKU 0x94 -#define VK_OEM_FJ_LOYA 0x95 -#define VK_OEM_FJ_ROYA 0x96 -#define VK_LSHIFT 0xA0 -#define WM_NCMOUSEMOVE 0x00A0 -#define VK_RSHIFT 0xA1 -#define WM_NCLBUTTONDOWN 0x00A1 -#define VK_LCONTROL 0xA2 -#define WM_NCLBUTTONUP 0x00A2 -#define VK_RCONTROL 0xA3 -#define WM_NCLBUTTONDBLCLK 0x00A3 -#define VK_LMENU 0xA4 -#define WM_NCRBUTTONDOWN 0x00A4 -#define VK_RMENU 0xA5 -#define WM_NCRBUTTONUP 0x00A5 -#define VK_BROWSER_BACK 0xA6 -#define WM_NCRBUTTONDBLCLK 0x00A6 -#define VK_BROWSER_FORWARD 0xA7 -#define WM_NCMBUTTONDOWN 0x00A7 -#define VK_BROWSER_REFRESH 0xA8 -#define WM_NCMBUTTONUP 0x00A8 -#define VK_BROWSER_STOP 0xA9 -#define WM_NCMBUTTONDBLCLK 0x00A9 -#define VK_BROWSER_SEARCH 0xAA -#define VK_BROWSER_FAVORITES 0xAB -#define WM_NCXBUTTONDOWN 0x00AB -#define VK_BROWSER_HOME 0xAC -#define WM_NCXBUTTONUP 0x00AC -#define VK_VOLUME_MUTE 0xAD -#define WM_NCXBUTTONDBLCLK 0x00AD -#define VK_VOLUME_DOWN 0xAE -#define VK_VOLUME_UP 0xAF -#define VK_MEDIA_NEXT_TRACK 0xB0 -#define EM_GETSEL 0x00B0 -#define VK_MEDIA_PREV_TRACK 0xB1 -#define EM_SETSEL 0x00B1 -#define VK_MEDIA_STOP 0xB2 -#define EM_GETRECT 0x00B2 -#define VK_MEDIA_PLAY_PAUSE 0xB3 -#define EM_SETRECT 0x00B3 -#define VK_LAUNCH_MAIL 0xB4 -#define EM_SETRECTNP 0x00B4 -#define VK_LAUNCH_MEDIA_SELECT 0xB5 -#define EM_SCROLL 0x00B5 -#define VK_LAUNCH_APP1 0xB6 -#define EM_LINESCROLL 0x00B6 -#define VK_LAUNCH_APP2 0xB7 -#define EM_SCROLLCARET 0x00B7 -#define EM_GETMODIFY 0x00B8 -#define EM_SETMODIFY 0x00B9 -#define VK_OEM_1 0xBA -#define EM_GETLINECOUNT 0x00BA -#define VK_OEM_PLUS 0xBB -#define EM_LINEINDEX 0x00BB -#define VK_OEM_COMMA 0xBC -#define EM_SETHANDLE 0x00BC -#define VK_OEM_MINUS 0xBD -#define EM_GETHANDLE 0x00BD -#define VK_OEM_PERIOD 0xBE -#define EM_GETTHUMB 0x00BE -#define VK_OEM_2 0xBF -#define VK_OEM_3 0xC0 -#define EM_LINELENGTH 0x00C1 -#define EM_REPLACESEL 0x00C2 -#define EM_GETLINE 0x00C4 -#define EM_LIMITTEXT 0x00C5 -#define EM_CANUNDO 0x00C6 -#define EM_UNDO 0x00C7 -#define EM_FMTLINES 0x00C8 -#define EM_LINEFROMCHAR 0x00C9 -#define EM_SETTABSTOPS 0x00CB -#define EM_SETPASSWORDCHAR 0x00CC -#define EM_EMPTYUNDOBUFFER 0x00CD -#define EM_GETFIRSTVISIBLELINE 0x00CE -#define EM_SETREADONLY 0x00CF -#define EM_SETWORDBREAKPROC 0x00D0 -#define EM_GETWORDBREAKPROC 0x00D1 -#define EM_GETPASSWORDCHAR 0x00D2 -#define EM_SETMARGINS 0x00D3 -#define EM_GETMARGINS 0x00D4 -#define EM_GETLIMITTEXT 0x00D5 -#define EM_POSFROMCHAR 0x00D6 -#define EM_CHARFROMPOS 0x00D7 -#define EM_SETIMESTATUS 0x00D8 -#define EM_GETIMESTATUS 0x00D9 -#define VK_OEM_4 0xDB -#define VK_OEM_5 0xDC -#define VK_OEM_6 0xDD -#define VK_OEM_7 0xDE -#define VK_OEM_8 0xDF -#define VK_OEM_AX 0xE1 -#define VK_OEM_102 0xE2 -#define VK_ICO_HELP 0xE3 -#define VK_ICO_00 0xE4 -#define VK_PROCESSKEY 0xE5 -#define VK_ICO_CLEAR 0xE6 -#define VK_PACKET 0xE7 -#define VK_OEM_RESET 0xE9 -#define VK_OEM_JUMP 0xEA -#define VK_OEM_PA1 0xEB -#define VK_OEM_PA2 0xEC -#define VK_OEM_PA3 0xED -#define VK_OEM_WSCTRL 0xEE -#define VK_OEM_CUSEL 0xEF -#define VK_OEM_ATTN 0xF0 -#define BM_GETCHECK 0x00F0 -#define VK_OEM_FINISH 0xF1 -#define BM_SETCHECK 0x00F1 -#define VK_OEM_COPY 0xF2 -#define BM_GETSTATE 0x00F2 -#define VK_OEM_AUTO 0xF3 -#define BM_SETSTATE 0x00F3 -#define VK_OEM_ENLW 0xF4 -#define BM_SETSTYLE 0x00F4 -#define VK_OEM_BACKTAB 0xF5 -#define BM_CLICK 0x00F5 -#define VK_ATTN 0xF6 -#define BM_GETIMAGE 0x00F6 -#define VK_CRSEL 0xF7 -#define BM_SETIMAGE 0x00F7 -#define VK_EXSEL 0xF8 -#define BM_SETDONTCLICK 0x00F8 -#define VK_EREOF 0xF9 -#define VK_PLAY 0xFA -#define VK_ZOOM 0xFB -#define VK_NONAME 0xFC -#define VK_PA1 0xFD -#define VK_OEM_CLEAR 0xFE -#define WM_INPUT_DEVICE_CHANGE 0x00FE -#define SUBVERSION_MASK 0x000000FF -#define WM_INPUT 0x00FF -#define WM_KEYFIRST 0x0100 -#define WM_KEYDOWN 0x0100 -#define WVR_HREDRAW 0x0100 -#define HDS_FILTERBAR 0x0100 -#define TBSTYLE_TOOLTIPS 0x0100 -#define RBS_TOOLTIPS 0x00000100 -#define TTS_USEVISUALSTYLE 0x100 -#define SBARS_SIZEGRIP 0x0100 -#define TBS_TOOLTIPS 0x0100 -#define UDS_HOTTRACK 0x0100 -#define LVS_AUTOARRANGE 0x0100 -#define TVS_CHECKBOXES 0x0100 -#define TVS_EX_EXCLUSIONCHECKBOXES 0x0100 -#define TCS_BUTTONS 0x0100 -#define MCS_NOSELCHANGEONNAV 0x0100 -#define WM_KEYUP 0x0101 -#define WM_CHAR 0x0102 -#define WM_DEADCHAR 0x0103 -#define WM_SYSKEYDOWN 0x0104 -#define WM_SYSKEYUP 0x0105 -#define WM_SYSCHAR 0x0106 -#define WM_SYSDEADCHAR 0x0107 -#define WM_UNICHAR 0x0109 -#define WM_KEYLAST 0x0109 -#define WM_IME_STARTCOMPOSITION 0x010D -#define WM_IME_ENDCOMPOSITION 0x010E -#define WM_IME_COMPOSITION 0x010F -#define WM_IME_KEYLAST 0x010F -#define WM_INITDIALOG 0x0110 -#define WM_COMMAND 0x0111 -#define WM_SYSCOMMAND 0x0112 -#define WM_TIMER 0x0113 -#define WM_HSCROLL 0x0114 -#define WM_VSCROLL 0x0115 -#define WM_INITMENU 0x0116 -#define WM_INITMENUPOPUP 0x0117 -#define WM_GESTURE 0x0119 -#define WM_GESTURENOTIFY 0x011A -#define WM_MENUSELECT 0x011F -#define WM_MENUCHAR 0x0120 -#define WM_ENTERIDLE 0x0121 -#define WM_MENURBUTTONUP 0x0122 -#define WM_MENUDRAG 0x0123 -#define WM_MENUGETOBJECT 0x0124 -#define WM_UNINITMENUPOPUP 0x0125 -#define WM_MENUCOMMAND 0x0126 -#define WM_CHANGEUISTATE 0x0127 -#define WM_UPDATEUISTATE 0x0128 -#define WM_QUERYUISTATE 0x0129 -#define WM_CTLCOLORMSGBOX 0x0132 -#define WM_CTLCOLOREDIT 0x0133 -#define WM_CTLCOLORLISTBOX 0x0134 -#define WM_CTLCOLORBTN 0x0135 -#define WM_CTLCOLORDLG 0x0136 -#define WM_CTLCOLORSCROLLBAR 0x0137 -#define WM_CTLCOLORSTATIC 0x0138 -#define MN_GETHMENU 0x01E1 -#define _WIN32_IE_IE20 0x0200 -#define WM_MOUSEFIRST 0x0200 -#define WM_MOUSEMOVE 0x0200 -#define WVR_VREDRAW 0x0200 -#define CS_NOCLOSE 0x0200 -#define CF_PRIVATEFIRST 0x0200 -#define HDS_FLAT 0x0200 -#define TBSTYLE_WRAPABLE 0x0200 -#define RBS_VARHEIGHT 0x00000200 -#define TBS_REVERSED 0x0200 -#define LVS_EDITLABELS 0x0200 -#define TVS_TRACKSELECT 0x0200 -#define TVS_EX_DIMMEDCHECKBOXES 0x0200 -#define TCS_MULTILINE 0x0200 -#define WM_LBUTTONDOWN 0x0201 -#define WM_LBUTTONUP 0x0202 -#define WM_LBUTTONDBLCLK 0x0203 -#define WM_RBUTTONDOWN 0x0204 -#define WM_RBUTTONUP 0x0205 -#define WM_RBUTTONDBLCLK 0x0206 -#define WM_MBUTTONDOWN 0x0207 -#define WM_MBUTTONUP 0x0208 -#define WM_MBUTTONDBLCLK 0x0209 -#define WM_MOUSEWHEEL 0x020A -#define WM_XBUTTONDOWN 0x020B -#define WM_XBUTTONUP 0x020C -#define WM_XBUTTONDBLCLK 0x020D -#define WM_MOUSEHWHEEL 0x020E -#define WM_MOUSELAST 0x020E -#define WM_PARENTNOTIFY 0x0210 -#define WM_ENTERMENULOOP 0x0211 -#define WM_EXITMENULOOP 0x0212 -#define WM_NEXTMENU 0x0213 -#define WM_SIZING 0x0214 -#define WM_CAPTURECHANGED 0x0215 -#define WM_MOVING 0x0216 -#define WM_POWERBROADCAST 0x0218 -#define WM_DEVICECHANGE 0x0219 -#define WM_MDICREATE 0x0220 -#define WM_MDIDESTROY 0x0221 -#define WM_MDIACTIVATE 0x0222 -#define WM_MDIRESTORE 0x0223 -#define WM_MDINEXT 0x0224 -#define WM_MDIMAXIMIZE 0x0225 -#define WM_MDITILE 0x0226 -#define WM_MDICASCADE 0x0227 -#define WM_MDIICONARRANGE 0x0228 -#define WM_MDIGETACTIVE 0x0229 -#define WM_MDISETMENU 0x0230 -#define WM_ENTERSIZEMOVE 0x0231 -#define WM_EXITSIZEMOVE 0x0232 -#define WM_DROPFILES 0x0233 -#define WM_MDIREFRESHMENU 0x0234 -#define WM_POINTERDEVICECHANGE 0x238 -#define WM_POINTERDEVICEINRANGE 0x239 -#define WM_POINTERDEVICEOUTOFRANGE 0x23A -#define WM_TOUCH 0x0240 -#define WM_NCPOINTERUPDATE 0x0241 -#define WM_NCPOINTERDOWN 0x0242 -#define WM_NCPOINTERUP 0x0243 -#define WM_POINTERUPDATE 0x0245 -#define WM_POINTERDOWN 0x0246 -#define WM_POINTERUP 0x0247 -#define WM_POINTERENTER 0x0249 -#define WM_POINTERLEAVE 0x024A -#define WM_POINTERACTIVATE 0x024B -#define WM_POINTERCAPTURECHANGED 0x024C -#define WM_TOUCHHITTESTING 0x024D -#define WM_POINTERWHEEL 0x024E -#define WM_POINTERHWHEEL 0x024F -#define WM_IME_SETCONTEXT 0x0281 -#define WM_IME_NOTIFY 0x0282 -#define WM_IME_CONTROL 0x0283 -#define WM_IME_COMPOSITIONFULL 0x0284 -#define WM_IME_SELECT 0x0285 -#define WM_IME_CHAR 0x0286 -#define WM_IME_REQUEST 0x0288 -#define WM_IME_KEYDOWN 0x0290 -#define WM_IME_KEYUP 0x0291 -#define WM_NCMOUSEHOVER 0x02A0 -#define WM_MOUSEHOVER 0x02A1 -#define WM_NCMOUSELEAVE 0x02A2 -#define WM_MOUSELEAVE 0x02A3 -#define WM_WTSSESSION_CHANGE 0x02B1 -#define WM_TABLET_FIRST 0x02c0 -#define WM_TABLET_LAST 0x02df -#define CF_PRIVATELAST 0x02FF -#define _WIN32_IE_IE30 0x0300 -#define WM_CUT 0x0300 -#define CF_GDIOBJFIRST 0x0300 -#define WM_COPY 0x0301 -#define _WIN32_IE_IE302 0x0302 -#define WM_PASTE 0x0302 -#define WM_CLEAR 0x0303 -#define WM_UNDO 0x0304 -#define WM_RENDERFORMAT 0x0305 -#define WM_RENDERALLFORMATS 0x0306 -#define WM_DESTROYCLIPBOARD 0x0307 -#define WM_DRAWCLIPBOARD 0x0308 -#define WM_PAINTCLIPBOARD 0x0309 -#define WM_VSCROLLCLIPBOARD 0x030A -#define WM_SIZECLIPBOARD 0x030B -#define WM_ASKCBFORMATNAME 0x030C -#define WM_CHANGECBCHAIN 0x030D -#define WM_HSCROLLCLIPBOARD 0x030E -#define WM_QUERYNEWPALETTE 0x030F -#define WM_PALETTEISCHANGING 0x0310 -#define WM_PALETTECHANGED 0x0311 -#define WM_HOTKEY 0x0312 -#define WM_PRINT 0x0317 -#define WM_PRINTCLIENT 0x0318 -#define WM_APPCOMMAND 0x0319 -#define WM_THEMECHANGED 0x031A -#define WM_CLIPBOARDUPDATE 0x031D -#define WM_DWMCOMPOSITIONCHANGED 0x031E -#define WM_DWMNCRENDERINGCHANGED 0x031F -#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320 -#define WM_DWMWINDOWMAXIMIZEDCHANGE 0x0321 -#define WM_DWMSENDICONICTHUMBNAIL 0x0323 -#define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326 -#define WM_GETTITLEBARINFOEX 0x033F -#define WM_HANDHELDFIRST 0x0358 -#define WM_HANDHELDLAST 0x035F -#define WM_AFXFIRST 0x0360 -#define WM_AFXLAST 0x037F -#define WM_PENWINFIRST 0x0380 -#define WM_PENWINLAST 0x038F -#define WM_DDE_FIRST 0x03E0 -#define CF_GDIOBJLAST 0x03FF -#define _WIN32_WINNT_NT4 0x0400 -#define _WIN32_IE_IE40 0x0400 -#define WM_USER 0x0400 -#define WVR_VALIDRECTS 0x0400 -#define HDS_CHECKBOXES 0x0400 -#define TBSTYLE_ALTDRAG 0x0400 -#define RBS_BANDBORDERS 0x00000400 -#define TBS_DOWNISLEFT 0x0400 -#define LVS_OWNERDRAWFIXED 0x0400 -#define TVS_SINGLEEXPAND 0x0400 -#define TVS_EX_DRAWIMAGEASYNC 0x0400 -#define TCS_FIXEDWIDTH 0x0400 -#define ctlFirst 0x0400 -#define psh1 0x0400 -#define _WIN32_IE_IE401 0x0401 -#define psh2 0x0401 -#define psh3 0x0402 -#define psh4 0x0403 -#define psh5 0x0404 -#define psh6 0x0405 -#define psh7 0x0406 -#define psh8 0x0407 -#define psh9 0x0408 -#define psh10 0x0409 -#define psh11 0x040a -#define psh12 0x040b -#define psh13 0x040c -#define psh14 0x040d -#define psh15 0x040e -#define psh16 0x040f -#define _WIN32_WINDOWS 0x0410 -#define chx1 0x0410 -#define chx2 0x0411 -#define chx3 0x0412 -#define chx4 0x0413 -#define chx5 0x0414 -#define chx6 0x0415 -#define chx7 0x0416 -#define chx8 0x0417 -#define chx9 0x0418 -#define chx10 0x0419 -#define chx11 0x041a -#define chx12 0x041b -#define chx13 0x041c -#define chx14 0x041d -#define chx15 0x041e -#define chx16 0x041f -#define rad1 0x0420 -#define rad2 0x0421 -#define rad3 0x0422 -#define rad4 0x0423 -#define rad5 0x0424 -#define rad6 0x0425 -#define rad7 0x0426 -#define rad8 0x0427 -#define rad9 0x0428 -#define rad10 0x0429 -#define rad11 0x042a -#define rad12 0x042b -#define rad13 0x042c -#define rad14 0x042d -#define rad15 0x042e -#define rad16 0x042f -#define grp1 0x0430 -#define grp2 0x0431 -#define grp3 0x0432 -#define grp4 0x0433 -#define frm1 0x0434 -#define frm2 0x0435 -#define frm3 0x0436 -#define frm4 0x0437 -#define rct1 0x0438 -#define rct2 0x0439 -#define rct3 0x043a -#define rct4 0x043b -#define ico1 0x043c -#define ico2 0x043d -#define ico3 0x043e -#define ico4 0x043f -#define stc1 0x0440 -#define stc2 0x0441 -#define stc3 0x0442 -#define stc4 0x0443 -#define stc5 0x0444 -#define stc6 0x0445 -#define stc7 0x0446 -#define stc8 0x0447 -#define stc9 0x0448 -#define stc10 0x0449 -#define stc11 0x044a -#define stc12 0x044b -#define stc13 0x044c -#define stc14 0x044d -#define stc15 0x044e -#define stc16 0x044f -#define stc17 0x0450 -#define stc18 0x0451 -#define stc19 0x0452 -#define stc20 0x0453 -#define stc21 0x0454 -#define stc22 0x0455 -#define stc23 0x0456 -#define stc24 0x0457 -#define stc25 0x0458 -#define stc26 0x0459 -#define stc27 0x045a -#define stc28 0x045b -#define stc29 0x045c -#define stc30 0x045d -#define stc31 0x045e -#define stc32 0x045f -#define lst1 0x0460 -#define lst2 0x0461 -#define lst3 0x0462 -#define lst4 0x0463 -#define lst5 0x0464 -#define lst6 0x0465 -#define lst7 0x0466 -#define lst8 0x0467 -#define lst9 0x0468 -#define lst10 0x0469 -#define lst11 0x046a -#define lst12 0x046b -#define lst13 0x046c -#define lst14 0x046d -#define lst15 0x046e -#define lst16 0x046f -#define cmb1 0x0470 -#define cmb2 0x0471 -#define cmb3 0x0472 -#define cmb4 0x0473 -#define cmb5 0x0474 -#define cmb6 0x0475 -#define cmb7 0x0476 -#define cmb8 0x0477 -#define cmb9 0x0478 -#define cmb10 0x0479 -#define cmb11 0x047a -#define cmb12 0x047b -#define cmb13 0x047c -#define cmb14 0x047d -#define cmb15 0x047e -#define cmb16 0x047f -#define edt1 0x0480 -#define edt2 0x0481 -#define edt3 0x0482 -#define edt4 0x0483 -#define edt5 0x0484 -#define edt6 0x0485 -#define edt7 0x0486 -#define edt8 0x0487 -#define edt9 0x0488 -#define edt10 0x0489 -#define edt11 0x048a -#define edt12 0x048b -#define edt13 0x048c -#define edt14 0x048d -#define edt15 0x048e -#define edt16 0x048f -#define scr1 0x0490 -#define scr2 0x0491 -#define scr3 0x0492 -#define scr4 0x0493 -#define scr5 0x0494 -#define scr6 0x0495 -#define scr7 0x0496 -#define scr8 0x0497 -#define ctl1 0x04A0 -#define ctlLast 0x04ff -#define _WIN32_WINNT_WIN2K 0x0500 -#define _WIN32_IE_IE50 0x0500 -#define _WIN32_WINNT_WINXP 0x0501 -#define _WIN32_IE_IE501 0x0501 -#define _WIN32_WINNT_WS03 0x0502 -#define _WIN32_IE_IE55 0x0550 -#define _WIN32_WINNT_WIN6 0x0600 -#define _WIN32_WINNT_VISTA 0x0600 -#define _WIN32_WINNT_WS08 0x0600 -#define _WIN32_WINNT_LONGHORN 0x0600 -#define _WIN32_IE_IE60 0x0600 -#define FILEOPENORD 1536 -#define _WIN32_WINNT_WIN7 0x0601 -#define _WIN32_IE_IE60SP1 0x0601 -#define MULTIFILEOPENORD 1537 -#define _WIN32_WINNT_WIN8 0x0602 -#define _WIN32_IE_WS03 0x0602 -#define _WIN32_WINNT 0x0600 -#define PRINTDLGORD 1538 -#define VER_PRODUCTVERSION_W 0x0602 -#define _WIN32_IE_IE60SP2 0x0603 -#define PRNSETUPDLGORD 1539 -#define FINDDLGORD 1540 -#define REPLACEDLGORD 1541 -#define FONTDLGORD 1542 -#define FORMATDLGORD31 1543 -#define FORMATDLGORD30 1544 -#define RUNDLGORD 1545 -#define PAGESETUPDLGORD 1546 -#define NEWFILEOPENORD 1547 -#define PRINTDLGEXORD 1549 -#define PAGESETUPDLGORDMOTIF 1550 -#define COLORMGMTDLGORD 1551 -#define NEWFILEOPENV2ORD 1552 -#define NEWFILEOPENV3ORD 1553 -#define NEWFORMATDLGWITHLINK 1591 -#define IDC_MANAGE_LINK 1592 -#define _WIN32_IE_IE70 0x0700 -#define _WIN32_IE_IE80 0x0800 -#define CS_SAVEBITS 0x0800 -#define HDS_NOSIZING 0x0800 -#define TBSTYLE_FLAT 0x0800 -#define RBS_FIXEDORDER 0x00000800 -#define SBARS_TOOLTIPS 0x0800 -#define SBT_TOOLTIPS 0x0800 -#define TBS_NOTIFYBEFOREMOVE 0x0800 -#define LVS_ALIGNLEFT 0x0800 -#define TVS_INFOTIP 0x0800 -#define TCS_RAGGEDRIGHT 0x0800 -#define _WIN32_IE_IE90 0x0900 -#define _WIN32_IE_IE100 0x0A00 -#define LVS_ALIGNMASK 0x0c00 -#define CS_BYTEALIGNCLIENT 0x1000 -#define HDS_OVERFLOW 0x1000 -#define TBSTYLE_LIST 0x1000 -#define RBS_REGISTERDROP 0x00001000 -#define TBS_TRANSPARENTBKGND 0x1000 -#define LVS_OWNERDATA 0x1000 -#define TVS_FULLROWSELECT 0x1000 -#define TCS_FOCUSONBUTTONDOWN 0x1000 -#define CS_BYTEALIGNWINDOW 0x2000 -#define TBSTYLE_CUSTOMERASE 0x2000 -#define RBS_AUTOSIZE 0x00002000 -#define LVS_NOSCROLL 0x2000 -#define TVS_NOSCROLL 0x2000 -#define TCS_OWNERDRAWFIXED 0x2000 -#define VER_PRODUCTBUILD 9200 -#define CS_GLOBALCLASS 0x4000 -#define TBSTYLE_REGISTERDROP 0x4000 -#define RBS_VERTICALGRIPPER 0x00004000 -#define LVS_NOCOLUMNHEADER 0x4000 -#define TVS_NONEVENHEIGHT 0x4000 -#define TCS_TOOLTIPS 0x4000 -#define VER_PRODUCTBUILD_QFE 20557 -#define VER_PACKAGEBUILD_QFE 20557 -#define IDH_NO_HELP 28440 -#define IDH_MISSING_CONTEXT 28441 -#define IDH_GENERIC_HELP_BUTTON 28442 -#define IDH_OK 28443 -#define IDH_CANCEL 28444 -#define IDH_HELP 28445 -#define LANG_BOSNIAN_NEUTRAL 0x781a -#define LANG_CHINESE_TRADITIONAL 0x7c04 -#define LANG_SERBIAN_NEUTRAL 0x7c1a -#define IDTIMEOUT 32000 -#define OCR_NORMAL 32512 -#define OIC_SAMPLE 32512 -#define IDI_APPLICATION 32512 -#define OCR_IBEAM 32513 -#define OIC_HAND 32513 -#define IDI_HAND 32513 -#define OCR_WAIT 32514 -#define OIC_QUES 32514 -#define IDI_QUESTION 32514 -#define OCR_CROSS 32515 -#define OIC_BANG 32515 -#define IDI_EXCLAMATION 32515 -#define OCR_UP 32516 -#define OIC_NOTE 32516 -#define IDI_ASTERISK 32516 -#define OIC_WINLOGO 32517 -#define IDI_WINLOGO 32517 -#define OIC_SHIELD 32518 -#define IDI_SHIELD 32518 -#define OCR_SIZE 32640 -#define OCR_ICON 32641 -#define OCR_SIZENWSE 32642 -#define OCR_SIZENESW 32643 -#define OCR_SIZEWE 32644 -#define OCR_SIZENS 32645 -#define OCR_SIZEALL 32646 -#define OCR_ICOCUR 32647 -#define OCR_NO 32648 -#define OCR_HAND 32649 -#define OCR_APPSTARTING 32650 -#define OBM_LFARROWI 32734 -#define OBM_RGARROWI 32735 -#define OBM_DNARROWI 32736 -#define OBM_UPARROWI 32737 -#define OBM_COMBO 32738 -#define OBM_MNARROW 32739 -#define OBM_LFARROWD 32740 -#define OBM_RGARROWD 32741 -#define OBM_DNARROWD 32742 -#define OBM_UPARROWD 32743 -#define OBM_RESTORED 32744 -#define OBM_ZOOMD 32745 -#define OBM_REDUCED 32746 -#define OBM_RESTORE 32747 -#define OBM_ZOOM 32748 -#define OBM_REDUCE 32749 -#define OBM_LFARROW 32750 -#define OBM_RGARROW 32751 -#define OBM_DNARROW 32752 -#define OBM_UPARROW 32753 -#define OBM_CLOSE 32754 -#define OBM_OLD_RESTORE 32755 -#define OBM_OLD_ZOOM 32756 -#define OBM_OLD_REDUCE 32757 -#define OBM_BTNCORNERS 32758 -#define OBM_CHECKBOXES 32759 -#define OBM_CHECK 32760 -#define OBM_BTSIZE 32761 -#define OBM_OLD_LFARROW 32762 -#define OBM_OLD_RGARROW 32763 -#define OBM_OLD_DNARROW 32764 -#define OBM_OLD_UPARROW 32765 -#define OBM_SIZE 32766 -#define OBM_OLD_CLOSE 32767 -#define WM_APP 0x8000 -#define HELP_TCARD 0x8000 -#define TBSTYLE_TRANSPARENT 0x8000 -#define RBS_DBLCLKTOGGLE 0x00008000 -#define LVS_NOSORTHEADER 0x8000 -#define TVS_NOHSCROLL 0x8000 -#define TCS_FOCUSNEVER 0x8000 -#define SC_SIZE 0xF000 -#define SC_SEPARATOR 0xF00F -#define SC_MOVE 0xF010 -#define SC_MINIMIZE 0xF020 -#define SC_MAXIMIZE 0xF030 -#define SC_NEXTWINDOW 0xF040 -#define SC_PREVWINDOW 0xF050 -#define SC_CLOSE 0xF060 -#define SC_VSCROLL 0xF070 -#define SC_HSCROLL 0xF080 -#define SC_MOUSEMENU 0xF090 -#define SC_KEYMENU 0xF100 -#define SC_ARRANGE 0xF110 -#define SC_RESTORE 0xF120 -#define SC_TASKLIST 0xF130 -#define SC_SCREENSAVE 0xF140 -#define SC_HOTKEY 0xF150 -#define SC_DEFAULT 0xF160 -#define SC_MONITORPOWER 0xF170 -#define SC_CONTEXTHELP 0xF180 -#define LVS_TYPESTYLEMASK 0xfc00 -#define SPVERSION_MASK 0x0000FF00 -#define HTERROR -2 -#define PWR_FAIL -1 -#define UNICODE_NOCHAR 0xFFFF -#define HTTRANSPARENT -1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1000 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/zto/windows/TapDriver6/resource.rc b/zto/windows/TapDriver6/resource.rc deleted file mode 100644 index 2b65e2b..0000000 --- a/zto/windows/TapDriver6/resource.rc +++ /dev/null @@ -1,88 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,0,0,0 - PRODUCTVERSION 3,0,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x9L -#else - FILEFLAGS 0x8L -#endif - FILEOS 0x40004L - FILETYPE 0x3L - FILESUBTYPE 0x6L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "ZeroTier Networks LLC" - VALUE "FileDescription", "ZeroTier One Virtual Network Port" - VALUE "FileVersion", "3.0.0 3/0" - VALUE "InternalName", "zttap300.sys" - VALUE "LegalCopyright", "ZeroTier, Inc., OpenVPN Technologies, Inc." - VALUE "OriginalFilename", "zttap300.sys" - VALUE "ProductName", "ZeroTier One Virtual Network Port" - VALUE "ProductVersion", "3.0.0 3/0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/zto/windows/TapDriver6/rxpath.c b/zto/windows/TapDriver6/rxpath.c deleted file mode 100644 index 318bc56..0000000 --- a/zto/windows/TapDriver6/rxpath.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// -// Include files. -// - -#include "tap.h" - -//====================================================================== -// TAP Receive Path Support -//====================================================================== - -#ifdef ALLOC_PRAGMA -#pragma alloc_text( PAGE, TapDeviceWrite) -#endif // ALLOC_PRAGMA - -//=============================================================== -// Used in cases where internally generated packets such as -// ARP or DHCP replies must be returned to the kernel, to be -// seen as an incoming packet "arriving" on the interface. -//=============================================================== - -VOID -IndicateReceivePacket( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in PUCHAR packetData, - __in const unsigned int packetLength - ) -{ - PUCHAR injectBuffer; - - // - // Handle miniport Pause - // --------------------- - // NDIS 6 miniports implement a temporary "Pause" state normally followed - // by the Restart. While in the Pause state it is forbidden for the miniport - // to indicate receive NBLs. - // - // That is: The device interface may be "up", but the NDIS miniport send/receive - // interface may be temporarily "down". - // - // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas inject path - // the code below will simply ignore inject packets passed to the driver while - // the miniport is in the Paused state. - // - // The correct implementation is to go ahead and build the NBLs corresponding - // to the inject packet - but queue them. When Restart is entered the - // queued NBLs would be dequeued and indicated to the host. - // - if(tapAdapterSendAndReceiveReady(Adapter) != NDIS_STATUS_SUCCESS) - { - DEBUGP (("[%s] Lying send in IndicateReceivePacket while adapter paused\n", - MINIPORT_INSTANCE_ID (Adapter))); - - return; - } - - // Allocate flat buffer for packet data. - injectBuffer = (PUCHAR )NdisAllocateMemoryWithTagPriority( - Adapter->MiniportAdapterHandle, - packetLength, - TAP_RX_INJECT_BUFFER_TAG, - NormalPoolPriority - ); - - if( injectBuffer) - { - PMDL mdl; - - // Copy packet data to flat buffer. - NdisMoveMemory (injectBuffer, packetData, packetLength); - - // Allocate MDL for flat buffer. - mdl = NdisAllocateMdl( - Adapter->MiniportAdapterHandle, - injectBuffer, - packetLength - ); - - if( mdl ) - { - PNET_BUFFER_LIST netBufferList; - - mdl->Next = NULL; // No next MDL - - // Allocate the NBL and NB. Link MDL chain to NB. - netBufferList = NdisAllocateNetBufferAndNetBufferList( - Adapter->ReceiveNblPool, - 0, // ContextSize - 0, // ContextBackFill - mdl, // MDL chain - 0, - packetLength - ); - - if(netBufferList != NULL) - { - ULONG receiveFlags = 0; - LONG nblCount; - - NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL - - if(KeGetCurrentIrql() == DISPATCH_LEVEL) - { - receiveFlags |= NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL; - } - - // Set flag indicating that this is an injected packet - TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); - TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED); - - netBufferList->MiniportReserved[0] = NULL; - netBufferList->MiniportReserved[1] = NULL; - - // Increment in-flight receive NBL count. - nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount); - ASSERT(nblCount > 0 ); - - netBufferList->SourceHandle = Adapter->MiniportAdapterHandle; - - // - // Indicate the packet - // ------------------- - // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length - // contains the complete packet including Ethernet header and payload. - // - NdisMIndicateReceiveNetBufferLists( - Adapter->MiniportAdapterHandle, - netBufferList, - NDIS_DEFAULT_PORT_NUMBER, - 1, // NumberOfNetBufferLists - receiveFlags - ); - - return; - } - else - { - DEBUGP (("[%s] NdisAllocateNetBufferAndNetBufferList failed in IndicateReceivePacket\n", - MINIPORT_INSTANCE_ID (Adapter))); - NOTE_ERROR (); - - NdisFreeMdl(mdl); - NdisFreeMemory(injectBuffer,0,0); - } - } - else - { - DEBUGP (("[%s] NdisAllocateMdl failed in IndicateReceivePacket\n", - MINIPORT_INSTANCE_ID (Adapter))); - NOTE_ERROR (); - - NdisFreeMemory(injectBuffer,0,0); - } - } - else - { - DEBUGP (("[%s] NdisAllocateMemoryWithTagPriority failed in IndicateReceivePacket\n", - MINIPORT_INSTANCE_ID (Adapter))); - NOTE_ERROR (); - } -} - -VOID -tapCompleteIrpAndFreeReceiveNetBufferList( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in PNET_BUFFER_LIST NetBufferList, // Only one NB here... - __in NTSTATUS IoCompletionStatus - ) -{ - PIRP irp; - ULONG frameType, netBufferCount, byteCount; - LONG nblCount; - - // Fetch NB frame type. - frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(NetBufferList)); - - // Fetch statistics for all NBs linked to the NB. - netBufferCount = tapGetNetBufferCountsFromNetBufferList( - NetBufferList, - &byteCount - ); - - // Update statistics by frame type - if(IoCompletionStatus == STATUS_SUCCESS) - { - switch(frameType) - { - case NDIS_PACKET_TYPE_DIRECTED: - Adapter->FramesRxDirected += netBufferCount; - Adapter->BytesRxDirected += byteCount; - break; - - case NDIS_PACKET_TYPE_BROADCAST: - Adapter->FramesRxBroadcast += netBufferCount; - Adapter->BytesRxBroadcast += byteCount; - break; - - case NDIS_PACKET_TYPE_MULTICAST: - Adapter->FramesRxMulticast += netBufferCount; - Adapter->BytesRxMulticast += byteCount; - break; - - default: - ASSERT(FALSE); - break; - } - } - - // - // Handle P2P Packet - // ----------------- - // Free MDL allocated for P2P Ethernet header. - // - if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_P2P)) - { - PNET_BUFFER netBuffer; - PMDL mdl; - - netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList); - mdl = NET_BUFFER_FIRST_MDL(netBuffer); - mdl->Next = NULL; - - NdisFreeMdl(mdl); - } - - // - // Handle Injected Packet - // ----------------------- - // Free MDL and data buffer allocated for injected packet. - // - if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED)) - { - PNET_BUFFER netBuffer; - PMDL mdl; - PUCHAR injectBuffer; - - netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList); - mdl = NET_BUFFER_FIRST_MDL(netBuffer); - - injectBuffer = (PUCHAR )MmGetSystemAddressForMdlSafe(mdl,NormalPagePriority); - - if(injectBuffer) - { - NdisFreeMemory(injectBuffer,0,0); - } - - NdisFreeMdl(mdl); - } - - // - // Complete the IRP - // - irp = (PIRP )NetBufferList->MiniportReserved[0]; - - if(irp) - { - irp->IoStatus.Status = IoCompletionStatus; - IoCompleteRequest(irp, IO_NO_INCREMENT); - } - - // Decrement in-flight receive NBL count. - nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount); - ASSERT(nblCount >= 0 ); - if (0 == nblCount) - { - NdisSetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent); - } - - // Free the NBL - NdisFreeNetBufferList(NetBufferList); -} - -VOID -AdapterReturnNetBufferLists( - __in NDIS_HANDLE MiniportAdapterContext, - __in PNET_BUFFER_LIST NetBufferLists, - __in ULONG ReturnFlags - ) -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - PNET_BUFFER_LIST currentNbl, nextNbl; - - UNREFERENCED_PARAMETER(ReturnFlags); - - // - // Process each NBL individually - // - currentNbl = NetBufferLists; - while (currentNbl) - { - PNET_BUFFER_LIST nextNbl; - - nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); - NET_BUFFER_LIST_NEXT_NBL(currentNbl) = NULL; - - // Complete write IRP and free NBL and associated resources. - tapCompleteIrpAndFreeReceiveNetBufferList( - adapter, - currentNbl, - STATUS_SUCCESS - ); - - // Move to next NBL - currentNbl = nextNbl; - } -} - -// IRP_MJ_WRITE callback. -NTSTATUS -TapDeviceWrite( - PDEVICE_OBJECT DeviceObject, - PIRP Irp - ) -{ - NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success - PIO_STACK_LOCATION irpSp;// Pointer to current stack location - PTAP_ADAPTER_CONTEXT adapter = NULL; - ULONG dataLength; - - PAGED_CODE(); - - irpSp = IoGetCurrentIrpStackLocation( Irp ); - - // - // Fetch adapter context for this device. - // -------------------------------------- - // Adapter pointer was stashed in FsContext when handle was opened. - // - adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; - - ASSERT(adapter); - - // - // Sanity checks on state variables - // - if (!tapAdapterReadAndWriteReady(adapter)) - { - //DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n", - // MINIPORT_INSTANCE_ID (adapter))); - //NOTE_ERROR(); - - Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED; - Irp->IoStatus.Information = 0; - IoCompleteRequest (Irp, IO_NO_INCREMENT); - - return ntStatus; - } - - // Save IRP-accessible copy of buffer length - Irp->IoStatus.Information = irpSp->Parameters.Write.Length; - - if (Irp->MdlAddress == NULL) - { - DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n", - MINIPORT_INSTANCE_ID (adapter))); - - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; - Irp->IoStatus.Information = 0; - IoCompleteRequest (Irp, IO_NO_INCREMENT); - - return ntStatus; - } - - // - // Try to get a virtual address for the MDL. - // - NdisQueryMdl( - Irp->MdlAddress, - &Irp->AssociatedIrp.SystemBuffer, - &dataLength, - NormalPagePriority - ); - - if (Irp->AssociatedIrp.SystemBuffer == NULL) - { - DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n", - MINIPORT_INSTANCE_ID (adapter))); - - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES; - Irp->IoStatus.Information = 0; - IoCompleteRequest (Irp, IO_NO_INCREMENT); - - return ntStatus; - } - - ASSERT(dataLength == irpSp->Parameters.Write.Length); - - Irp->IoStatus.Information = irpSp->Parameters.Write.Length; - - // - // Handle miniport Pause - // --------------------- - // NDIS 6 miniports implement a temporary "Pause" state normally followed - // by the Restart. While in the Pause state it is forbidden for the miniport - // to indicate receive NBLs. - // - // That is: The device interface may be "up", but the NDIS miniport send/receive - // interface may be temporarily "down". - // - // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path - // the code below will perform a "lying send" for write IRPs passed to the - // driver while the miniport is in the Paused state. - // - // The correct implementation is to go ahead and build the NBLs corresponding - // to the user-mode write - but queue them. When Restart is entered the - // queued NBLs would be dequeued and indicated to the host. - // - if(tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS) - { - if (/*!adapter->m_tun &&*/ ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE)) - { - PNET_BUFFER_LIST netBufferList; - - DUMP_PACKET ("IRP_MJ_WRITE ETH", - (unsigned char *) Irp->AssociatedIrp.SystemBuffer, - irpSp->Parameters.Write.Length); - - //===================================================== - // If IPv4 packet, check whether or not packet - // was truncated. - //===================================================== -#if PACKET_TRUNCATION_CHECK - IPv4PacketSizeVerify ( - (unsigned char *) Irp->AssociatedIrp.SystemBuffer, - irpSp->Parameters.Write.Length, - FALSE, - "RX", - &adapter->m_RxTrunc - ); -#endif - (Irp->MdlAddress)->Next = NULL; // No next MDL - - // Allocate the NBL and NB. Link MDL chain to NB. - netBufferList = NdisAllocateNetBufferAndNetBufferList( - adapter->ReceiveNblPool, - 0, // ContextSize - 0, // ContextBackFill - Irp->MdlAddress, // MDL chain - 0, - dataLength - ); - - if(netBufferList != NULL) - { - LONG nblCount; - - NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL - - // Stash IRP pointer in NBL MiniportReserved[0] field. - netBufferList->MiniportReserved[0] = Irp; - netBufferList->MiniportReserved[1] = NULL; - - // This IRP is pended. - IoMarkIrpPending(Irp); - - // This IRP cannot be cancelled while in-flight. - IoSetCancelRoutine(Irp,NULL); - - TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); - - // Increment in-flight receive NBL count. - nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); - ASSERT(nblCount > 0 ); - - // - // Indicate the packet - // ------------------- - // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length - // contains the complete packet including Ethernet header and payload. - // - NdisMIndicateReceiveNetBufferLists( - adapter->MiniportAdapterHandle, - netBufferList, - NDIS_DEFAULT_PORT_NUMBER, - 1, // NumberOfNetBufferLists - 0 // ReceiveFlags - ); - - ntStatus = STATUS_PENDING; - } - else - { - DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", - MINIPORT_INSTANCE_ID (adapter))); - NOTE_ERROR (); - - // Fail the IRP - Irp->IoStatus.Information = 0; - ntStatus = STATUS_INSUFFICIENT_RESOURCES; - } - } - /* - else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE)) - { - PETH_HEADER p_UserToTap = &adapter->m_UserToTap; - PMDL mdl; // Head of MDL chain. - - // For IPv6, need to use Ethernet header with IPv6 proto - if ( IPH_GET_VER( ((IPHDR*) Irp->AssociatedIrp.SystemBuffer)->version_len) == 6 ) - { - p_UserToTap = &adapter->m_UserToTap_IPv6; - } - - DUMP_PACKET2 ("IRP_MJ_WRITE P2P", - p_UserToTap, - (unsigned char *) Irp->AssociatedIrp.SystemBuffer, - irpSp->Parameters.Write.Length); - - //===================================================== - // If IPv4 packet, check whether or not packet - // was truncated. - //===================================================== -#if PACKET_TRUNCATION_CHECK - IPv4PacketSizeVerify ( - (unsigned char *) Irp->AssociatedIrp.SystemBuffer, - irpSp->Parameters.Write.Length, - TRUE, - "RX", - &adapter->m_RxTrunc - ); -#endif - - // - // Allocate MDL for Ethernet header - // -------------------------------- - // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length - // contains the only the Ethernet payload. Prepend the user-mode provided - // payload with the Ethernet header pointed to by p_UserToTap. - // - mdl = NdisAllocateMdl( - adapter->MiniportAdapterHandle, - p_UserToTap, - sizeof(ETH_HEADER) - ); - - if(mdl != NULL) - { - PNET_BUFFER_LIST netBufferList; - - // Chain user's Ethernet payload behind Ethernet header. - mdl->Next = Irp->MdlAddress; - (Irp->MdlAddress)->Next = NULL; // No next MDL - - // Allocate the NBL and NB. Link MDL chain to NB. - netBufferList = NdisAllocateNetBufferAndNetBufferList( - adapter->ReceiveNblPool, - 0, // ContextSize - 0, // ContextBackFill - mdl, // MDL chain - 0, - sizeof(ETH_HEADER) + dataLength - ); - - if(netBufferList != NULL) - { - LONG nblCount; - - NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL - - // This IRP is pended. - IoMarkIrpPending(Irp); - - // This IRP cannot be cancelled while in-flight. - IoSetCancelRoutine(Irp,NULL); - - // Stash IRP pointer in NBL MiniportReserved[0] field. - netBufferList->MiniportReserved[0] = Irp; - netBufferList->MiniportReserved[1] = NULL; - - // Set flag indicating that this is P2P packet - TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); - TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_P2P); - - // Increment in-flight receive NBL count. - nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); - ASSERT(nblCount > 0 ); - - // - // Indicate the packet - // - NdisMIndicateReceiveNetBufferLists( - adapter->MiniportAdapterHandle, - netBufferList, - NDIS_DEFAULT_PORT_NUMBER, - 1, // NumberOfNetBufferLists - 0 // ReceiveFlags - ); - - ntStatus = STATUS_PENDING; - } - else - { - mdl->Next = NULL; - NdisFreeMdl(mdl); - - DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", - MINIPORT_INSTANCE_ID (adapter))); - NOTE_ERROR (); - - // Fail the IRP - Irp->IoStatus.Information = 0; - ntStatus = STATUS_INSUFFICIENT_RESOURCES; - } - } - else - { - DEBUGP (("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n", - MINIPORT_INSTANCE_ID (adapter))); - NOTE_ERROR (); - - // Fail the IRP - Irp->IoStatus.Information = 0; - ntStatus = STATUS_INSUFFICIENT_RESOURCES; - } - } - */ - else - { - DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n", - MINIPORT_INSTANCE_ID (adapter), - irpSp->Parameters.Write.Length)); - NOTE_ERROR (); - - Irp->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE; - Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; - } - } - else - { - DEBUGP (("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n", - MINIPORT_INSTANCE_ID (adapter))); - - ntStatus = STATUS_SUCCESS; - } - - if (ntStatus != STATUS_PENDING) - { - Irp->IoStatus.Status = ntStatus; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - } - - return ntStatus; -} - diff --git a/zto/windows/TapDriver6/tap-windows.h b/zto/windows/TapDriver6/tap-windows.h deleted file mode 100644 index fd41a79..0000000 --- a/zto/windows/TapDriver6/tap-windows.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __TAP_WIN_H -#define __TAP_WIN_H - -/* - * ============= - * TAP IOCTLs - * ============= - */ - -#define TAP_WIN_CONTROL_CODE(request,method) \ - CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) - -/* Present in 8.1 */ - -#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED) -//#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED) -//#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED) -#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED) -//#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED) -#if DBG -#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED) -#endif -//#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED) - -/* Added in 8.2 */ - -/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */ -//#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED) - -// Used by ZT1 to get multicast memberships at the L2 level -- Windows provides no native way to do this that I know of -#define TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS TAP_WIN_CONTROL_CODE (11, METHOD_BUFFERED) -// Must be the same as NIC_MAX_MCAST_LIST in constants.h -#define TAP_MAX_MCAST_LIST 128 -// Amount of memory that must be provided to ioctl TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS -#define TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE (TAP_MAX_MCAST_LIST * 6) - -/* - * ================= - * Registry keys - * ================= - */ - -#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" - -#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" - -/* - * ====================== - * Filesystem prefixes - * ====================== - */ - -#define USERMODEDEVICEDIR "\\\\.\\Global\\" -#define SYSDEVICEDIR "\\Device\\" -#define USERDEVICEDIR "\\DosDevices\\Global\\" -#define TAP_WIN_SUFFIX ".tap" - -#endif // __TAP_WIN_H diff --git a/zto/windows/TapDriver6/tap.h b/zto/windows/TapDriver6/tap.h deleted file mode 100644 index 079b279..0000000 --- a/zto/windows/TapDriver6/tap.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __TAP_H -#define __TAP_H - -#ifndef NDIS_SUPPORT_NDIS6 -#define NDIS_SUPPORT_NDIS6 1 -#define NDIS_SUPPORT_NDIS61 1 -#define NDIS_WDM1 1 -#define NDIS61_MINIPORT 1 -#endif - -#include -#include -#include -#include - -#include "config.h" -#include "lock.h" -#include "constants.h" -#include "proto.h" -#include "mem.h" -#include "macinfo.h" -#include "error.h" -#include "endian.h" -#include "types.h" -#include "adapter.h" -#include "device.h" -#include "prototypes.h" -#include "tap-windows.h" - -//======================================================== -// Check for truncated IPv4 packets, log errors if found. -//======================================================== -#define PACKET_TRUNCATION_CHECK 0 - -//======================================================== -// EXPERIMENTAL -- Configure TAP device object to be -// accessible from non-administrative accounts, based -// on an advanced properties setting. -// -// Duplicates the functionality of OpenVPN's -// --allow-nonadmin directive. -//======================================================== -#define ENABLE_NONADMIN 1 - -// -// The driver has exactly one instance of the TAP_GLOBAL structure. NDIS keeps -// an opaque handle to this data, (it doesn't attempt to read or interpret this -// data), and it passes the handle back to the miniport in MiniportSetOptions -// and MiniportInitializeEx. -// -typedef struct _TAP_GLOBAL -{ - LIST_ENTRY AdapterList; - - NDIS_RW_LOCK Lock; - - NDIS_HANDLE NdisDriverHandle; // From NdisMRegisterMiniportDriver - -} TAP_GLOBAL, *PTAP_GLOBAL; - - -// Global data -extern TAP_GLOBAL GlobalData; - -#endif // __TAP_H diff --git a/zto/windows/TapDriver6/tapdrvr.c b/zto/windows/TapDriver6/tapdrvr.c deleted file mode 100644 index 6c537f1..0000000 --- a/zto/windows/TapDriver6/tapdrvr.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -//====================================================== -// This driver is designed to work on Windows Vista or higher -// versions of Windows. -// -// It is SMP-safe and handles power management. -// -// By default we operate as a "tap" virtual ethernet -// 802.3 interface, but we can emulate a "tun" -// interface (point-to-point IPv4) through the -// TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT or -// TAP_WIN_IOCTL_CONFIG_TUN ioctl. -//====================================================== - -// -// Include files. -// - -#include - -#include "tap.h" - - -// Global data -TAP_GLOBAL GlobalData; - - -#ifdef ALLOC_PRAGMA -#pragma alloc_text( INIT, DriverEntry ) -#pragma alloc_text( PAGE, TapDriverUnload) -#endif // ALLOC_PRAGMA - -NTSTATUS -DriverEntry( - __in PDRIVER_OBJECT DriverObject, - __in PUNICODE_STRING RegistryPath - ) -/*++ -Routine Description: - - In the context of its DriverEntry function, a miniport driver associates - itself with NDIS, specifies the NDIS version that it is using, and - registers its entry points. - - -Arguments: - PVOID DriverObject - pointer to the driver object. - PVOID RegistryPath - pointer to the driver registry path. - - Return Value: - - NTSTATUS code - ---*/ -{ - NTSTATUS status; - - UNREFERENCED_PARAMETER(RegistryPath); - - DEBUGP (("[TAP] --> DriverEntry; version [%d.%d] %s %s\n", - TAP_DRIVER_MAJOR_VERSION, - TAP_DRIVER_MINOR_VERSION, - __DATE__, - __TIME__)); - - DEBUGP (("[TAP] Registry Path: '%wZ'\n", RegistryPath)); - - // - // Initialize any driver-global variables here. - // - NdisZeroMemory(&GlobalData, sizeof(GlobalData)); - - // - // The ApaterList in the GlobalData structure is used to track multiple - // adapters controlled by this miniport. - // - NdisInitializeListHead(&GlobalData.AdapterList); - - // - // This lock protects the AdapterList. - // - NdisInitializeReadWriteLock(&GlobalData.Lock); - - do - { - NDIS_MINIPORT_DRIVER_CHARACTERISTICS miniportCharacteristics; - - NdisZeroMemory(&miniportCharacteristics, sizeof(miniportCharacteristics)); - - {C_ASSERT(sizeof(miniportCharacteristics) >= NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2);} - miniportCharacteristics.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS; - miniportCharacteristics.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2; - miniportCharacteristics.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2; - - miniportCharacteristics.MajorNdisVersion = TAP_NDIS_MAJOR_VERSION; - miniportCharacteristics.MinorNdisVersion = TAP_NDIS_MINOR_VERSION; - - miniportCharacteristics.MajorDriverVersion = TAP_DRIVER_MAJOR_VERSION; - miniportCharacteristics.MinorDriverVersion = TAP_DRIVER_MINOR_VERSION; - - miniportCharacteristics.Flags = 0; - - //miniportCharacteristics.SetOptionsHandler = MPSetOptions; // Optional - miniportCharacteristics.InitializeHandlerEx = AdapterCreate; - miniportCharacteristics.HaltHandlerEx = AdapterHalt; - miniportCharacteristics.UnloadHandler = TapDriverUnload; - miniportCharacteristics.PauseHandler = AdapterPause; - miniportCharacteristics.RestartHandler = AdapterRestart; - miniportCharacteristics.OidRequestHandler = AdapterOidRequest; - miniportCharacteristics.SendNetBufferListsHandler = AdapterSendNetBufferLists; - miniportCharacteristics.ReturnNetBufferListsHandler = AdapterReturnNetBufferLists; - miniportCharacteristics.CancelSendHandler = AdapterCancelSend; - miniportCharacteristics.CheckForHangHandlerEx = AdapterCheckForHangEx; - miniportCharacteristics.ResetHandlerEx = AdapterReset; - miniportCharacteristics.DevicePnPEventNotifyHandler = AdapterDevicePnpEventNotify; - miniportCharacteristics.ShutdownHandlerEx = AdapterShutdownEx; - miniportCharacteristics.CancelOidRequestHandler = AdapterCancelOidRequest; - - // - // Associate the miniport driver with NDIS by calling the - // NdisMRegisterMiniportDriver. This function returns an NdisDriverHandle. - // The miniport driver must retain this handle but it should never attempt - // to access or interpret this handle. - // - // By calling NdisMRegisterMiniportDriver, the driver indicates that it - // is ready for NDIS to call the driver's MiniportSetOptions and - // MiniportInitializeEx handlers. - // - DEBUGP (("[TAP] Calling NdisMRegisterMiniportDriver...\n")); - //NDIS_DECLARE_MINIPORT_DRIVER_CONTEXT(TAP_GLOBAL); - status = NdisMRegisterMiniportDriver( - DriverObject, - RegistryPath, - &GlobalData, - &miniportCharacteristics, - &GlobalData.NdisDriverHandle - ); - - if (NDIS_STATUS_SUCCESS == status) - { - DEBUGP (("[TAP] Registered miniport successfully\n")); - } - else - { - DEBUGP(("[TAP] NdisMRegisterMiniportDriver failed: %8.8X\n", status)); - TapDriverUnload(DriverObject); - status = NDIS_STATUS_FAILURE; - break; - } - } while(FALSE); - - DEBUGP (("[TAP] <-- DriverEntry; status = %8.8X\n",status)); - - return status; -} - -VOID -TapDriverUnload( - __in PDRIVER_OBJECT DriverObject - ) -/*++ - -Routine Description: - - The unload handler is called during driver unload to free up resources - acquired in DriverEntry. This handler is registered in DriverEntry through - NdisMRegisterMiniportDriver. Note that an unload handler differs from - a MiniportHalt function in that this unload handler releases resources that - are global to the driver, while the halt handler releases resource for a - particular adapter. - - Runs at IRQL = PASSIVE_LEVEL. - -Arguments: - - DriverObject Not used - -Return Value: - - None. - ---*/ -{ - PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; - UNICODE_STRING uniWin32NameString; - - DEBUGP (("[TAP] --> TapDriverUnload; version [%d.%d] %s %s unloaded\n", - TAP_DRIVER_MAJOR_VERSION, - TAP_DRIVER_MINOR_VERSION, - __DATE__, - __TIME__ - )); - - PAGED_CODE(); - - // - // Clean up all globals that were allocated in DriverEntry - // - - ASSERT(IsListEmpty(&GlobalData.AdapterList)); - - if(GlobalData.NdisDriverHandle != NULL ) - { - NdisMDeregisterMiniportDriver(GlobalData.NdisDriverHandle); - } - - DEBUGP (("[TAP] <-- TapDriverUnload\n")); -} - diff --git a/zto/windows/TapDriver6/txpath.c b/zto/windows/TapDriver6/txpath.c deleted file mode 100644 index 7993ca4..0000000 --- a/zto/windows/TapDriver6/txpath.c +++ /dev/null @@ -1,1175 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// -// Include files. -// - -#include "tap.h" - -//====================================================================== -// TAP Send Path Support -//====================================================================== - -#ifdef ALLOC_PRAGMA -#pragma alloc_text( PAGE, TapDeviceRead) -#endif // ALLOC_PRAGMA - -// checksum code for ICMPv6 packet, taken from dhcp.c / udp_checksum -// see RFC 4443, 2.3, and RFC 2460, 8.1 -USHORT -icmpv6_checksum( - __in const UCHAR *buf, - __in const int len_icmpv6, - __in const UCHAR *saddr6, - __in const UCHAR *daddr6 - ) -{ - USHORT word16; - ULONG sum = 0; - int i; - - // make 16 bit words out of every two adjacent 8 bit words and - // calculate the sum of all 16 bit words - for (i = 0; i < len_icmpv6; i += 2) - { - word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_icmpv6) ? (buf[i+1] & 0xFF) : 0); - sum += word16; - } - - // add the IPv6 pseudo header which contains the IP source and destination addresses - for (i = 0; i < 16; i += 2) - { - word16 =((saddr6[i] << 8) & 0xFF00) + (saddr6[i+1] & 0xFF); - sum += word16; - } - - for (i = 0; i < 16; i += 2) - { - word16 =((daddr6[i] << 8) & 0xFF00) + (daddr6[i+1] & 0xFF); - sum += word16; - } - - // the next-header number and the length of the ICMPv6 packet - sum += (USHORT) IPPROTO_ICMPV6 + (USHORT) len_icmpv6; - - // keep only the last 16 bits of the 32 bit calculated sum and add the carries - while (sum >> 16) - sum = (sum & 0xFFFF) + (sum >> 16); - - // Take the one's complement of sum - return ((USHORT) ~sum); -} - -/* - -// check IPv6 packet for "is this an IPv6 Neighbor Solicitation that -// the tap driver needs to answer?" -// see RFC 4861 4.3 for the different cases -static IPV6ADDR IPV6_NS_TARGET_MCAST = - { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x08 }; -static IPV6ADDR IPV6_NS_TARGET_UNICAST = - { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 }; - -BOOLEAN -HandleIPv6NeighborDiscovery( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in UCHAR * m_Data - ) -{ - const ETH_HEADER * e = (ETH_HEADER *) m_Data; - const IPV6HDR *ipv6 = (IPV6HDR *) (m_Data + sizeof (ETH_HEADER)); - const ICMPV6_NS * icmpv6_ns = (ICMPV6_NS *) (m_Data + sizeof (ETH_HEADER) + sizeof (IPV6HDR)); - ICMPV6_NA_PKT *na; - USHORT icmpv6_len, icmpv6_csum; - - // we don't really care about the destination MAC address here - // - it's either a multicast MAC, or the userland destination MAC - // but since the TAP driver is point-to-point, all packets are "for us" - - // IPv6 target address must be ff02::1::ff00:8 (multicast for - // initial NS) or fe80::1 (unicast for recurrent NUD) - if ( memcmp( ipv6->daddr, IPV6_NS_TARGET_MCAST, - sizeof(IPV6ADDR) ) != 0 && - memcmp( ipv6->daddr, IPV6_NS_TARGET_UNICAST, - sizeof(IPV6ADDR) ) != 0 ) - { - return FALSE; // wrong target address - } - - // IPv6 Next-Header must be ICMPv6 - if ( ipv6->nexthdr != IPPROTO_ICMPV6 ) - { - return FALSE; // wrong next-header - } - - // ICMPv6 type+code must be 135/0 for NS - if ( icmpv6_ns->type != ICMPV6_TYPE_NS || - icmpv6_ns->code != ICMPV6_CODE_0 ) - { - return FALSE; // wrong ICMPv6 type - } - - // ICMPv6 target address must be fe80::8 (magic) - if ( memcmp( icmpv6_ns->target_addr, IPV6_NS_TARGET_UNICAST, - sizeof(IPV6ADDR) ) != 0 ) - { - return FALSE; // not for us - } - - // packet identified, build magic response packet - - na = (ICMPV6_NA_PKT *) MemAlloc (sizeof (ICMPV6_NA_PKT), TRUE); - if ( !na ) return FALSE; - - //------------------------------------------------ - // Initialize Neighbour Advertisement reply packet - //------------------------------------------------ - - // ethernet header - na->eth.proto = htons(NDIS_ETH_TYPE_IPV6); - ETH_COPY_NETWORK_ADDRESS(na->eth.dest, Adapter->PermanentAddress); - ETH_COPY_NETWORK_ADDRESS(na->eth.src, Adapter->m_TapToUser.dest); - - // IPv6 header - na->ipv6.version_prio = ipv6->version_prio; - NdisMoveMemory( na->ipv6.flow_lbl, ipv6->flow_lbl, - sizeof(na->ipv6.flow_lbl) ); - icmpv6_len = sizeof(ICMPV6_NA_PKT) - sizeof(ETH_HEADER) - sizeof(IPV6HDR); - na->ipv6.payload_len = htons(icmpv6_len); - na->ipv6.nexthdr = IPPROTO_ICMPV6; - na->ipv6.hop_limit = 255; - NdisMoveMemory( na->ipv6.saddr, IPV6_NS_TARGET_UNICAST, - sizeof(IPV6ADDR) ); - NdisMoveMemory( na->ipv6.daddr, ipv6->saddr, - sizeof(IPV6ADDR) ); - - // ICMPv6 - na->icmpv6.type = ICMPV6_TYPE_NA; - na->icmpv6.code = ICMPV6_CODE_0; - na->icmpv6.checksum = 0; - na->icmpv6.rso_bits = 0x60; // Solicited + Override - NdisZeroMemory( na->icmpv6.reserved, sizeof(na->icmpv6.reserved) ); - NdisMoveMemory( na->icmpv6.target_addr, IPV6_NS_TARGET_UNICAST, - sizeof(IPV6ADDR) ); - - // ICMPv6 option "Target Link Layer Address" - na->icmpv6.opt_type = ICMPV6_OPTION_TLLA; - na->icmpv6.opt_length = ICMPV6_LENGTH_TLLA; - ETH_COPY_NETWORK_ADDRESS( na->icmpv6.target_macaddr, Adapter->m_TapToUser.dest ); - - // calculate and set checksum - icmpv6_csum = icmpv6_checksum ( - (UCHAR*) &(na->icmpv6), - icmpv6_len, - na->ipv6.saddr, - na->ipv6.daddr - ); - - na->icmpv6.checksum = htons( icmpv6_csum ); - - DUMP_PACKET ("HandleIPv6NeighborDiscovery", - (unsigned char *) na, - sizeof (ICMPV6_NA_PKT)); - - IndicateReceivePacket (Adapter, (UCHAR *) na, sizeof (ICMPV6_NA_PKT)); - - MemFree (na, sizeof (ICMPV6_NA_PKT)); - - return TRUE; // all fine -} - -//=================================================== -// Generate an ARP reply message for specific kinds -// ARP queries. -//=================================================== -BOOLEAN -ProcessARP( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in const PARP_PACKET src, - __in const IPADDR adapter_ip, - __in const IPADDR ip_network, - __in const IPADDR ip_netmask, - __in const MACADDR mac - ) -{ - //----------------------------------------------- - // Is this the kind of packet we are looking for? - //----------------------------------------------- - if (src->m_Proto == htons (NDIS_ETH_TYPE_ARP) - && MAC_EQUAL (src->m_MAC_Source, Adapter->PermanentAddress) - && MAC_EQUAL (src->m_ARP_MAC_Source, Adapter->PermanentAddress) - && ETH_IS_BROADCAST(src->m_MAC_Destination) - && src->m_ARP_Operation == htons (ARP_REQUEST) - && src->m_MAC_AddressType == htons (MAC_ADDR_TYPE) - && src->m_MAC_AddressSize == sizeof (MACADDR) - && src->m_PROTO_AddressType == htons (NDIS_ETH_TYPE_IPV4) - && src->m_PROTO_AddressSize == sizeof (IPADDR) - && src->m_ARP_IP_Source == adapter_ip - && (src->m_ARP_IP_Destination & ip_netmask) == ip_network - && src->m_ARP_IP_Destination != adapter_ip) - { - ARP_PACKET *arp = (ARP_PACKET *) MemAlloc (sizeof (ARP_PACKET), TRUE); - if (arp) - { - //---------------------------------------------- - // Initialize ARP reply fields - //---------------------------------------------- - arp->m_Proto = htons (NDIS_ETH_TYPE_ARP); - arp->m_MAC_AddressType = htons (MAC_ADDR_TYPE); - arp->m_PROTO_AddressType = htons (NDIS_ETH_TYPE_IPV4); - arp->m_MAC_AddressSize = sizeof (MACADDR); - arp->m_PROTO_AddressSize = sizeof (IPADDR); - arp->m_ARP_Operation = htons (ARP_REPLY); - - //---------------------------------------------- - // ARP addresses - //---------------------------------------------- - ETH_COPY_NETWORK_ADDRESS (arp->m_MAC_Source, mac); - ETH_COPY_NETWORK_ADDRESS (arp->m_MAC_Destination, Adapter->PermanentAddress); - ETH_COPY_NETWORK_ADDRESS (arp->m_ARP_MAC_Source, mac); - ETH_COPY_NETWORK_ADDRESS (arp->m_ARP_MAC_Destination, Adapter->PermanentAddress); - arp->m_ARP_IP_Source = src->m_ARP_IP_Destination; - arp->m_ARP_IP_Destination = adapter_ip; - - DUMP_PACKET ("ProcessARP", - (unsigned char *) arp, - sizeof (ARP_PACKET)); - - IndicateReceivePacket (Adapter, (UCHAR *) arp, sizeof (ARP_PACKET)); - - MemFree (arp, sizeof (ARP_PACKET)); - } - - return TRUE; - } - else - return FALSE; -} -*/ - -//============================================================= -// CompleteIRP is normally called with an adapter -> userspace -// network packet and an IRP (Pending I/O request) from userspace. -// -// The IRP will normally represent a queued overlapped read -// operation from userspace that is in a wait state. -// -// Use the ethernet packet to satisfy the IRP. -//============================================================= - -VOID -tapCompletePendingReadIrp( - __in PIRP Irp, - __in PTAP_PACKET TapPacket - ) -{ - int offset; - int len; - NTSTATUS status = STATUS_UNSUCCESSFUL; - - ASSERT(Irp); - ASSERT(TapPacket); - - //------------------------------------------- - // While TapPacket always contains a - // full ethernet packet, including the - // ethernet header, in point-to-point mode, - // we only want to return the IPv4 - // component. - //------------------------------------------- - - if (TapPacket->m_SizeFlags & TP_TUN) - { - offset = ETHERNET_HEADER_SIZE; - len = (int) (TapPacket->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE; - } - else - { - offset = 0; - len = (TapPacket->m_SizeFlags & TP_SIZE_MASK); - } - - if (len < 0 || (int) Irp->IoStatus.Information < len) - { - Irp->IoStatus.Information = 0; - Irp->IoStatus.Status = status = STATUS_BUFFER_OVERFLOW; - NOTE_ERROR (); - } - else - { - Irp->IoStatus.Information = len; - Irp->IoStatus.Status = status = STATUS_SUCCESS; - - // Copy packet data - NdisMoveMemory( - Irp->AssociatedIrp.SystemBuffer, - TapPacket->m_Data + offset, - len - ); - } - - // Free the TAP packet - NdisFreeMemory(TapPacket,0,0); - - // Complete the IRP - IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); -} - -VOID -tapProcessSendPacketQueue( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - KIRQL irql; - - // Process the send packet queue - KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql); - - while(Adapter->SendPacketQueue.Count > 0 ) - { - PIRP irp; - PTAP_PACKET tapPacket; - - // Fetch a read IRP - irp = IoCsqRemoveNextIrp( - &Adapter->PendingReadIrpQueue.CsqQueue, - NULL - ); - - if( irp == NULL ) - { - // No IRP to satisfy - break; - } - - // Fetch a queued TAP send packet - tapPacket = tapPacketRemoveHeadLocked( - &Adapter->SendPacketQueue - ); - - ASSERT(tapPacket); - - // BUGBUG!!! Investigate whether release/reacquire can cause - // out-of-order IRP completion. Also, whether user-mode can - // tolerate out-of-order packets. - - // Release packet queue lock while completing the IRP - //KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql); - - // Complete the read IRP from queued TAP send packet. - tapCompletePendingReadIrp(irp,tapPacket); - - // Reqcquire packet queue lock after completing the IRP - //KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql); - } - - KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql); -} - -// Flush the pending send TAP packet queue. -VOID -tapFlushSendPacketQueue( - __in PTAP_ADAPTER_CONTEXT Adapter - ) -{ - KIRQL irql; - - // Process the send packet queue - KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql); - - DEBUGP (("[TAP] tapFlushSendPacketQueue: Flushing %d TAP packets\n", - Adapter->SendPacketQueue.Count)); - - while(Adapter->SendPacketQueue.Count > 0 ) - { - PTAP_PACKET tapPacket; - - // Fetch a queued TAP send packet - tapPacket = tapPacketRemoveHeadLocked( - &Adapter->SendPacketQueue - ); - - ASSERT(tapPacket); - - // Free the TAP packet - NdisFreeMemory(tapPacket,0,0); - } - - KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql); -} - -VOID -tapAdapterTransmit( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in PNET_BUFFER NetBuffer, - __in BOOLEAN DispatchLevel - ) -/*++ - -Routine Description: - - This routine is called to transmit an individual net buffer using a - style similar to the previous NDIS 5 AdapterTransmit function. - - In this implementation adapter state and NB length checks have already - been done before this function has been called. - - The net buffer will be completed by the calling routine after this - routine exits. So, under this design it is necessary to make a deep - copy of frame data in the net buffer. - - This routine creates a flat buffer copy of NB frame data. This is an - unnecessary performance bottleneck. However, the bottleneck is probably - not significant or measurable except for adapters running at 1Gbps or - greater speeds. Since this adapter is currently running at 100Mbps this - defect can be ignored. - - Runs at IRQL <= DISPATCH_LEVEL - -Arguments: - - Adapter Pointer to our adapter context - NetBuffer Pointer to the net buffer to transmit - DispatchLevel TRUE if called at IRQL == DISPATCH_LEVEL - -Return Value: - - None. - - In the Microsoft NDIS 6 architecture there is no per-packet status. - ---*/ -{ - NDIS_STATUS status; - ULONG packetLength; - PTAP_PACKET tapPacket; - PVOID packetData; - - packetLength = NET_BUFFER_DATA_LENGTH(NetBuffer); - - // Allocate TAP packet memory - tapPacket = (PTAP_PACKET )NdisAllocateMemoryWithTagPriority( - Adapter->MiniportAdapterHandle, - TAP_PACKET_SIZE (packetLength), - TAP_PACKET_TAG, - NormalPoolPriority - ); - - if(tapPacket == NULL) - { - DEBUGP (("[TAP] tapAdapterTransmit: TAP packet allocation failed\n")); - return; - } - - tapPacket->m_SizeFlags = (packetLength & TP_SIZE_MASK); - - // - // Reassemble packet contents - // -------------------------- - // NdisGetDataBuffer does most of the work. There are two cases: - // - // 1.) If the NB data was not contiguous it will copy the entire - // NB's data to m_data and return pointer to m_data. - // 2.) If the NB data was contiguous it returns a pointer to the - // first byte of the contiguous data instead of a pointer to m_Data. - // In this case the data will not have been copied to m_Data. Copy - // to m_Data will need to be done in an extra step. - // - // Case 1.) is the most likely in normal operation. - // - packetData = NdisGetDataBuffer(NetBuffer,packetLength,tapPacket->m_Data,1,0); - - if(packetData == NULL) - { - DEBUGP (("[TAP] tapAdapterTransmit: Could not get packet data\n")); - - NdisFreeMemory(tapPacket,0,0); - - return; - } - - if(packetData != tapPacket->m_Data) - { - // Packet data was contiguous and not yet copied to m_Data. - NdisMoveMemory(tapPacket->m_Data,packetData,packetLength); - } - - DUMP_PACKET ("AdapterTransmit", tapPacket->m_Data, packetLength); - - //===================================================== - // If IPv4 packet, check whether or not packet - // was truncated. - //===================================================== -#if PACKET_TRUNCATION_CHECK - IPv4PacketSizeVerify( - tapPacket->m_Data, - packetLength, - FALSE, - "TX", - &Adapter->m_TxTrunc - ); -#endif - - //===================================================== - // Are we running in DHCP server masquerade mode? - // - // If so, catch both DHCP requests and ARP queries - // to resolve the address of our virtual DHCP server. - //===================================================== -#if 0 - if (Adapter->m_dhcp_enabled) - { - const ETH_HEADER *eth = (ETH_HEADER *) tapPacket->m_Data; - const IPHDR *ip = (IPHDR *) (tapPacket->m_Data + sizeof (ETH_HEADER)); - const UDPHDR *udp = (UDPHDR *) (tapPacket->m_Data + sizeof (ETH_HEADER) + sizeof (IPHDR)); - - // ARP packet? - if (packetLength == sizeof (ARP_PACKET) - && eth->proto == htons (NDIS_ETH_TYPE_ARP) - && Adapter->m_dhcp_server_arp - ) - { - if (ProcessARP( - Adapter, - (PARP_PACKET) tapPacket->m_Data, - Adapter->m_dhcp_addr, - Adapter->m_dhcp_server_ip, - ~0, - Adapter->m_dhcp_server_mac) - ) - { - goto no_queue; - } - } - - // DHCP packet? - else if (packetLength >= sizeof (ETH_HEADER) + sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) - && eth->proto == htons (NDIS_ETH_TYPE_IPV4) - && ip->version_len == 0x45 // IPv4, 20 byte header - && ip->protocol == IPPROTO_UDP - && udp->dest == htons (BOOTPS_PORT) - ) - { - const DHCP *dhcp = (DHCP *) (tapPacket->m_Data - + sizeof (ETH_HEADER) - + sizeof (IPHDR) - + sizeof (UDPHDR)); - - const int optlen = packetLength - - sizeof (ETH_HEADER) - - sizeof (IPHDR) - - sizeof (UDPHDR) - - sizeof (DHCP); - - if (optlen > 0) // we must have at least one DHCP option - { - if (ProcessDHCP (Adapter, eth, ip, udp, dhcp, optlen)) - { - goto no_queue; - } - } - else - { - goto no_queue; - } - } - } -#endif - - //=============================================== - // In Point-To-Point mode, check to see whether - // packet is ARP (handled) or IPv4 (sent to app). - // IPv6 packets are inspected for neighbour discovery - // (to be handled locally), and the rest is forwarded - // all other protocols are dropped - //=============================================== -#if 0 - if (Adapter->m_tun) - { - ETH_HEADER *e; - - e = (ETH_HEADER *) tapPacket->m_Data; - - switch (ntohs (e->proto)) - { - case NDIS_ETH_TYPE_ARP: - - // Make sure that packet is the right size for ARP. - if (packetLength != sizeof (ARP_PACKET)) - { - goto no_queue; - } - - ProcessARP ( - Adapter, - (PARP_PACKET) tapPacket->m_Data, - Adapter->m_localIP, - Adapter->m_remoteNetwork, - Adapter->m_remoteNetmask, - Adapter->m_TapToUser.dest - ); - - default: - goto no_queue; - - case NDIS_ETH_TYPE_IPV4: - - // Make sure that packet is large enough to be IPv4. - if (packetLength < (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)) - { - goto no_queue; - } - - // Only accept directed packets, not broadcasts. - if (memcmp (e, &Adapter->m_TapToUser, ETHERNET_HEADER_SIZE)) - { - goto no_queue; - } - - // Packet looks like IPv4, queue it. :-) - tapPacket->m_SizeFlags |= TP_TUN; - break; - - case NDIS_ETH_TYPE_IPV6: - // Make sure that packet is large enough to be IPv6. - if (packetLength < (ETHERNET_HEADER_SIZE + IPV6_HEADER_SIZE)) - { - goto no_queue; - } - - // Broadcasts and multicasts are handled specially - // (to be implemented) - - // Neighbor discovery packets to fe80::8 are special - // OpenVPN sets this next-hop to signal "handled by tapdrv" - if ( HandleIPv6NeighborDiscovery(Adapter,tapPacket->m_Data) ) - { - goto no_queue; - } - - // Packet looks like IPv6, queue it. :-) - tapPacket->m_SizeFlags |= TP_TUN; - } - } -#endif - - //=============================================== - // Push packet onto queue to wait for read from - // userspace. - //=============================================== - if(tapAdapterReadAndWriteReady(Adapter)) - { - tapPacketQueueInsertTail(&Adapter->SendPacketQueue,tapPacket); - } - else - { - // - // Tragedy. All this work and the packet is of no use... - // - NdisFreeMemory(tapPacket,0,0); - } - - // Return after queuing or freeing TAP packet. - return; - - // Free TAP packet without queuing. -no_queue: - if(tapPacket != NULL ) - { - NdisFreeMemory(tapPacket,0,0); - } - -exit_success: - return; -} - -VOID -tapSendNetBufferListsComplete( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in PNET_BUFFER_LIST NetBufferLists, - __in NDIS_STATUS SendCompletionStatus, - __in BOOLEAN DispatchLevel - ) -{ - PNET_BUFFER_LIST currentNbl; - PNET_BUFFER_LIST nextNbl = NULL; - ULONG sendCompleteFlags = 0; - - for ( - currentNbl = NetBufferLists; - currentNbl != NULL; - currentNbl = nextNbl - ) - { - ULONG frameType; - ULONG netBufferCount; - ULONG byteCount; - - nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); - - // Set NBL completion status. - NET_BUFFER_LIST_STATUS(currentNbl) = SendCompletionStatus; - - // Fetch first NBs frame type. All linked NBs will have same type. - frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(currentNbl)); - - // Fetch statistics for all NBs linked to the NB. - netBufferCount = tapGetNetBufferCountsFromNetBufferList( - currentNbl, - &byteCount - ); - - // Update statistics by frame type - if(SendCompletionStatus == NDIS_STATUS_SUCCESS) - { - switch(frameType) - { - case NDIS_PACKET_TYPE_DIRECTED: - Adapter->FramesTxDirected += netBufferCount; - Adapter->BytesTxDirected += byteCount; - break; - - case NDIS_PACKET_TYPE_BROADCAST: - Adapter->FramesTxBroadcast += netBufferCount; - Adapter->BytesTxBroadcast += byteCount; - break; - - case NDIS_PACKET_TYPE_MULTICAST: - Adapter->FramesTxMulticast += netBufferCount; - Adapter->BytesTxMulticast += byteCount; - break; - - default: - ASSERT(FALSE); - break; - } - } - else - { - // Transmit error. - Adapter->TransmitFailuresOther += netBufferCount; - } - - currentNbl = nextNbl; - } - - if(DispatchLevel) - { - sendCompleteFlags |= NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL; - } - - // Complete the NBLs - NdisMSendNetBufferListsComplete( - Adapter->MiniportAdapterHandle, - NetBufferLists, - sendCompleteFlags - ); -} - -BOOLEAN -tapNetBufferListNetBufferLengthsValid( - __in PTAP_ADAPTER_CONTEXT Adapter, - __in PNET_BUFFER_LIST NetBufferLists - ) -/*++ - -Routine Description: - - Scan all NBLs and their linked NBs for valid lengths. - - Fairly absurd to find and packets with bogus lengths, but wise - to check anyway. If ANY packet has a bogus length, then abort the - entire send. - - The only time that one might see this check fail might be during - HCK driver testing. The HKC test might send oversize packets to - determine if the miniport can gracefully deal with them. - - This check is fairly fast. Unlike NDIS 5 packets, fetching NDIS 6 - packets lengths do not require any computation. - -Arguments: - - Adapter Pointer to our adapter context - NetBufferLists Head of a list of NBLs to examine - -Return Value: - - Returns TRUE if all NBs have reasonable lengths. - Otherwise, returns FALSE. - ---*/ -{ - PNET_BUFFER_LIST currentNbl; - - currentNbl = NetBufferLists; - - while (currentNbl) - { - PNET_BUFFER_LIST nextNbl; - PNET_BUFFER currentNb; - - // Locate next NBL - nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); - - // Locate first NB (aka "packet") - currentNb = NET_BUFFER_LIST_FIRST_NB(currentNbl); - - // - // Process all NBs linked to this NBL - // - while(currentNb) - { - PNET_BUFFER nextNb; - ULONG packetLength; - - // Locate next NB - nextNb = NET_BUFFER_NEXT_NB(currentNb); - - packetLength = NET_BUFFER_DATA_LENGTH(currentNb); - - // Minimum packet size is size of Ethernet plus IPv4 headers. - ASSERT(packetLength >= (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)); - - if(packetLength < (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)) - { - return FALSE; - } - - // Maximum size should be Ethernet header size plus MTU plus modest pad for - // VLAN tag. - ASSERT( packetLength <= (ETHERNET_HEADER_SIZE + VLAN_TAG_SIZE + Adapter->MtuSize)); - - if(packetLength > (ETHERNET_HEADER_SIZE + VLAN_TAG_SIZE + Adapter->MtuSize)) - { - return FALSE; - } - - // Move to next NB - currentNb = nextNb; - } - - // Move to next NBL - currentNbl = nextNbl; - } - - return TRUE; -} - -VOID -AdapterSendNetBufferLists( - __in NDIS_HANDLE MiniportAdapterContext, - __in PNET_BUFFER_LIST NetBufferLists, - __in NDIS_PORT_NUMBER PortNumber, - __in ULONG SendFlags - ) -/*++ - -Routine Description: - - Send Packet Array handler. Called by NDIS whenever a protocol - bound to our miniport sends one or more packets. - - The input packet descriptor pointers have been ordered according - to the order in which the packets should be sent over the network - by the protocol driver that set up the packet array. The NDIS - library preserves the protocol-determined ordering when it submits - each packet array to MiniportSendPackets - - As a deserialized driver, we are responsible for holding incoming send - packets in our internal queue until they can be transmitted over the - network and for preserving the protocol-determined ordering of packet - descriptors incoming to its MiniportSendPackets function. - A deserialized miniport driver must complete each incoming send packet - with NdisMSendComplete, and it cannot call NdisMSendResourcesAvailable. - - Runs at IRQL <= DISPATCH_LEVEL - -Arguments: - - MiniportAdapterContext Pointer to our adapter - NetBufferLists Head of a list of NBLs to send - PortNumber A miniport adapter port. Default is 0. - SendFlags Additional flags for the send operation - -Return Value: - - None. Write status directly into each NBL with the NET_BUFFER_LIST_STATUS - macro. - ---*/ -{ - NDIS_STATUS status; - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - BOOLEAN DispatchLevel = (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL); - PNET_BUFFER_LIST currentNbl; - BOOLEAN validNbLengths; - - UNREFERENCED_PARAMETER(NetBufferLists); - UNREFERENCED_PARAMETER(PortNumber); - UNREFERENCED_PARAMETER(SendFlags); - - ASSERT(PortNumber == 0); // Only the default port is supported - - // - // Can't process sends if TAP device is not open. - // ---------------------------------------------- - // Just perform a "lying send" and return packets as if they - // were successfully sent. - // - if(adapter->TapFileObject == NULL) - { - // - // Complete all NBLs and return if adapter not ready. - // - tapSendNetBufferListsComplete( - adapter, - NetBufferLists, - NDIS_STATUS_SUCCESS, - DispatchLevel - ); - - return; - } - - // - // Check Adapter send/receive ready state. - // - status = tapAdapterSendAndReceiveReady(adapter); - - if(status != NDIS_STATUS_SUCCESS) - { - // - // Complete all NBLs and return if adapter not ready. - // - tapSendNetBufferListsComplete( - adapter, - NetBufferLists, - status, - DispatchLevel - ); - - return; - } - - // - // Scan all NBLs and linked packets for valid lengths. - // --------------------------------------------------- - // If _ANY_ NB length is invalid, then fail the entire send operation. - // - // BUGBUG!!! Perhaps this should be less agressive. Fail only individual - // NBLs... - // - // If length check is valid, then TAP_PACKETS can be safely allocated - // and processed for all NBs being sent. - // - validNbLengths = tapNetBufferListNetBufferLengthsValid( - adapter, - NetBufferLists - ); - - if(!validNbLengths) - { - // - // Complete all NBLs and return if and NB length is invalid. - // - tapSendNetBufferListsComplete( - adapter, - NetBufferLists, - NDIS_STATUS_INVALID_LENGTH, - DispatchLevel - ); - - return; - } - - // - // Process each NBL individually - // - currentNbl = NetBufferLists; - - while (currentNbl) - { - PNET_BUFFER_LIST nextNbl; - PNET_BUFFER currentNb; - - // Locate next NBL - nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); - - // Locate first NB (aka "packet") - currentNb = NET_BUFFER_LIST_FIRST_NB(currentNbl); - - // Transmit all NBs linked to this NBL - while(currentNb) - { - PNET_BUFFER nextNb; - - // Locate next NB - nextNb = NET_BUFFER_NEXT_NB(currentNb); - - // Transmit the NB - tapAdapterTransmit(adapter,currentNb,DispatchLevel); - - // Move to next NB - currentNb = nextNb; - } - - // Move to next NBL - currentNbl = nextNbl; - } - - // Complete all NBLs - tapSendNetBufferListsComplete( - adapter, - NetBufferLists, - NDIS_STATUS_SUCCESS, - DispatchLevel - ); - - // Attempt to complete pending read IRPs from pending TAP - // send packet queue. - tapProcessSendPacketQueue(adapter); -} - -VOID -AdapterCancelSend( - __in NDIS_HANDLE MiniportAdapterContext, - __in PVOID CancelId - ) -{ - PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; - - // - // This miniport completes its sends quickly, so it isn't strictly - // neccessary to implement MiniportCancelSend. - // - // If we did implement it, we'd have to walk the Adapter->SendWaitList - // and look for any NB that points to a NBL where the CancelId matches - // NDIS_GET_NET_BUFFER_LIST_CANCEL_ID(Nbl). For any NB that so matches, - // we'd remove the NB from the SendWaitList and set the NBL's status to - // NDIS_STATUS_SEND_ABORTED, then complete the NBL. - // -} - -// IRP_MJ_READ callback. -NTSTATUS -TapDeviceRead( - PDEVICE_OBJECT DeviceObject, - PIRP Irp - ) -{ - NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success - PIO_STACK_LOCATION irpSp;// Pointer to current stack location - PTAP_ADAPTER_CONTEXT adapter = NULL; - - PAGED_CODE(); - - irpSp = IoGetCurrentIrpStackLocation( Irp ); - - // - // Fetch adapter context for this device. - // -------------------------------------- - // Adapter pointer was stashed in FsContext when handle was opened. - // - adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; - - ASSERT(adapter); - - // - // Sanity checks on state variables - // - if (!tapAdapterReadAndWriteReady(adapter)) - { - //DEBUGP (("[%s] Interface is down in IRP_MJ_READ\n", - // MINIPORT_INSTANCE_ID (adapter))); - //NOTE_ERROR(); - - Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED; - Irp->IoStatus.Information = 0; - IoCompleteRequest (Irp, IO_NO_INCREMENT); - - return ntStatus; - } - - // Save IRP-accessible copy of buffer length - Irp->IoStatus.Information = irpSp->Parameters.Read.Length; - - if (Irp->MdlAddress == NULL) - { - DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_READ\n", - MINIPORT_INSTANCE_ID (adapter))); - - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; - Irp->IoStatus.Information = 0; - IoCompleteRequest (Irp, IO_NO_INCREMENT); - - return ntStatus; - } - - if ((Irp->AssociatedIrp.SystemBuffer - = MmGetSystemAddressForMdlSafe( - Irp->MdlAddress, - NormalPagePriority - ) ) == NULL - ) - { - DEBUGP (("[%s] Could not map address in IRP_MJ_READ\n", - MINIPORT_INSTANCE_ID (adapter))); - - NOTE_ERROR(); - Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES; - Irp->IoStatus.Information = 0; - IoCompleteRequest (Irp, IO_NO_INCREMENT); - - return ntStatus; - } - - // BUGBUG!!! Use RemoveLock??? - - // - // Queue the IRP and return STATUS_PENDING. - // ---------------------------------------- - // Note: IoCsqInsertIrp marks the IRP pending. - // - - // BUGBUG!!! NDIS 5 implementation has IRP_QUEUE_SIZE of 16 and - // does not queue IRP if this capacity is exceeded. - // - // Is this needed??? - // - IoCsqInsertIrp(&adapter->PendingReadIrpQueue.CsqQueue, Irp, NULL); - - // Attempt to complete pending read IRPs from pending TAP - // send packet queue. - tapProcessSendPacketQueue(adapter); - - ntStatus = STATUS_PENDING; - - return ntStatus; -} - diff --git a/zto/windows/TapDriver6/types.h b/zto/windows/TapDriver6/types.h deleted file mode 100644 index acea175..0000000 --- a/zto/windows/TapDriver6/types.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * TAP-Windows -- A kernel driver to provide virtual tap - * device functionality on Windows. - * - * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. - * - * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TAP_TYPES_DEFINED -#define TAP_TYPES_DEFINED - -//typedef -//struct _Queue -//{ -// ULONG base; -// ULONG size; -// ULONG capacity; -// ULONG max_size; -// PVOID data[]; -//} Queue; - -//typedef struct _TAP_PACKET; - -//typedef struct _TapExtension -//{ -// // TAP device object and packet queues -// Queue *m_PacketQueue, *m_IrpQueue; -// PDEVICE_OBJECT m_TapDevice; -// NDIS_HANDLE m_TapDeviceHandle; -// ULONG TapFileIsOpen; -// -// // Used to lock packet queues -// NDIS_SPIN_LOCK m_QueueLock; -// BOOLEAN m_AllocatedSpinlocks; -// -// // Used to bracket open/close -// // state changes. -// MUTEX m_OpenCloseMutex; -// -// // True if device has been permanently halted -// BOOLEAN m_Halt; -// -// // TAP device name -// unsigned char *m_TapName; -// UNICODE_STRING m_UnicodeLinkName; -// BOOLEAN m_CreatedUnicodeLinkName; -// -// // Used for device status ioctl only -// const char *m_LastErrorFilename; -// int m_LastErrorLineNumber; -// LONG TapFileOpenCount; -// -// // Flags -// BOOLEAN TapDeviceCreated; -// BOOLEAN m_CalledTapDeviceFreeResources; -// -// // DPC queue for deferred packet injection -// BOOLEAN m_InjectDpcInitialized; -// KDPC m_InjectDpc; -// NDIS_SPIN_LOCK m_InjectLock; -// Queue *m_InjectQueue; -//} -//TapExtension, *TapExtensionPointer; - -typedef struct _InjectPacket - { -# define INJECT_PACKET_SIZE(data_size) (sizeof (InjectPacket) + (data_size)) -# define INJECT_PACKET_FREE(ib) NdisFreeMemory ((ib), INJECT_PACKET_SIZE ((ib)->m_Size), 0) - ULONG m_Size; - UCHAR m_Data []; // m_Data must be the last struct member - } -InjectPacket, *InjectPacketPointer; - -#endif diff --git a/zto/windows/TapDriver6/zttap300.inf b/zto/windows/TapDriver6/zttap300.inf deleted file mode 100644 index f901b13..0000000 --- a/zto/windows/TapDriver6/zttap300.inf +++ /dev/null @@ -1,143 +0,0 @@ -; -; ZeroTier One Virtual Network Port NDIS6 Driver -; -; Based on the OpenVPN tap-windows6 driver version 9.21.1 git -; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3. -; See: https://github.com/OpenVPN/tap-windows6 -; -; Modified by ZeroTier, Inc. - https://www.zerotier.com/ -; -; (1) Comment out 'tun' functionality and related features such as DHCP -; emulation, since we don't use any of that. Just want straight 'tap'. -; (2) Added custom IOCTL to enumerate L2 multicast memberships. -; (3) Increase maximum number of multicast memberships to 128. -; (4) Set default and max device MTU to 2800. -; (5) Rename/rebrand driver as ZeroTier network port driver. -; -; Original copyright below. Modifications released under GPLv2 as well. -; -; **************************************************************************** -; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * -; * This program is free software; you can redistribute it and/or modify * -; * it under the terms of the GNU General Public License version 2 * -; * as published by the Free Software Foundation. * -; **************************************************************************** -; - -[Version] -Signature = "$Windows NT$" -CatalogFile = zttap300.cat -ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} -Provider = %Provider% -Class = Net -DriverVer=04/25/2015,3.00.00.0 - -[Strings] -DeviceDescription = "ZeroTier One Virtual Port" -Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat. - -; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back! -[Manufacturer] -%Provider%=zttap300,NTamd64 - -[zttap300] -%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated -%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy - -[zttap300.NTamd64] -%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated -%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy - -;----------------- Characteristics ------------ -; NCF_PHYSICAL = 0x04 -; NCF_VIRTUAL = 0x01 -; NCF_SOFTWARE_ENUMERATED = 0x02 -; NCF_HIDDEN = 0x08 -; NCF_NO_SERVICE = 0x10 -; NCF_HAS_UI = 0x80 -;----------------- Characteristics ------------ -[zttap300.ndi] -CopyFiles = zttap300.driver, zttap300.files -AddReg = zttap300.reg -AddReg = zttap300.params.reg -Characteristics = 0x81 -*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD -*MediaType = 0x0 ; NdisMedium802_3 -*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 - -[zttap300.ndi.Services] -AddService = zttap300, 2, zttap300.service - -[zttap300.reg] -HKR, Ndi, Service, 0, "zttap300" -HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows. -HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" -HKR, , Manufacturer, 0, "%Provider%" -HKR, , ProductName, 0, "%DeviceDescription%" - -[zttap300.params.reg] -HKR, Ndi\params\MTU, ParamDesc, 0, "MTU" -HKR, Ndi\params\MTU, Type, 0, "int" -HKR, Ndi\params\MTU, Default, 0, "2800" -HKR, Ndi\params\MTU, Optional, 0, "0" -HKR, Ndi\params\MTU, Min, 0, "100" -HKR, Ndi\params\MTU, Max, 0, "2800" -HKR, Ndi\params\MTU, Step, 0, "1" -HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status" -HKR, Ndi\params\MediaStatus, Type, 0, "enum" -HKR, Ndi\params\MediaStatus, Default, 0, "0" -HKR, Ndi\params\MediaStatus, Optional, 0, "0" -HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled" -HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected" -HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address" -HKR, Ndi\params\MAC, Type, 0, "edit" -HKR, Ndi\params\MAC, Optional, 0, "1" -HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access" -HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum" -HKR, Ndi\params\AllowNonAdmin, Default, 0, "0" -HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0" -HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed" -HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed" - -;---------- Service Type ------------- -; SERVICE_KERNEL_DRIVER = 0x01 -; SERVICE_WIN32_OWN_PROCESS = 0x10 -;---------- Service Type ------------- - -;---------- Start Mode --------------- -; SERVICE_BOOT_START = 0x0 -; SERVICE_SYSTEM_START = 0x1 -; SERVICE_AUTO_START = 0x2 -; SERVICE_DEMAND_START = 0x3 -; SERVICE_DISABLED = 0x4 -;---------- Start Mode --------------- - -[zttap300.service] -DisplayName = %DeviceDescription% -ServiceType = 1 -StartType = 3 -ErrorControl = 1 -LoadOrderGroup = NDIS -ServiceBinary = %12%\zttap300.sys - -;----------------- Copy Flags ------------ -; COPYFLG_NOSKIP = 0x02 -; COPYFLG_NOVERSIONCHECK = 0x04 -;----------------- Copy Flags ------------ - -[SourceDisksNames] -1 = %DeviceDescription%, zttap300.sys - -[SourceDisksFiles] -zttap300.sys = 1 - -[DestinationDirs] -zttap300.files = 11 -zttap300.driver = 12 - -[zttap300.files] -; - -[zttap300.driver] -zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK - diff --git a/zto/windows/WinUI/APIHandler.cs b/zto/windows/WinUI/APIHandler.cs deleted file mode 100644 index 419a11c..0000000 --- a/zto/windows/WinUI/APIHandler.cs +++ /dev/null @@ -1,419 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Net; -using System.IO; -using System.Windows; -using Newtonsoft.Json; -using System.Diagnostics; - -namespace WinUI -{ - - - public class APIHandler - { - private string authtoken; - - private string url = null; - - private static volatile APIHandler instance; - private static object syncRoot = new Object(); - - public delegate void NetworkListCallback(List networks); - public delegate void StatusCallback(ZeroTierStatus status); - - public static APIHandler Instance - { - get - { - if (instance == null) - { - lock (syncRoot) - { - if (instance == null) - { - if (!initHandler()) - { - return null; - } - } - } - } - - return instance; - } - } - - private static bool initHandler(bool resetToken = false) - { - String localZtDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\ZeroTier\\One"; - String globalZtDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\ZeroTier\\One"; - - String authToken = ""; - Int32 port = 9993; - - if (resetToken) - { - instance = null; - if (File.Exists(localZtDir + "\\authtoken.secret")) - { - File.Delete(localZtDir + "\\authtoken.secret"); - } - - if (File.Exists(localZtDir + "\\zerotier-one.port")) - { - File.Delete(localZtDir + "\\zerotier-one.port"); - } - } - - if (!File.Exists(localZtDir + "\\authtoken.secret") || !File.Exists(localZtDir + "\\zerotier-one.port")) - { - // launch external process to copy file into place - String curPath = System.Reflection.Assembly.GetEntryAssembly().Location; - int index = curPath.LastIndexOf("\\"); - curPath = curPath.Substring(0, index); - ProcessStartInfo startInfo = new ProcessStartInfo(curPath + "\\copyutil.exe", "\""+globalZtDir+"\"" + " " + "\""+localZtDir+"\""); - startInfo.Verb = "runas"; - - - var process = Process.Start(startInfo); - process.WaitForExit(); - } - - authToken = readAuthToken(localZtDir + "\\authtoken.secret"); - - if ((authToken == null) || (authToken.Length <= 0)) - { - MessageBox.Show("Unable to read ZeroTier One authtoken", "ZeroTier One"); - return false; - } - - port = readPort(localZtDir + "\\zerotier-one.port"); - instance = new APIHandler(port, authToken); - return true; - } - - private static String readAuthToken(String path) - { - String authToken = ""; - - if (File.Exists(path)) - { - try - { - byte[] tmp = File.ReadAllBytes(path); - authToken = System.Text.Encoding.UTF8.GetString(tmp).Trim(); - } - catch - { - MessageBox.Show("Unable to read ZeroTier One Auth Token from:\r\n" + path, "ZeroTier One"); - } - } - - return authToken; - } - - private static Int32 readPort(String path) - { - Int32 port = 9993; - - try - { - byte[] tmp = File.ReadAllBytes(path); - port = Int32.Parse(System.Text.Encoding.ASCII.GetString(tmp).Trim()); - if ((port <= 0) || (port > 65535)) - port = 9993; - } - catch - { - } - - return port; - } - - private APIHandler() - { - url = "http://127.0.0.1:9993"; - } - - public APIHandler(int port, string authtoken) - { - url = "http://127.0.0.1:" + port; - this.authtoken = authtoken; - } - - - - public void GetStatus(StatusCallback cb) - { - var request = WebRequest.Create(url + "/status" + "?auth=" + authtoken) as HttpWebRequest; - if (request != null) - { - request.Method = "GET"; - request.ContentType = "application/json"; - } - - try - { - var httpResponse = (HttpWebResponse)request.GetResponse(); - if (httpResponse.StatusCode == HttpStatusCode.OK) - { - using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) - { - var responseText = streamReader.ReadToEnd(); - - ZeroTierStatus status = null; - try - { - status = JsonConvert.DeserializeObject(responseText); - } - catch (JsonReaderException e) - { - Console.WriteLine(e.ToString()); - } - cb(status); - } - } - else if (httpResponse.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - } - catch (System.Net.Sockets.SocketException) - { - cb(null); - } - catch (System.Net.WebException e) - { - if (((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - else - { - cb(null); - } - } - } - - - - public void GetNetworks(NetworkListCallback cb) - { - var request = WebRequest.Create(url + "/network" + "?auth=" + authtoken) as HttpWebRequest; - if (request == null) - { - cb(null); - } - - request.Method = "GET"; - request.ContentType = "application/json"; - request.Timeout = 10000; - - try - { - var httpResponse = (HttpWebResponse)request.GetResponse(); - - if (httpResponse.StatusCode == HttpStatusCode.OK) - { - using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) - { - var responseText = streamReader.ReadToEnd(); - - List networkList = null; - try - { - networkList = JsonConvert.DeserializeObject>(responseText); - foreach (ZeroTierNetwork n in networkList) - { - // all networks received via JSON are connected by definition - n.IsConnected = true; - } - } - catch (JsonReaderException e) - { - Console.WriteLine(e.ToString()); - } - cb(networkList); - } - } - else if (httpResponse.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - } - catch (System.Net.Sockets.SocketException) - { - cb(null); - } - catch (System.Net.WebException e) - { - if (((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - else - { - cb(null); - } - } - } - - public void JoinNetwork(string nwid, bool allowManaged = true, bool allowGlobal = false, bool allowDefault = false) - { - var request = WebRequest.Create(url + "/network/" + nwid + "?auth=" + authtoken) as HttpWebRequest; - if (request == null) - { - return; - } - - request.Method = "POST"; - request.ContentType = "applicaiton/json"; - request.Timeout = 10000; - try - { - using (var streamWriter = new StreamWriter(((HttpWebRequest)request).GetRequestStream())) - { - string json = "{\"allowManaged\":" + (allowManaged ? "true" : "false") + "," + - "\"allowGlobal\":" + (allowGlobal ? "true" : "false") + "," + - "\"allowDefault\":" + (allowDefault ? "true" : "false") + "}"; - streamWriter.Write(json); - streamWriter.Flush(); - streamWriter.Close(); - } - } - catch (System.Net.WebException) - { - MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service."); - return; - } - - try - { - var httpResponse = (HttpWebResponse)request.GetResponse(); - - if (httpResponse.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - else if (httpResponse.StatusCode != HttpStatusCode.OK) - { - Console.WriteLine("Error sending join network message"); - } - } - catch (System.Net.Sockets.SocketException) - { - MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service."); - } - catch (System.Net.WebException e) - { - if (((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service."); - } - } - - public void LeaveNetwork(string nwid) - { - var request = WebRequest.Create(url + "/network/" + nwid + "?auth=" + authtoken) as HttpWebRequest; - if (request == null) - { - return; - } - - request.Method = "DELETE"; - request.Timeout = 10000; - - try - { - var httpResponse = (HttpWebResponse)request.GetResponse(); - - if (httpResponse.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - else if (httpResponse.StatusCode != HttpStatusCode.OK) - { - Console.WriteLine("Error sending leave network message"); - } - } - catch (System.Net.Sockets.SocketException) - { - MessageBox.Show("Error Leaving Network: Cannot connect to ZeroTier service."); - } - catch (System.Net.WebException e) - { - if (((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - MessageBox.Show("Error Leaving Network: Cannot connect to ZeroTier service."); - } - catch - { - Console.WriteLine("Error leaving network: Unknown error"); - } - } - - public delegate void PeersCallback(List peers); - - public void GetPeers(PeersCallback cb) - { - var request = WebRequest.Create(url + "/peer" + "?auth=" + authtoken) as HttpWebRequest; - if (request == null) - { - cb(null); - } - - request.Method = "GET"; - request.ContentType = "application/json"; - - try - { - var httpResponse = (HttpWebResponse)request.GetResponse(); - if (httpResponse.StatusCode == HttpStatusCode.OK) - { - using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) - { - var responseText = streamReader.ReadToEnd(); - //Console.WriteLine(responseText); - List peerList = null; - try - { - peerList = JsonConvert.DeserializeObject>(responseText); - } - catch (JsonReaderException e) - { - Console.WriteLine(e.ToString()); - } - cb(peerList); - } - } - else if (httpResponse.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - } - catch (System.Net.Sockets.SocketException) - { - cb(null); - } - catch (System.Net.WebException e) - { - if (((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - else - { - cb(null); - } - } - } - } -} diff --git a/zto/windows/WinUI/AboutView.xaml b/zto/windows/WinUI/AboutView.xaml deleted file mode 100644 index b6be235..0000000 --- a/zto/windows/WinUI/AboutView.xaml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/zto/windows/WinUI/AboutView.xaml.cs b/zto/windows/WinUI/AboutView.xaml.cs deleted file mode 100644 index 9c48493..0000000 --- a/zto/windows/WinUI/AboutView.xaml.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace WinUI -{ - /// - /// Interaction logic for AboutView.xaml - /// - public partial class AboutView : Window - { - public AboutView() - { - InitializeComponent(); - } - - private void Hyperlink_MouseLeftButtonDown(object sender, RequestNavigateEventArgs e) - { - var hyperlink = (Hyperlink)sender; - Process.Start(hyperlink.NavigateUri.ToString()); - } - } -} diff --git a/zto/windows/WinUI/App.config b/zto/windows/WinUI/App.config deleted file mode 100644 index 8e15646..0000000 --- a/zto/windows/WinUI/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/zto/windows/WinUI/App.xaml b/zto/windows/WinUI/App.xaml deleted file mode 100644 index 12ed85f..0000000 --- a/zto/windows/WinUI/App.xaml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - diff --git a/zto/windows/WinUI/App.xaml.cs b/zto/windows/WinUI/App.xaml.cs deleted file mode 100644 index 53ef2f6..0000000 --- a/zto/windows/WinUI/App.xaml.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; -using Hardcodet.Wpf.TaskbarNotification; - -namespace WinUI -{ - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - private TaskbarIcon tb; - - private void InitApplication() - { - tb = (TaskbarIcon)FindResource("NotifyIcon"); - tb.Visibility = Visibility.Visible; - } - } -} diff --git a/zto/windows/WinUI/JoinNetworkView.xaml b/zto/windows/WinUI/JoinNetworkView.xaml deleted file mode 100644 index 1cd1e98..0000000 --- a/zto/windows/WinUI/JoinNetworkView.xaml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - -
- -

This page is being served from a Docker container with its own private TCP/IP microservice.

- -

-It's connected to a virtual network, but if you "docker exec" into it and look around you won't find any special devices. No special privileges or configuration changes on the Docker host were needed. Everything is completely "stock" and completely self-contained. -

- -

-There's nothing special about the web server. It's just Apache. There's nothing special about the Linux image. It's based on a regular Fedora Docker base image. Other than Apache, the only thing this image contains is the ZeroTier network containers microservice and dynamic library. -

- -

-When Apache is run, our launcher script configures it to load a special dynamic library. This library intercepts calls to the Linux C networking API, redirecting network I/O to our private network stack microservice instead of the standard Linux kernel network path. This microservice takes care of the rest, automatically encapsulating traffic and sending it over the virtual network instead of the physical. -

- -

-It's a bit like how networking would work on a microkernel: modular, composable, portable, and independent. -

- -

-SDK allows a Docker (or LXC, CoreOS/rkt, runc, OpenVZ, SmartOS/Triton, bocker, or even just bare metal Linux) system to connect to virtual networks without requiring any special permissions or special configuration on the host node. Processes inside the container don't even need to run with root permissions. It's 100% user-space, making it ideal for multi-tenant deployments or any other situation where modifying the configuration of the host node is impossible or just inconvenient. -

- -

-Once properly tuned and optimized, SDK also has the potential to be much faster than tun/tap or pcap based network overlays. It imposes only a single context switch from application/service to virtual network microservice as opposed to at least four for tun/tap and pcap-based solutions, since the latter require two trips through the kernel network stack. We believe it may be possible to approach or even equal the performance of VXLAN/IPSec or other fully kernel-mode configurations, but with the ease and total independence of a fully container-based solution. -

- -

-We created this container image to show you a preview of one of the projects we've been working on at ZeroTier. We still have a good deal of packaging, testing, and performance optimization work to do before SDK will be ready for a real public beta release. Follow the blog or @zerotier for updates and announcements. -

- -

-P.S. If you want to use ZeroTier in Docker today, you can do it with the same ZeroTier One endpoint service you're using to access this network. The only catch is that you have to launch your containers with "--device=/dev/net/tun --cap-add=NET_ADMIN". SDK eliminates the need for these special options. -

- -